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 |