How to intercept events from specific windows in OSX - macos

I want to have the following workflow:
User presses hotkey, or status bar menu button
User clicks on a window
Window is now "registered" in my app
App intercepts mouse events from all registered windows
I've read a lot on CGEvents, CGEventTaps and NSEvents. I can intercept global events and post new ones using CGEvents and CGEventTaps but there is not window information like windowNumber in NSEvent, only PSD (and I'm not sure how to use those), so I can't filter out events from non-registered windows. NSEvent, on the other hand, doesn't let me to intercept global events, only local ones through a localMonitor.
How could I achieve the desired functionality?

You can use the Mac OS X Accessibility API to get details about the currently focused window or application.
The UIElementInspector Apple Sample Code gives many examples.
// Given a uiElement and its attribute, return the value of an accessibility object's attribute.
+ (id)valueOfAttribute:(NSString *)attribute ofUIElement:(AXUIElementRef)element;
Use the kAXFocusedApplicationAttribute or kAXFocusedWindowAttribute attributes with valueOfAttribute:ofUIElement: to get the window/app when you "register" it with your app.
When a CGEvent comes in, compare the currently focused window/app to your list of registered windows/apps to determine if the event should be intercepted.

Related

Outlook VSTO - ActiveInspector returns the incorrect contact window's information

Globals.ThisAddIn.Application.Explorers.NewExplorer += new ExplorersEvents_NewExplorerEventHandler(DoNewExplorer);
I am trying to get the information from an email that I previously opened (by double-clicking) in outlook.
The code works fine until I open multiple emails. What I am finding is that when I click on an email, the inspector activates, but I am getting the information from the last active window, not the current one that I clicked on.
In the Activate event handler you can always call the ActiveInspector method of the Outlook Application class.
Note, the Inspectors collection contains all opened inspector windows, so you could get all of them or find the required one.
Firstly, your code tracks the Explorers.NewExplorer event, not Inspectors.NewInspector.
Secondly, for the Inspectors.NewInspector event, make sure you are using the Inspector object passed to your event handler rather than Application.ActiveInspector: by the time Inspectors.NewInspector event fires, the inspector might not yet be visible/active.

How to make a Finder Sync Extension change badges in response to outside events

I have a Finder Sync Extension that will display a badge on a file based on the state of a local database. It's straightforward enough to query this database in the requestBadgeIdentifierForURL function, but what if I want the badge to change for a Finder item that's already visible if the state of that database has changed (which can be via a notification through any variety of mechanisms). The documentation (https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Finder.html) would seem to imply this is possible with this statement:
You might also want to track these URLs, in order to update their
badges whenever their state changes.
The only ways I can imagine this would be possible (and most seem wrong) would be:
call setBadgeIdentifier:forURL from another application that is aware of the change
Launch a thread in the init function of my extension which listens for notifications and calls setBadgeIdentifier:forURL when it receives them
Call some OS API that prompts Finder that the extension should be triggered via requestBadgeIdentifierForURL.
Only the last one seems feasible, and could be managed via the extension informing the outside resource what needs refreshing via the beginObservingDirectoryAtURL/endObservingDirectoryAtURL callbacks, but i don't know what mechanism could do this.

Adding alarm from BackgroundAgent (not working, looking for workarounds) - Windows Phone 8

