MD Downloads: prevent search text from overlapping with the cancel search (X)
[chromium-blink-merge.git] / ui / events / keycodes / keyboard_code_conversion.cc
blob38432670d9ba436a542ef916bdc4c477c602d5cd
1 // Copyright (c) 2011 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/keyboard_code_conversion.h"
7 #include <algorithm>
9 #include "ui/events/event_constants.h"
10 #include "ui/events/keycodes/dom/dom_code.h"
11 #include "ui/events/keycodes/dom/dom_key.h"
12 #include "ui/events/keycodes/dom_us_layout_data.h"
14 namespace ui {
16 namespace {
18 bool IsRightSideDomCode(DomCode code) {
19 return (code == DomCode::SHIFT_RIGHT) || (code == DomCode::CONTROL_RIGHT) ||
20 (code == DomCode::ALT_RIGHT) || (code == DomCode::OS_RIGHT);
23 bool IsModifierDomCode(DomCode code) {
24 return (code == DomCode::CONTROL_LEFT) || (code == DomCode::CONTROL_RIGHT) ||
25 (code == DomCode::SHIFT_LEFT) || (code == DomCode::SHIFT_RIGHT) ||
26 (code == DomCode::ALT_LEFT) || (code == DomCode::ALT_RIGHT) ||
27 (code == DomCode::OS_LEFT) || (code == DomCode::OS_RIGHT);
30 } // anonymous namespace
32 base::char16 DomCodeToUsLayoutCharacter(DomCode dom_code, int flags) {
33 DomKey dom_key;
34 KeyboardCode key_code;
35 if (DomCodeToUsLayoutDomKey(dom_code, flags, &dom_key, &key_code) &&
36 dom_key.IsCharacter()) {
37 return dom_key.ToCharacter();
39 return 0;
42 bool DomCodeToUsLayoutDomKey(DomCode dom_code,
43 int flags,
44 DomKey* out_dom_key,
45 KeyboardCode* out_key_code) {
46 if ((flags & EF_CONTROL_DOWN) == EF_CONTROL_DOWN) {
47 if (DomCodeToControlCharacter(dom_code, flags, out_dom_key, out_key_code)) {
48 return true;
50 if (!IsModifierDomCode(dom_code)) {
51 *out_dom_key = DomKey::UNIDENTIFIED;
52 *out_key_code = LocatedToNonLocatedKeyboardCode(
53 DomCodeToUsLayoutKeyboardCode(dom_code));
54 return true;
56 } else {
57 for (const auto& it : kPrintableCodeMap) {
58 if (it.dom_code == dom_code) {
59 int state = ((flags & EF_SHIFT_DOWN) == EF_SHIFT_DOWN);
60 base::char16 ch = it.character[state];
61 if ((flags & EF_CAPS_LOCK_DOWN) == EF_CAPS_LOCK_DOWN) {
62 ch |= 0x20;
63 if ((ch >= 'a') && (ch <= 'z'))
64 ch = it.character[state ^ 1];
66 *out_dom_key = DomKey::FromCharacter(ch);
67 *out_key_code = LocatedToNonLocatedKeyboardCode(
68 DomCodeToUsLayoutKeyboardCode(dom_code));
69 return true;
73 for (const auto& it : kNonPrintableCodeMap) {
74 if (it.dom_code == dom_code) {
75 *out_dom_key = it.dom_key;
76 *out_key_code = NonPrintableDomKeyToKeyboardCode(it.dom_key);
77 return true;
80 if ((flags & EF_CONTROL_DOWN) == EF_CONTROL_DOWN) {
81 *out_dom_key = DomKey::UNIDENTIFIED;
82 *out_key_code = LocatedToNonLocatedKeyboardCode(
83 DomCodeToUsLayoutKeyboardCode(dom_code));
84 return true;
86 return false;
89 bool DomCodeToControlCharacter(DomCode dom_code,
90 int flags,
91 DomKey* dom_key,
92 KeyboardCode* key_code) {
93 if ((flags & EF_CONTROL_DOWN) == 0)
94 return false;
96 int code = static_cast<int>(dom_code);
97 const int kKeyA = static_cast<int>(DomCode::KEY_A);
98 // Control-A - Control-Z map to 0x01 - 0x1A.
99 if (code >= kKeyA && code <= static_cast<int>(DomCode::KEY_Z)) {
100 *dom_key = DomKey::FromCharacter(code - kKeyA + 1);
101 *key_code = static_cast<KeyboardCode>(code - kKeyA + VKEY_A);
102 switch (dom_code) {
103 case DomCode::KEY_H:
104 *key_code = VKEY_BACK;
105 break;
106 case DomCode::KEY_I:
107 *key_code = VKEY_TAB;
108 break;
109 case DomCode::KEY_M:
110 *key_code = VKEY_RETURN;
111 break;
112 default:
113 break;
115 return true;
118 if (flags & EF_SHIFT_DOWN) {
119 switch (dom_code) {
120 case DomCode::DIGIT2:
121 // NUL
122 *dom_key = DomKey::FromCharacter(0);
123 *key_code = VKEY_2;
124 return true;
125 case DomCode::DIGIT6:
126 // RS
127 *dom_key = DomKey::FromCharacter(0x1E);
128 *key_code = VKEY_6;
129 return true;
130 case DomCode::MINUS:
131 // US
132 *dom_key = DomKey::FromCharacter(0x1F);
133 *key_code = VKEY_OEM_MINUS;
134 return true;
135 default:
136 return false;
140 switch (dom_code) {
141 case DomCode::ENTER:
142 // NL
143 *dom_key = DomKey::FromCharacter(0x0A);
144 *key_code = VKEY_RETURN;
145 return true;
146 case DomCode::BRACKET_LEFT:
147 // ESC
148 *dom_key = DomKey::FromCharacter(0x1B);
149 *key_code = VKEY_OEM_4;
150 return true;
151 case DomCode::BACKSLASH:
152 // FS
153 *dom_key = DomKey::FromCharacter(0x1C);
154 *key_code = VKEY_OEM_5;
155 return true;
156 case DomCode::BRACKET_RIGHT:
157 // GS
158 *dom_key = DomKey::FromCharacter(0x1D);
159 *key_code = VKEY_OEM_6;
160 return true;
161 default:
162 return false;
166 // Returns a Windows-based VKEY for a non-printable DOM Level 3 |key|.
167 // The returned VKEY is non-positional (e.g. VKEY_SHIFT).
168 KeyboardCode NonPrintableDomKeyToKeyboardCode(DomKey dom_key) {
169 for (const auto& it : kDomKeyToKeyboardCodeMap) {
170 if (it.dom_key == dom_key)
171 return it.key_code;
173 return VKEY_UNKNOWN;
176 // Determine the non-located VKEY corresponding to a located VKEY.
177 KeyboardCode LocatedToNonLocatedKeyboardCode(KeyboardCode key_code) {
178 switch (key_code) {
179 case VKEY_RWIN:
180 return VKEY_LWIN;
181 case VKEY_LSHIFT:
182 case VKEY_RSHIFT:
183 return VKEY_SHIFT;
184 case VKEY_LCONTROL:
185 case VKEY_RCONTROL:
186 return VKEY_CONTROL;
187 case VKEY_LMENU:
188 case VKEY_RMENU:
189 return VKEY_MENU;
190 case VKEY_NUMPAD0:
191 return VKEY_0;
192 case VKEY_NUMPAD1:
193 return VKEY_1;
194 case VKEY_NUMPAD2:
195 return VKEY_2;
196 case VKEY_NUMPAD3:
197 return VKEY_3;
198 case VKEY_NUMPAD4:
199 return VKEY_4;
200 case VKEY_NUMPAD5:
201 return VKEY_5;
202 case VKEY_NUMPAD6:
203 return VKEY_6;
204 case VKEY_NUMPAD7:
205 return VKEY_7;
206 case VKEY_NUMPAD8:
207 return VKEY_8;
208 case VKEY_NUMPAD9:
209 return VKEY_9;
210 default:
211 return key_code;
215 // Determine the located VKEY corresponding to a non-located VKEY.
216 KeyboardCode NonLocatedToLocatedKeyboardCode(KeyboardCode key_code,
217 DomCode dom_code) {
218 switch (key_code) {
219 case VKEY_SHIFT:
220 return IsRightSideDomCode(dom_code) ? VKEY_RSHIFT : VKEY_LSHIFT;
221 case VKEY_CONTROL:
222 return IsRightSideDomCode(dom_code) ? VKEY_RCONTROL : VKEY_LCONTROL;
223 case VKEY_MENU:
224 return IsRightSideDomCode(dom_code) ? VKEY_RMENU : VKEY_LMENU;
225 case VKEY_LWIN:
226 return IsRightSideDomCode(dom_code) ? VKEY_RWIN : VKEY_LWIN;
227 case VKEY_0:
228 return (dom_code == DomCode::NUMPAD0) ? VKEY_NUMPAD0 : VKEY_0;
229 case VKEY_1:
230 return (dom_code == DomCode::NUMPAD1) ? VKEY_NUMPAD1 : VKEY_1;
231 case VKEY_2:
232 return (dom_code == DomCode::NUMPAD2) ? VKEY_NUMPAD2 : VKEY_2;
233 case VKEY_3:
234 return (dom_code == DomCode::NUMPAD3) ? VKEY_NUMPAD3 : VKEY_3;
235 case VKEY_4:
236 return (dom_code == DomCode::NUMPAD4) ? VKEY_NUMPAD4 : VKEY_4;
237 case VKEY_5:
238 return (dom_code == DomCode::NUMPAD5) ? VKEY_NUMPAD5 : VKEY_5;
239 case VKEY_6:
240 return (dom_code == DomCode::NUMPAD6) ? VKEY_NUMPAD6 : VKEY_6;
241 case VKEY_7:
242 return (dom_code == DomCode::NUMPAD7) ? VKEY_NUMPAD7 : VKEY_7;
243 case VKEY_8:
244 return (dom_code == DomCode::NUMPAD8) ? VKEY_NUMPAD8 : VKEY_8;
245 case VKEY_9:
246 return (dom_code == DomCode::NUMPAD9) ? VKEY_NUMPAD9 : VKEY_9;
247 default:
248 return key_code;
252 DomCode UsLayoutKeyboardCodeToDomCode(KeyboardCode key_code) {
253 key_code = NonLocatedToLocatedKeyboardCode(key_code, DomCode::NONE);
254 for (const auto& it : kDomCodeToKeyboardCodeMap) {
255 if (it.key_code == key_code)
256 return it.dom_code;
258 for (const auto& it : kFallbackKeyboardCodeToDomCodeMap) {
259 if (it.key_code == key_code)
260 return it.dom_code;
262 return DomCode::NONE;
265 KeyboardCode DomCodeToUsLayoutKeyboardCode(DomCode dom_code) {
266 const DomCodeToKeyboardCodeEntry* end =
267 kDomCodeToKeyboardCodeMap + arraysize(kDomCodeToKeyboardCodeMap);
268 const DomCodeToKeyboardCodeEntry* found = std::lower_bound(
269 kDomCodeToKeyboardCodeMap, end, dom_code,
270 [](const DomCodeToKeyboardCodeEntry& a, DomCode b) {
271 return static_cast<int>(a.dom_code) < static_cast<int>(b);
273 if ((found != end) && (found->dom_code == dom_code))
274 return found->key_code;
276 return VKEY_UNKNOWN;
279 } // namespace ui