Home | History | Annotate | Download | only in keycodes
      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 
     14 namespace ui {
     15 
     16 namespace {
     17 
     18 // A struct to hold a Windows keycode to Mac virtual keycode mapping.
     19 struct 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.
     26 bool 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.
     33 const 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.
    204 const char kShiftCharsForNumberKeys[] = ")!@#$%^&*(";
    205 
    206 // Translates from character code to keyboard code.
    207 KeyboardCode 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 
    314 KeyboardCode 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 
    454 int 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   // TODO(suzhe): Support characters for Option key bindings.
    525   return macKeycode;
    526 }
    527 
    528 KeyboardCode KeyboardCodeFromNSEvent(NSEvent* event) {
    529   KeyboardCode code = VKEY_UNKNOWN;
    530 
    531   if ([event type] == NSKeyDown || [event type] == NSKeyUp) {
    532     NSString* characters = [event characters];
    533     if ([characters length] > 0)
    534       code = KeyboardCodeFromCharCode([characters characterAtIndex:0]);
    535     if (code)
    536       return code;
    537 
    538     characters = [event charactersIgnoringModifiers];
    539     if ([characters length] > 0)
    540       code = KeyboardCodeFromCharCode([characters characterAtIndex:0]);
    541     if (code)
    542       return code;
    543   }
    544   return KeyboardCodeFromKeyCode([event keyCode]);
    545 }
    546 
    547 const char* CodeFromNSEvent(NSEvent* event) {
    548   return KeycodeConverter::GetInstance()->NativeKeycodeToCode(
    549       [event keyCode]);
    550 }
    551 
    552 }  // namespace ui
    553