I'm writing a Cocoa app that needs to be able to capture keyboard events even when not focused. (It's controlling another app via the Apple Scripting Bridge).
I have tried the solution here: OSX: Detect system-wide keyDown events?
It compiles fine, but doesn't actually do anything. I'm putting the code in my init method.
I also can't get CGEventTap to work either. Any suggestions?
Here's my code:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSEvent addGlobalMonitorForEventsMatchingMask:(NSKeyDownMask) handler:^(NSEvent *event){
NSLog(#"test");
}];
}
Also, I'm aware that assistive devices needs turned on. Unfortunately when I go into the settings it only lists specific apps. Mine isn't one of them.
Use AXIsProcessTrustedWithOptions to request access. Then you'll show up in System Preferences.
Related
Coming from a .NET background I'm used to events getting fired so trapping a lost focus event is easy but I'm not sure how to do this in Obj-C. Basically I want my app to know when another application has gotten focus and it no longer has it so it can perform some actions.
Can you please tell me how I can implement this kind of functionality in Obj-C for an OSX app?
Have a look at the NSWindow notifications. Specifically, you're interested in NSWindowDidBecomeKeyNotification and NSWindowDidResignKeyNotification. You can also create a delegate for the window and implement its windowDidBecomeKey: and windowDidResignKey: methods, as noted in the NSWindowDelegate protocol documentation.
Or, if you just wanted to know when the application (not a window) has gained focus, you can subscribe to the NSApplicationDidBecomeActiveNotification. Likewise, NSApplicationDidResignActiveNotification will notify you when your app loses focus. These notifications are discussed more here. You can also implement applicationWillBecomeActive: and applicationWillResignActive: in the application delegate.
It's unclear if you want notification of a single window losing focus or notification of your entire app losing focus. My answer here provides notification for the entire application losing focus. (See mipadi's answer if you just want to know when one of your app's window loses focus.)
Observe the appropriate notification:
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:#selector(appDeactivated:)
name:NSWorkspaceDidDeactivateApplicationNotification
object:nil];
Then add the handler method:
-(void) appDeactivated:(NSNotification *)notification
{
NSRunningApplication* app = [notification.userInfo objectForKey:#"NSWorkspaceApplicationKey"];
if (app == [NSRunningApplication currentApplication]) {
// your cleanup code here
}
}
This question might seem kind of odd. Basically I'm trying to make a menubar application. When the user presses command, I want to make so that you can't interact with other apps running (write/select/click etc).
Im using this code to detect if command and mouse button is pressed:
mouseEventMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:(NSLeftMouseDownMask ) {
if (event.modifierFlags & NSCommandKeyMask)
{
// "Freeze" all other apps.
}
}];
When I use this on the desktop it works find, however, using this xcode in safari or xcode causes huge lag because they conflict with my app. I also tried adding a invisible window behind this. But, when I did so the mouseEventMonitor will not work because it only work for events outside of the app.
I hope i explained this well enough.
Cheers.
I am don't really understand your question, but for invisible background window (inside your app) you can try use LocalMonitor instead GlobalMonitor:
mouseEventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:(NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask) handler:^NSEvent *(NSEvent *event) {
NSLog(#"theEvent->%#",event);
return event;
}];
Is there any posible way to know if a Mac is in background or foreground?
In iOS we have the following methods:
applicationWillEnterForeground
applicationWillenterBackground
But is there any way to know if a Mac is active or inactive?
It depends on your application layout, but in general use an NSApplication delegate and implement:
- (void)applicationWillBecomeActive:(NSNotification *)aNotification
as well as its counterpart
- (void)applicationWillResignActive:(NSNotification *)aNotification
There are other notifications as well. See the linked document above. Also note that OS X allows real multitasking and thus background/foreground usually refer to having focus or not having focus.
I'm using addGlobalMonitorForEventsMatchingMask to listen to events in Cocoa:
[NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDraggedMask
handler:^(NSEvent *event) {
NSLog(#"Dragged...");
}];
Though I would like to know if I'm dragging/moving a window (and which window that is, I can find the focused window though when holding command and dragging a window it doesn't get focus as far as I know.)
So, can I detect whether or not I'm dragging a window?
Update:
I now have a class: "SATest : NSObject <NSWindowDelegate>" in which I implement the windowDidMove method (and later perhaps windowWillMove too.) Though, now the next step would be attaching this to a window, right? So my question now is: How do I attach the delegate to all windows of all apps?
Update 2:
I now can find a list of all open windows on the screen:
AXUIElementRef _systemWideElement;
_systemWideElement = AXUIElementCreateSystemWide();
CFArrayRef _windows;
AXUIElementCopyAttributeValues(_systemWideElement, kAXWindowsAttribute, 0, 100, &_windows);
Now I have to iterate over the windows, and of each get it's NSWindow so I can add my delegate to it: [window setDelegate:self];
Update 3: To be clear, this question is about detecting the dragging of ALL windows of ALL apps. Not only the windows of my own app.
Also, I'm very new to this event and window management stuff, so no need to keep your answer short I'm happy to read a lot :P
Thanks!
-P
To find out if a window is being dragged you need to have an object that acts as the delegate of the window by responding to the following messages of the NSWindowDelegate protocol:
windowWillMove - this tells the delegate that the window is about to move.
windowDidMove - this tells the delegate that the window has moved.
You can retrieve the NSWindow object in question by sending object to the notification parameter sent to these methods:
e.g.
NSWindow draggedWindow = [notification object];
More information can be found here.
Update:
In response to your request about getting this information for all windows the NSApplication class provides a method which returns an array of all windows owned by the application. The typical way of getting this information is to use one of the NSApplicationDelegate methods to get a reference to your application object.
For example, in your app delegate (pseudocode):
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSApplication * app = [aNotification object];
// you now have a reference to your application.
// and can iterate over the collection of windows and call
// [window setDelegate:self]; for each window.
}
Note that you will need to add / remove you delegates as windows are added and removed. The best method for doing this is – applicationDidUpdate:.
This should be enough to get you started solving your problem.
As suggested by Benjamin the answer lies in the accessibility API. I was looking around in this for a while, even before I asked this question, but never got it to do what I wanted. I now have found a pretty nice solution.
At a high-level I do the following:
Listen to the mouse down event and remember both on which window you clicked and it's location.
Listen to the mouse up event and check if the location has changed, if so you know you moved a window
You can do something similar for the size if you also want to know if you resized. There might be a better solution, but after days of trying stuff this is the only way I got it to work the way I wanted.
Hope this helps anyone who was looking for something similar.
-Pablo
Is it possible to run a method every time the user presses a key. Basically I want to run a sound like on the iPhone or iPad when a key is pressed. I do not want to detect key presses in my window or in a certain control, I want to detect ALL presses (such as when they are typing in Safari or something. I do not need to know what the key is.
Thanks
Use CGEventTapCreate documented here:
https://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html
Or use NSEvents addGlobalMonitorForEventsMatchingMask:handler: documented here:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nsevent_Class/Reference/Reference.html
NSEvent Example:
[NSEvent addGlobalMonitorForEventsMatchingMask:(NSKeyDownMask) handler:^(NSEvent *event){
[self keyWasPressedFunction: event];
//Or just put your code here
}];
I would say NSEvents are easier...
Note:
For security reasons, Apple requires you have "Enable access for assistive devices" turned on in System Preferences, in order to use ether of the above methods.
You can get pretty close with a Quartz event tap, but some keypresses aren't detectable even with one for the sake of security.
If you tell us the broader goal you have in mind, we can suggest alternatives. Are you trying to establish a global hotkey for your app? Are you writing a keylogger or malware? What?
Use NSEvents addGlobalMonitorForEventsMatchingMask:handler:
In applicationDidFinishLaunching add the following code, build & go!
[NSEvent addGlobalMonitorForEventsMatchingMask:(NSKeyDownMask) handler:^(NSEvent *event){
NSLog(#"%#", event.characters);
}];
Apple requires you have "Enable access for assistive devices" turned on in System Preferences.
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nsevent_Class/Reference/Reference.html