keyboard_code_conversion_mac.mm revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
1// Copyright (c) 2012 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.
4
5#import "ui/events/keycodes/keyboard_code_conversion_mac.h"
6
7#include <algorithm>
8
9#import <Carbon/Carbon.h>
10
11#include "base/logging.h"
12#include "ui/events/keycodes/dom4/keycode_converter.h"
13
14namespace ui {
15
16namespace {
17
18// A struct to hold a Windows keycode to Mac virtual keycode mapping.
19struct KeyCodeMap {
20  KeyboardCode keycode;
21  int macKeycode;
22  unichar characterIgnoringModifiers;
23};
24
25// Customized less operator for using std::lower_bound() on a KeyCodeMap array.
26bool operator<(const KeyCodeMap& a, const KeyCodeMap& b) {
27  return a.keycode < b.keycode;
28}
29
30// This array must keep sorted ascending according to the value of |keycode|,
31// so that we can binary search it.
32// TODO(suzhe): This map is not complete, missing entries have macKeycode == -1.
33const KeyCodeMap kKeyCodesMap[] = {
34  { VKEY_BACK /* 0x08 */, kVK_Delete, kBackspaceCharCode },
35  { VKEY_TAB /* 0x09 */, kVK_Tab, kTabCharCode },
36  { VKEY_BACKTAB /* 0x0A */, 0x21E4, '\031' },
37  { VKEY_CLEAR /* 0x0C */, kVK_ANSI_KeypadClear, kClearCharCode },
38  { VKEY_RETURN /* 0x0D */, kVK_Return, kReturnCharCode },
39  { VKEY_SHIFT /* 0x10 */, kVK_Shift, 0 },
40  { VKEY_CONTROL /* 0x11 */, kVK_Control, 0 },
41  { VKEY_MENU /* 0x12 */, kVK_Option, 0 },
42  { VKEY_PAUSE /* 0x13 */, -1, NSPauseFunctionKey },
43  { VKEY_CAPITAL /* 0x14 */, kVK_CapsLock, 0 },
44  { VKEY_KANA /* 0x15 */, kVK_JIS_Kana, 0 },
45  { VKEY_HANGUL /* 0x15 */, -1, 0 },
46  { VKEY_JUNJA /* 0x17 */, -1, 0 },
47  { VKEY_FINAL /* 0x18 */, -1, 0 },
48  { VKEY_HANJA /* 0x19 */, -1, 0 },
49  { VKEY_KANJI /* 0x19 */, -1, 0 },
50  { VKEY_ESCAPE /* 0x1B */, kVK_Escape, kEscapeCharCode },
51  { VKEY_CONVERT /* 0x1C */, -1, 0 },
52  { VKEY_NONCONVERT /* 0x1D */, -1, 0 },
53  { VKEY_ACCEPT /* 0x1E */, -1, 0 },
54  { VKEY_MODECHANGE /* 0x1F */, -1, 0 },
55  { VKEY_SPACE /* 0x20 */, kVK_Space, kSpaceCharCode },
56  { VKEY_PRIOR /* 0x21 */, kVK_PageUp, NSPageUpFunctionKey },
57  { VKEY_NEXT /* 0x22 */, kVK_PageDown, NSPageDownFunctionKey },
58  { VKEY_END /* 0x23 */, kVK_End, NSEndFunctionKey },
59  { VKEY_HOME /* 0x24 */, kVK_Home, NSHomeFunctionKey },
60  { VKEY_LEFT /* 0x25 */, kVK_LeftArrow, NSLeftArrowFunctionKey },
61  { VKEY_UP /* 0x26 */, kVK_UpArrow, NSUpArrowFunctionKey },
62  { VKEY_RIGHT /* 0x27 */, kVK_RightArrow, NSRightArrowFunctionKey },
63  { VKEY_DOWN /* 0x28 */, kVK_DownArrow, NSDownArrowFunctionKey },
64  { VKEY_SELECT /* 0x29 */, -1, 0 },
65  { VKEY_PRINT /* 0x2A */, -1, NSPrintFunctionKey },
66  { VKEY_EXECUTE /* 0x2B */, -1, NSExecuteFunctionKey },
67  { VKEY_SNAPSHOT /* 0x2C */, -1, NSPrintScreenFunctionKey },
68  { VKEY_INSERT /* 0x2D */, -1, NSInsertFunctionKey },
69  { VKEY_DELETE /* 0x2E */, kVK_ForwardDelete, kDeleteCharCode },
70  { VKEY_HELP /* 0x2F */, kVK_Help, kHelpCharCode },
71  { VKEY_0 /* 0x30 */, kVK_ANSI_0, '0' },
72  { VKEY_1 /* 0x31 */, kVK_ANSI_1, '1' },
73  { VKEY_2 /* 0x32 */, kVK_ANSI_2, '2' },
74  { VKEY_3 /* 0x33 */, kVK_ANSI_3, '3' },
75  { VKEY_4 /* 0x34 */, kVK_ANSI_4, '4' },
76  { VKEY_5 /* 0x35 */, kVK_ANSI_5, '5' },
77  { VKEY_6 /* 0x36 */, kVK_ANSI_6, '6' },
78  { VKEY_7 /* 0x37 */, kVK_ANSI_7, '7' },
79  { VKEY_8 /* 0x38 */, kVK_ANSI_8, '8' },
80  { VKEY_9 /* 0x39 */, kVK_ANSI_9, '9' },
81  { VKEY_A /* 0x41 */, kVK_ANSI_A, 'a' },
82  { VKEY_B /* 0x42 */, kVK_ANSI_B, 'b' },
83  { VKEY_C /* 0x43 */, kVK_ANSI_C, 'c' },
84  { VKEY_D /* 0x44 */, kVK_ANSI_D, 'd' },
85  { VKEY_E /* 0x45 */, kVK_ANSI_E, 'e' },
86  { VKEY_F /* 0x46 */, kVK_ANSI_F, 'f' },
87  { VKEY_G /* 0x47 */, kVK_ANSI_G, 'g' },
88  { VKEY_H /* 0x48 */, kVK_ANSI_H, 'h' },
89  { VKEY_I /* 0x49 */, kVK_ANSI_I, 'i' },
90  { VKEY_J /* 0x4A */, kVK_ANSI_J, 'j' },
91  { VKEY_K /* 0x4B */, kVK_ANSI_K, 'k' },
92  { VKEY_L /* 0x4C */, kVK_ANSI_L, 'l' },
93  { VKEY_M /* 0x4D */, kVK_ANSI_M, 'm' },
94  { VKEY_N /* 0x4E */, kVK_ANSI_N, 'n' },
95  { VKEY_O /* 0x4F */, kVK_ANSI_O, 'o' },
96  { VKEY_P /* 0x50 */, kVK_ANSI_P, 'p' },
97  { VKEY_Q /* 0x51 */, kVK_ANSI_Q, 'q' },
98  { VKEY_R /* 0x52 */, kVK_ANSI_R, 'r' },
99  { VKEY_S /* 0x53 */, kVK_ANSI_S, 's' },
100  { VKEY_T /* 0x54 */, kVK_ANSI_T, 't' },
101  { VKEY_U /* 0x55 */, kVK_ANSI_U, 'u' },
102  { VKEY_V /* 0x56 */, kVK_ANSI_V, 'v' },
103  { VKEY_W /* 0x57 */, kVK_ANSI_W, 'w' },
104  { VKEY_X /* 0x58 */, kVK_ANSI_X, 'x' },
105  { VKEY_Y /* 0x59 */, kVK_ANSI_Y, 'y' },
106  { VKEY_Z /* 0x5A */, kVK_ANSI_Z, 'z' },
107  { VKEY_LWIN /* 0x5B */, kVK_Command, 0 },
108  { VKEY_RWIN /* 0x5C */, 0x36, 0 },
109  { VKEY_APPS /* 0x5D */, 0x36, 0 },
110  { VKEY_SLEEP /* 0x5F */, -1, 0 },
111  { VKEY_NUMPAD0 /* 0x60 */, kVK_ANSI_Keypad0, '0' },
112  { VKEY_NUMPAD1 /* 0x61 */, kVK_ANSI_Keypad1, '1' },
113  { VKEY_NUMPAD2 /* 0x62 */, kVK_ANSI_Keypad2, '2' },
114  { VKEY_NUMPAD3 /* 0x63 */, kVK_ANSI_Keypad3, '3' },
115  { VKEY_NUMPAD4 /* 0x64 */, kVK_ANSI_Keypad4, '4' },
116  { VKEY_NUMPAD5 /* 0x65 */, kVK_ANSI_Keypad5, '5' },
117  { VKEY_NUMPAD6 /* 0x66 */, kVK_ANSI_Keypad6, '6' },
118  { VKEY_NUMPAD7 /* 0x67 */, kVK_ANSI_Keypad7, '7' },
119  { VKEY_NUMPAD8 /* 0x68 */, kVK_ANSI_Keypad8, '8' },
120  { VKEY_NUMPAD9 /* 0x69 */, kVK_ANSI_Keypad9, '9' },
121  { VKEY_MULTIPLY /* 0x6A */, kVK_ANSI_KeypadMultiply, '*' },
122  { VKEY_ADD /* 0x6B */, kVK_ANSI_KeypadPlus, '+' },
123  { VKEY_SEPARATOR /* 0x6C */, -1, 0 },
124  { VKEY_SUBTRACT /* 0x6D */, kVK_ANSI_KeypadMinus, '-' },
125  { VKEY_DECIMAL /* 0x6E */, kVK_ANSI_KeypadDecimal, '.' },
126  { VKEY_DIVIDE /* 0x6F */, kVK_ANSI_KeypadDivide, '/' },
127  { VKEY_F1 /* 0x70 */, kVK_F1, NSF1FunctionKey },
128  { VKEY_F2 /* 0x71 */, kVK_F2, NSF2FunctionKey },
129  { VKEY_F3 /* 0x72 */, kVK_F3, NSF3FunctionKey },
130  { VKEY_F4 /* 0x73 */, kVK_F4, NSF4FunctionKey },
131  { VKEY_F5 /* 0x74 */, kVK_F5, NSF5FunctionKey },
132  { VKEY_F6 /* 0x75 */, kVK_F6, NSF6FunctionKey },
133  { VKEY_F7 /* 0x76 */, kVK_F7, NSF7FunctionKey },
134  { VKEY_F8 /* 0x77 */, kVK_F8, NSF8FunctionKey },
135  { VKEY_F9 /* 0x78 */, kVK_F9, NSF9FunctionKey },
136  { VKEY_F10 /* 0x79 */, kVK_F10, NSF10FunctionKey },
137  { VKEY_F11 /* 0x7A */, kVK_F11, NSF11FunctionKey },
138  { VKEY_F12 /* 0x7B */, kVK_F12, NSF12FunctionKey },
139  { VKEY_F13 /* 0x7C */, kVK_F13, NSF13FunctionKey },
140  { VKEY_F14 /* 0x7D */, kVK_F14, NSF14FunctionKey },
141  { VKEY_F15 /* 0x7E */, kVK_F15, NSF15FunctionKey },
142  { VKEY_F16 /* 0x7F */, kVK_F16, NSF16FunctionKey },
143  { VKEY_F17 /* 0x80 */, kVK_F17, NSF17FunctionKey },
144  { VKEY_F18 /* 0x81 */, kVK_F18, NSF18FunctionKey },
145  { VKEY_F19 /* 0x82 */, kVK_F19, NSF19FunctionKey },
146  { VKEY_F20 /* 0x83 */, kVK_F20, NSF20FunctionKey },
147  { VKEY_F21 /* 0x84 */, -1, NSF21FunctionKey },
148  { VKEY_F22 /* 0x85 */, -1, NSF22FunctionKey },
149  { VKEY_F23 /* 0x86 */, -1, NSF23FunctionKey },
150  { VKEY_F24 /* 0x87 */, -1, NSF24FunctionKey },
151  { VKEY_NUMLOCK /* 0x90 */, -1, 0 },
152  { VKEY_SCROLL /* 0x91 */, -1, NSScrollLockFunctionKey },
153  { VKEY_LSHIFT /* 0xA0 */, kVK_Shift, 0 },
154  { VKEY_RSHIFT /* 0xA1 */, kVK_Shift, 0 },
155  { VKEY_LCONTROL /* 0xA2 */, kVK_Control, 0 },
156  { VKEY_RCONTROL /* 0xA3 */, kVK_Control, 0 },
157  { VKEY_LMENU /* 0xA4 */, -1, 0 },
158  { VKEY_RMENU /* 0xA5 */, -1, 0 },
159  { VKEY_BROWSER_BACK /* 0xA6 */, -1, 0 },
160  { VKEY_BROWSER_FORWARD /* 0xA7 */, -1, 0 },
161  { VKEY_BROWSER_REFRESH /* 0xA8 */, -1, 0 },
162  { VKEY_BROWSER_STOP /* 0xA9 */, -1, 0 },
163  { VKEY_BROWSER_SEARCH /* 0xAA */, -1, 0 },
164  { VKEY_BROWSER_FAVORITES /* 0xAB */, -1, 0 },
165  { VKEY_BROWSER_HOME /* 0xAC */, -1, 0 },
166  { VKEY_VOLUME_MUTE /* 0xAD */, -1, 0 },
167  { VKEY_VOLUME_DOWN /* 0xAE */, -1, 0 },
168  { VKEY_VOLUME_UP /* 0xAF */, -1, 0 },
169  { VKEY_MEDIA_NEXT_TRACK /* 0xB0 */, -1, 0 },
170  { VKEY_MEDIA_PREV_TRACK /* 0xB1 */, -1, 0 },
171  { VKEY_MEDIA_STOP /* 0xB2 */, -1, 0 },
172  { VKEY_MEDIA_PLAY_PAUSE /* 0xB3 */, -1, 0 },
173  { VKEY_MEDIA_LAUNCH_MAIL /* 0xB4 */, -1, 0 },
174  { VKEY_MEDIA_LAUNCH_MEDIA_SELECT /* 0xB5 */, -1, 0 },
175  { VKEY_MEDIA_LAUNCH_APP1 /* 0xB6 */, -1, 0 },
176  { VKEY_MEDIA_LAUNCH_APP2 /* 0xB7 */, -1, 0 },
177  { VKEY_OEM_1 /* 0xBA */, kVK_ANSI_Semicolon, ';' },
178  { VKEY_OEM_PLUS /* 0xBB */, kVK_ANSI_Equal, '=' },
179  { VKEY_OEM_COMMA /* 0xBC */, kVK_ANSI_Comma, ',' },
180  { VKEY_OEM_MINUS /* 0xBD */, kVK_ANSI_Minus, '-' },
181  { VKEY_OEM_PERIOD /* 0xBE */, kVK_ANSI_Period, '.' },
182  { VKEY_OEM_2 /* 0xBF */, kVK_ANSI_Slash, '/' },
183  { VKEY_OEM_3 /* 0xC0 */, kVK_ANSI_Grave, '`' },
184  { VKEY_OEM_4 /* 0xDB */, kVK_ANSI_LeftBracket, '[' },
185  { VKEY_OEM_5 /* 0xDC */, kVK_ANSI_Backslash, '\\' },
186  { VKEY_OEM_6 /* 0xDD */, kVK_ANSI_RightBracket, ']' },
187  { VKEY_OEM_7 /* 0xDE */, kVK_ANSI_Quote, '\'' },
188  { VKEY_OEM_8 /* 0xDF */, -1, 0 },
189  { VKEY_OEM_102 /* 0xE2 */, -1, 0 },
190  { VKEY_PROCESSKEY /* 0xE5 */, -1, 0 },
191  { VKEY_PACKET /* 0xE7 */, -1, 0 },
192  { VKEY_ATTN /* 0xF6 */, -1, 0 },
193  { VKEY_CRSEL /* 0xF7 */, -1, 0 },
194  { VKEY_EXSEL /* 0xF8 */, -1, 0 },
195  { VKEY_EREOF /* 0xF9 */, -1, 0 },
196  { VKEY_PLAY /* 0xFA */, -1, 0 },
197  { VKEY_ZOOM /* 0xFB */, -1, 0 },
198  { VKEY_NONAME /* 0xFC */, -1, 0 },
199  { VKEY_PA1 /* 0xFD */, -1, 0 },
200  { VKEY_OEM_CLEAR /* 0xFE */, kVK_ANSI_KeypadClear, kClearCharCode }
201};
202
203// A convenient array for getting symbol characters on the number keys.
204const char kShiftCharsForNumberKeys[] = ")!@#$%^&*(";
205
206// Translates from character code to keyboard code.
207KeyboardCode KeyboardCodeFromCharCode(unichar charCode) {
208  switch (charCode) {
209    case 8: case 0x7F: return VKEY_BACK;
210    case 9: return VKEY_TAB;
211    case 0xD: case 3: return VKEY_RETURN;
212    case 0x1B: return VKEY_ESCAPE;
213    case ' ': return VKEY_SPACE;
214    case NSHomeFunctionKey: return VKEY_HOME;
215    case NSEndFunctionKey: return VKEY_END;
216    case NSPageUpFunctionKey: return VKEY_PRIOR;
217    case NSPageDownFunctionKey: return VKEY_NEXT;
218    case NSUpArrowFunctionKey: return VKEY_UP;
219    case NSDownArrowFunctionKey: return VKEY_DOWN;
220    case NSLeftArrowFunctionKey: return VKEY_LEFT;
221    case NSRightArrowFunctionKey: return VKEY_RIGHT;
222    case NSDeleteFunctionKey: return VKEY_DELETE;
223
224    case '0': case ')': return VKEY_0;
225    case '1': case '!': return VKEY_1;
226    case '2': case '@': return VKEY_2;
227    case '3': case '#': return VKEY_3;
228    case '4': case '$': return VKEY_4;
229    case '5': case '%': return VKEY_5;
230    case '6': case '^': return VKEY_6;
231    case '7': case '&': return VKEY_7;
232    case '8': case '*': return VKEY_8;
233    case '9': case '(': return VKEY_9;
234
235    case 'a': case 'A': return VKEY_A;
236    case 'b': case 'B': return VKEY_B;
237    case 'c': case 'C': return VKEY_C;
238    case 'd': case 'D': return VKEY_D;
239    case 'e': case 'E': return VKEY_E;
240    case 'f': case 'F': return VKEY_F;
241    case 'g': case 'G': return VKEY_G;
242    case 'h': case 'H': return VKEY_H;
243    case 'i': case 'I': return VKEY_I;
244    case 'j': case 'J': return VKEY_J;
245    case 'k': case 'K': return VKEY_K;
246    case 'l': case 'L': return VKEY_L;
247    case 'm': case 'M': return VKEY_M;
248    case 'n': case 'N': return VKEY_N;
249    case 'o': case 'O': return VKEY_O;
250    case 'p': case 'P': return VKEY_P;
251    case 'q': case 'Q': return VKEY_Q;
252    case 'r': case 'R': return VKEY_R;
253    case 's': case 'S': return VKEY_S;
254    case 't': case 'T': return VKEY_T;
255    case 'u': case 'U': return VKEY_U;
256    case 'v': case 'V': return VKEY_V;
257    case 'w': case 'W': return VKEY_W;
258    case 'x': case 'X': return VKEY_X;
259    case 'y': case 'Y': return VKEY_Y;
260    case 'z': case 'Z': return VKEY_Z;
261
262    case NSPauseFunctionKey: return VKEY_PAUSE;
263    case NSSelectFunctionKey: return VKEY_SELECT;
264    case NSPrintFunctionKey: return VKEY_PRINT;
265    case NSExecuteFunctionKey: return VKEY_EXECUTE;
266    case NSPrintScreenFunctionKey: return VKEY_SNAPSHOT;
267    case NSInsertFunctionKey: return VKEY_INSERT;
268    case NSHelpFunctionKey: return VKEY_INSERT;
269
270    case NSF1FunctionKey: return VKEY_F1;
271    case NSF2FunctionKey: return VKEY_F2;
272    case NSF3FunctionKey: return VKEY_F3;
273    case NSF4FunctionKey: return VKEY_F4;
274    case NSF5FunctionKey: return VKEY_F5;
275    case NSF6FunctionKey: return VKEY_F6;
276    case NSF7FunctionKey: return VKEY_F7;
277    case NSF8FunctionKey: return VKEY_F8;
278    case NSF9FunctionKey: return VKEY_F9;
279    case NSF10FunctionKey: return VKEY_F10;
280    case NSF11FunctionKey: return VKEY_F11;
281    case NSF12FunctionKey: return VKEY_F12;
282    case NSF13FunctionKey: return VKEY_F13;
283    case NSF14FunctionKey: return VKEY_F14;
284    case NSF15FunctionKey: return VKEY_F15;
285    case NSF16FunctionKey: return VKEY_F16;
286    case NSF17FunctionKey: return VKEY_F17;
287    case NSF18FunctionKey: return VKEY_F18;
288    case NSF19FunctionKey: return VKEY_F19;
289    case NSF20FunctionKey: return VKEY_F20;
290
291    case NSF21FunctionKey: return VKEY_F21;
292    case NSF22FunctionKey: return VKEY_F22;
293    case NSF23FunctionKey: return VKEY_F23;
294    case NSF24FunctionKey: return VKEY_F24;
295    case NSScrollLockFunctionKey: return VKEY_SCROLL;
296
297      // U.S. Specific mappings.  Mileage may vary.
298    case ';': case ':': return VKEY_OEM_1;
299    case '=': case '+': return VKEY_OEM_PLUS;
300    case ',': case '<': return VKEY_OEM_COMMA;
301    case '-': case '_': return VKEY_OEM_MINUS;
302    case '.': case '>': return VKEY_OEM_PERIOD;
303    case '/': case '?': return VKEY_OEM_2;
304    case '`': case '~': return VKEY_OEM_3;
305    case '[': case '{': return VKEY_OEM_4;
306    case '\\': case '|': return VKEY_OEM_5;
307    case ']': case '}': return VKEY_OEM_6;
308    case '\'': case '"': return VKEY_OEM_7;
309  }
310
311  return VKEY_UNKNOWN;
312}
313
314KeyboardCode KeyboardCodeFromKeyCode(unsigned short keyCode) {
315  static const KeyboardCode kKeyboardCodes[] = {
316    /* 0 */ VKEY_A,
317    /* 1 */ VKEY_S,
318    /* 2 */ VKEY_D,
319    /* 3 */ VKEY_F,
320    /* 4 */ VKEY_H,
321    /* 5 */ VKEY_G,
322    /* 6 */ VKEY_Z,
323    /* 7 */ VKEY_X,
324    /* 8 */ VKEY_C,
325    /* 9 */ VKEY_V,
326    /* 0x0A */ VKEY_OEM_3, // Section key.
327    /* 0x0B */ VKEY_B,
328    /* 0x0C */ VKEY_Q,
329    /* 0x0D */ VKEY_W,
330    /* 0x0E */ VKEY_E,
331    /* 0x0F */ VKEY_R,
332    /* 0x10 */ VKEY_Y,
333    /* 0x11 */ VKEY_T,
334    /* 0x12 */ VKEY_1,
335    /* 0x13 */ VKEY_2,
336    /* 0x14 */ VKEY_3,
337    /* 0x15 */ VKEY_4,
338    /* 0x16 */ VKEY_6,
339    /* 0x17 */ VKEY_5,
340    /* 0x18 */ VKEY_OEM_PLUS, // =+
341    /* 0x19 */ VKEY_9,
342    /* 0x1A */ VKEY_7,
343    /* 0x1B */ VKEY_OEM_MINUS, // -_
344    /* 0x1C */ VKEY_8,
345    /* 0x1D */ VKEY_0,
346    /* 0x1E */ VKEY_OEM_6, // ]}
347    /* 0x1F */ VKEY_O,
348    /* 0x20 */ VKEY_U,
349    /* 0x21 */ VKEY_OEM_4, // {[
350    /* 0x22 */ VKEY_I,
351    /* 0x23 */ VKEY_P,
352    /* 0x24 */ VKEY_RETURN, // Return
353    /* 0x25 */ VKEY_L,
354    /* 0x26 */ VKEY_J,
355    /* 0x27 */ VKEY_OEM_7, // '"
356    /* 0x28 */ VKEY_K,
357    /* 0x29 */ VKEY_OEM_1, // ;:
358    /* 0x2A */ VKEY_OEM_5, // \|
359    /* 0x2B */ VKEY_OEM_COMMA, // ,<
360    /* 0x2C */ VKEY_OEM_2, // /?
361    /* 0x2D */ VKEY_N,
362    /* 0x2E */ VKEY_M,
363    /* 0x2F */ VKEY_OEM_PERIOD, // .>
364    /* 0x30 */ VKEY_TAB,
365    /* 0x31 */ VKEY_SPACE,
366    /* 0x32 */ VKEY_OEM_3, // `~
367    /* 0x33 */ VKEY_BACK, // Backspace
368    /* 0x34 */ VKEY_UNKNOWN, // n/a
369    /* 0x35 */ VKEY_ESCAPE,
370    /* 0x36 */ VKEY_APPS, // Right Command
371    /* 0x37 */ VKEY_LWIN, // Left Command
372    /* 0x38 */ VKEY_SHIFT, // Left Shift
373    /* 0x39 */ VKEY_CAPITAL, // Caps Lock
374    /* 0x3A */ VKEY_MENU, // Left Option
375    /* 0x3B */ VKEY_CONTROL, // Left Ctrl
376    /* 0x3C */ VKEY_SHIFT, // Right Shift
377    /* 0x3D */ VKEY_MENU, // Right Option
378    /* 0x3E */ VKEY_CONTROL, // Right Ctrl
379    /* 0x3F */ VKEY_UNKNOWN, // fn
380    /* 0x40 */ VKEY_F17,
381    /* 0x41 */ VKEY_DECIMAL, // Num Pad .
382    /* 0x42 */ VKEY_UNKNOWN, // n/a
383    /* 0x43 */ VKEY_MULTIPLY, // Num Pad *
384    /* 0x44 */ VKEY_UNKNOWN, // n/a
385    /* 0x45 */ VKEY_ADD, // Num Pad +
386    /* 0x46 */ VKEY_UNKNOWN, // n/a
387    /* 0x47 */ VKEY_CLEAR, // Num Pad Clear
388    /* 0x48 */ VKEY_VOLUME_UP,
389    /* 0x49 */ VKEY_VOLUME_DOWN,
390    /* 0x4A */ VKEY_VOLUME_MUTE,
391    /* 0x4B */ VKEY_DIVIDE, // Num Pad /
392    /* 0x4C */ VKEY_RETURN, // Num Pad Enter
393    /* 0x4D */ VKEY_UNKNOWN, // n/a
394    /* 0x4E */ VKEY_SUBTRACT, // Num Pad -
395    /* 0x4F */ VKEY_F18,
396    /* 0x50 */ VKEY_F19,
397    /* 0x51 */ VKEY_OEM_PLUS, // Num Pad =.
398    /* 0x52 */ VKEY_NUMPAD0,
399    /* 0x53 */ VKEY_NUMPAD1,
400    /* 0x54 */ VKEY_NUMPAD2,
401    /* 0x55 */ VKEY_NUMPAD3,
402    /* 0x56 */ VKEY_NUMPAD4,
403    /* 0x57 */ VKEY_NUMPAD5,
404    /* 0x58 */ VKEY_NUMPAD6,
405    /* 0x59 */ VKEY_NUMPAD7,
406    /* 0x5A */ VKEY_F20,
407    /* 0x5B */ VKEY_NUMPAD8,
408    /* 0x5C */ VKEY_NUMPAD9,
409    /* 0x5D */ VKEY_UNKNOWN, // Yen (JIS Keyboard Only)
410    /* 0x5E */ VKEY_UNKNOWN, // Underscore (JIS Keyboard Only)
411    /* 0x5F */ VKEY_UNKNOWN, // KeypadComma (JIS Keyboard Only)
412    /* 0x60 */ VKEY_F5,
413    /* 0x61 */ VKEY_F6,
414    /* 0x62 */ VKEY_F7,
415    /* 0x63 */ VKEY_F3,
416    /* 0x64 */ VKEY_F8,
417    /* 0x65 */ VKEY_F9,
418    /* 0x66 */ VKEY_UNKNOWN, // Eisu (JIS Keyboard Only)
419    /* 0x67 */ VKEY_F11,
420    /* 0x68 */ VKEY_UNKNOWN, // Kana (JIS Keyboard Only)
421    /* 0x69 */ VKEY_F13,
422    /* 0x6A */ VKEY_F16,
423    /* 0x6B */ VKEY_F14,
424    /* 0x6C */ VKEY_UNKNOWN, // n/a
425    /* 0x6D */ VKEY_F10,
426    /* 0x6E */ VKEY_UNKNOWN, // n/a (Windows95 key?)
427    /* 0x6F */ VKEY_F12,
428    /* 0x70 */ VKEY_UNKNOWN, // n/a
429    /* 0x71 */ VKEY_F15,
430    /* 0x72 */ VKEY_INSERT, // Help
431    /* 0x73 */ VKEY_HOME, // Home
432    /* 0x74 */ VKEY_PRIOR, // Page Up
433    /* 0x75 */ VKEY_DELETE, // Forward Delete
434    /* 0x76 */ VKEY_F4,
435    /* 0x77 */ VKEY_END, // End
436    /* 0x78 */ VKEY_F2,
437    /* 0x79 */ VKEY_NEXT, // Page Down
438    /* 0x7A */ VKEY_F1,
439    /* 0x7B */ VKEY_LEFT, // Left Arrow
440    /* 0x7C */ VKEY_RIGHT, // Right Arrow
441    /* 0x7D */ VKEY_DOWN, // Down Arrow
442    /* 0x7E */ VKEY_UP, // Up Arrow
443    /* 0x7F */ VKEY_UNKNOWN // n/a
444  };
445
446  if (keyCode >= 0x80)
447    return VKEY_UNKNOWN;
448
449  return kKeyboardCodes[keyCode];
450}
451
452}  // namespace
453
454int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode,
455                                NSUInteger flags,
456                                unichar* character,
457                                unichar* characterIgnoringModifiers) {
458  KeyCodeMap from;
459  from.keycode = keycode;
460
461  const KeyCodeMap* ptr = std::lower_bound(
462      kKeyCodesMap, kKeyCodesMap + arraysize(kKeyCodesMap), from);
463
464  if (ptr >= kKeyCodesMap + arraysize(kKeyCodesMap) ||
465      ptr->keycode != keycode || ptr->macKeycode == -1)
466    return -1;
467
468  int macKeycode = ptr->macKeycode;
469  if (characterIgnoringModifiers)
470    *characterIgnoringModifiers = ptr->characterIgnoringModifiers;
471
472  if (!character)
473    return macKeycode;
474
475  *character = ptr->characterIgnoringModifiers;
476
477  // Fill in |character| according to flags.
478  if (flags & NSShiftKeyMask) {
479    if (keycode >= VKEY_0 && keycode <= VKEY_9) {
480      *character = kShiftCharsForNumberKeys[keycode - VKEY_0];
481    } else if (keycode >= VKEY_A && keycode <= VKEY_Z) {
482      *character = 'A' + (keycode - VKEY_A);
483    } else {
484      switch (macKeycode) {
485        case kVK_ANSI_Grave:
486          *character = '~';
487          break;
488        case kVK_ANSI_Minus:
489          *character = '_';
490          break;
491        case kVK_ANSI_Equal:
492          *character = '+';
493          break;
494        case kVK_ANSI_LeftBracket:
495          *character = '{';
496          break;
497        case kVK_ANSI_RightBracket:
498          *character = '}';
499          break;
500        case kVK_ANSI_Backslash:
501          *character = '|';
502          break;
503        case kVK_ANSI_Semicolon:
504          *character = ':';
505          break;
506        case kVK_ANSI_Quote:
507          *character = '\"';
508          break;
509        case kVK_ANSI_Comma:
510          *character = '<';
511          break;
512        case kVK_ANSI_Period:
513          *character = '>';
514          break;
515        case kVK_ANSI_Slash:
516          *character = '?';
517          break;
518        default:
519          break;
520      }
521    }
522  }
523
524  // Control characters.
525  if (flags & NSControlKeyMask) {
526    if (keycode >= VKEY_A && keycode <= VKEY_Z)
527      *character = 1 + keycode - VKEY_A;
528    else if (macKeycode == kVK_ANSI_LeftBracket)
529      *character = 27;
530    else if (macKeycode == kVK_ANSI_Backslash)
531      *character = 28;
532    else if (macKeycode == kVK_ANSI_RightBracket)
533      *character = 29;
534  }
535
536  // TODO(suzhe): Support characters for Option key bindings.
537  return macKeycode;
538}
539
540KeyboardCode KeyboardCodeFromNSEvent(NSEvent* event) {
541  KeyboardCode code = VKEY_UNKNOWN;
542
543  if ([event type] == NSKeyDown || [event type] == NSKeyUp) {
544    NSString* characters = [event characters];
545    if ([characters length] > 0)
546      code = KeyboardCodeFromCharCode([characters characterAtIndex:0]);
547    if (code)
548      return code;
549
550    characters = [event charactersIgnoringModifiers];
551    if ([characters length] > 0)
552      code = KeyboardCodeFromCharCode([characters characterAtIndex:0]);
553    if (code)
554      return code;
555  }
556  return KeyboardCodeFromKeyCode([event keyCode]);
557}
558
559const char* CodeFromNSEvent(NSEvent* event) {
560  return KeycodeConverter::GetInstance()->NativeKeycodeToCode(
561      [event keyCode]);
562}
563
564}  // namespace ui
565