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);
}