From 7062da944a3fdec34f1ed608bfad35fc7fcb2151 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 29 Mar 2018 14:22:14 +0200 Subject: [PATCH] cocoa: fix ability to type AltGr characters and dead keys It would seem that interpretKeyEvents/insertText would be the right way to do this, but while that does handle AltGr keys correctly, it does not handle dead keys at all. This approach seems to do the right things. --- panda/src/cocoadisplay/cocoaGraphicsWindow.h | 1 + panda/src/cocoadisplay/cocoaGraphicsWindow.mm | 47 ++++++++++++++----- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/panda/src/cocoadisplay/cocoaGraphicsWindow.h b/panda/src/cocoadisplay/cocoaGraphicsWindow.h index 6432ecc3e8..de2bd8d61c 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsWindow.h +++ b/panda/src/cocoadisplay/cocoaGraphicsWindow.h @@ -87,6 +87,7 @@ private: NSWindow *_window; NSView *_view; NSUInteger _modifier_keys; + UInt32 _dead_key_state; CGDirectDisplayID _display; bool _mouse_hidden; bool _context_needs_update; diff --git a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm index 39ecf09162..4984c27062 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm @@ -625,6 +625,9 @@ open_window() { } _fb_properties = cocoagsg->get_fb_properties(); + // Reset dead key state. + _dead_key_state = 0; + // Get the initial mouse position. NSPoint pos = [_window mouseLocationOutsideOfEventStream]; NSPoint loc = [_view convertPoint:pos fromView:nil]; @@ -1391,6 +1394,8 @@ handle_foreground_event(bool foreground) { } } + _dead_key_state = 0; + WindowProperties properties; properties.set_foreground(foreground); system_changed_properties(properties); @@ -1564,25 +1569,43 @@ handle_key_event(NSEvent *event) { return; } + if ([event type] == NSKeyDown) { + // Translate it to a unicode character for keystrokes. I would use + // interpretKeyEvents and insertText, but that doesn't handle dead keys. + TISInputSourceRef input_source = TISCopyCurrentKeyboardInputSource(); + CFDataRef layout_data = (CFDataRef)TISGetInputSourceProperty(input_source, kTISPropertyUnicodeKeyLayoutData); + const UCKeyboardLayout *layout = (const UCKeyboardLayout *)CFDataGetBytePtr(layout_data); + + UInt32 modifier_state = (modifierFlags >> 16) & 0xFF; + UniChar ustr[8]; + UniCharCount length; + + UCKeyTranslate(layout, [event keyCode], kUCKeyActionDown, modifier_state, + LMGetKbdType(), 0, &_dead_key_state, sizeof(ustr), &length, ustr); + CFRelease(input_source); + + for (int i = 0; i < length; ++i) { + UniChar c = ustr[i]; + if (cocoadisplay_cat.is_spam()) { + cocoadisplay_cat.spam() + << "Handling keystroke, character " << (int)c; + if (c < 128 && isprint(c)) { + cocoadisplay_cat.spam(false) << " '" << (char)c << "'"; + } + cocoadisplay_cat.spam(false) << "\n"; + } + _input->keystroke(c); + } + } + NSString *str = [event charactersIgnoringModifiers]; if (str == nil || [str length] == 0) { return; } - nassertv([str length] == 1); + nassertv_always([str length] == 1); unichar c = [str characterAtIndex: 0]; ButtonHandle button = map_key(c); - - if (c < 0xF700 || c >= 0xF900) { - // If a down event and not a special function key, process it as keystroke - // as well. - if ([event type] == NSKeyDown) { - NSString *origstr = [event characters]; - c = [str characterAtIndex: 0]; - _input_devices[0].keystroke(c); - } - } - if (button == ButtonHandle::none()) { // That done, continue trying to find out the button handle. if ([str canBeConvertedToEncoding: NSASCIIStringEncoding]) {