How to hook/remap an arbitrary keyboard event on OSX? - macos

I would like to map:
CAPS-LOCK to Fn
Fn to Left-MOUSE
LSHIFT+3 to #
RSHIFT+3 to something else
etc.
I have searched exhaustively for any tool that offers complete freedom for remapping keyboard input, but cannot find one. (Windows has AutoHotkey).
I'm planning to write my own tool that parses a config file.
But how to actually dig in and do this?
Solving this problem will require a thorough understanding of the journey of a keystroke through the operating system, so as to intercept at the appropriate point.
I think I need to eat the event at a low-level, where it is still a virtual key code, then provide my own customised mapping system and inject an appropriate event further up the system.
But where (and how)?
Edit: I am detailing the results of my research in an answer below (which maybe should be migrated back into the question at some point).

I'm making this community wiki, please feel welcome to improve it.
Sub-Questions I've asked:
Make SHIFT+3 produce `#` not `£` on OSX by code
How to tap (hook) F7 through F12 and Power/Eject on a MacBook keyboard
How to tap/hook keyboard events in OSX and record which keyboard fires each event
-> https://github.com/Daij-Djan/DDHidLib
Trap each SHIFT key independently on OS X
In OSX, how to determine which keyboard generated an NSEvent?
I can intercept almost all keydown/keyup events at the bottom of the middle tier. Except for power, and also CAPSLOCK key-UP when it is transitioning from ON to OFF.
Pretty nasty!
Working at the bottom tier level, I can get all key up/down except for the PowerKey.
If it were not for that awkward 75% success rate for CapsLock I would have a good solution. It is vexing that handling a key in such a useful location massively escalates the required complexity.
I have found DDHidLib and am currently looking through it to figure out if it smoothes that problem.
Research
Googling "keyEventWithType CGEventTapCreate" seems like a good idea, as those are essential ingredients for Tapping the event and Re-Emitting it.
Yay! Modify keyDown output -- that code compiles, and with minor tweaking (CGEventMaskBit( kCGEventKeyDown ) | CGEventMaskBit( kCGEventFlagsChanged ),) I can pick up modifier keys also. I get different keycodes for LSHIFT and RSHIFT. Brilliant!
Problems with the above:
Tapping kCGEventKeyDown works for some function keys but not others. It looks as though Apple have only overloaded certain keys, and the overloaded ones seem to get caught at a lower level.
Power/Eject key doesn't get caught.
I don't see any way to disambiguate which device the keystroke is coming from.
How to tap (hook) F7 through F12 and Power/Eject on a MacBook keyboard
http://blog.tklee.org/2008/09/modifiers-across-keyboards.html
-> http://forums.macrumors.com/showthread.php?t=778484
-> https://github.com/maravillas/dual-keyboards
https://github.com/pkamb/PowerKey may provide some insight
-> https://github.com/pkamb/PowerKey/blob/master/PowerKey/PKPowerKeyEventListener.m
-> Apple Keyboard Media Key Event Handling -- Rogue Amoeba
... system wide shortcut for Mac OS X
-> http://snippets.aktagon.com/snippets/361-registering-global-hot-keys-with-cocoa-and-objective-c
Another problem is: LSHIFT-down RSHIFT-down&up LSHIFT-up. The RSHIFT events wouldn't get caught.
Looks like I need to dip down into IOKit
Using IOHIDManager to Get Modifier Key Events
-> https://github.com/candera/khordr/blob/master/src/c/keygrab/hid-scratch.c
kEventRawKeyDown in:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/
Developer/SDKs/MacOSX10.10.sdk/System/Library/
Frameworks//Carbon.framework/Frameworks/HIToolbox.framework/
Headers/CarbonEvents.h
Resources
3-tier:
Cocoa/AppKit is a higher-level wrapper
Quartz takes the events from IOKit routes them to apps
Note: NSEvent is built over Quartz Event
IOKit -- talks to the hardware
Top Tier (Cocoa/AppKit)
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/EventArchitecture/EventArchitecture.html -- this document is a must-see, and shows the above basic 3-tier architecture pic. However, it appears to only focus on the top tier (Cocoa/AppKit).
http://www.hcs.harvard.edu/~jrus/Site/Cocoa%20Text%20System.html <-- this article shows you 3 OSX config files that operate at an even higher level, letting you script your own mappings. This is documented here.
^ KeyBindingsEditor lets you make the above modifications.
Middle Tier (Quartz)
QuartzEventServicesRef
NSEvent -- specifically Creating Events
A couple of working code examples at this level. However, they all perform the same basic trick of receiving one virtual key code and emitting another. So you could use this technique for example to swap 'a' and 'z'.
Intercept keyboard input in OSX -- leads to Quartz Event Taps
Modify NSEvent to send a different key than the one that was pressed -- Dave De Long provide a working example, also using QET.
https://gist.github.com/wewearglasses/8313195 <-- "Global keyboard hook for OSX" -- another short working demo using QET.
Ukelele lets you choose which Unicode gets associated with a particular key, or Modifier+key. Doesn't allow remapping of modifiers, nor does it disambiguate left from right shift keys etc.
Keyboard input on OSX -- answer points towards addGlobalMonitorForEventsMatchingMask in NSEvent (in AppKit)
Base Tier (IOKit)
IOKitFundamentals <-- Also IOKit ("Interrupt Handling in the I/O Kit... Two types of events trigger an interrupt: ... Asynchronous events, such as keyboard presses")
https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Other_APIs/AH_Other_APIs.html
How can Mac OS X games receive low-level keyboard input events? <-- gamers are interested in this!
http://phrack.org/issues/66/16.html#article -- sometimes the hackers present things most clearly, haven't read through this yet. IOKit again, it seems.
More Links...
How do you implement global keyboard hooks in Mac OS X? <-- links to an article.
OS X: Detect system-wide keyDown events? <-- slightly OT as this is just to do with global monitoring, i.e. read-only.
http://www.codeitive.com/7QHSeVjPWq/where-can-i-find-kcgkeyboardeventkeycode-list-of-key-codes-for-cyrillic-language.html

