Observe global mouse location on screen in Cocoa? - objective-c

I'd like to be notified when the mouse moves and get the location on the screen. I tried this:
[NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMovedMask handler:^(NSEvent *event) {
CGPoint location = [NSEvent mouseLocation];
NSLog(#"Position: %#", NSStringFromPoint(location));
}];
However this seems to only work as long as the mouse is in my app's window. As soon as leave it I'm not notified. Until I enter the window again. Shouldn't this event be global?
UPDATE:
I extracted the code in question and made a separate sample project (Dropbox-Link). Just to be sure, there is nothing else interfering with it. It's a clean project with just the code above in applicationDidFinishLaunching:. I get the same results and it's really strange. I uploaded a video to youtube: http://www.youtube.com/watch?v=I3AKgmURaMk.
These are my observations:
Immediately after launching the app, no events at all are delivered, no matter where I move the mouse.
Clicking the app's window will somehow activate event delivery. Now I receive NSMouseMovedMask events, no matter where I move the mouse (this is what I want to achieve).
Clicking back to Xcode doesn't change anything. I keep getting the events.
However, moving the focus back to my app results in a strange behavior. When I move my mouse over Xcode I only get events over some parts of the window, while some parts seem to absorb the event. More specifically I don't receive events over the editor or the log view. I only receive them while moving the mouse over the gray split view separator area (with the tab bars embedded in them).

It should work, I've seen weird behavior when the window is up but not in the foreground. I've noticed that if the application is in the background but not in the dock you will only get events when the mouse transitions between windows in the foreground. Minimizing the application seems to fix this problem.. I'm very new at cocoa dev/ObjC.. I might be wrong, but I've noticed when I minimize my app, I get all events.

Related

Detect mouse cursor icon change in application

I've been looking for awhile now to no avail for this.
What I'm trying to do is find a way to detect if a mouse icon changes when you mouse over something.
For example: If you mouse over a link it changes from the arrow to a finger.
My plan is to grab the ID of a window, and scan it for clickable objects based on the mouse icon changing. I can grab the window, bring it to the front, and move the mouse around by setting the x,y coord of the mouse, but I don't see a way to detect if the mouse has found anything.
I would prefer this to be something built into vb.net, but if I have to use an API I'm fine with that.
The approach is wrong because the concepts are different from what you observe visually.
There's no such thing as "click" -- there's Button Down event (Windows message sent by the GUI subsystem to the application), Button Up event and Mouse Move event. If there were Button Down and Button Up with no or little Mouse Move, then the OS considers this a click.
All events are sent to the window under the mouse cursor hotspot unless the mouse input is captured by the other window.
When the cursor is moved over the window, the OS sends WM_NCHITTEST message to the window to determine, how the window treats the area under the cursor. Based on window's response Windows either performs the window operation (window move or resize etc) or passes mouse-related events to the window procedure. The procedure then decides how to react - do nothing, make visual changes, perform some action etc.
As you can see from the description, cursor change and actual actions are two different loosely related operations. There can be an action without cursor change or cursor change without an action.

In Objective-C/Cocoa, are there global events for when mission control is activated or spaces are changed?

I'm currently working on an OSX menubar app that uses a custom status item view and a NSPopover to display content.
I'm trying to get it to dismiss at times that would make sense like when spaces are changed, since the popover doesn't move spaces like a window does, or when mission controller is activated.
Currently, when in mission control, the NSPopover stays on top as shown in this screenshot.
Currently I'm using NSEvent addGlobalMonitorForEventsMatchingMask: with some mouse event masks and that works alright but doesn't cover all needed events.
So, is there a way to detect when major OS events happen like opening mission control, changing spaces etc?
Any help would be greatly appreciated.
You can get notified of space changes by registering for NSWorkspace's NSWorkspaceActiveSpaceDidChangeNotification. There isn't a notification as such for Mission Control, but you might investigate whether NSWorkspaceDidActivateApplicationNotification or other notifications can be used to determine what you need.
HTH

Cocoa: how to prevent mouse move past coordinates?

Final goal is to prevent mouse move to another screen (dual display setup) unless a hotkey is held.
The best I came up with, is this:
[NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMovedMask handler:^(NSEvent *mouseMovedEvent) {
// does nothing yet
}]
The reason I went for global monitor is that my app does not have any windows (and views), it's a status bar app. So NSTrackingArea went home.
Any help would be much appreciated. In Java world, I would simply preventDefault() the event object. Now I need to get the same functionality in Objective-C. Ideally, I'd wish there would be "MouseMovedPastScreen" event, but apparently there's not.
Thanks.
EDIT
Again, in Java, I would get the bounds of both screens, and stopped mouse at the corner positions. And then would allow the event to bubble if the ⌘ key has been held during the event execution.
Controlling the mouse cursor From the Quartz Display Services programming guide. Particularly
CGAssociateMouseAndMouseCursorPosition (false);

NSPanel in "Non-Activating"-Mode does not always show correct cursors

I've created a simple Cocoa-Application in XCode 4.6 with an NSPanel instead of the default NSWindow. When I enable the Non-Activating
option and start the application everything works fine:
The panel is displayed in front of everything else and when
the mouse cursor hovers over the panel's edges it changes from a normal
arrow-cursor to the appropriate resize-cursor, so the user knows that he can resize
the panel.
This works fine as longs as I don't click on any other application
as for example Safari or Finder.
From the moment I once give focus to another application,
I can click on and hover over my panel as much as I want, the
cursor style will not change anymore - it always stays an arrow and it's not possible to return to the normal behavior.
The panel stays selectable and in the front, you still can move and resize it,
but the mouse cursor stays an arrow all the time. You then cannot even change it
manually using something like: [[NSCursor crosshairCursor] set].
So I need to find a way to create a NSPanel that keeps the normal
automatic-change-cursorstyle-when-hovering-over-panel-edges-behaviour
even when you give focus to another application.
I have already tried to use an customized NSPanel-class,
where I have overwritten the canBecomeKeyWindow and
canBecomeMainWindow methods, so that they return YES
but even when I make my Panel KeyWindow and MainWindow...
[myPanel makeKeyAndOrderFront:self];
[myPanel makeMainWindow];
...it doesn't solve the cursor issue.
Would be great if someone could help me here :)
PS.: the Base SDK and the Deployment Target are set to 10.8 in my project
So I found out that the described issue has nothing to to with the panel's window-state. It really doesn't matter if it is set to key or to main, instead the cursor-problem (stays arrow all the time)is related to the application's activation state.
Everything works fine as long as the application that owns the panel is active but if you click on another application my application is deactivated and does not get activated again - even if you click on the panel - because the "non-activating"-option is enabled.
The problem is that i need the "non activating"-option because I am creating a status-bar-screen-capturing app that should be displayed and operate in front of everything else but without deactivating any running application. I could solve the cursor problem by
[NSApp activateIgnoringOtherApps];
but then taking a screenshot of a fullscreen video running in Safari would deactivate Safari and minimize the video, which I don't want.
I don’t think it’s possible through normal APIs to change the cursor when your app isn’t active. I’m pretty sure the window system doesn’t allow it: it’d be a violation of the boundaries between apps—if you try to set a cursor from the background, and the foreground app also tries to set a cursor, who would win?
Of course the system can do it (like when you take a screenshot with ⌘⇧4), because that’s in the window system itself.

Cocoa: Limit mouse to screen

I'm developing a kiosk mode application for OSX. In some circumstances, another screen gets attached. My application runs in fullscreen on one screen using:
[self.window.contentView enterFullScreenMode:s
withOptions:[NSDictionary dictionaryWithObject:appOptions
forKey:NSFullScreenModeApplicationPresentationOptions]];
The options are the following:
[NSNumber numberWithUnsignedInt:(NSApplicationPresentationHideMenuBar|
NSApplicationPresentationHideDock|
NSApplicationPresentationDisableHideApplication|
NSApplicationPresentationDisableProcessSwitching|
NSApplicationPresentationDisableAppleMenu)];
What I want is limit the mouse cursor to the screen where the game is running.
How can I accomplish that?
Add an NSTrackingArea to the screens you don't want the mouse entering. When you get notified that the mouse has entered the tracking area, use CGEventCreateMouseEvent and CGPostEvent to move the mouse back to a safe location, probably the nearest point on the main screen.