Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ui/events/keycodes/key_map_win.h" | |
| 6 | |
| 7 #include <utility> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "base/macros.h" | |
| 11 | |
| 12 #include "ui/events/event_constants.h" | |
| 13 #include "ui/events/keycodes/dom/dom_code.h" | |
| 14 | |
| 15 namespace ui { | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 struct DomCodeEntry { | |
| 20 DomCode dom_code; | |
| 21 int scan_code; | |
| 22 }; | |
| 23 #define USB_KEYMAP_DECLARATION const DomCodeEntry supported_dom_code_list[] = | |
| 24 #define USB_KEYMAP(usb, evdev, xkb, win, mac, code, id) {DomCode::id, win} | |
| 25 #include "ui/events/keycodes/dom/keycode_converter_data.inc" | |
| 26 #undef USB_KEYMAP | |
| 27 #undef USB_KEYMAP_DECLARATION | |
| 28 | |
| 29 // List of modifiers mentioned in https://w3c.github.io/uievents/#keys-modifiers | |
| 30 // Some modifiers are commented out because they usually don't change keys. | |
| 31 const EventFlags flags_index[] = { | |
|
Wez
2016/02/09 00:18:57
nit: This is the list of interesting modifier flag
| |
| 32 EF_SHIFT_DOWN, | |
| 33 EF_CONTROL_DOWN, | |
| 34 EF_ALT_DOWN, | |
| 35 // EF_COMMAND_DOWN, | |
| 36 EF_ALTGR_DOWN, | |
| 37 // EF_NUM_LOCK_ON, | |
| 38 EF_CAPS_LOCK_ON, | |
| 39 // EF_SCROLL_LOCK_ON | |
| 40 }; | |
| 41 const int kMaxEventFlagsIndex = (1 << arraysize(flags_index)) - 1; | |
|
Wez
2016/02/09 00:18:57
This still isn't the maximum index of the flags_in
| |
| 42 | |
| 43 int GetEventFlagsIndex(int flags) { | |
|
Wez
2016/02/09 00:18:57
I don't see this used anywhere?
| |
| 44 int index = 0; | |
| 45 for (int i = 0; i < arraysize(flags_index); ++i) { | |
| 46 if (flags & flags_index[i]) | |
| 47 index |= 1 << i; | |
| 48 } | |
| 49 return index; | |
| 50 } | |
| 51 | |
| 52 int EventFlagsFromIndex(int index) { | |
|
Wez
2016/02/09 00:18:57
nit: Suggest GetModifierFlags(int combination) if
| |
| 53 int flags = EF_NONE; | |
| 54 for (int i = 0; i < arraysize(flags_index); ++i) { | |
| 55 if (index & (1 << i)) | |
| 56 flags |= flags_index[i]; | |
| 57 } | |
| 58 return flags; | |
| 59 } | |
| 60 | |
| 61 void SetModifierState(BYTE* keyboard_state, int flags) { | |
| 62 if (flags & EF_SHIFT_DOWN) | |
| 63 keyboard_state[VK_SHIFT] |= 0x80; | |
| 64 | |
| 65 if (flags & EF_CONTROL_DOWN) | |
| 66 keyboard_state[VK_CONTROL] |= 0x80; | |
| 67 | |
| 68 if (flags & EF_ALT_DOWN) | |
| 69 keyboard_state[VK_MENU] |= 0x80; | |
| 70 | |
| 71 if (flags & EF_ALTGR_DOWN) { | |
| 72 // AltGr should be RightAlt+LeftControl within Windows, but actually only | |
| 73 // the non-located keys will work here. | |
| 74 keyboard_state[VK_MENU] |= 0x80; | |
|
chongz
2016/02/04 21:10:25
I'm not sure why but only the non-located Alt+Cont
Wez
2016/02/09 00:18:57
OK, sorry for the misleading comment earlier! Not
| |
| 75 keyboard_state[VK_CONTROL] |= 0x80; | |
| 76 } | |
| 77 | |
| 78 if (flags & EF_COMMAND_DOWN) | |
| 79 keyboard_state[VK_LWIN] |= 0x80; | |
| 80 | |
| 81 if (flags & EF_NUM_LOCK_ON) | |
| 82 keyboard_state[VK_NUMLOCK] |= 0x01; | |
| 83 | |
| 84 if (flags & EF_CAPS_LOCK_ON) | |
| 85 keyboard_state[VK_CAPITAL] |= 0x01; | |
| 86 | |
| 87 if (flags & EF_SCROLL_LOCK_ON) | |
| 88 keyboard_state[VK_SCROLL] |= 0x01; | |
| 89 } | |
| 90 | |
| 91 } // anonymous namespace | |
| 92 | |
| 93 WindowsKeyMap::WindowsKeyMap() : keyboard_layout_(0) {} | |
|
Wez
2016/02/09 00:18:57
nit: You can set this via inline initializer in th
| |
| 94 | |
| 95 WindowsKeyMap::WindowsKeyMap(HKL layout) : WindowsKeyMap() { | |
|
Wez
2016/02/09 00:18:57
See above re inline initializer for |keyboard_layo
| |
| 96 LoadLayout(layout); | |
| 97 } | |
| 98 | |
| 99 DomKey WindowsKeyMap::DomCodeToKey(DomCode code, int flags) const { | |
| 100 const int flags_to_try[] = { | |
| 101 // Trying to match Firefox's behavior and UIEvents DomKey guidelines. | |
| 102 // If the combination doesn't produce a printable character, the key value | |
| 103 // should be the key with no modifiers except for Shift and AltGr. | |
| 104 // See https://w3c.github.io/uievents/#keys-guidelines | |
| 105 flags, | |
| 106 flags & (EF_SHIFT_DOWN | EF_ALTGR_DOWN | EF_CAPS_LOCK_ON), | |
| 107 flags & (EF_SHIFT_DOWN | EF_CAPS_LOCK_ON), | |
| 108 EF_NONE, | |
| 109 }; | |
| 110 | |
| 111 DomKey key = DomKey::NONE; | |
| 112 for (auto try_flags : flags_to_try) { | |
| 113 const auto& it = key_map_.find(std::make_pair(code, try_flags)); | |
| 114 if (it != key_map_.end()) | |
| 115 key = it->second.key; | |
| 116 if (key != DomKey::NONE) | |
|
Wez
2016/02/09 00:18:57
nit: You're doing this if() even if you didn't cha
| |
| 117 break; | |
| 118 } | |
| 119 return key; | |
| 120 } | |
| 121 | |
| 122 KeyboardCode WindowsKeyMap::DomCodeToKeyboardCode(DomCode code) const { | |
| 123 const auto& it = key_map_.find(std::make_pair(code, EF_NONE)); | |
| 124 if (it != key_map_.end()) | |
| 125 return it->second.legacy_key_code; | |
| 126 return static_cast<KeyboardCode>(0); | |
| 127 } | |
| 128 | |
| 129 DomCode WindowsKeyMap::KeyboardCodeToDomCode(KeyboardCode key_code) const { | |
|
dtapuska
2016/02/04 20:31:45
Is this really required? I'm not sure if we need a
chongz
2016/02/04 21:10:25
I guess Wez wants it in case user only gives us Ke
Wez
2016/02/09 00:18:57
Let's add it if/when it's actually used!
I was th
| |
| 130 // TODO(chongz): Could create another map to improve efficiency if necessary. | |
| 131 for (const auto& dom_code_entry : supported_dom_code_list) { | |
| 132 if (DomCodeToKeyboardCode(dom_code_entry.dom_code) == key_code) | |
| 133 return dom_code_entry.dom_code; | |
| 134 } | |
| 135 return DomCode::NONE; | |
| 136 } | |
| 137 | |
| 138 DomKey WindowsKeyMap::DomCodeToSystemLayoutKey(DomCode code, int flags) { | |
|
Wez
2016/02/09 00:18:57
static methods should be prefixed with a "// stati
| |
| 139 static base::LazyInstance<WindowsKeyMap>::Leaky s_instance = | |
| 140 LAZY_INSTANCE_INITIALIZER; | |
|
Wez
2016/02/09 00:18:57
Note that the LazyInstance header says it "really
| |
| 141 HKL current_layout = ::GetKeyboardLayout(0); | |
|
chongz
2016/02/04 21:10:25
Still, should I add a lock or only allow it to be
Wez
2016/02/09 00:18:57
GetKeyboardLayout(0) gets the current layout for t
dtapuska
2016/02/09 16:46:39
Likely this code is probably only going to execute
Wez
2016/02/09 22:40:01
On-demand thread-local instance SGTM - do we have
| |
| 142 if (s_instance.Get().keyboard_layout_ != current_layout) | |
| 143 s_instance.Get().LoadLayout(current_layout); | |
| 144 return s_instance.Get().DomCodeToKey(code, flags); | |
| 145 } | |
| 146 | |
| 147 void WindowsKeyMap::LoadLayout(HKL layout) { | |
| 148 keyboard_layout_ = layout; | |
| 149 key_map_.clear(); | |
| 150 | |
| 151 BYTE keyboard_state_to_restore[256]; | |
| 152 ::GetKeyboardState(keyboard_state_to_restore); | |
| 153 | |
| 154 for (int eindex = 0; eindex <= kMaxEventFlagsIndex; ++eindex) { | |
| 155 BYTE keyboard_state[256]; | |
| 156 memset(keyboard_state, 0, sizeof(keyboard_state)); | |
| 157 int flags = EventFlagsFromIndex(eindex); | |
| 158 SetModifierState(keyboard_state, flags); | |
| 159 for (const auto& dom_code_entry : supported_dom_code_list) { | |
| 160 wchar_t translated_chars[5]; | |
| 161 int key_code = ::MapVirtualKeyEx(dom_code_entry.scan_code, | |
| 162 MAPVK_VSC_TO_VK, keyboard_layout_); | |
| 163 int rv = ::ToUnicodeEx(key_code, 0, keyboard_state, translated_chars, | |
| 164 arraysize(translated_chars), 0, keyboard_layout_); | |
| 165 | |
| 166 if (rv < 0) { | |
| 167 // Dead key, injecting VK_SPACE to get character representation. | |
| 168 BYTE empty_state[256]; | |
| 169 memset(empty_state, 0, sizeof(empty_state)); | |
| 170 rv = ::ToUnicodeEx(VK_SPACE, 0, empty_state, translated_chars, | |
| 171 arraysize(translated_chars), 0, keyboard_layout_); | |
| 172 // Must be a repeat of dead key character. | |
| 173 DCHECK(rv == 2); | |
| 174 AddKeyMapEntry( | |
| 175 dom_code_entry.dom_code, | |
| 176 DomKey::DeadKeyFromCombiningCharacter(translated_chars[0]), | |
| 177 static_cast<KeyboardCode>(key_code), flags); | |
| 178 } else if (rv == 1) { | |
| 179 if (translated_chars[0] >= 0x20) { | |
| 180 AddKeyMapEntry(dom_code_entry.dom_code, | |
| 181 DomKey::FromCharacter(translated_chars[0]), | |
| 182 static_cast<KeyboardCode>(key_code), flags); | |
| 183 } else { | |
| 184 // Ignores legacy non-printable control characters. | |
| 185 } | |
| 186 } else { | |
| 187 // TODO(chongz): Handle multiple characters case. | |
|
dtapuska
2016/02/04 20:31:45
What are we going to do with non-printable charact
chongz
2016/02/04 21:10:25
I will add (copy?) the US non-printable table here
| |
| 188 } | |
| 189 } | |
| 190 } | |
| 191 ::SetKeyboardState(keyboard_state_to_restore); | |
| 192 } | |
| 193 | |
| 194 void WindowsKeyMap::AddKeyMapEntry(DomCode code, | |
| 195 DomKey key, | |
| 196 KeyboardCode legacy_key_code, | |
| 197 int flags) { | |
| 198 key_map_[std::make_pair(code, flags)] = | |
| 199 KeyMapEntry{code, key, legacy_key_code, flags}; | |
| 200 } | |
| 201 | |
| 202 } // namespace ui | |
| OLD | NEW |