Have you checked out Karabiner (which does all that you want to do.. up till OSX 10.11 .. MacOS 10.12 changed the keyboard driver model, and the authors - mainly Tekezo- are still re writing Karabiner to take account of the new model - this is as of feb 2017)
Karabiner is open source, and you can download the code from Github and twiddle with it.
As part of the re-write they have released Karabiner-elements which works on 10.12 Sierra, but cannot yet do everything that karabiner did.
Karabiner is very powerful, and I miss it greatly on 10.12

Related

iOS custom keyboard - preserve state between appearances

I'm having some performance problems with a custom keyboard I'm working on. Loading all the words in the spell correction tree takes quite a bit of time. This seems to be done each time the keyboard appears - is there any way to preserve the state of the keyboard? Apps can do suspend / resume etc - but I can't find any documentation on how to do this for extensions, or if there's any mechanism for doing this att all.
Thanks!
You are loading dictionary from Internet or from the disk?
For the first case NSUserDefaults, encoding (NsCopying) are the options to store info. You can load it in background.
According to the docs, os typically kills extension process, so, I think there is no way to prevent keyboard objects from deallocation (you may use nskeydarchiver).

Detecting CGAssociateMouseAndMouseCursorPosition

We're making a user-space device driver for OS X that moves the cursor using Quartz Events, and we ran into a problem when games — especially ones that run in a windowed mode — can't properly capture the mouse pointer (= contain/keep it within the boundaries of their windows). For example, it would go outside the game window and click on the desktop or nearby inactive applications.
We could fix this if only we could detect when an active application calls CGAssociateMouseAndMouseCursorPosition.
How would you do this? Any ideas are appreciated.
I dont know if this can help you
There is an option called Focus Follows Mouse
Focus Follows Mouse - The Mouse pointer will grab automatically change focus to a new window inisde this one app if you mouse over it, instead of having to click a window to get focus, then clicking to do something.
http://wineskin.urgesoftware.com/tiki-index.php?page=Manual+4.6+Advanced+-+Options
I have written a few different mouse logical layers (for bridging different input devices, etc.). I have found that hooking into the OS level WM_INPUT event is a sure way of getting very real-time mouse position information. There is also a less rigorous solution of just polling the mouse data you need from one of Windows' very primitive DLLs. They are lightning fast. You could poll on a 10ms timer and never see performance loss on a modern machine.

No, really. What is the proper way to handle keyboard input in a game using Cocoa?

