Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / events / keycodes / dom / keycode_converter.cc
blob60b6ad4bb02835cba0c3090c251fa32ffa11ecf7
1 // Copyright 2013 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.
5 #include "ui/events/keycodes/dom/keycode_converter.h"
7 #include "base/logging.h"
8 #include "base/strings/utf_string_conversion_utils.h"
9 #include "ui/events/keycodes/dom/dom_code.h"
10 #include "ui/events/keycodes/dom/dom_key.h"
12 namespace ui {
14 namespace {
16 // Table of USB codes (equivalent to DomCode values), native scan codes,
17 // and DOM Level 3 |code| strings.
18 #if defined(OS_WIN)
19 #define USB_KEYMAP(usb, evdev, xkb, win, mac, code, id) {usb, win, code}
20 #elif defined(OS_LINUX)
21 #define USB_KEYMAP(usb, evdev, xkb, win, mac, code, id) {usb, xkb, code}
22 #elif defined(OS_MACOSX)
23 #define USB_KEYMAP(usb, evdev, xkb, win, mac, code, id) {usb, mac, code}
24 #elif defined(OS_ANDROID)
25 #define USB_KEYMAP(usb, evdev, xkb, win, mac, code, id) {usb, evdev, code}
26 #else
27 #define USB_KEYMAP(usb, evdev, xkb, win, mac, code, id) {usb, 0, code}
28 #endif
29 #define USB_KEYMAP_DECLARATION const KeycodeMapEntry usb_keycode_map[] =
30 #include "ui/events/keycodes/dom/keycode_converter_data.inc"
31 #undef USB_KEYMAP
32 #undef USB_KEYMAP_DECLARATION
34 const size_t kKeycodeMapEntries = arraysize(usb_keycode_map);
36 // Table of DomKey enum values and DOM Level 3 |key| strings.
37 struct DomKeyMapEntry {
38 DomKey dom_key;
39 const char* string;
42 #define DOM_KEY_MAP_DECLARATION const DomKeyMapEntry dom_key_map[] =
43 #define DOM_KEY_UNI(key, id, value) {DomKey::id, key}
44 #define DOM_KEY_MAP_BEGIN
45 #define DOM_KEY_MAP(key, id) {DomKey::id, key}
46 #define DOM_KEY_MAP_END
47 #include "ui/events/keycodes/dom/dom_key_data.inc"
48 #undef DOM_KEY_MAP_DECLARATION
49 #undef DOM_KEY_MAP_BEGIN
50 #undef DOM_KEY_MAP
51 #undef DOM_KEY_MAP_END
52 #undef DOM_KEY_UNI
54 const size_t kDomKeyMapEntries = arraysize(dom_key_map);
56 } // namespace
58 // static
59 size_t KeycodeConverter::NumKeycodeMapEntriesForTest() {
60 return kKeycodeMapEntries;
63 // static
64 const KeycodeMapEntry* KeycodeConverter::GetKeycodeMapForTest() {
65 return &usb_keycode_map[0];
68 // static
69 const char* KeycodeConverter::DomKeyStringForTest(size_t index) {
70 if (index >= kDomKeyMapEntries)
71 return nullptr;
72 return dom_key_map[index].string;
75 // static
76 int KeycodeConverter::InvalidNativeKeycode() {
77 return usb_keycode_map[0].native_keycode;
80 // static
81 DomCode KeycodeConverter::NativeKeycodeToDomCode(int native_keycode) {
82 for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
83 if (usb_keycode_map[i].native_keycode == native_keycode) {
84 if (usb_keycode_map[i].code != NULL)
85 return static_cast<DomCode>(usb_keycode_map[i].usb_keycode);
86 break;
89 return DomCode::NONE;
92 // static
93 int KeycodeConverter::DomCodeToNativeKeycode(DomCode code) {
94 return UsbKeycodeToNativeKeycode(static_cast<uint32_t>(code));
97 // static
98 DomCode KeycodeConverter::CodeStringToDomCode(const char* code) {
99 if (!code || !*code) {
100 LOG(WARNING) << "empty code string";
101 return DomCode::NONE;
103 for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
104 if (usb_keycode_map[i].code &&
105 strcmp(usb_keycode_map[i].code, code) == 0) {
106 return static_cast<DomCode>(usb_keycode_map[i].usb_keycode);
109 LOG(WARNING) << "unrecognized code string '" << code << "'";
110 return DomCode::NONE;
113 // static
114 const char* KeycodeConverter::DomCodeToCodeString(DomCode dom_code) {
115 for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
116 if (usb_keycode_map[i].usb_keycode == static_cast<uint32_t>(dom_code)) {
117 if (usb_keycode_map[i].code)
118 return usb_keycode_map[i].code;
119 break;
122 return "";
125 // static
126 DomKeyLocation KeycodeConverter::DomCodeToLocation(DomCode dom_code) {
127 static const struct {
128 DomCode code;
129 DomKeyLocation location;
130 } kLocations[] = {{DomCode::CONTROL_LEFT, DomKeyLocation::LEFT},
131 {DomCode::SHIFT_LEFT, DomKeyLocation::LEFT},
132 {DomCode::ALT_LEFT, DomKeyLocation::LEFT},
133 {DomCode::OS_LEFT, DomKeyLocation::LEFT},
134 {DomCode::CONTROL_RIGHT, DomKeyLocation::RIGHT},
135 {DomCode::SHIFT_RIGHT, DomKeyLocation::RIGHT},
136 {DomCode::ALT_RIGHT, DomKeyLocation::RIGHT},
137 {DomCode::OS_RIGHT, DomKeyLocation::RIGHT},
138 {DomCode::NUMPAD_DIVIDE, DomKeyLocation::NUMPAD},
139 {DomCode::NUMPAD_MULTIPLY, DomKeyLocation::NUMPAD},
140 {DomCode::NUMPAD_SUBTRACT, DomKeyLocation::NUMPAD},
141 {DomCode::NUMPAD_ADD, DomKeyLocation::NUMPAD},
142 {DomCode::NUMPAD_ENTER, DomKeyLocation::NUMPAD},
143 {DomCode::NUMPAD1, DomKeyLocation::NUMPAD},
144 {DomCode::NUMPAD2, DomKeyLocation::NUMPAD},
145 {DomCode::NUMPAD3, DomKeyLocation::NUMPAD},
146 {DomCode::NUMPAD4, DomKeyLocation::NUMPAD},
147 {DomCode::NUMPAD5, DomKeyLocation::NUMPAD},
148 {DomCode::NUMPAD6, DomKeyLocation::NUMPAD},
149 {DomCode::NUMPAD7, DomKeyLocation::NUMPAD},
150 {DomCode::NUMPAD8, DomKeyLocation::NUMPAD},
151 {DomCode::NUMPAD9, DomKeyLocation::NUMPAD},
152 {DomCode::NUMPAD0, DomKeyLocation::NUMPAD},
153 {DomCode::NUMPAD_DECIMAL, DomKeyLocation::NUMPAD},
154 {DomCode::NUMPAD_EQUAL, DomKeyLocation::NUMPAD},
155 {DomCode::NUMPAD_COMMA, DomKeyLocation::NUMPAD},
156 {DomCode::NUMPAD_PAREN_LEFT, DomKeyLocation::NUMPAD},
157 {DomCode::NUMPAD_PAREN_RIGHT, DomKeyLocation::NUMPAD},
158 {DomCode::NUMPAD_BACKSPACE, DomKeyLocation::NUMPAD},
159 {DomCode::NUMPAD_MEMORY_STORE, DomKeyLocation::NUMPAD},
160 {DomCode::NUMPAD_MEMORY_RECALL, DomKeyLocation::NUMPAD},
161 {DomCode::NUMPAD_MEMORY_CLEAR, DomKeyLocation::NUMPAD},
162 {DomCode::NUMPAD_MEMORY_ADD, DomKeyLocation::NUMPAD},
163 {DomCode::NUMPAD_MEMORY_SUBTRACT, DomKeyLocation::NUMPAD},
164 {DomCode::NUMPAD_SIGN_CHANGE, DomKeyLocation::NUMPAD},
165 {DomCode::NUMPAD_CLEAR, DomKeyLocation::NUMPAD},
166 {DomCode::NUMPAD_CLEAR_ENTRY, DomKeyLocation::NUMPAD}};
167 for (const auto& key : kLocations) {
168 if (key.code == dom_code)
169 return key.location;
171 return DomKeyLocation::STANDARD;
174 // static
175 DomKey KeycodeConverter::KeyStringToDomKey(const char* key) {
176 if (!key || !*key)
177 return DomKey::NONE;
178 // Check for standard key names.
179 for (size_t i = 0; i < kDomKeyMapEntries; ++i) {
180 if (dom_key_map[i].string && strcmp(dom_key_map[i].string, key) == 0) {
181 return dom_key_map[i].dom_key;
184 if (strcmp(key, "Dead") == 0) {
185 // The web KeyboardEvent string does not encode the combining character,
186 // so we just set it to the Unicode designated non-character 0xFFFF.
187 // This will round-trip convert back to 'Dead' but take no part in
188 // character composition.
189 return DomKey::DeadKeyFromCombiningCharacter(0xFFFF);
191 // Otherwise, if the string contains a single Unicode character,
192 // the key value is that character.
193 int32_t char_index = 0;
194 uint32_t character;
195 if (base::ReadUnicodeCharacter(key, static_cast<int32_t>(strlen(key)),
196 &char_index, &character) &&
197 key[++char_index] == 0) {
198 return DomKey::FromCharacter(character);
200 return DomKey::NONE;
203 // static
204 std::string KeycodeConverter::DomKeyToKeyString(DomKey dom_key) {
205 if (dom_key.IsDeadKey()) {
206 // All dead-key combining codes collapse to 'Dead', as UI Events
207 // KeyboardEvent represents the combining character separately.
208 return "Dead";
210 for (size_t i = 0; i < kDomKeyMapEntries; ++i) {
211 if (dom_key_map[i].dom_key == dom_key) {
212 if (dom_key_map[i].string)
213 return dom_key_map[i].string;
214 break;
217 if (dom_key.IsCharacter()) {
218 std::string s;
219 base::WriteUnicodeCharacter(dom_key.ToCharacter(), &s);
220 return s;
222 return std::string();
225 // static
226 bool KeycodeConverter::IsDomKeyForModifier(DomKey dom_key) {
227 switch (dom_key) {
228 case DomKey::ACCEL:
229 case DomKey::ALT:
230 case DomKey::ALT_GRAPH:
231 case DomKey::CAPS_LOCK:
232 case DomKey::CONTROL:
233 case DomKey::FN:
234 case DomKey::FN_LOCK:
235 case DomKey::HYPER:
236 case DomKey::META:
237 case DomKey::NUM_LOCK:
238 case DomKey::OS:
239 case DomKey::SCROLL_LOCK:
240 case DomKey::SHIFT:
241 case DomKey::SUPER:
242 case DomKey::SYMBOL:
243 case DomKey::SYMBOL_LOCK:
244 case DomKey::SHIFT_LEVEL5:
245 return true;
246 default:
247 return false;
251 // USB keycodes
252 // Note that USB keycodes are not part of any web standard.
253 // Please don't use USB keycodes in new code.
255 // static
256 uint32_t KeycodeConverter::InvalidUsbKeycode() {
257 return usb_keycode_map[0].usb_keycode;
260 // static
261 int KeycodeConverter::UsbKeycodeToNativeKeycode(uint32_t usb_keycode) {
262 // Deal with some special-cases that don't fit the 1:1 mapping.
263 if (usb_keycode == 0x070032) // non-US hash.
264 usb_keycode = 0x070031; // US backslash.
265 #if defined(OS_MACOSX)
266 if (usb_keycode == 0x070046) // PrintScreen.
267 usb_keycode = 0x070068; // F13.
268 #endif
270 for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
271 if (usb_keycode_map[i].usb_keycode == usb_keycode)
272 return usb_keycode_map[i].native_keycode;
274 return InvalidNativeKeycode();
277 // static
278 uint32_t KeycodeConverter::NativeKeycodeToUsbKeycode(int native_keycode) {
279 for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
280 if (usb_keycode_map[i].native_keycode == native_keycode)
281 return usb_keycode_map[i].usb_keycode;
283 return InvalidUsbKeycode();
286 // static
287 DomCode KeycodeConverter::UsbKeycodeToDomCode(uint32_t usb_keycode) {
288 for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
289 if (usb_keycode_map[i].usb_keycode == usb_keycode)
290 return static_cast<DomCode>(usb_keycode);
292 return DomCode::NONE;
295 // static
296 uint32_t KeycodeConverter::DomCodeToUsbKeycode(DomCode dom_code) {
297 for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
298 if (usb_keycode_map[i].usb_keycode == static_cast<uint32_t>(dom_code))
299 return usb_keycode_map[i].usb_keycode;
301 return InvalidUsbKeycode();
304 // static
305 uint32_t KeycodeConverter::CodeToUsbKeycode(const char* code) {
306 if (!code || !*code)
307 return InvalidUsbKeycode();
309 for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
310 if (usb_keycode_map[i].code &&
311 strcmp(usb_keycode_map[i].code, code) == 0) {
312 return usb_keycode_map[i].usb_keycode;
315 return InvalidUsbKeycode();
318 } // namespace ui