问题
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)?
回答1:
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);
}
回答2:
subclass the view/window you want to capture the "é" event in and add this instance variable
BOOL optionE_Pressed;
then, override keyDown: with this
-(void) keyDown:(NSEvent *)theEvent {
NSString *chars = theEvent.charactersIgnoringModifiers;
unichar aChar = [chars characterAtIndex: 0];
if (aChar==101 && [theEvent modifierFlags]&NSAlternateKeyMask) {
optionE_Pressed=YES;
}
else if (aChar==101 && optionE_Pressed) {
NSLog(@"spanish é pressed");
}
else {
optionE_Pressed=NO;
}
[super keyDown:theEvent];
}
The Boolean variable "optionE_Pressed" is activated when the user holds down the option and e keys. If the next key that is pressed is e, meaning that they have effectively created a spanish é, then it will log "spanish é pressed." Otherwise, the Boolien is switched back to NO. The "super" call at the end allows the user to still be able to type all events as normal
来源:https://stackoverflow.com/questions/22566665/how-to-capture-unicode-from-key-events-without-an-nstextview