Let's say you're creating a game for Mac OS X. In fact, let's say you're creating Quake, only it's 2011 and you'd prefer to only use modern, non-deprecated frameworks.
You want your game to be notified when the user presses (or releases) a key, any key, on the keyboard. This includes modifer keys, like shift and control. Edited to add: Also, you want to know if the left or right version of a modifier key was pressed.
You also want your game to have a config screen, where the user can inspect and modify the keyboard config. It should contain things like:
Move forward: W
Jump: SPACE
Fire: LCTRL
What do you do? I've been trying to find a good answer to this for a day or so now, but haven't succeeded.
This is what I've came up with:
Subclass NSResponder, implement keyUp: and keyDown:, like in this answer. A problem with this approach, is that keyUp: and keyDown: won't get called when the user presses only a modifier key. To work around that, you can implement flagsChanged:, but that feels like a hack.
Use a Quartz Event Tap. This only works if the app runs as root, or the user has enabled access for assistive devices. Also, modifier key events still do not count as regular key events.
Use the HIToolbox. There is virtually no mention at all of it in the 10.6 developer docs. It appears to be very, very deprecated.
So, what's the proper way to do this? This really feels like a problem that should have a well-known, well-documented solution. It's not like games are incredibly niche.
As others have said, there’s nothing wrong with using -flagsChanged:. There is another option: use the IOKit HID API. You should be using this anyway for joystick/gamepad input, and arguably mouse input; it may or may not be convenient for keyboard input too, depending on what you’re doing.
This looks promising:
+[ NSEvent addLocalMonitorForEventsMatchingMask:handler: ]
Seems to be new in 10.6 and sounds just like what you're looking for. More here:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSEvent_Class/Reference/Reference.html%23//apple_ref/occ/clm/NSEvent/addLocalMonitorForEventsMatchingMask:handler:

Is it possible to programmatically turn on the Macbook Pro's keyboard backlight for individual keys?

Although I have a feeling that this isn't technically possible, it's worth asking anyways. Is it possible to turn on the Macbook Pro's keyboard backlights for individual keys? I am working on a piece of grid-based software which allows the user to navigate around by pressing any key on the keyboard to position the cursor at that point in the grid. It would be very cool if I could somehow just turn on the backlight for certain keys to give the user an easy way to see the current position of the cursor.
Is it even possible for an application to control the keyboard backlighting at all, let alone for individual keys?
Yes, on programs controlling the backlight.
iTunes visualizer that pusles keyboard backlighting to music:
http://www.youtube.com/watch?v=LUXLkwlF9e8
How to manually adjust (via plugin):
http://osxdaily.com/2006/11/30/how-to-manually-adjust-the-macbook-pro-keyboard-backlight/
Not sure on programs controlling individual keys, but as that would require additional hardware to be installed on Mac's part, i doubt it.
Well after trawling the webs, it looks like the answer to that is no. But I'd like to point out that each key does have its own key- a tiny little LED (same kind they use under phone keypad buttons). Also, I've seen some people saying that flashing these lights on and off repeatedly is bad for them. Bullshit- all digital electronics control light output from LED's by flashing on and off many many times a second. Read up on PWM on wikipedia or something..
Anyways just had to get that out there :)
Thanks,
Nic

In writing games that deal with scancodes, what do I need to know to support international keyboards on Mac and PC?

I am writing an input system for a game that needs to be able to handle keyboard schemes that are not just qwerty. In designing the system, I must take into consideration:
Two types of input: standard shooter controls (lots of buttons being pressed and raw samples collected) and flight sim controls (the button's label is what the user presses to toggle something)
Alternative software keyboard layouts (dvorak, azerty, etc) as supplied by the OS
Alternative hardware keyboard layouts that supply Unicode characters
My initial inclination is to sample the USB HID unicode scancodes. Interested on thoughts on what I need to do to be compatible with the world's input devices and recommendation of input APIs on both platforms.
Simple solution is to allow customization of input. In the control customization, record what key the OS tells you has been pressed. In game, when you get a key press, check it against your list of bound keys and do the appropriate action.
It looks You need a cross platform library for games. You can look at SDL:
http://www.libsdl.org/
It is quite popular in game development.
http://en.wikipedia.org/wiki/List_of_games_using_SDL
The library is quite modular. You can only use part that control input.

Resources