Chromium Code Reviews| Index: ui/events/keycodes/keyboard_code_conversion_mac.mm |
| diff --git a/ui/events/keycodes/keyboard_code_conversion_mac.mm b/ui/events/keycodes/keyboard_code_conversion_mac.mm |
| index f435f4ed2b966d19a8524ccc2fe63ef61c93c91f..96f75a5a86ee918090aa4c8684ffe640764f24b7 100644 |
| --- a/ui/events/keycodes/keyboard_code_conversion_mac.mm |
| +++ b/ui/events/keycodes/keyboard_code_conversion_mac.mm |
| @@ -9,6 +9,7 @@ |
| #import <Carbon/Carbon.h> |
| #include "base/logging.h" |
| +#include "base/mac/scoped_cftyperef.h" |
| #include "base/macros.h" |
| #include "ui/events/keycodes/dom/keycode_converter.h" |
| @@ -635,6 +636,57 @@ DomKey DomKeyFromCharCode(unichar char_code) { |
| } |
| } |
| +UniChar KeycodeAndModifiersToCharacter(unsigned short native_key_code, |
| + int modifiers, |
| + bool& is_deadkey) { |
| + // Convert EventRecord modifiers to format UCKeyTranslate accepts. See docs |
| + // on UCKeyTranslate for more info. |
| + int native_modifiersers = 0; |
| + if (modifiers & NSShiftKeyMask) |
| + native_modifiersers |= shiftKey; |
| + if (modifiers & NSAlphaShiftKeyMask) |
| + native_modifiersers |= alphaLock; |
| + if (modifiers & NSControlKeyMask) |
| + native_modifiersers |= controlKey; |
| + if (modifiers & NSAlternateKeyMask) |
| + native_modifiersers |= optionKey; |
| + if (modifiers & NSCommandKeyMask) |
| + native_modifiersers |= cmdKey; |
| + UInt32 modifier_key_state = (native_modifiersers >> 8) & 0xFF; |
| + |
| + base::ScopedCFTypeRef<TISInputSourceRef> input_source_copy( |
| + TISCopyCurrentKeyboardLayoutInputSource()); |
| + CFDataRef layout_data = static_cast<CFDataRef>(TISGetInputSourceProperty( |
| + input_source_copy, kTISPropertyUnicodeKeyLayoutData)); |
| + |
| + UInt32 dead_key_state = 0; |
| + UniCharCount char_count = 0; |
| + UniChar character = 0; |
| + OSStatus status = UCKeyTranslate( |
| + reinterpret_cast<const UCKeyboardLayout*>(CFDataGetBytePtr(layout_data)), |
| + static_cast<UInt16>(native_key_code), kUCKeyActionDown, |
| + modifier_key_state, LMGetKbdLast(), kUCKeyTranslateNoDeadKeysBit, |
| + &dead_key_state, 1, &char_count, &character); |
| + |
| + // According to Apple's doc an empty string means dead keys. |
| + // https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSEvent_Class/#//apple_ref/occ/instp/NSEvent/characters |
| + if (status == noErr && char_count == 0) |
| + is_deadkey = true; |
| + else |
| + is_deadkey = false; |
| + |
| + if (is_deadkey) { |
| + // Inject space to get character value of dead key. |
| + UCKeyTranslate(reinterpret_cast<const UCKeyboardLayout*>( |
| + CFDataGetBytePtr(layout_data)), |
| + static_cast<UInt16>(kVK_Space), kUCKeyActionDown, 0, |
| + LMGetKbdLast(), kUCKeyTranslateNoDeadKeysBit, |
| + &dead_key_state, 1, &char_count, &character); |
| + } |
| + |
| + return character; |
| +} |
| + |
| } // namespace |
| int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode, |
| @@ -745,9 +797,29 @@ DomKey DomKeyFromNSEvent(NSEvent* event) { |
| // Keyboard layout and modifers already applied; whereas the keyCode |
| // doesn't. |
| if ([event type] == NSKeyDown || [event type] == NSKeyUp) { |
| + // Need [event characters] to handle dead key state. |
| NSString* characters = [event characters]; |
| - if ([characters length] > 0) |
| - return DomKeyFromCharCode([characters characterAtIndex:0]); |
| + if ([characters length] > 0) { |
| + // An invalid dead key combination will produce two characters, according |
| + // to spec DomKey should be the last character. |
| + // e.g. On French keyboard [+a will produce "^q", DomKey should be 'q'. |
| + unichar dom_key_char = |
|
chongz
2016/02/18 06:04:08
French [Digit2] and [Shift + Digit2] will both pro
|
| + [characters characterAtIndex:[characters length] - 1]; |
| + if ([event modifierFlags] != 0 && std::iscntrl(dom_key_char)) { |
| + // According to spec if the key combination produces a non-printable |
| + // character, the key value should be the character without modifiers |
| + // except Shift and AltGr. |
| + // See https://w3c.github.io/uievents/#keys-guidelines |
| + bool is_deadkey; |
| + const int fallback_modifiers = |
| + NSShiftKeyMask | NSAlphaShiftKeyMask | NSAlternateKeyMask; |
|
chongz
2016/02/18 06:04:07
Use custom fallback modifiers here since NSEvent::
|
| + // KeycodeAndModifiersToCharacter() is efficient (around 1.2E-3 ms). |
| + dom_key_char = KeycodeAndModifiersToCharacter( |
|
chongz
2016/02/18 06:04:08
In this stage we don't care about dead keys any mo
|
| + [event keyCode], [event modifierFlags] & fallback_modifiers, |
| + is_deadkey); |
| + } |
| + return DomKeyFromCharCode(dom_key_char); |
| + } |
| } |
| return DomKeyFromKeyCode([event keyCode]); |
| } |