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

Side by Side Diff: ui/events/keycodes/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: dtapuska's review 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/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,
Wez 2016/02/11 23:14:45 nit: This indentation doesn't match DomCodeEntry,
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 if (flags & EF_SHIFT_DOWN)
56 keyboard_state[VK_SHIFT] |= 0x80;
57
58 if (flags & EF_CONTROL_DOWN)
59 keyboard_state[VK_CONTROL] |= 0x80;
60
61 if (flags & EF_ALT_DOWN)
62 keyboard_state[VK_MENU] |= 0x80;
63
64 if (flags & EF_ALTGR_DOWN) {
65 // AltGr should be RightAlt+LeftControl within Windows, but actually only
66 // the non-located keys will work here.
67 keyboard_state[VK_MENU] |= 0x80;
68 keyboard_state[VK_CONTROL] |= 0x80;
69 }
70
71 if (flags & EF_COMMAND_DOWN)
72 keyboard_state[VK_LWIN] |= 0x80;
73
74 if (flags & EF_NUM_LOCK_ON)
Wez 2016/02/11 23:14:45 nit: Consider adding a block comment to explain th
75 keyboard_state[VK_NUMLOCK] |= 0x01;
76
77 if (flags & EF_CAPS_LOCK_ON)
78 keyboard_state[VK_CAPITAL] |= 0x01;
79
80 if (flags & EF_SCROLL_LOCK_ON)
81 keyboard_state[VK_SCROLL] |= 0x01;
82 }
83
84 // Use TLS because KeyboardLayout is per thread.
85 // However currently WindowsKeyMap will only be used by the host application,
86 // which is just one process and one thread.
87 void TLSCleanupFunction(void* data) {
Wez 2016/02/11 23:14:45 nit: Style-guide prefers that even abbreviations o
88 WindowsKeyMap* key_map = static_cast<WindowsKeyMap*>(data);
Wez 2016/02/11 23:14:44 reinterpret_cast<> would be more appropriate here,
89 if (key_map)
Wez 2016/02/11 23:14:44 This if() is redundant - delete is fine to call on
90 delete key_map;
91 }
92
93 struct TLSWindowsKeyMapInstanceTraits
94 : public base::DefaultLazyInstanceTraits<base::ThreadLocalStorage::Slot> {
95 static base::ThreadLocalStorage::Slot* New(void* instance) {
96 // Use placement new to initialize our instance in our preallocated space.
97 return new (instance) base::ThreadLocalStorage::Slot(TLSCleanupFunction);
98 }
99 };
100
101 base::LazyInstance<base::ThreadLocalStorage::Slot,
102 TLSWindowsKeyMapInstanceTraits>
103 lazy_tls_key_map = LAZY_INSTANCE_INITIALIZER;
104
105 } // anonymous namespace
106
107 DomKey WindowsKeyMap::DomCodeAndFlagsToDomKey(DomCode code, int flags) const {
108 const int flags_to_try[] = {
109 // Trying to match Firefox's behavior and UIEvents DomKey guidelines.
Wez 2016/02/11 23:14:45 nit: Indentation looks wrong here? Is this what g
110 // If the combination doesn't produce a printable character, the key value
111 // should be the key with no modifiers except for Shift and AltGr.
112 // See https://w3c.github.io/uievents/#keys-guidelines
113 flags,
114 flags & (EF_SHIFT_DOWN | EF_ALTGR_DOWN | EF_CAPS_LOCK_ON),
115 flags & (EF_SHIFT_DOWN | EF_CAPS_LOCK_ON),
116 EF_NONE,
117 };
118
119 DomKey key = DomKey::NONE;
120 for (auto try_flags : flags_to_try) {
121 const auto& it =
122 key_map_.find(std::make_pair(static_cast<int>(code), try_flags));
123 if (it != key_map_.end()) {
124 key = it->second;
125 if (key != DomKey::NONE)
126 break;
127 }
128 }
129 return key;
130 }
131
132 // static
133 DomKey WindowsKeyMap::DomCodeAndFlagsToDomKeyStatic(DomCode code, int flags) {
134 base::ThreadLocalStorage::Slot* tls_slot = lazy_tls_key_map.Pointer();
135 WindowsKeyMap* tls_key_map = static_cast<WindowsKeyMap*>(tls_slot->Get());
136 if (!tls_key_map) {
137 tls_key_map = new WindowsKeyMap();
138 tls_slot->Set(tls_key_map);
139 }
140
141 HKL current_layout = ::GetKeyboardLayout(0);
142 tls_key_map->UpdateLayout(current_layout);
143 return tls_key_map->DomCodeAndFlagsToDomKey(code, flags);
144 }
145
146 void WindowsKeyMap::UpdateLayout(HKL layout) {
147 if (layout == keyboard_layout_)
148 return;
149
150 keyboard_layout_ = layout;
151 key_map_.clear();
152 // Usually the map has ~1000 entries.
Wez 2016/02/11 23:14:45 nit: Have we actually verified exactly how many we
153 key_map_.reserve(1000);
154
155 BYTE keyboard_state_to_restore[256];
156 ::GetKeyboardState(keyboard_state_to_restore);
157
158 for (int eindex = 0; eindex <= kModifierFlagsCombinations; ++eindex) {
159 BYTE keyboard_state[256];
160 memset(keyboard_state, 0, sizeof(keyboard_state));
161 int flags = GetModifierFlags(eindex);
162 SetModifierState(keyboard_state, flags);
163 for (const auto& dom_code_entry : supported_dom_code_list) {
164 wchar_t translated_chars[5];
165 int key_code = ::MapVirtualKeyEx(dom_code_entry.scan_code,
166 MAPVK_VSC_TO_VK, keyboard_layout_);
167 int rv = ::ToUnicodeEx(key_code, 0, keyboard_state, translated_chars,
168 arraysize(translated_chars), 0, keyboard_layout_);
169
170 if (rv < 0) {
171 // Dead key, injecting VK_SPACE to get character representation.
172 BYTE empty_state[256];
173 memset(empty_state, 0, sizeof(empty_state));
174 rv = ::ToUnicodeEx(VK_SPACE, 0, empty_state, translated_chars,
175 arraysize(translated_chars), 0, keyboard_layout_);
176 // Must be a repeat of dead key character.
177 DCHECK(rv == 2);
178 key_map_[std::make_pair(static_cast<int>(dom_code_entry.dom_code),
179 flags)] =
180 DomKey::DeadKeyFromCombiningCharacter(translated_chars[0]);
181 } else if (rv == 1) {
182 if (translated_chars[0] >= 0x20) {
183 key_map_[std::make_pair(static_cast<int>(dom_code_entry.dom_code),
184 flags)] =
185 DomKey::FromCharacter(translated_chars[0]);
186 } else {
187 // Ignores legacy non-printable control characters.
188 }
189 } else {
190 // TODO(chongz): Handle multiple characters case.
191 }
192 }
193 }
194 ::SetKeyboardState(keyboard_state_to_restore);
195 }
196
197 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698