Search code examples
macoscocoansevent

Get the char accent in NSEvent


In Cocoa you can override the keyDown(event:NSEvent) method in some classes to get notified when the user presses a key. In most cases, the event will contain, among other things, the key code and the characters pressed. However, if you press ' or " on the US Extended keyboard, you will get the key code, but not the symbol. When you type, say in a text editor, you will get the corresponding symbol on an orange background, and then, if you type a letter, if that letter can be accented by that symbol, you will get the accented letter, like ò or öor ó.

Can I somehow get the accent from the event, or look it up somewhere immediately after event?


Solution

  • First, keys such as this are called "dead keys". They don't produce characters by themselves, they modify what characters are produced by subsequent keystrokes.

    As to your question, there is no one accent for a dead key event. A dead key just changes the state of an internal state machine. In some keyboard layouts, a single dead key can have a variety of effects depending on the subsequent keys. For example, with the Estonian keyboard layout, Option-(the key just to the left of backspace) sets up a dead key state which changes "a" to "ä", "i" to "ů", "z" to "ż", and "ö" to "ő".

    Anyway, if you want to process key events manually, you would use UCKeyTranslate(). You need the keyboard layout 'uchr' data, which you can get using TISCopyCurrentKeyboardLayoutInputSource() and calling TISGetInputSourceProperty() on that with the key kTISPropertyUnicodeKeyLayoutData.

    You also need the keyboard type, which you can get from the CGEvent on which the NSEvent is based. Call CGEvent() on the NSEvent and then call CGEventGetIntegerValueField() on that with the key kCGKeyboardEventKeyboardType.

    You'll also have to translate the Cocoa values for the modifier keys in the event to the Carbon values (combinations of shiftKey, cmdKey, etc.) shifted right 8 bits.

    You'd need to keep track of the running dead-key state. Initially, you'd set that to 0 and then for every key event you'd let UCKeyTranslate() update it. You'd reset it to 0 when focus shifts to another control or window.

    If the dead-key state is non-zero on return from UCKeyTranslate() there was a dead key. UCKeyTranslate() may also have produced characters. That is, a key stroke can both produce real characters and set up a dead-key state that will modify subsequent keystrokes.

    If you want to present a character to represent the dead-key state, you would process the keystroke through UCKeyTranslate() a second time with the dead-key state and kUCKeyTranslateNoDeadKeysMask in the options. I believe that's how the "marked" character (shown in orange) is determined, although, as I say above, that character does not necessarily have any particular relationship to how the dead-key state will actually affect a subsequent keystroke. You could also process a fake press of the Space key to determine this character.