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 "ui/events/event_constants.h"
8 #include "ui/events/keycodes/dom3/dom_code.h"
9 #include "ui/events/keycodes/dom3/dom_key.h"
15 // This table maps a subset of |KeyboardCode| (VKEYs) to DomKey and character.
16 // Only values not otherwise handled by GetMeaningFromKeyCode() are here.
17 const struct KeyboardCodeToMeaning
{
18 KeyboardCode key_code
;
20 base::char16 plain_character
;
21 base::char16 shift_character
;
22 } kKeyboardCodeToMeaning
[] = {
23 {VKEY_BACK
, DomKey::BACKSPACE
, '\b', 0},
24 {VKEY_TAB
, DomKey::TAB
, '\t', 0},
25 {VKEY_RETURN
, DomKey::ENTER
, '\r', 0},
26 {VKEY_ESCAPE
, DomKey::ESCAPE
, 0x1B, 0},
27 {VKEY_SPACE
, DomKey::CHARACTER
, ' ', 0},
28 {VKEY_MULTIPLY
, DomKey::CHARACTER
, '*', 0},
29 {VKEY_ADD
, DomKey::CHARACTER
, '+', 0},
30 {VKEY_SEPARATOR
, DomKey::CHARACTER
, ',', 0},
31 {VKEY_SUBTRACT
, DomKey::CHARACTER
, '-', 0},
32 {VKEY_DECIMAL
, DomKey::CHARACTER
, '.', 0},
33 {VKEY_DIVIDE
, DomKey::CHARACTER
, '/', 0},
34 {VKEY_OEM_1
, DomKey::CHARACTER
, ';', ':'},
35 {VKEY_OEM_PLUS
, DomKey::CHARACTER
, '=', '+'},
36 {VKEY_OEM_COMMA
, DomKey::CHARACTER
, ',', '<'},
37 {VKEY_OEM_MINUS
, DomKey::CHARACTER
, '-', '_'},
38 {VKEY_OEM_PERIOD
, DomKey::CHARACTER
, '.', '>'},
39 {VKEY_OEM_2
, DomKey::CHARACTER
, '/', '?'},
40 {VKEY_OEM_3
, DomKey::CHARACTER
, '`', '~'},
41 {VKEY_OEM_4
, DomKey::CHARACTER
, '[', '{'},
42 {VKEY_OEM_5
, DomKey::CHARACTER
, '\\', '|'},
43 {VKEY_OEM_6
, DomKey::CHARACTER
, ']', '}'},
44 {VKEY_OEM_7
, DomKey::CHARACTER
, '\'', '"'},
45 {VKEY_OEM_102
, DomKey::CHARACTER
, '<', '>'},
46 {VKEY_CLEAR
, DomKey::CLEAR
, 0, 0},
47 {VKEY_SHIFT
, DomKey::SHIFT
, 0, 0},
48 {VKEY_CONTROL
, DomKey::CONTROL
, 0, 0},
49 {VKEY_MENU
, DomKey::ALT
, 0, 0},
50 {VKEY_PAUSE
, DomKey::PAUSE
, 0, 0},
51 {VKEY_CAPITAL
, DomKey::CAPS_LOCK
, 0, 0},
52 // Windows conflates 'KanaMode' and 'HangulMode'.
53 {VKEY_KANA
, DomKey::KANA_MODE
, 0, 0},
54 {VKEY_JUNJA
, DomKey::JUNJA_MODE
, 0, 0},
55 {VKEY_FINAL
, DomKey::FINAL_MODE
, 0, 0},
56 // Windows conflates 'HanjaMode' and 'KanjiMode'.
57 {VKEY_HANJA
, DomKey::HANJA_MODE
, 0, 0},
58 {VKEY_CONVERT
, DomKey::CONVERT
, 0, 0},
59 {VKEY_NONCONVERT
, DomKey::NON_CONVERT
, 0, 0},
60 {VKEY_ACCEPT
, DomKey::ACCEPT
, 0, 0},
61 {VKEY_MODECHANGE
, DomKey::MODE_CHANGE
, 0, 0},
62 {VKEY_PRIOR
, DomKey::PAGE_UP
, 0, 0},
63 {VKEY_NEXT
, DomKey::PAGE_DOWN
, 0, 0},
64 {VKEY_END
, DomKey::END
, 0, 0},
65 {VKEY_HOME
, DomKey::HOME
, 0, 0},
66 {VKEY_LEFT
, DomKey::ARROW_LEFT
, 0, 0},
67 {VKEY_UP
, DomKey::ARROW_UP
, 0, 0},
68 {VKEY_RIGHT
, DomKey::ARROW_RIGHT
, 0, 0},
69 {VKEY_DOWN
, DomKey::ARROW_DOWN
, 0, 0},
70 {VKEY_SELECT
, DomKey::SELECT
, 0, 0},
71 {VKEY_PRINT
, DomKey::PRINT
, 0, 0},
72 {VKEY_EXECUTE
, DomKey::EXECUTE
, 0, 0},
73 {VKEY_SNAPSHOT
, DomKey::PRINT_SCREEN
, 0, 0},
74 {VKEY_INSERT
, DomKey::INSERT
, 0, 0},
75 {VKEY_DELETE
, DomKey::DEL
, 0, 0},
76 {VKEY_HELP
, DomKey::HELP
, 0, 0},
77 {VKEY_LWIN
, DomKey::OS
, 0, 0},
78 {VKEY_RWIN
, DomKey::OS
, 0, 0},
79 {VKEY_APPS
, DomKey::MEDIA_APPS
, 0, 0},
80 {VKEY_NUMLOCK
, DomKey::NUM_LOCK
, 0, 0},
81 {VKEY_SCROLL
, DomKey::SCROLL_LOCK
, 0, 0},
82 {VKEY_LSHIFT
, DomKey::SHIFT
, 0, 0},
83 {VKEY_RSHIFT
, DomKey::SHIFT
, 0, 0},
84 {VKEY_LCONTROL
, DomKey::CONTROL
, 0, 0},
85 {VKEY_RCONTROL
, DomKey::CONTROL
, 0, 0},
86 {VKEY_LMENU
, DomKey::ALT
, 0, 0},
87 {VKEY_RMENU
, DomKey::ALT
, 0, 0},
88 {VKEY_BROWSER_BACK
, DomKey::BROWSER_BACK
, 0, 0},
89 {VKEY_BROWSER_FORWARD
, DomKey::BROWSER_FORWARD
, 0, 0},
90 {VKEY_BROWSER_REFRESH
, DomKey::BROWSER_REFRESH
, 0, 0},
91 {VKEY_BROWSER_STOP
, DomKey::BROWSER_STOP
, 0, 0},
92 {VKEY_BROWSER_SEARCH
, DomKey::BROWSER_SEARCH
, 0, 0},
93 {VKEY_BROWSER_FAVORITES
, DomKey::BROWSER_FAVORITES
, 0, 0},
94 {VKEY_BROWSER_HOME
, DomKey::BROWSER_HOME
, 0, 0},
95 {VKEY_VOLUME_MUTE
, DomKey::VOLUME_MUTE
, 0, 0},
96 {VKEY_VOLUME_DOWN
, DomKey::VOLUME_DOWN
, 0, 0},
97 {VKEY_VOLUME_UP
, DomKey::VOLUME_UP
, 0, 0},
98 {VKEY_MEDIA_NEXT_TRACK
, DomKey::MEDIA_TRACK_NEXT
, 0, 0},
99 {VKEY_MEDIA_PREV_TRACK
, DomKey::MEDIA_TRACK_PREVIOUS
, 0, 0},
100 {VKEY_MEDIA_STOP
, DomKey::MEDIA_STOP
, 0, 0},
101 {VKEY_MEDIA_PLAY_PAUSE
, DomKey::MEDIA_PLAY_PAUSE
, 0, 0},
102 {VKEY_MEDIA_LAUNCH_MAIL
, DomKey::LAUNCH_MAIL
, 0, 0},
103 {VKEY_MEDIA_LAUNCH_MEDIA_SELECT
, DomKey::LAUNCH_MEDIA_PLAYER
, 0, 0},
104 {VKEY_MEDIA_LAUNCH_APP1
, DomKey::LAUNCH_MY_COMPUTER
, 0, 0},
105 {VKEY_MEDIA_LAUNCH_APP2
, DomKey::LAUNCH_CALCULATOR
, 0, 0},
106 {VKEY_OEM_8
, DomKey::SUPER
, 0, 0}, // ISO Level 5 Shift in ChromeOS
107 {VKEY_PROCESSKEY
, DomKey::PROCESS
, 0, 0},
108 {VKEY_DBE_SBCSCHAR
, DomKey::HANKAKU
, 0, 0},
109 {VKEY_DBE_DBCSCHAR
, DomKey::ZENKAKU
, 0, 0},
110 {VKEY_ATTN
, DomKey::ATTN
, 0, 0},
111 {VKEY_CRSEL
, DomKey::CR_SEL
, 0, 0},
112 {VKEY_EXSEL
, DomKey::EX_SEL
, 0, 0},
113 {VKEY_EREOF
, DomKey::ERASE_EOF
, 0, 0},
114 {VKEY_PLAY
, DomKey::MEDIA_PLAY
, 0, 0},
115 {VKEY_ZOOM
, DomKey::ZOOM_TOGGLE
, 0, 0},
116 {VKEY_OEM_CLEAR
, DomKey::CLEAR
, 0, 0},
117 {VKEY_ALTGR
, DomKey::ALT_GRAPH
, 0, 0},
118 #if defined(OS_POSIX)
119 {VKEY_POWER
, DomKey::POWER
, 0, 0},
120 {VKEY_BRIGHTNESS_DOWN
, DomKey::BRIGHTNESS_DOWN
, 0, 0},
121 {VKEY_BRIGHTNESS_UP
, DomKey::BRIGHTNESS_UP
, 0, 0},
122 {VKEY_COMPOSE
, DomKey::COMPOSE
, 0, 0},
123 {VKEY_OEM_103
, DomKey::MEDIA_REWIND
, 0, 0},
124 {VKEY_OEM_104
, DomKey::MEDIA_FAST_FORWARD
, 0, 0},
128 bool IsRightSideDomCode(DomCode code
) {
129 return (code
== DomCode::SHIFT_RIGHT
) || (code
== DomCode::CONTROL_RIGHT
) ||
130 (code
== DomCode::ALT_RIGHT
) || (code
== DomCode::OS_RIGHT
);
133 } // anonymous namespace
135 base::char16
GetCharacterFromKeyCode(KeyboardCode key_code
, int flags
) {
137 base::char16 character
;
138 if (GetMeaningFromKeyCode(key_code
, flags
, &dom_key
, &character
))
143 bool GetMeaningFromKeyCode(KeyboardCode key_code
,
146 base::char16
* character
) {
147 const bool ctrl
= (flags
& EF_CONTROL_DOWN
) != 0;
148 const bool shift
= (flags
& EF_SHIFT_DOWN
) != 0;
149 const bool upper
= shift
^ ((flags
& EF_CAPS_LOCK_DOWN
) != 0);
151 // Control characters.
153 // Following Windows behavior to map ctrl-a ~ ctrl-z to \x01 ~ \x1A.
154 if (key_code
>= VKEY_A
&& key_code
<= VKEY_Z
) {
155 *character
= static_cast<uint16
>(key_code
- VKEY_A
+ 1);
158 *dom_key
= DomKey::BACKSPACE
;
161 *dom_key
= DomKey::TAB
;
165 *dom_key
= DomKey::ENTER
;
168 *dom_key
= DomKey::CHARACTER
;
173 // Other control characters.
175 // The following graphics characters require the shift key to input.
177 // ctrl-@ maps to \x00 (Null byte)
179 *dom_key
= DomKey::CHARACTER
;
182 // ctrl-^ maps to \x1E (Record separator, Information separator two)
184 *dom_key
= DomKey::CHARACTER
;
187 // ctrl-_ maps to \x1F (Unit separator, Information separator one)
189 *dom_key
= DomKey::CHARACTER
;
192 // Returns 0 for all other keys to avoid inputting unexpected chars.
194 *dom_key
= DomKey::UNIDENTIFIED
;
200 // ctrl-[ maps to \x1B (Escape)
202 *dom_key
= DomKey::ESCAPE
;
205 // ctrl-\ maps to \x1C (File separator, Information separator four)
207 *dom_key
= DomKey::CHARACTER
;
210 // ctrl-] maps to \x1D (Group separator, Information separator three)
212 *dom_key
= DomKey::CHARACTER
;
215 // ctrl-Enter maps to \x0A (Line feed)
217 *dom_key
= DomKey::CHARACTER
;
220 // Returns 0 for all other keys to avoid inputting unexpected chars.
222 *dom_key
= DomKey::UNIDENTIFIED
;
229 // ASCII alphanumeric characters.
230 if (key_code
>= VKEY_A
&& key_code
<= VKEY_Z
) {
231 *dom_key
= DomKey::CHARACTER
;
232 *character
= static_cast<uint16
>(key_code
- VKEY_A
+ (upper
? 'A' : 'a'));
235 if (key_code
>= VKEY_0
&& key_code
<= VKEY_9
) {
236 *dom_key
= DomKey::CHARACTER
;
238 shift
? ")!@#$%^&*("[key_code
- VKEY_0
] : static_cast<uint16
>(key_code
);
241 if (key_code
>= VKEY_NUMPAD0
&& key_code
<= VKEY_NUMPAD9
) {
242 *dom_key
= DomKey::CHARACTER
;
243 *character
= static_cast<uint16
>(key_code
- VKEY_NUMPAD0
+ '0');
248 if (key_code
>= VKEY_F1
&& key_code
<= VKEY_F24
) {
250 static_cast<DomKey
>(key_code
- VKEY_F1
+ static_cast<int>(DomKey::F1
));
256 for (size_t i
= 0; i
< arraysize(kKeyboardCodeToMeaning
); ++i
) {
257 if (kKeyboardCodeToMeaning
[i
].key_code
== key_code
) {
258 const KeyboardCodeToMeaning
* p
= &kKeyboardCodeToMeaning
[i
];
260 *character
= (shift
&& p
->shift_character
) ? p
->shift_character
261 : p
->plain_character
;
265 *dom_key
= DomKey::UNIDENTIFIED
;
270 // Determine the non-located VKEY corresponding to a located VKEY.
271 KeyboardCode
LocatedToNonLocatedKeyboardCode(KeyboardCode key_code
) {
309 // Determine the located VKEY corresponding to a non-located VKEY.
310 KeyboardCode
NonLocatedToLocatedKeyboardCode(KeyboardCode key_code
,
314 return IsRightSideDomCode(dom_code
) ? VKEY_RSHIFT
: VKEY_LSHIFT
;
316 return IsRightSideDomCode(dom_code
) ? VKEY_RCONTROL
: VKEY_LCONTROL
;
318 return IsRightSideDomCode(dom_code
) ? VKEY_RMENU
: VKEY_LMENU
;
320 return IsRightSideDomCode(dom_code
) ? VKEY_RWIN
: VKEY_LWIN
;
322 return (dom_code
== DomCode::NUMPAD0
) ? VKEY_NUMPAD0
: VKEY_0
;
324 return (dom_code
== DomCode::NUMPAD1
) ? VKEY_NUMPAD1
: VKEY_1
;
326 return (dom_code
== DomCode::NUMPAD2
) ? VKEY_NUMPAD2
: VKEY_2
;
328 return (dom_code
== DomCode::NUMPAD3
) ? VKEY_NUMPAD3
: VKEY_3
;
330 return (dom_code
== DomCode::NUMPAD4
) ? VKEY_NUMPAD4
: VKEY_4
;
332 return (dom_code
== DomCode::NUMPAD5
) ? VKEY_NUMPAD5
: VKEY_5
;
334 return (dom_code
== DomCode::NUMPAD6
) ? VKEY_NUMPAD6
: VKEY_6
;
336 return (dom_code
== DomCode::NUMPAD7
) ? VKEY_NUMPAD7
: VKEY_7
;
338 return (dom_code
== DomCode::NUMPAD8
) ? VKEY_NUMPAD8
: VKEY_8
;
340 return (dom_code
== DomCode::NUMPAD9
) ? VKEY_NUMPAD9
: VKEY_9
;