Hide global mouse cursor on macOS dock

I'm working on a macOS background app which hide mouse cursor for all apps. I use eventTap to listen keystroke, then call CGDisplayHideCursor and SetsCursorInBackground trick to hide cursor when specific key is down. It works on most case, except one - when mouse hover on dock.

I'm not sure why mouse cursor can't be hidden when over dock, maybe some kind of elevated privilege? Is there a way to hide it?

Thanks.

Answered by DTS Engineer in 789080022

I'm not sure why mouse cursor can't be hidden when over dock

Because of how critical the dock is to normal system navigation, there is special logic in the window server that ensure the Dock maintains cursor control whenever it would be the active target. That ends up blocking "SetsCursorInBackground".

maybe some kind of elevated privilege?

No, at least not in the root/security sense. Generally speaking, the window server just doesn't work in those terms. What you will see (and this is an example of this) is that it does have a large number of edge case and "exception", none of which are documented in any formal way.

Is there a way to hide it?

That depends on what you're actually trying to do. There are a few different approachs I would try:

  1. Warp the cursor offscreen instead of hiding it. Moving the mouse directly will cause other side effects (like hiding the dock), but "CGWarpMouseCursorPosition" might let you get offscreen without that happening. You'd then use EventTap to block further mouse activity and then call CGWarpMouseCursorPosition or CGDisplayMoveCursorToPoint to move the cursor back to it's original location when your key is released.

  2. Add a window above the dock. I'd probably use "kCGScreenSaverWindowLevelKey", but any level significantly above kCGDockWindowLevelKey should work. FYI, anytime you try this sort of an approach, you should always start with partially (NOT full) transparent window. I generally pick a color and then set it to 5-10% opacity. That's transparent enough that you can still see the full UI, opaque enough that it's obvious where your window is. This lets you verify that the window is where it's "supposed" to be and lets you validate that things are working the way you want before you got fully transparent. Don't skip this step. I've seen a lot of time wasted because someone skipped this step and their transparent window simply wasn't where they thought it was. Full transparency is the other complication here- the window server doesn't treat completely transparent windows the "same" as, so there are cases where even 1% opacity will work fine and 0% won't.

  3. Try harder at hiding. The heuristics around exactly when an app has control of the cursor are complicated enough that combining different approaches sometimes works fine when a single approach doesn't. If 1 & 2 don't work for you, then I would start with 2 and then hide the cursor using AppKit, even using a timer to call "hide" repeatedly. It's not particularly elegant, but it could be worth trying.


-Kevin Elliott
DTS Engineer, CoreOS/Hardware

Accepted Answer

I'm not sure why mouse cursor can't be hidden when over dock

Because of how critical the dock is to normal system navigation, there is special logic in the window server that ensure the Dock maintains cursor control whenever it would be the active target. That ends up blocking "SetsCursorInBackground".

maybe some kind of elevated privilege?

No, at least not in the root/security sense. Generally speaking, the window server just doesn't work in those terms. What you will see (and this is an example of this) is that it does have a large number of edge case and "exception", none of which are documented in any formal way.

Is there a way to hide it?

That depends on what you're actually trying to do. There are a few different approachs I would try:

  1. Warp the cursor offscreen instead of hiding it. Moving the mouse directly will cause other side effects (like hiding the dock), but "CGWarpMouseCursorPosition" might let you get offscreen without that happening. You'd then use EventTap to block further mouse activity and then call CGWarpMouseCursorPosition or CGDisplayMoveCursorToPoint to move the cursor back to it's original location when your key is released.

  2. Add a window above the dock. I'd probably use "kCGScreenSaverWindowLevelKey", but any level significantly above kCGDockWindowLevelKey should work. FYI, anytime you try this sort of an approach, you should always start with partially (NOT full) transparent window. I generally pick a color and then set it to 5-10% opacity. That's transparent enough that you can still see the full UI, opaque enough that it's obvious where your window is. This lets you verify that the window is where it's "supposed" to be and lets you validate that things are working the way you want before you got fully transparent. Don't skip this step. I've seen a lot of time wasted because someone skipped this step and their transparent window simply wasn't where they thought it was. Full transparency is the other complication here- the window server doesn't treat completely transparent windows the "same" as, so there are cases where even 1% opacity will work fine and 0% won't.

  3. Try harder at hiding. The heuristics around exactly when an app has control of the cursor are complicated enough that combining different approaches sometimes works fine when a single approach doesn't. If 1 & 2 don't work for you, then I would start with 2 and then hide the cursor using AppKit, even using a timer to call "hide" repeatedly. It's not particularly elegant, but it could be worth trying.


-Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hide global mouse cursor on macOS dock
 
 
Q