NSEvent keyCode gives a keyboard scan code, which is a hardware specific code representing the physical key. I want to convert the scan code to a virtual key code, which is the logical key based on the users keyboard layout (QWERTY, AZERTY, etc).
In Windows I can do this via MapVirtualKey. What is the OS X equivalent?
Virtual keys mainly consist of actual keyboard keys, but also include "virtual" elements such as the three mouse buttons. The virtual keys also include many "keys" which usually do not exist at all. A key's virtual-key code does not change when modifier keys (Ctrl, Alt, Shift, etc.)
Key codes are numeric values that correspond to physical keys on the keyboard but do not necessarily correspond to a particular character.
The virtual key code is precisely not based on the user's keyboard layout. It indicates which key was pressed, not what character that key would produce nor how it's labeled.
For example, kVK_ANSI_A
(from Carbon/HIToolbox/Events.h, value 0x00
) does not mean the key which produces the 'A' character, it means the key which is in the position that the 'A' key is in an ANSI standard keyboard. If a French keyboard layout is active, that key will produce 'Q'. If the physical keyboard is a French keyboard, that key will probably be labeled 'Q', too.
So, the virtual key code is sort of akin to a scan code, but from an idealized, standard keyboard. It is, as noted, hardware-independent. It is also independent of the keyboard layout.
To translate from the virtual key code to a character, you can use UCKeyTranslate()
. You need the 'uchr' data for the current keyboard layout. You can get that using TISCopyCurrentKeyboardLayoutInputSource()
and then TISGetInputSourceProperty()
with kTISPropertyUnicodeKeyLayoutData
as the property key.
You also need the keyboard type code. I believe it's still supported to use LMGetKbdType()
to get that, even though it's no longer documented except in the legacy section. If you don't like that, you can obtain a CGEvent
from the NSEvent
, create a and call CGEventSource
from that using CGEventCreateSourceFromEvent()
, and then use CGEventSourceGetKeyboardType()
CGEventGetIntegerValueField()
with kCGKeyboardEventKeyboardType
to get the keyboard type.
Of course, it's much easier to simply use -[NSEvent characters]
or -[NSEvent charactersIgnoringModifiers]
. Or, if you're implementing a text view, send key-down events to -[NSResponder interpretKeyEvents:]
(as discussed in Cocoa Event Handling Guide: Handling Key Events) or -[NSTextInputContext handleEvent:]
(as discussed in Cocoa Text Architecture Guide:Text Editing). Either of those will call back to the view with the appropriate action selector, like moveBackward:
, or with -insertText:
if the keystroke (in context of recent events and the input source) would produce text.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With