programatically forcing function keys on Mac touch bar - macos

I know that users can set specific apps to run with the function keys active on the touch bar by default in their system keyboard prefs as per https://support.apple.com/en-us/HT207240. But is there anyway for a developer to request this from within their app? I browsed the Apple developer docs on this subject but did not see any way to do this, if it's there it's well hidden - seems like Apple is more into encouraging devs to forget about the existence of the f-keys and embrace the dynamic functionality of the touch bar.

Related

Can a Mac App provide a Touch Bar while in the background?

Some Apple apps (such as Xcode and iTunes) add an item to the Control Strip on the Touch Bar that when selected shows the app's Touch Bar (e.g. Xcode's debugger and iTunes' scrubber) without bringing the app to the foreground.
Is it possible for a third party app to do something similar?
Yes. Spotify and TouchSwitcher do the same. Unfortunately, I am not aware of any open source program that you could look into.

NSStatusItem not keyboard navigable

I've created an NSStatusItem for my app, but would like it to be navigable, as the system items are, when using Control+F8 (Control+fn+f8).
The status item is inexplicably skipped in the navigation sequence. Is there a secret handshake of accepting first responder or something that needs to be done for this?
This is basically all the setup code I have for the item:
statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(28)
statusItem.menu = menu
statusItem.button?.image = NSImage(named: "menuIcon")
I found a a similar question asked on quoara.com: http://www.quora.com/Why-cant-I-focus-third-party-icons-in-the-status-menu-area-on-OS-X-with-a-keyboard-shortcut-like-Ctrl-F8-SOLVED.
Quoting Colin Barrett:
The third party items are implemented with a different API (NSStatusItem) than the built-in ones (NSMenuExtra). Note that you can drag to re-arrange the menu extras but not the status items (which always appear to the left of menu extras).
Unfortunately NSMenuExtra is private API and with the Mac App Store you're likely to see less and less apps using it.
Just as an example of third party apps which do support this, you can probably F8 to the MenuMeters icon / graph.
So if you really want to make your status menu items available via keyboard you'll have to dig within Apple's private frameworks, however that's an unstable territory, as they're subject to change at any time, without any notification.
As of at least macOS 10.12, it is possible to navigate to an NSStatusItem using the keyboard with Control+F8. This change presumably occurred between OS X 10.10 and macOS 10.12 (I haven’t tested this with any versions earlier than 10.12).
In order to enable keyboard navigation, the NSStatusItem’s menu property must be defined.

How do you get current keyboard focus coordinates in Mac OS X's Accessibility API?

