Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: ui/events/keycodes/platform_key_map_win.cc

Issue 1585193002: Build key map DomCodeToKey() for Windows (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Wez's review 3 Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/platform_key_map_win.h"
6
7 #include <utility>
8
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "base/threading/thread_local_storage.h"
13
14 #include "ui/events/event_constants.h"
15 #include "ui/events/keycodes/dom/dom_code.h"
16
17 namespace ui {
18
19 namespace {
20
21 struct DomCodeEntry {
22 DomCode dom_code;
23 int scan_code;
24 };
25 #define USB_KEYMAP_DECLARATION const DomCodeEntry supported_dom_code_list[] =
26 #define USB_KEYMAP(usb, evdev, xkb, win, mac, code, id) {DomCode::id, win}
27 #include "ui/events/keycodes/dom/keycode_converter_data.inc"
28 #undef USB_KEYMAP
29 #undef USB_KEYMAP_DECLARATION
30
31 // List of modifiers mentioned in https://w3c.github.io/uievents/#keys-modifiers
32 // Some modifiers are commented out because they usually don't change keys.
33 const EventFlags modifier_flags[] = {
34 EF_SHIFT_DOWN,
chongz 2016/02/12 16:04:03 Yes cl-format wants 4-space indentation. I guess t
35 EF_CONTROL_DOWN,
36 EF_ALT_DOWN,
37 // EF_COMMAND_DOWN,
38 EF_ALTGR_DOWN,
39 // EF_NUM_LOCK_ON,
40 EF_CAPS_LOCK_ON,
41 // EF_SCROLL_LOCK_ON
42 };
43 const int kModifierFlagsCombinations = (1 << arraysize(modifier_flags)) - 1;
44
45 int GetModifierFlags(int combination) {
46 int flags = EF_NONE;
47 for (int i = 0; i < arraysize(modifier_flags); ++i) {
48 if (combination & (1 << i))
49 flags |= modifier_flags[i];
50 }
51 return flags;
52 }
53
54 void SetModifierState(BYTE* keyboard_state, int flags) {
55 // According to MSDN GetKeyState():
56 // 1. If the high-order bit is 1, the key is down; otherwise, it is up.
57 // 2. If the low-order bit is 1, the key is toggled. A key, such as the
58 // CAPS LOCK key, is toggled if it is turned on. The key is off and
59 // untoggled if the low-order bit is 0.
60 // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms646301.aspx
61 if (flags & EF_SHIFT_DOWN)
62 keyboard_state[VK_SHIFT] |= 0x80;
63
64 if (flags & EF_CONTROL_DOWN)
65 keyboard_state[VK_CONTROL] |= 0x80;
66
67 if (flags & EF_ALT_DOWN)
68 keyboard_state[VK_MENU] |= 0x80;
69
70 if (flags & EF_ALTGR_DOWN) {
71 // AltGr should be RightAlt+LeftControl within Windows, but actually only
72 // the non-located keys will work here.
73 keyboard_state[VK_MENU] |= 0x80;
74 keyboard_state[VK_CONTROL] |= 0x80;
75 }
76
77 if (flags & EF_COMMAND_DOWN)
78 keyboard_state[VK_LWIN] |= 0x80;
79
80 if (flags & EF_NUM_LOCK_ON)
81 keyboard_state[VK_NUMLOCK] |= 0x01;
82
83 if (flags & EF_CAPS_LOCK_ON)
84 keyboard_state[VK_CAPITAL] |= 0x01;
85
86 if (flags & EF_SCROLL_LOCK_ON)
87 keyboard_state[VK_SCROLL] |= 0x01;
88 }
89
90 // Use TLS because KeyboardLayout is per thread.
91 // However currently PlatformKeyMap will only be used by the host application,
92 // which is just one process and one thread.
Wez 2016/02/12 21:29:37 nit: This comment looks like it applies to the fun
93 void CleanupKeyMapTls(void* data) {
94 PlatformKeyMap* key_map = reinterpret_cast<PlatformKeyMap*>(data);
95 delete key_map;
96 }
Wez 2016/02/12 21:29:37 nit: I wonder if you could use std::default_delete
97
98 struct PlatformKeyMapInstanceTlsTraits
99 : public base::DefaultLazyInstanceTraits<base::ThreadLocalStorage::Slot> {
100 static base::ThreadLocalStorage::Slot* New(void* instance) {
101 // Use placement new to initialize our instance in our preallocated space.
102 return new (instance) base::ThreadLocalStorage::Slot(CleanupKeyMapTls);
103 }
104 };
105
106 base::LazyInstance<base::ThreadLocalStorage::Slot,
107 PlatformKeyMapInstanceTlsTraits>
108 platform_key_map_tls_lazy = LAZY_INSTANCE_INITIALIZER;
Wez 2016/02/12 21:29:37 nit: Suggest using the g_ prefix as suggested by s
109
110 } // anonymous namespace
111
112 PlatformKeyMap::PlatformKeyMap() {}
113
114 PlatformKeyMap::PlatformKeyMap(HKL layout) {
115 UpdateLayout(layout);
116 }
117
118 DomKey PlatformKeyMap::DomCodeAndFlagsToDomKey(DomCode code, int flags) const {
119 const int flags_to_try[] = {
120 // Trying to match Firefox's behavior and UIEvents DomKey guidelines.
121 // If the combination doesn't produce a printable character, the key value
122 // should be the key with no modifiers except for Shift and AltGr.
123 // See https://w3c.github.io/uievents/#keys-guidelines
124 flags,
chongz 2016/02/12 16:04:03 Same as above.
125 flags & (EF_SHIFT_DOWN | EF_ALTGR_DOWN | EF_CAPS_LOCK_ON),
126 flags & (EF_SHIFT_DOWN | EF_CAPS_LOCK_ON),
127 EF_NONE,
128 };
129
130 DomKey key = DomKey::NONE;
131 for (auto try_flags : flags_to_try) {
132 const auto& it = code_key_map_.find(std::make_pair(code, try_flags));
133 if (it != code_key_map_.end()) {
134 key = it->second;
135 if (key != DomKey::NONE)
136 break;
137 }
138 }
139 return key;
140 }
141
142 // static
143 DomKey PlatformKeyMap::DomCodeAndFlagsToDomKeyStatic(DomCode code, int flags) {
144 base::ThreadLocalStorage::Slot* platform_key_map_tls =
145 platform_key_map_tls_lazy.Pointer();
146 PlatformKeyMap* platform_key_map =
147 reinterpret_cast<PlatformKeyMap*>(platform_key_map_tls->Get());
148 if (!platform_key_map) {
149 platform_key_map = new PlatformKeyMap();
150 platform_key_map_tls->Set(platform_key_map);
151 }
152
153 HKL current_layout = ::GetKeyboardLayout(0);
154 platform_key_map->UpdateLayout(current_layout);
155 return platform_key_map->DomCodeAndFlagsToDomKey(code, flags);
156 }
157
158 void PlatformKeyMap::UpdateLayout(HKL layout) {
159 if (layout == keyboard_layout_)
160 return;
161
162 keyboard_layout_ = layout;
Wez 2016/02/12 21:29:37 nit: Suggest adding a comment here mentioning that
163 code_key_map_.clear();
164 // Map size for some sample keyboard layouts:
165 // US: 428, French: 554, Persian: 434, Vietnamese: 1388
166 code_key_map_.reserve(500);
chongz 2016/02/12 16:04:03 Exact number for some sample layouts without Comma
167
168 BYTE keyboard_state_to_restore[256];
169 ::GetKeyboardState(keyboard_state_to_restore);
170
171 for (int eindex = 0; eindex <= kModifierFlagsCombinations; ++eindex) {
172 BYTE keyboard_state[256];
173 memset(keyboard_state, 0, sizeof(keyboard_state));
174 int flags = GetModifierFlags(eindex);
175 SetModifierState(keyboard_state, flags);
176 for (const auto& dom_code_entry : supported_dom_code_list) {
177 wchar_t translated_chars[5];
178 int key_code = ::MapVirtualKeyEx(dom_code_entry.scan_code,
179 MAPVK_VSC_TO_VK, keyboard_layout_);
180 int rv = ::ToUnicodeEx(key_code, 0, keyboard_state, translated_chars,
181 arraysize(translated_chars), 0, keyboard_layout_);
182
183 if (rv < 0) {
Wez 2016/02/12 21:29:37 The ToUnicodeEx specification says that it returns
184 // Dead key, injecting VK_SPACE to get character representation.
185 BYTE empty_state[256];
186 memset(empty_state, 0, sizeof(empty_state));
187 rv = ::ToUnicodeEx(VK_SPACE, 0, empty_state, translated_chars,
188 arraysize(translated_chars), 0, keyboard_layout_);
189 // Must be a repeat of dead key character.
190 DCHECK(rv == 2);
Wez 2016/02/12 21:29:37 nit: DCHECK_EQ How will this code behave if the s
191 code_key_map_[std::make_pair(dom_code_entry.dom_code, flags)] =
192 DomKey::DeadKeyFromCombiningCharacter(translated_chars[0]);
193 } else if (rv == 1) {
194 if (translated_chars[0] >= 0x20) {
195 code_key_map_[std::make_pair(dom_code_entry.dom_code, flags)] =
196 DomKey::FromCharacter(translated_chars[0]);
197 } else {
198 // Ignores legacy non-printable control characters.
199 }
200 } else {
201 // TODO(chongz): Handle multiple characters case.
202 }
203 }
204 }
205 ::SetKeyboardState(keyboard_state_to_restore);
206 }
207
208 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698