Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to capture Unicode from key events without an NSTextView

I'd like to capture key events from any window in the application and interpret them as Unicode. For example, if the user types Option-e-e (on a default-configured US English keyboard), I would like to recognize that as "é".

I tried capturing keypress events and calling -[NSEvent characters]. However, as it says in the documentation, "This method returns an empty string for dead keys, such as Option-e." If I type Option-e-e, then it gives me nothing for the Option-e and plain "e" for the second e.

Is there a way to combine a series of keycodes (from -[NSEvent keyCode]) into a Unicode character?

Or a way to receive an event for each Unicode character typed (like Java's key-typed event)?

like image 512
jlstrecker Avatar asked Mar 21 '14 18:03

jlstrecker


1 Answers

Here's a way to take a series of key press events and get the Unicode character(s) they'd type.

Basically, call UCKeyTranslate() for each key press event received. Use its deadKeyState argument to capture a dead key and pass it along to the subsequent call.

Example:

  • Receive key press event for Option-e.
  • Call UCKeyTranslate() with the virtual key code (for e), the modifier key state (for Option), and a variable to store the dead key state.
    • UCKeyTranslate() outputs an empty string and updates the dead key state.
  • Receive key press event for e.
  • Call UCKeyTranlate() with the virtual key code (for e) and the variable that holds the dead key state.
    • UCKeyTranslate() outputs "é".

Sample code (the function to call for each key press event):

/**
 * Returns the Unicode characters that would be typed by a key press.
 *
 * @param event A key press event.
 * @param deadKeyState To capture multi-keystroke characters (e.g. Option-E-E for "é"), pass a reference to the same
 *      variable on consecutive calls to this function. Before the first call, you should initialize the variable to 0.
 * @return One or more Unicode characters.
 */
CFStringRef getCharactersForKeyPress(NSEvent *event, UInt32 *deadKeyState)
{
    // http://stackoverflow.com/questions/12547007/convert-key-code-into-key-equivalent-string
    // http://stackoverflow.com/questions/8263618/convert-virtual-key-code-to-unicode-string

    TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
    CFDataRef layoutData = TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
    const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);

    CGEventFlags flags = [event modifierFlags];
    UInt32 modifierKeyState = (flags >> 16) & 0xFF;

    const size_t unicodeStringLength = 4;
    UniChar unicodeString[unicodeStringLength];
    UniCharCount realLength;

    UCKeyTranslate(keyboardLayout,
                   [event keyCode],
                   kUCKeyActionDown,
                   modifierKeyState,
                   LMGetKbdType(),
                   0,
                   deadKeyState,
                   unicodeStringLength,
                   &realLength,
                   unicodeString);
    CFRelease(currentKeyboard);
    return CFStringCreateWithCharacters(kCFAllocatorDefault, unicodeString, realLength);
}
like image 101
jlstrecker Avatar answered Sep 19 '22 00:09

jlstrecker