| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ui/events/keycodes/keyboard_code_conversion_mac.h" | 5 #import "ui/events/keycodes/keyboard_code_conversion_mac.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #import <Carbon/Carbon.h> | 9 #import <Carbon/Carbon.h> |
| 10 | 10 |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/mac/mac_logging.h" |
| 13 #include "base/mac/scoped_cftyperef.h" |
| 12 #include "base/macros.h" | 14 #include "base/macros.h" |
| 13 #include "ui/events/keycodes/dom/keycode_converter.h" | 15 #include "ui/events/keycodes/dom/keycode_converter.h" |
| 14 | 16 |
| 15 namespace ui { | 17 namespace ui { |
| 16 | 18 |
| 17 namespace { | 19 namespace { |
| 18 | 20 |
| 19 // A struct to hold a Windows keycode to Mac virtual keycode mapping. | 21 // A struct to hold a Windows keycode to Mac virtual keycode mapping. |
| 20 struct KeyCodeMap { | 22 struct KeyCodeMap { |
| 21 KeyboardCode keycode; | 23 KeyboardCode keycode; |
| (...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 }; | 434 }; |
| 433 | 435 |
| 434 if (keyCode >= 0x80) | 436 if (keyCode >= 0x80) |
| 435 return VKEY_UNKNOWN; | 437 return VKEY_UNKNOWN; |
| 436 | 438 |
| 437 return kKeyboardCodes[keyCode]; | 439 return kKeyboardCodes[keyCode]; |
| 438 } | 440 } |
| 439 | 441 |
| 440 DomKey DomKeyFromKeyCode(unsigned short keyCode) { | 442 DomKey DomKeyFromKeyCode(unsigned short keyCode) { |
| 441 switch (keyCode) { | 443 switch (keyCode) { |
| 444 case kVK_ANSI_KeypadEnter: |
| 442 case kVK_Return: | 445 case kVK_Return: |
| 443 return DomKey::ENTER; | 446 return DomKey::ENTER; |
| 444 case kVK_Tab: | 447 case kVK_Tab: |
| 445 return DomKey::TAB; | 448 return DomKey::TAB; |
| 446 case kVK_Delete: | 449 case kVK_Delete: |
| 447 return DomKey::BACKSPACE; | 450 return DomKey::BACKSPACE; |
| 448 case kVK_Escape: | 451 case kVK_Escape: |
| 449 return DomKey::ESCAPE; | 452 return DomKey::ESCAPE; |
| 450 case kVK_Command: | 453 case kVK_Command: |
| 451 return DomKey::META; | 454 return DomKey::META; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 528 return DomKey::ARROW_DOWN; | 531 return DomKey::ARROW_DOWN; |
| 529 case kVK_UpArrow: | 532 case kVK_UpArrow: |
| 530 return DomKey::ARROW_UP; | 533 return DomKey::ARROW_UP; |
| 531 default: | 534 default: |
| 532 return DomKey::NONE; | 535 return DomKey::NONE; |
| 533 } | 536 } |
| 534 } | 537 } |
| 535 | 538 |
| 536 DomKey DomKeyFromCharCode(unichar char_code) { | 539 DomKey DomKeyFromCharCode(unichar char_code) { |
| 537 switch (char_code) { | 540 switch (char_code) { |
| 538 case 0x03: | |
| 539 return DomKey::ENTER; // Numpad Enter | |
| 540 // Mac maps backspace to forward delete unicode. | |
| 541 case 0x7f: | |
| 542 return DomKey::BACKSPACE; | |
| 543 case NSUpArrowFunctionKey: | 541 case NSUpArrowFunctionKey: |
| 544 return DomKey::ARROW_UP; | 542 return DomKey::ARROW_UP; |
| 545 case NSDownArrowFunctionKey: | 543 case NSDownArrowFunctionKey: |
| 546 return DomKey::ARROW_DOWN; | 544 return DomKey::ARROW_DOWN; |
| 547 case NSLeftArrowFunctionKey: | 545 case NSLeftArrowFunctionKey: |
| 548 return DomKey::ARROW_LEFT; | 546 return DomKey::ARROW_LEFT; |
| 549 case NSRightArrowFunctionKey: | 547 case NSRightArrowFunctionKey: |
| 550 return DomKey::ARROW_RIGHT; | 548 return DomKey::ARROW_RIGHT; |
| 551 case NSF1FunctionKey: | 549 case NSF1FunctionKey: |
| 552 return DomKey::F1; | 550 return DomKey::F1; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 return DomKey::REDO; | 626 return DomKey::REDO; |
| 629 case NSFindFunctionKey: | 627 case NSFindFunctionKey: |
| 630 return DomKey::FIND; | 628 return DomKey::FIND; |
| 631 case NSHelpFunctionKey: | 629 case NSHelpFunctionKey: |
| 632 return DomKey::HELP; | 630 return DomKey::HELP; |
| 633 default: | 631 default: |
| 634 return DomKey::FromCharacter(char_code); | 632 return DomKey::FromCharacter(char_code); |
| 635 } | 633 } |
| 636 } | 634 } |
| 637 | 635 |
| 636 UniChar MacKeycodeAndModifiersToCharacter(unsigned short mac_keycode, |
| 637 int modifiers) { |
| 638 // Convert NSEvent modifiers to format UCKeyTranslate accepts. See docs |
| 639 // on UCKeyTranslate for more info. |
| 640 int unicode_modifiers = 0; |
| 641 if (modifiers & NSShiftKeyMask) |
| 642 unicode_modifiers |= shiftKey; |
| 643 if (modifiers & NSAlphaShiftKeyMask) |
| 644 unicode_modifiers |= alphaLock; |
| 645 // if (modifiers & NSControlKeyMask) |
| 646 // unicode_modifiers |= controlKey; |
| 647 if (modifiers & NSAlternateKeyMask) |
| 648 unicode_modifiers |= optionKey; |
| 649 // if (modifiers & NSCommandKeyMask) |
| 650 // unicode_modifiers |= cmdKey; |
| 651 UInt32 modifier_key_state = (unicode_modifiers >> 8) & 0xFF; |
| 652 |
| 653 base::ScopedCFTypeRef<TISInputSourceRef> input_source_copy( |
| 654 TISCopyCurrentKeyboardLayoutInputSource()); |
| 655 CFDataRef layout_data = static_cast<CFDataRef>(TISGetInputSourceProperty( |
| 656 input_source_copy, kTISPropertyUnicodeKeyLayoutData)); |
| 657 const UCKeyboardLayout* layout = |
| 658 reinterpret_cast<const UCKeyboardLayout*>(CFDataGetBytePtr(layout_data)); |
| 659 |
| 660 UInt32 dead_key_state = 0; |
| 661 UniCharCount char_count = 0; |
| 662 // According Apple's doc UCKeyTranslate::maxStringLength maybe up to 255 but |
| 663 // would actually be rare to get more than 4. |
| 664 UniChar unicode_string[4]; |
| 665 OSStatus status = |
| 666 UCKeyTranslate(layout, static_cast<UInt16>(mac_keycode), kUCKeyActionDown, |
| 667 modifier_key_state, LMGetKbdLast(), 0, &dead_key_state, |
| 668 arraysize(unicode_string), &char_count, unicode_string); |
| 669 |
| 670 OSSTATUS_DCHECK(status == noErr, status); |
| 671 if (dead_key_state != 0) { |
| 672 // A dead key, injecting space to get the diacritic in an isolated form. |
| 673 status = UCKeyTranslate(layout, static_cast<UInt16>(kVK_Space), |
| 674 kUCKeyActionDown, 0, LMGetKbdLast(), 0, |
| 675 &dead_key_state, arraysize(unicode_string), |
| 676 &char_count, unicode_string); |
| 677 OSSTATUS_DCHECK(status == noErr, status); |
| 678 } |
| 679 |
| 680 // TODO(chongz): Handle multiple character case. Should be rare. |
| 681 return unicode_string[0]; |
| 682 } |
| 683 |
| 638 } // namespace | 684 } // namespace |
| 639 | 685 |
| 640 int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode, | 686 int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode, |
| 641 NSUInteger flags, | 687 NSUInteger flags, |
| 642 unichar* us_keyboard_shifted_character, | 688 unichar* us_keyboard_shifted_character, |
| 643 unichar* keyboard_character) { | 689 unichar* keyboard_character) { |
| 644 // In release code, |flags| is used to lookup accelerators, so logic to handle | 690 // In release code, |flags| is used to lookup accelerators, so logic to handle |
| 645 // caps lock properly isn't implemented. | 691 // caps lock properly isn't implemented. |
| 646 DCHECK_EQ(0u, flags & NSAlphaShiftKeyMask); | 692 DCHECK_EQ(0u, flags & NSAlphaShiftKeyMask); |
| 647 | 693 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 } | 781 } |
| 736 return KeyboardCodeFromKeyCode([event keyCode]); | 782 return KeyboardCodeFromKeyCode([event keyCode]); |
| 737 } | 783 } |
| 738 | 784 |
| 739 DomCode DomCodeFromNSEvent(NSEvent* event) { | 785 DomCode DomCodeFromNSEvent(NSEvent* event) { |
| 740 return ui::KeycodeConverter::NativeKeycodeToDomCode([event keyCode]); | 786 return ui::KeycodeConverter::NativeKeycodeToDomCode([event keyCode]); |
| 741 } | 787 } |
| 742 | 788 |
| 743 DomKey DomKeyFromNSEvent(NSEvent* event) { | 789 DomKey DomKeyFromNSEvent(NSEvent* event) { |
| 744 // Apply the lookup based on the character first since that has the | 790 // Apply the lookup based on the character first since that has the |
| 745 // Keyboard layout and modifers already applied; whereas the keyCode | 791 // Keyboard layout and modifiers already applied; whereas the keyCode |
| 746 // doesn't. | 792 // doesn't. |
| 747 if ([event type] == NSKeyDown || [event type] == NSKeyUp) { | 793 if ([event type] == NSKeyDown || [event type] == NSKeyUp) { |
| 794 // Have to use [event characters] to handle dead key state. |
| 748 NSString* characters = [event characters]; | 795 NSString* characters = [event characters]; |
| 749 if ([characters length] > 0) | 796 if ([characters length] > 0) { |
| 750 return DomKeyFromCharCode([characters characterAtIndex:0]); | 797 // An invalid dead key combination will produce two characters, according |
| 798 // to spec DomKey should be the last character. |
| 799 // e.g. On French keyboard [+a will produce "^q", DomKey should be 'q'. |
| 800 unichar dom_key_char = |
| 801 [characters characterAtIndex:[characters length] - 1]; |
| 802 const bool is_ctrl_down = ([event modifierFlags] & NSControlKeyMask) && |
| 803 !([event modifierFlags] & NSAlternateKeyMask); |
| 804 const bool is_command_down = [event modifierFlags] & NSCommandKeyMask; |
| 805 // On Mac Blink won't insert ASCII character if either Ctrl or Command, or |
| 806 // both, are down. |
| 807 // See EditingBehavior::shouldInsertCharacter() |
| 808 if (std::iscntrl(dom_key_char) || |
| 809 (dom_key_char < 0x80 && (is_ctrl_down || is_command_down))) { |
| 810 // According to spec if the key combination produces a non-printable |
| 811 // character, the key value should be the character without modifiers |
| 812 // except Shift and AltGr. |
| 813 // See https://w3c.github.io/uievents/#keys-guidelines |
| 814 const int kAllowedModifiersMask = |
| 815 NSShiftKeyMask | NSAlphaShiftKeyMask | NSAlternateKeyMask; |
| 816 // MacKeycodeAndModifiersToCharacter() is efficient (around 6E-4 ms). |
| 817 dom_key_char = MacKeycodeAndModifiersToCharacter( |
| 818 [event keyCode], [event modifierFlags] & kAllowedModifiersMask); |
| 819 } |
| 820 if (!std::iscntrl(dom_key_char)) |
| 821 return DomKeyFromCharCode(dom_key_char); |
| 822 } |
| 751 } | 823 } |
| 752 return DomKeyFromKeyCode([event keyCode]); | 824 return DomKeyFromKeyCode([event keyCode]); |
| 753 } | 825 } |
| 754 | 826 |
| 755 } // namespace ui | 827 } // namespace ui |
| OLD | NEW |