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

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: wez's review 2 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/logging.h"
10 #include "base/macros.h"
11 #include "base/threading/thread_local_storage.h"
12
13 #include "ui/events/event_constants.h"
14 #include "ui/events/keycodes/dom/dom_code.h"
15
16 namespace ui {
17
18 namespace {
19
20 struct DomCodeEntry {
21 DomCode dom_code;
22 int scan_code;
23 };
24 #define USB_KEYMAP_DECLARATION const DomCodeEntry supported_dom_code_list[] =
25 #define USB_KEYMAP(usb, evdev, xkb, win, mac, code, id) {DomCode::id, win}
26 #include "ui/events/keycodes/dom/keycode_converter_data.inc"
27 #undef USB_KEYMAP
28 #undef USB_KEYMAP_DECLARATION
29
30 // List of modifiers mentioned in https://w3c.github.io/uievents/#keys-modifiers
31 // Some modifiers are commented out because they usually don't change keys.
32 const EventFlags modifier_flags[] = {
33 EF_SHIFT_DOWN,
34 EF_CONTROL_DOWN,
35 EF_ALT_DOWN,
36 // EF_COMMAND_DOWN,
37 EF_ALTGR_DOWN,
38 // EF_NUM_LOCK_ON,
39 EF_CAPS_LOCK_ON,
40 // EF_SCROLL_LOCK_ON
41 };
42 const int kModifierFlagsCombinations = (1 << arraysize(modifier_flags)) - 1;
43
44 int GetModifierFlags(int combination) {
45 int flags = EF_NONE;
46 for (int i = 0; i < arraysize(modifier_flags); ++i) {
47 if (combination & (1 << i))
48 flags |= modifier_flags[i];
49 }
50 return flags;
51 }
52
53 void SetModifierState(BYTE* keyboard_state, int flags) {
54 if (flags & EF_SHIFT_DOWN)
55 keyboard_state[VK_SHIFT] |= 0x80;
56
57 if (flags & EF_CONTROL_DOWN)
58 keyboard_state[VK_CONTROL] |= 0x80;
59
60 if (flags & EF_ALT_DOWN)
61 keyboard_state[VK_MENU] |= 0x80;
62
63 if (flags & EF_ALTGR_DOWN) {
64 // AltGr should be RightAlt+LeftControl within Windows, but actually only
65 // the non-located keys will work here.
66 keyboard_state[VK_MENU] |= 0x80;
67 keyboard_state[VK_CONTROL] |= 0x80;
68 }
69
70 if (flags & EF_COMMAND_DOWN)
71 keyboard_state[VK_LWIN] |= 0x80;
72
73 if (flags & EF_NUM_LOCK_ON)
74 keyboard_state[VK_NUMLOCK] |= 0x01;
75
76 if (flags & EF_CAPS_LOCK_ON)
77 keyboard_state[VK_CAPITAL] |= 0x01;
78
79 if (flags & EF_SCROLL_LOCK_ON)
80 keyboard_state[VK_SCROLL] |= 0x01;
81 }
82
83 // Use TLS because KeyboardLayout is per thread.
84 // However usually WindowsKeyMap will be used by the host application, which is
85 // just one process and one thread.
86 static base::ThreadLocalStorage::StaticSlot s_tls_key_map = TLS_INITIALIZER;
chongz 2016/02/10 01:25:10 I'm not sure I'm using it in the right way?
dtapuska 2016/02/10 21:56:34 From the other patterns this seems fine; although
87
88 void ThreadCleanupFunction(void* data) {
89 WindowsKeyMap* key_map = static_cast<WindowsKeyMap*>(data);
90 if (key_map)
91 delete key_map;
92 }
93
94 } // anonymous namespace
95
96 DomKey WindowsKeyMap::DomCodeAndFlagsToKey(DomCode code, int flags) const {
97 const int flags_to_try[] = {
98 // Trying to match Firefox's behavior and UIEvents DomKey guidelines.
99 // If the combination doesn't produce a printable character, the key value
100 // should be the key with no modifiers except for Shift and AltGr.
101 // See https://w3c.github.io/uievents/#keys-guidelines
102 flags,
103 flags & (EF_SHIFT_DOWN | EF_ALTGR_DOWN | EF_CAPS_LOCK_ON),
104 flags & (EF_SHIFT_DOWN | EF_CAPS_LOCK_ON),
105 EF_NONE,
106 };
107
108 DomKey key = DomKey::NONE;
109 for (auto try_flags : flags_to_try) {
110 const auto& it =
111 key_map_.find(std::make_pair(static_cast<int>(code), try_flags));
112 if (it != key_map_.end()) {
113 key = it->second;
114 if (key != DomKey::NONE)
115 break;
116 }
117 }
118 return key;
119 }
120
121 // static
122 DomKey WindowsKeyMap::CodeAndFlagsToDomKey(DomCode code, int flags) {
123 if (!s_tls_key_map.initialized()) {
124 s_tls_key_map.Initialize(ThreadCleanupFunction);
chongz 2016/02/10 01:25:10 Should I add a lock here? Currently it's only used
125 }
126 WindowsKeyMap* tls_key_map = static_cast<WindowsKeyMap*>(s_tls_key_map.Get());
127 if (!tls_key_map) {
128 tls_key_map = new WindowsKeyMap();
129 s_tls_key_map.Set(tls_key_map);
130 }
131
132 HKL current_layout = ::GetKeyboardLayout(0);
133 tls_key_map->UpdateLayout(current_layout);
134 return tls_key_map->DomCodeAndFlagsToKey(code, flags);
135 }
136
137 void WindowsKeyMap::UpdateLayout(HKL layout) {
138 if (layout == keyboard_layout_)
139 return;
140
141 keyboard_layout_ = layout;
142 key_map_.clear();
143 // Usually the map has ~1000 entries.
144 key_map_.reserve(1000);
chongz 2016/02/10 01:25:10 Could be less if we can use some fallback for the
145
146 BYTE keyboard_state_to_restore[256];
147 ::GetKeyboardState(keyboard_state_to_restore);
148
149 for (int eindex = 0; eindex <= kModifierFlagsCombinations; ++eindex) {
150 BYTE keyboard_state[256];
151 memset(keyboard_state, 0, sizeof(keyboard_state));
152 int flags = GetModifierFlags(eindex);
153 SetModifierState(keyboard_state, flags);
154 for (const auto& dom_code_entry : supported_dom_code_list) {
155 wchar_t translated_chars[5];
156 int key_code = ::MapVirtualKeyEx(dom_code_entry.scan_code,
157 MAPVK_VSC_TO_VK, keyboard_layout_);
158 int rv = ::ToUnicodeEx(key_code, 0, keyboard_state, translated_chars,
159 arraysize(translated_chars), 0, keyboard_layout_);
160
161 if (rv < 0) {
162 // Dead key, injecting VK_SPACE to get character representation.
163 BYTE empty_state[256];
164 memset(empty_state, 0, sizeof(empty_state));
165 rv = ::ToUnicodeEx(VK_SPACE, 0, empty_state, translated_chars,
166 arraysize(translated_chars), 0, keyboard_layout_);
167 // Must be a repeat of dead key character.
168 DCHECK(rv == 2);
169 key_map_[std::make_pair(static_cast<int>(dom_code_entry.dom_code),
170 flags)] =
171 DomKey::DeadKeyFromCombiningCharacter(translated_chars[0]);
172 } else if (rv == 1) {
173 if (translated_chars[0] >= 0x20) {
174 key_map_[std::make_pair(static_cast<int>(dom_code_entry.dom_code),
175 flags)] =
176 DomKey::FromCharacter(translated_chars[0]);
177 } else {
178 // Ignores legacy non-printable control characters.
179 }
180 } else {
181 // TODO(chongz): Handle multiple characters case.
182 }
183 }
184 }
185 ::SetKeyboardState(keyboard_state_to_restore);
186 }
187
188 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698