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_key.h"
14 // This table maps a subset of |KeyboardCode| (VKEYs) to DomKey and character.
15 // Only values not otherwise handled by GetMeaningFromKeyCode() are here.
16 const struct KeyboardCodeToMeaning
{
17 KeyboardCode key_code
;
19 base::char16 plain_character
;
20 base::char16 shift_character
;
21 } kKeyboardCodeToMeaning
[] = {
22 {VKEY_BACK
, DomKey::BACKSPACE
, '\b', 0},
23 {VKEY_TAB
, DomKey::TAB
, '\t', 0},
24 {VKEY_RETURN
, DomKey::ENTER
, '\r', 0},
25 {VKEY_ESCAPE
, DomKey::ESCAPE
, 0x1B, 0},
26 {VKEY_SPACE
, DomKey::CHARACTER
, ' ', 0},
27 {VKEY_MULTIPLY
, DomKey::CHARACTER
, '*', 0},
28 {VKEY_ADD
, DomKey::CHARACTER
, '+', 0},
29 {VKEY_SEPARATOR
, DomKey::CHARACTER
, ',', 0},
30 {VKEY_SUBTRACT
, DomKey::CHARACTER
, '-', 0},
31 {VKEY_DECIMAL
, DomKey::CHARACTER
, '.', 0},
32 {VKEY_DIVIDE
, DomKey::CHARACTER
, '/', 0},
33 {VKEY_OEM_1
, DomKey::CHARACTER
, ';', ':'},
34 {VKEY_OEM_PLUS
, DomKey::CHARACTER
, '=', '+'},
35 {VKEY_OEM_COMMA
, DomKey::CHARACTER
, ',', '<'},
36 {VKEY_OEM_MINUS
, DomKey::CHARACTER
, '-', '_'},
37 {VKEY_OEM_PERIOD
, DomKey::CHARACTER
, '.', '>'},
38 {VKEY_OEM_2
, DomKey::CHARACTER
, '/', '?'},
39 {VKEY_OEM_3
, DomKey::CHARACTER
, '`', '~'},
40 {VKEY_OEM_4
, DomKey::CHARACTER
, '[', '{'},
41 {VKEY_OEM_5
, DomKey::CHARACTER
, '\\', '|'},
42 {VKEY_OEM_6
, DomKey::CHARACTER
, ']', '}'},
43 {VKEY_OEM_7
, DomKey::CHARACTER
, '\'', '"'},
44 {VKEY_OEM_102
, DomKey::CHARACTER
, '<', '>'},
45 {VKEY_CLEAR
, DomKey::CLEAR
, 0, 0},
46 {VKEY_SHIFT
, DomKey::SHIFT
, 0, 0},
47 {VKEY_CONTROL
, DomKey::CONTROL
, 0, 0},
48 {VKEY_MENU
, DomKey::ALT
, 0, 0},
49 {VKEY_PAUSE
, DomKey::PAUSE
, 0, 0},
50 {VKEY_CAPITAL
, DomKey::CAPS_LOCK
, 0, 0},
51 // Windows conflates 'KanaMode' and 'HangulMode'.
52 {VKEY_KANA
, DomKey::KANA_MODE
, 0, 0},
53 {VKEY_JUNJA
, DomKey::JUNJA_MODE
, 0, 0},
54 {VKEY_FINAL
, DomKey::FINAL_MODE
, 0, 0},
55 // Windows conflates 'HanjaMode' and 'KanjiMode'.
56 {VKEY_HANJA
, DomKey::HANJA_MODE
, 0, 0},
57 {VKEY_CONVERT
, DomKey::CONVERT
, 0, 0},
58 {VKEY_NONCONVERT
, DomKey::NON_CONVERT
, 0, 0},
59 {VKEY_ACCEPT
, DomKey::ACCEPT
, 0, 0},
60 {VKEY_MODECHANGE
, DomKey::MODE_CHANGE
, 0, 0},
61 {VKEY_PRIOR
, DomKey::PAGE_UP
, 0, 0},
62 {VKEY_NEXT
, DomKey::PAGE_DOWN
, 0, 0},
63 {VKEY_END
, DomKey::END
, 0, 0},
64 {VKEY_HOME
, DomKey::HOME
, 0, 0},
65 {VKEY_LEFT
, DomKey::ARROW_LEFT
, 0, 0},
66 {VKEY_UP
, DomKey::ARROW_UP
, 0, 0},
67 {VKEY_RIGHT
, DomKey::ARROW_RIGHT
, 0, 0},
68 {VKEY_DOWN
, DomKey::ARROW_DOWN
, 0, 0},
69 {VKEY_SELECT
, DomKey::SELECT
, 0, 0},
70 {VKEY_PRINT
, DomKey::PRINT
, 0, 0},
71 {VKEY_EXECUTE
, DomKey::EXECUTE
, 0, 0},
72 {VKEY_SNAPSHOT
, DomKey::PRINT_SCREEN
, 0, 0},
73 {VKEY_INSERT
, DomKey::INSERT
, 0, 0},
74 {VKEY_DELETE
, DomKey::DEL
, 0, 0},
75 {VKEY_HELP
, DomKey::HELP
, 0, 0},
76 {VKEY_LWIN
, DomKey::OS
, 0, 0},
77 {VKEY_RWIN
, DomKey::OS
, 0, 0},
78 {VKEY_APPS
, DomKey::MEDIA_APPS
, 0, 0},
79 {VKEY_NUMLOCK
, DomKey::NUM_LOCK
, 0, 0},
80 {VKEY_SCROLL
, DomKey::SCROLL_LOCK
, 0, 0},
81 {VKEY_LSHIFT
, DomKey::SHIFT
, 0, 0},
82 {VKEY_RSHIFT
, DomKey::SHIFT
, 0, 0},
83 {VKEY_LCONTROL
, DomKey::CONTROL
, 0, 0},
84 {VKEY_RCONTROL
, DomKey::CONTROL
, 0, 0},
85 {VKEY_LMENU
, DomKey::ALT
, 0, 0},
86 {VKEY_RMENU
, DomKey::ALT
, 0, 0},
87 {VKEY_BROWSER_BACK
, DomKey::BROWSER_BACK
, 0, 0},
88 {VKEY_BROWSER_FORWARD
, DomKey::BROWSER_FORWARD
, 0, 0},
89 {VKEY_BROWSER_REFRESH
, DomKey::BROWSER_REFRESH
, 0, 0},
90 {VKEY_BROWSER_STOP
, DomKey::BROWSER_STOP
, 0, 0},
91 {VKEY_BROWSER_SEARCH
, DomKey::BROWSER_SEARCH
, 0, 0},
92 {VKEY_BROWSER_FAVORITES
, DomKey::BROWSER_FAVORITES
, 0, 0},
93 {VKEY_BROWSER_HOME
, DomKey::BROWSER_HOME
, 0, 0},
94 {VKEY_VOLUME_MUTE
, DomKey::VOLUME_MUTE
, 0, 0},
95 {VKEY_VOLUME_DOWN
, DomKey::VOLUME_DOWN
, 0, 0},
96 {VKEY_VOLUME_UP
, DomKey::VOLUME_UP
, 0, 0},
97 {VKEY_MEDIA_NEXT_TRACK
, DomKey::MEDIA_TRACK_NEXT
, 0, 0},
98 {VKEY_MEDIA_PREV_TRACK
, DomKey::MEDIA_TRACK_PREVIOUS
, 0, 0},
99 {VKEY_MEDIA_STOP
, DomKey::MEDIA_STOP
, 0, 0},
100 {VKEY_MEDIA_PLAY_PAUSE
, DomKey::MEDIA_PLAY_PAUSE
, 0, 0},
101 {VKEY_MEDIA_LAUNCH_MAIL
, DomKey::LAUNCH_MAIL
, 0, 0},
102 {VKEY_MEDIA_LAUNCH_MEDIA_SELECT
, DomKey::LAUNCH_MEDIA_PLAYER
, 0, 0},
103 {VKEY_MEDIA_LAUNCH_APP1
, DomKey::LAUNCH_MY_COMPUTER
, 0, 0},
104 {VKEY_MEDIA_LAUNCH_APP2
, DomKey::LAUNCH_CALCULATOR
, 0, 0},
105 {VKEY_OEM_8
, DomKey::SUPER
, 0, 0}, // ISO Level 5 Shift in ChromeOS
106 {VKEY_PROCESSKEY
, DomKey::PROCESS
, 0, 0},
107 {VKEY_DBE_SBCSCHAR
, DomKey::HANKAKU
, 0, 0},
108 {VKEY_DBE_DBCSCHAR
, DomKey::ZENKAKU
, 0, 0},
109 {VKEY_ATTN
, DomKey::ATTN
, 0, 0},
110 {VKEY_CRSEL
, DomKey::CR_SEL
, 0, 0},
111 {VKEY_EXSEL
, DomKey::EX_SEL
, 0, 0},
112 {VKEY_EREOF
, DomKey::ERASE_EOF
, 0, 0},
113 {VKEY_PLAY
, DomKey::MEDIA_PLAY
, 0, 0},
114 {VKEY_ZOOM
, DomKey::ZOOM_TOGGLE
, 0, 0},
115 {VKEY_OEM_CLEAR
, DomKey::CLEAR
, 0, 0},
116 {VKEY_ALTGR
, DomKey::ALT_GRAPH
, 0, 0},
117 #if defined(OS_POSIX)
118 {VKEY_POWER
, DomKey::POWER
, 0, 0},
119 {VKEY_BRIGHTNESS_DOWN
, DomKey::BRIGHTNESS_DOWN
, 0, 0},
120 {VKEY_BRIGHTNESS_UP
, DomKey::BRIGHTNESS_UP
, 0, 0},
121 {VKEY_COMPOSE
, DomKey::COMPOSE
, 0, 0},
122 {VKEY_OEM_103
, DomKey::MEDIA_REWIND
, 0, 0},
123 {VKEY_OEM_104
, DomKey::MEDIA_FAST_FORWARD
, 0, 0},
127 } // anonymous namespace
129 base::char16
GetCharacterFromKeyCode(KeyboardCode key_code
, int flags
) {
131 base::char16 character
;
132 if (GetMeaningFromKeyCode(key_code
, flags
, &dom_key
, &character
))
137 bool GetMeaningFromKeyCode(KeyboardCode key_code
,
140 base::char16
* character
) {
141 const bool ctrl
= (flags
& EF_CONTROL_DOWN
) != 0;
142 const bool shift
= (flags
& EF_SHIFT_DOWN
) != 0;
143 const bool upper
= shift
^ ((flags
& EF_CAPS_LOCK_DOWN
) != 0);
145 // Control characters.
147 // Following Windows behavior to map ctrl-a ~ ctrl-z to \x01 ~ \x1A.
148 if (key_code
>= VKEY_A
&& key_code
<= VKEY_Z
) {
149 *character
= static_cast<uint16
>(key_code
- VKEY_A
+ 1);
152 *dom_key
= DomKey::BACKSPACE
;
155 *dom_key
= DomKey::TAB
;
159 *dom_key
= DomKey::ENTER
;
162 *dom_key
= DomKey::CHARACTER
;
167 // Other control characters.
169 // The following graphics characters require the shift key to input.
171 // ctrl-@ maps to \x00 (Null byte)
173 *dom_key
= DomKey::CHARACTER
;
176 // ctrl-^ maps to \x1E (Record separator, Information separator two)
178 *dom_key
= DomKey::CHARACTER
;
181 // ctrl-_ maps to \x1F (Unit separator, Information separator one)
183 *dom_key
= DomKey::CHARACTER
;
186 // Returns 0 for all other keys to avoid inputting unexpected chars.
188 *dom_key
= DomKey::UNIDENTIFIED
;
194 // ctrl-[ maps to \x1B (Escape)
196 *dom_key
= DomKey::ESCAPE
;
199 // ctrl-\ maps to \x1C (File separator, Information separator four)
201 *dom_key
= DomKey::CHARACTER
;
204 // ctrl-] maps to \x1D (Group separator, Information separator three)
206 *dom_key
= DomKey::CHARACTER
;
209 // ctrl-Enter maps to \x0A (Line feed)
211 *dom_key
= DomKey::CHARACTER
;
214 // Returns 0 for all other keys to avoid inputting unexpected chars.
216 *dom_key
= DomKey::UNIDENTIFIED
;
223 // ASCII alphanumeric characters.
224 if (key_code
>= VKEY_A
&& key_code
<= VKEY_Z
) {
225 *dom_key
= DomKey::CHARACTER
;
226 *character
= static_cast<uint16
>(key_code
- VKEY_A
+ (upper
? 'A' : 'a'));
229 if (key_code
>= VKEY_0
&& key_code
<= VKEY_9
) {
230 *dom_key
= DomKey::CHARACTER
;
232 shift
? ")!@#$%^&*("[key_code
- VKEY_0
] : static_cast<uint16
>(key_code
);
235 if (key_code
>= VKEY_NUMPAD0
&& key_code
<= VKEY_NUMPAD9
) {
236 *dom_key
= DomKey::CHARACTER
;
237 *character
= static_cast<uint16
>(key_code
- VKEY_NUMPAD0
+ '0');
242 if (key_code
>= VKEY_F1
&& key_code
<= VKEY_F24
) {
244 static_cast<DomKey
>(key_code
- VKEY_F1
+ static_cast<int>(DomKey::F1
));
250 for (size_t i
= 0; i
< arraysize(kKeyboardCodeToMeaning
); ++i
) {
251 if (kKeyboardCodeToMeaning
[i
].key_code
== key_code
) {
252 const KeyboardCodeToMeaning
* p
= &kKeyboardCodeToMeaning
[i
];
254 *character
= (shift
&& p
->shift_character
) ? p
->shift_character
255 : p
->plain_character
;
259 *dom_key
= DomKey::UNIDENTIFIED
;