I'm looking for a Mac OS X Accessibility API to get the coordinates of the location of the current keyboard (not mouse) focus. According to page 2 of the document I found at http://www.apple.com/accessibility/pdf/Mac_OS_X_Tiger_vpat.pdf, it's doable:
Supported:
Mac OS X exposes the location of the current keyboard and
mouse focus to assistive technologies via the Accessibility API and
also provides a visual indication of the focus on-screen.
Despite the statement above, I can't seem to find the API itself. I'm a seasoned dev (coding since 1982), but have never developed on Mac OS X; please be gentle.
OSX appears to have an asymmetric accessibility API; you can use the NSAccessibilityProtocol to make your own app accessible, but to access accessibility of another app, you have to use a separate set of interfaces/objects, AXUIElement and friends.
I found an article on Retreiving the window that has focus that may be of use here: seems the key steps are:
Use AXUIElementCreateSystemWide to create a 'system wide' accessibility object
Ask that object for the currently focused application by calling AXUIElementCopyAttributeValue asking for kAXFocusedApplicationAttribute
Ask the returned object for the focused window again using AXUIElementCopyAttributeValue, but this time for NSAccessibilityFocusedWindowAttribute - actually looks like you can skip this step below, and go straight from focused application to focused UI Element...
Ask the returned object for the currently focused element using the same API again, but this time with NSAccessibilityFocusedUIElementAttribute
Ask that element for its kAXSizeAttribute / kAXPositionAttribute
You might also want to check out the source code for UIElementInspector which displays information about the element under the mouse pointer (though it doesn't appear to do anything with focus).
Also looks like you'll need to enable the accessibility API either via GUI (see article above) or via terminal for any of the above to work - presumably this is to give users a defense against rogue apps taking control of their desktop.
I haven't used any of these personally (yet); but I'm familiar enough with accessibility APIs to know where to look - hope this helps.

Can app preferences be read only on startup?

I have implemented inappsettings to have a preferences view in my application to be able to edit settings.bundle values straight in the app.
However now I wanted to read from settings.bundle but reading the iOS programming guide I found out that settings.bundle should be read on application startup.
So is it not possible to access this preferences any time in my code? Inappsettings would not make any sense if the user could not update preferences any time while the app is running.
Inappsettings offers the method InAppSettings registerDefaults
- (void)initialize{
if([self class] == [AppDelegate class]){
[InAppSettings registerDefaults];
}
}
But I am not sure if that makes it possible to read preferences any time. Any suggestions?
Edit: in my app I have three views, one is the dashboard. The other, a option and a mail view, are shown modally.
In the preferences the user can setup some basic things that I need to send the message. So when the user just started typing and wants to change e.g. the transmission gateway he opens the option view, which is the inappsettings view, and changes some things. I would like to read this changes without restarting the app.
Clearly Apple wants to impose external preferences UI paradigm on us. Please recall how Mail.app works. Sometimes that paradigm makes sense, sometimes doesn't. If you have immutable preference set, you don't have to think about events handling onPrefferenceChange, concurrency, synchronization, OS backup and replication issues,etc... However the facilities that Apple provided are very limited in what they can do. You can't even enter an arbitrary string there (Mail.app clearly uses some private API for that). So you have to make a choice whether you can use what Apple offers or implement your own preference system (may be based on top of NSUSerDefaults or something). I implemented my own once and I use it ever since. I prefer to have a real in-app preference system. The main advantage of that is to able changing its value without leaving an app.

How do I get keyboard events in an NSStatusWindowLevel window while my application is not frontmost?

After creating a translucent window (based on example code by Matt Gemmell) I want to get keyboard events in this window. It seems that there are only keyboard events when my application is the active application while I want keyboard events even when my application isn't active but the window is visible.
Basically I want behavior like that provided by the Quicksilver application (by blacktree).
Does anybody have any hints on how to do this?
There are two options:
Use GetEventMonitorTarget() with a tacked-on Carbon run loop to grab keyboard events. Sample code is available on this page at CocoaDev.
Register an event trap with CGEventTapCreate. Sample code can be found in this thread from the Apple developer mailing list.
Edit: Note that these methods only work if you check off “Enable access for assistive devices” in the Universal Access preference pane.
A simpler route that may work better for you is to make your app background-only. The discussion on CocoaDev of the LSUIElement plist key explains how to set it up. Basically, your application will not appear in the dock or the app switcher, and will not replace the current application's menu bar when activated. From a user perspective it's never the 'active' application, but any windows you open can get activated and respond to events normally. The only caveat is that you'll never get to show your menu bar, so you'll probably have to set up an NSStatusItem (one of those icon menus that show up on the right side of the menu bar) to control (i.e. quit, bring up prefs, etc.) your application.
Edit: I completely forgot about the Non-Activating Panel checkbox in Interface Builder. You need to use an NSPanel instead of an NSWindow to get this choice. This setting lets your panel accept clicks and keyboard input without activating your application. I'm betting that some mix of this setting and the Carbon Hot Keys API is what QuickSilver is using for their UI.
Update:
Apple actually seems to have changed everything again starting with 10.5 BTW (I recently upgraded and my sample code did not work as before).
Now you can indeed only capture keydown events setting up an event tap if you are either root or assistive devices are enabled, regardless on which level you plan to capture and regardless if you selected to capture (which allows you to modify and even discard events) or to be listen only. You can still get information when flags have changed (actually even change these) and other events, but keydown under no other circumstances.
However, using the carbon event handler and the method RegisterEventHotKey() allows you to register a hotkey and you'll get notified when it is pressed, you neither need to be root for that nor do you need anything like assistive devices enabled. I think Quicksilver is probably doing it that way.

Resources