I am developing an application which needs to notify the user at a pre-difined time with the help of background agent,
So I tried to add an Alarm, but according to MSDN's "Unsupported APIs for Background Agents for Windows Phone" all the methods regarding Microsoft.Phone.Scheduler (Add, Remove, Replace) are not supported (when ever i try to call Add method from background agent it gives error "BNS Error: The API can only be called from foreground app".). I tried to add the alarm when in foreground and then play with the "BeginTime" property and use the Replace method from the my scheduledTask (specifically, PeriodicTask which runs its code every 30 minutes) but to no avail, it did nothing.
What is important for me is to notify the user (with longer-enough sound) at the date and time that decided in the background-agent's Invoke method (My class derives from ScheduledTaskAgent and override the Invoke method), So I'm looking for workarounds. If there would be a toast that appears at a pre-defined time that would be ok somehow. Or maybe a toast that stays for a longer time on the top of the screen (from the moment the scheduled-task came up with an instance of DateTime until[and even after] the time that specifiend in this DateTime instance).
Please confirm, is it only the background agent that can calculate the correct time for the alarm to go off?
Assuming this is so, you can notify the user by sending a toast (which will also vibrate the phone, unless user has disabled that) and updating a tile pinned to the home page. These are both permitted APIs. So the toast message could tell the user to go look at the tile, which could have specific details about the alarm. The tile state will persist until you change it. If your foreground app would pin the tile for the user, that's a start. If you can then get the user to move the tile to the top of the screen, so it's always visible, you should be all set.
Considering that the alarm time might happen when the user is not actively using the phone, perhaps you want to do the toast plus a notification on the lock screen (as well as updating the tile)? That will provide another visual indication, though, again, it depends on the user configuring a lock screen.

NSView keyDown not called during drag and drop in Cocoa application

I have a cocoa application where i need to respond to keyDown events during dragging sessions in order to trigger other things. The keys are not modifiers only but can be any kind of key.
The problem is, when i start a dragging session by calling NSWindow.dragImage, i don't get keyDown events during that dragging operation. When i drag an external resource over/into the application window (e.g. a file from Finder) it works fine, NSView.keyDown gets called.
Is there any way of getting around this? Thanks you!
This is probably because the dragging session is using a 'mouse-tracking loop' to handle the drag events. This effectively blocks all other events from being sent to their targets except for the drag events. You can read about this here in the event documentation.
The reason dragging items onto your app does NOT do this is because only the app initiating the drag session is event blocked, not the app receiving the drop.
Having said this, you could try to capture the keyEvents during the mouseDragged event using nextEventMatchingMask:untilDate:inMode:dequeue: this should allow you to pop-off any key events that might be in the event queue.
Also in the documentation linked above they discuss handling key events during mouse drag operations. However the examples don't specifically fit when initiating a drag session with dragImage:at:offset:event:pasteboard:source:slideBack: but you may try watching the performKeyEquivalent as they mention or even seeing if NSWindow's sendEvent: is receiving events during the drag session.

How can a Mac app determine the method used to launch it?

I have a Mac OS X application that is also a protocol handler (just as, for example, Safari is a protocol handler for the HTTP and HTTPS protocols). So when a user clicks a link of the form myscheme://some-kind-of-info in any application at all, my application launches to handle the link.
Now I need to be able to determine if the application was launched by such a link click, or if it was launched by any other method. In other words, it was launched by any method besides a link click. (In those cases, I want the app to stay open, but if it was launched by a link it should quit and ignore the link. This way it only operates when already running.)
Is there some way within the app at startup to introspect and find out that it was launched by a standard method rather than by an AppleScript GetURL event? I'd like to find out through a documented method, rather than - for example - just have my app only open these links after it's been running for a half a second.
You can register a handler for each of the possible Apple Events you'll get on launch, and make note of which one you receive first.
If the application is launched without documents, you'll get kAEOpenApplication.
If it's launched with documents, you'll get kAEOpenDocuments (or
kAEPrintDocuments).
If it's launched with a URL, then (obviously) you'll get kAEGetURL.
There's also kAEOpenContents, but I wasn't able to trigger it easily in my test app; it's probably worth supporting no matter what.
How Cocoa Applications Handle Apple Events documents all of this stuff.
There is one error in there, though; it says that AppleScript's "launch" will send kAEOpenApplication. It won't, it'll send ascr/noop (kASAppleScriptSuite/kASLaunchEvent, defined in ASRegistry.h). I couldn't get the usual Cocoa event handler mechanism to trap this event, so you may need to do some more digging there.
One way you can check if the event is sent at launch is to register the event handlers in your application delegate's applicationWillFinishLaunching: method; they should deliver by the time applicationDidFinishLaunching: is invoked. With that method, you could potentially only check for kAEGetURL.

Resources