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"
16 // Table of USB codes (equivalent to DomCode values), native scan codes,
17 // and DOM Level 3 |code| strings.
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}
27 #define USB_KEYMAP(usb, evdev, xkb, win, mac, code, id) {usb, 0, code}
29 #define USB_KEYMAP_DECLARATION const KeycodeMapEntry usb_keycode_map[] =
30 #include "ui/events/keycodes/dom/keycode_converter_data.inc"
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
{
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
51 #undef DOM_KEY_MAP_END
54 const size_t kDomKeyMapEntries
= arraysize(dom_key_map
);
59 size_t KeycodeConverter::NumKeycodeMapEntriesForTest() {
60 return kKeycodeMapEntries
;
64 const KeycodeMapEntry
* KeycodeConverter::GetKeycodeMapForTest() {
65 return &usb_keycode_map
[0];
69 const char* KeycodeConverter::DomKeyStringForTest(size_t index
) {
70 if (index
>= kDomKeyMapEntries
)
72 return dom_key_map
[index
].string
;
76 int KeycodeConverter::InvalidNativeKeycode() {
77 return usb_keycode_map
[0].native_keycode
;
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
);
93 int KeycodeConverter::DomCodeToNativeKeycode(DomCode code
) {
94 return UsbKeycodeToNativeKeycode(static_cast<uint32_t>(code
));
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
;
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
;
126 DomKeyLocation
KeycodeConverter::DomCodeToLocation(DomCode dom_code
) {
127 static const struct {
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
)
171 return DomKeyLocation::STANDARD
;
175 DomKey
KeycodeConverter::KeyStringToDomKey(const char* key
) {
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;
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
);
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.
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
;
217 if (dom_key
.IsCharacter()) {
219 base::WriteUnicodeCharacter(dom_key
.ToCharacter(), &s
);
222 return std::string();
226 bool KeycodeConverter::IsDomKeyForModifier(DomKey dom_key
) {
230 case DomKey::ALT_GRAPH
:
231 case DomKey::CAPS_LOCK
:
232 case DomKey::CONTROL
:
234 case DomKey::FN_LOCK
:
237 case DomKey::NUM_LOCK
:
239 case DomKey::SCROLL_LOCK
:
243 case DomKey::SYMBOL_LOCK
:
244 case DomKey::SHIFT_LEVEL5
:
252 // Note that USB keycodes are not part of any web standard.
253 // Please don't use USB keycodes in new code.
256 uint32_t KeycodeConverter::InvalidUsbKeycode() {
257 return usb_keycode_map
[0].usb_keycode
;
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.
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();
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();
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
;
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();
305 uint32_t KeycodeConverter::CodeToUsbKeycode(const char* 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();