OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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 "base/keyboard_code_conversion_mac.h" |
| 6 |
| 7 #include <algorithm> |
| 8 #import <Carbon/Carbon.h> |
| 9 |
| 10 #include "base/logging.h" |
| 11 |
| 12 namespace base { |
| 13 |
| 14 namespace { |
| 15 |
| 16 // A struct to hold a Windows keycode to Mac virtual keycode mapping. |
| 17 struct KeyCodeMap { |
| 18 KeyboardCode keycode; |
| 19 int macKeycode; |
| 20 unichar characterIgnoringModifiers; |
| 21 }; |
| 22 |
| 23 // Customized less operator for using std::lower_bound() on a KeyCodeMap array. |
| 24 bool operator<(const KeyCodeMap& a, const KeyCodeMap& b) { |
| 25 return a.keycode < b.keycode; |
| 26 } |
| 27 |
| 28 // This array must keep sorted ascending according to the value of |keycode|, |
| 29 // so that we can binary search it. |
| 30 // TODO(suzhe): This map is not complete, missing entries have macKeycode == -1. |
| 31 const KeyCodeMap kKeyCodesMap[] = { |
| 32 { VKEY_BACK /* 0x08 */, kVK_Delete, kBackspaceCharCode }, |
| 33 { VKEY_TAB /* 0x09 */, kVK_Tab, kTabCharCode }, |
| 34 { VKEY_CLEAR /* 0x0C */, kVK_ANSI_KeypadClear, kClearCharCode }, |
| 35 { VKEY_RETURN /* 0x0D */, kVK_Return, kReturnCharCode }, |
| 36 { VKEY_SHIFT /* 0x10 */, kVK_Shift, 0 }, |
| 37 { VKEY_CONTROL /* 0x11 */, kVK_Control, 0 }, |
| 38 { VKEY_MENU /* 0x12 */, kVK_Option, 0 }, |
| 39 { VKEY_PAUSE /* 0x13 */, -1, NSPauseFunctionKey }, |
| 40 { VKEY_CAPITAL /* 0x14 */, kVK_CapsLock, 0 }, |
| 41 { VKEY_KANA /* 0x15 */, kVK_JIS_Kana, 0 }, |
| 42 { VKEY_HANGUL /* 0x15 */, -1, 0 }, |
| 43 { VKEY_JUNJA /* 0x17 */, -1, 0 }, |
| 44 { VKEY_FINAL /* 0x18 */, -1, 0 }, |
| 45 { VKEY_HANJA /* 0x19 */, -1, 0 }, |
| 46 { VKEY_KANJI /* 0x19 */, -1, 0 }, |
| 47 { VKEY_ESCAPE /* 0x1B */, kVK_Escape, kEscapeCharCode }, |
| 48 { VKEY_CONVERT /* 0x1C */, -1, 0 }, |
| 49 { VKEY_NONCONVERT /* 0x1D */, -1, 0 }, |
| 50 { VKEY_ACCEPT /* 0x1E */, -1, 0 }, |
| 51 { VKEY_MODECHANGE /* 0x1F */, -1, 0 }, |
| 52 { VKEY_SPACE /* 0x20 */, kVK_Space, kSpaceCharCode }, |
| 53 { VKEY_PRIOR /* 0x21 */, kVK_PageUp, NSPageUpFunctionKey }, |
| 54 { VKEY_NEXT /* 0x22 */, kVK_PageDown, NSPageDownFunctionKey }, |
| 55 { VKEY_END /* 0x23 */, kVK_End, NSEndFunctionKey }, |
| 56 { VKEY_HOME /* 0x24 */, kVK_Home, NSHomeFunctionKey }, |
| 57 { VKEY_LEFT /* 0x25 */, kVK_LeftArrow, NSLeftArrowFunctionKey }, |
| 58 { VKEY_UP /* 0x26 */, kVK_UpArrow, NSUpArrowFunctionKey }, |
| 59 { VKEY_RIGHT /* 0x27 */, kVK_RightArrow, NSRightArrowFunctionKey }, |
| 60 { VKEY_DOWN /* 0x28 */, kVK_DownArrow, NSDownArrowFunctionKey }, |
| 61 { VKEY_SELECT /* 0x29 */, -1, 0 }, |
| 62 { VKEY_PRINT /* 0x2A */, -1, NSPrintFunctionKey }, |
| 63 { VKEY_EXECUTE /* 0x2B */, -1, NSExecuteFunctionKey }, |
| 64 { VKEY_SNAPSHOT /* 0x2C */, -1, NSPrintScreenFunctionKey }, |
| 65 { VKEY_INSERT /* 0x2D */, -1, NSInsertFunctionKey }, |
| 66 { VKEY_DELETE /* 0x2E */, kVK_ForwardDelete, kDeleteCharCode }, |
| 67 { VKEY_HELP /* 0x2F */, kVK_Help, kHelpCharCode }, |
| 68 { VKEY_0 /* 0x30 */, kVK_ANSI_0, '0' }, |
| 69 { VKEY_1 /* 0x31 */, kVK_ANSI_1, '1' }, |
| 70 { VKEY_2 /* 0x32 */, kVK_ANSI_2, '2' }, |
| 71 { VKEY_3 /* 0x33 */, kVK_ANSI_3, '3' }, |
| 72 { VKEY_4 /* 0x34 */, kVK_ANSI_4, '4' }, |
| 73 { VKEY_5 /* 0x35 */, kVK_ANSI_5, '5' }, |
| 74 { VKEY_6 /* 0x36 */, kVK_ANSI_6, '6' }, |
| 75 { VKEY_7 /* 0x37 */, kVK_ANSI_7, '7' }, |
| 76 { VKEY_8 /* 0x38 */, kVK_ANSI_8, '8' }, |
| 77 { VKEY_9 /* 0x39 */, kVK_ANSI_9, '9' }, |
| 78 { VKEY_A /* 0x41 */, kVK_ANSI_A, 'a' }, |
| 79 { VKEY_B /* 0x42 */, kVK_ANSI_B, 'b' }, |
| 80 { VKEY_C /* 0x43 */, kVK_ANSI_C, 'c' }, |
| 81 { VKEY_D /* 0x44 */, kVK_ANSI_D, 'd' }, |
| 82 { VKEY_E /* 0x45 */, kVK_ANSI_E, 'e' }, |
| 83 { VKEY_F /* 0x46 */, kVK_ANSI_F, 'f' }, |
| 84 { VKEY_G /* 0x47 */, kVK_ANSI_G, 'g' }, |
| 85 { VKEY_H /* 0x48 */, kVK_ANSI_H, 'h' }, |
| 86 { VKEY_I /* 0x49 */, kVK_ANSI_I, 'i' }, |
| 87 { VKEY_J /* 0x4A */, kVK_ANSI_J, 'j' }, |
| 88 { VKEY_K /* 0x4B */, kVK_ANSI_K, 'k' }, |
| 89 { VKEY_L /* 0x4C */, kVK_ANSI_L, 'l' }, |
| 90 { VKEY_M /* 0x4D */, kVK_ANSI_M, 'm' }, |
| 91 { VKEY_N /* 0x4E */, kVK_ANSI_N, 'n' }, |
| 92 { VKEY_O /* 0x4F */, kVK_ANSI_O, 'o' }, |
| 93 { VKEY_P /* 0x50 */, kVK_ANSI_P, 'p' }, |
| 94 { VKEY_Q /* 0x51 */, kVK_ANSI_Q, 'q' }, |
| 95 { VKEY_R /* 0x52 */, kVK_ANSI_R, 'r' }, |
| 96 { VKEY_S /* 0x53 */, kVK_ANSI_S, 's' }, |
| 97 { VKEY_T /* 0x54 */, kVK_ANSI_T, 't' }, |
| 98 { VKEY_U /* 0x55 */, kVK_ANSI_U, 'u' }, |
| 99 { VKEY_V /* 0x56 */, kVK_ANSI_V, 'v' }, |
| 100 { VKEY_W /* 0x57 */, kVK_ANSI_W, 'w' }, |
| 101 { VKEY_X /* 0x58 */, kVK_ANSI_X, 'x' }, |
| 102 { VKEY_Y /* 0x59 */, kVK_ANSI_Y, 'y' }, |
| 103 { VKEY_Z /* 0x5A */, kVK_ANSI_Z, 'z' }, |
| 104 { VKEY_LWIN /* 0x5B */, kVK_Command, 0 }, |
| 105 { VKEY_RWIN /* 0x5C */, 0x36, 0 }, |
| 106 { VKEY_APPS /* 0x5D */, 0x36, 0 }, |
| 107 { VKEY_SLEEP /* 0x5F */, -1, 0 }, |
| 108 { VKEY_NUMPAD0 /* 0x60 */, kVK_ANSI_Keypad0, '0' }, |
| 109 { VKEY_NUMPAD1 /* 0x61 */, kVK_ANSI_Keypad1, '1' }, |
| 110 { VKEY_NUMPAD2 /* 0x62 */, kVK_ANSI_Keypad2, '2' }, |
| 111 { VKEY_NUMPAD3 /* 0x63 */, kVK_ANSI_Keypad3, '3' }, |
| 112 { VKEY_NUMPAD4 /* 0x64 */, kVK_ANSI_Keypad4, '4' }, |
| 113 { VKEY_NUMPAD5 /* 0x65 */, kVK_ANSI_Keypad5, '5' }, |
| 114 { VKEY_NUMPAD6 /* 0x66 */, kVK_ANSI_Keypad6, '6' }, |
| 115 { VKEY_NUMPAD7 /* 0x67 */, kVK_ANSI_Keypad7, '7' }, |
| 116 { VKEY_NUMPAD8 /* 0x68 */, kVK_ANSI_Keypad8, '8' }, |
| 117 { VKEY_NUMPAD9 /* 0x69 */, kVK_ANSI_Keypad9, '9' }, |
| 118 { VKEY_MULTIPLY /* 0x6A */, kVK_ANSI_KeypadMultiply, '*' }, |
| 119 { VKEY_ADD /* 0x6B */, kVK_ANSI_KeypadPlus, '+' }, |
| 120 { VKEY_SEPARATOR /* 0x6C */, -1, 0 }, |
| 121 { VKEY_SUBTRACT /* 0x6D */, kVK_ANSI_KeypadMinus, '-' }, |
| 122 { VKEY_DECIMAL /* 0x6E */, kVK_ANSI_KeypadDecimal, '.' }, |
| 123 { VKEY_DIVIDE /* 0x6F */, kVK_ANSI_KeypadDivide, '/' }, |
| 124 { VKEY_F1 /* 0x70 */, kVK_F1, NSF1FunctionKey }, |
| 125 { VKEY_F2 /* 0x71 */, kVK_F2, NSF2FunctionKey }, |
| 126 { VKEY_F3 /* 0x72 */, kVK_F3, NSF3FunctionKey }, |
| 127 { VKEY_F4 /* 0x73 */, kVK_F4, NSF4FunctionKey }, |
| 128 { VKEY_F5 /* 0x74 */, kVK_F5, NSF5FunctionKey }, |
| 129 { VKEY_F6 /* 0x75 */, kVK_F6, NSF6FunctionKey }, |
| 130 { VKEY_F7 /* 0x76 */, kVK_F7, NSF7FunctionKey }, |
| 131 { VKEY_F8 /* 0x77 */, kVK_F8, NSF8FunctionKey }, |
| 132 { VKEY_F9 /* 0x78 */, kVK_F9, NSF9FunctionKey }, |
| 133 { VKEY_F10 /* 0x79 */, kVK_F10, NSF10FunctionKey }, |
| 134 { VKEY_F11 /* 0x7A */, kVK_F11, NSF11FunctionKey }, |
| 135 { VKEY_F12 /* 0x7B */, kVK_F12, NSF12FunctionKey }, |
| 136 { VKEY_F13 /* 0x7C */, kVK_F13, NSF13FunctionKey }, |
| 137 { VKEY_F14 /* 0x7D */, kVK_F14, NSF14FunctionKey }, |
| 138 { VKEY_F15 /* 0x7E */, kVK_F15, NSF15FunctionKey }, |
| 139 { VKEY_F16 /* 0x7F */, kVK_F16, NSF16FunctionKey }, |
| 140 { VKEY_F17 /* 0x80 */, kVK_F17, NSF17FunctionKey }, |
| 141 { VKEY_F18 /* 0x81 */, kVK_F18, NSF18FunctionKey }, |
| 142 { VKEY_F19 /* 0x82 */, kVK_F19, NSF19FunctionKey }, |
| 143 { VKEY_F20 /* 0x83 */, kVK_F20, NSF20FunctionKey }, |
| 144 { VKEY_F21 /* 0x84 */, -1, NSF21FunctionKey }, |
| 145 { VKEY_F22 /* 0x85 */, -1, NSF22FunctionKey }, |
| 146 { VKEY_F23 /* 0x86 */, -1, NSF23FunctionKey }, |
| 147 { VKEY_F24 /* 0x87 */, -1, NSF24FunctionKey }, |
| 148 { VKEY_NUMLOCK /* 0x90 */, -1, 0 }, |
| 149 { VKEY_SCROLL /* 0x91 */, -1, NSScrollLockFunctionKey }, |
| 150 { VKEY_LSHIFT /* 0xA0 */, kVK_Shift, 0 }, |
| 151 { VKEY_RSHIFT /* 0xA1 */, kVK_Shift, 0 }, |
| 152 { VKEY_LCONTROL /* 0xA2 */, kVK_Control, 0 }, |
| 153 { VKEY_RCONTROL /* 0xA3 */, kVK_Control, 0 }, |
| 154 { VKEY_LMENU /* 0xA4 */, -1, 0 }, |
| 155 { VKEY_RMENU /* 0xA5 */, -1, 0 }, |
| 156 { VKEY_BROWSER_BACK /* 0xA6 */, -1, 0 }, |
| 157 { VKEY_BROWSER_FORWARD /* 0xA7 */, -1, 0 }, |
| 158 { VKEY_BROWSER_REFRESH /* 0xA8 */, -1, 0 }, |
| 159 { VKEY_BROWSER_STOP /* 0xA9 */, -1, 0 }, |
| 160 { VKEY_BROWSER_SEARCH /* 0xAA */, -1, 0 }, |
| 161 { VKEY_BROWSER_FAVORITES /* 0xAB */, -1, 0 }, |
| 162 { VKEY_BROWSER_HOME /* 0xAC */, -1, 0 }, |
| 163 { VKEY_VOLUME_MUTE /* 0xAD */, -1, 0 }, |
| 164 { VKEY_VOLUME_DOWN /* 0xAE */, -1, 0 }, |
| 165 { VKEY_VOLUME_UP /* 0xAF */, -1, 0 }, |
| 166 { VKEY_MEDIA_NEXT_TRACK /* 0xB0 */, -1, 0 }, |
| 167 { VKEY_MEDIA_PREV_TRACK /* 0xB1 */, -1, 0 }, |
| 168 { VKEY_MEDIA_STOP /* 0xB2 */, -1, 0 }, |
| 169 { VKEY_MEDIA_PLAY_PAUSE /* 0xB3 */, -1, 0 }, |
| 170 { VKEY_MEDIA_LAUNCH_MAIL /* 0xB4 */, -1, 0 }, |
| 171 { VKEY_MEDIA_LAUNCH_MEDIA_SELECT /* 0xB5 */, -1, 0 }, |
| 172 { VKEY_MEDIA_LAUNCH_APP1 /* 0xB6 */, -1, 0 }, |
| 173 { VKEY_MEDIA_LAUNCH_APP2 /* 0xB7 */, -1, 0 }, |
| 174 { VKEY_OEM_1 /* 0xBA */, kVK_ANSI_Semicolon, ';' }, |
| 175 { VKEY_OEM_PLUS /* 0xBB */, kVK_ANSI_Equal, '=' }, |
| 176 { VKEY_OEM_COMMA /* 0xBC */, kVK_ANSI_Comma, ',' }, |
| 177 { VKEY_OEM_MINUS /* 0xBD */, kVK_ANSI_Minus, '-' }, |
| 178 { VKEY_OEM_PERIOD /* 0xBE */, kVK_ANSI_Period, '.' }, |
| 179 { VKEY_OEM_2 /* 0xBF */, kVK_ANSI_Slash, '/' }, |
| 180 { VKEY_OEM_3 /* 0xC0 */, kVK_ANSI_Grave, '`' }, |
| 181 { VKEY_OEM_4 /* 0xDB */, kVK_ANSI_LeftBracket, '[' }, |
| 182 { VKEY_OEM_5 /* 0xDC */, kVK_ANSI_Backslash, '\\' }, |
| 183 { VKEY_OEM_6 /* 0xDD */, kVK_ANSI_RightBracket, ']' }, |
| 184 { VKEY_OEM_7 /* 0xDE */, kVK_ANSI_Quote, '\'' }, |
| 185 { VKEY_OEM_8 /* 0xDF */, -1, 0 }, |
| 186 { VKEY_OEM_102 /* 0xE2 */, -1, 0 }, |
| 187 { VKEY_PROCESSKEY /* 0xE5 */, -1, 0 }, |
| 188 { VKEY_PACKET /* 0xE7 */, -1, 0 }, |
| 189 { VKEY_ATTN /* 0xF6 */, -1, 0 }, |
| 190 { VKEY_CRSEL /* 0xF7 */, -1, 0 }, |
| 191 { VKEY_EXSEL /* 0xF8 */, -1, 0 }, |
| 192 { VKEY_EREOF /* 0xF9 */, -1, 0 }, |
| 193 { VKEY_PLAY /* 0xFA */, -1, 0 }, |
| 194 { VKEY_ZOOM /* 0xFB */, -1, 0 }, |
| 195 { VKEY_NONAME /* 0xFC */, -1, 0 }, |
| 196 { VKEY_PA1 /* 0xFD */, -1, 0 }, |
| 197 { VKEY_OEM_CLEAR /* 0xFE */, kVK_ANSI_KeypadClear, kClearCharCode } |
| 198 }; |
| 199 |
| 200 // A convenient array for getting symbol characters on the number keys. |
| 201 const char kShiftCharsForNumberKeys[] = ")!@#$%^&*("; |
| 202 |
| 203 } // anonymous namespace |
| 204 |
| 205 int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode, |
| 206 NSUInteger flags, |
| 207 unichar* character, |
| 208 unichar* characterIgnoringModifiers) { |
| 209 KeyCodeMap from; |
| 210 from.keycode = keycode; |
| 211 |
| 212 const KeyCodeMap* ptr = std::lower_bound( |
| 213 kKeyCodesMap, kKeyCodesMap + arraysize(kKeyCodesMap), from); |
| 214 |
| 215 if (ptr >= kKeyCodesMap + arraysize(kKeyCodesMap) || |
| 216 ptr->keycode != keycode || ptr->macKeycode == -1) { |
| 217 NOTREACHED() << "Unsupported keycode:" << keycode; |
| 218 return -1; |
| 219 } |
| 220 |
| 221 int macKeycode = ptr->macKeycode; |
| 222 if (characterIgnoringModifiers) |
| 223 *characterIgnoringModifiers = ptr->characterIgnoringModifiers; |
| 224 |
| 225 if (!character) |
| 226 return macKeycode; |
| 227 |
| 228 *character = ptr->characterIgnoringModifiers; |
| 229 |
| 230 // Fill in |character| according to flags. |
| 231 if (flags & NSShiftKeyMask) { |
| 232 if (keycode >= VKEY_0 && keycode <= VKEY_9) { |
| 233 *character = kShiftCharsForNumberKeys[keycode - VKEY_0]; |
| 234 } else if (keycode >= VKEY_A && keycode <= VKEY_Z) { |
| 235 *character = 'A' + (keycode - VKEY_A); |
| 236 } else { |
| 237 switch (macKeycode) { |
| 238 case kVK_ANSI_Grave: |
| 239 *character = '~'; |
| 240 break; |
| 241 case kVK_ANSI_Minus: |
| 242 *character = '_'; |
| 243 break; |
| 244 case kVK_ANSI_Equal: |
| 245 *character = '+'; |
| 246 break; |
| 247 case kVK_ANSI_LeftBracket: |
| 248 *character = '{'; |
| 249 break; |
| 250 case kVK_ANSI_RightBracket: |
| 251 *character = '}'; |
| 252 break; |
| 253 case kVK_ANSI_Backslash: |
| 254 *character = '|'; |
| 255 break; |
| 256 case kVK_ANSI_Semicolon: |
| 257 *character = ':'; |
| 258 break; |
| 259 case kVK_ANSI_Quote: |
| 260 *character = '\"'; |
| 261 break; |
| 262 case kVK_ANSI_Comma: |
| 263 *character = '<'; |
| 264 break; |
| 265 case kVK_ANSI_Period: |
| 266 *character = '>'; |
| 267 break; |
| 268 case kVK_ANSI_Slash: |
| 269 *character = '?'; |
| 270 break; |
| 271 default: |
| 272 break; |
| 273 } |
| 274 } |
| 275 } |
| 276 |
| 277 // Control characters. |
| 278 if (flags & NSControlKeyMask) { |
| 279 if (keycode >= VKEY_A && keycode <= VKEY_Z) |
| 280 *character = 1 + keycode - VKEY_A; |
| 281 else if (macKeycode == kVK_ANSI_LeftBracket) |
| 282 *character = 27; |
| 283 else if (macKeycode == kVK_ANSI_Backslash) |
| 284 *character = 28; |
| 285 else if (macKeycode == kVK_ANSI_RightBracket) |
| 286 *character = 29; |
| 287 } |
| 288 |
| 289 // TODO(suzhe): Support characters for Option key bindings. |
| 290 return macKeycode; |
| 291 } |
| 292 |
| 293 } // namespace base |
OLD | NEW |