1/* 2 * Copyright (C) 2011 Samsung Electronics 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "config.h" 29#include "EflKeyboardUtilities.h" 30 31#include "KeyboardEvent.h" 32#include "WindowsKeyboardCodes.h" 33#include <wtf/HashMap.h> 34#include <wtf/HexNumber.h> 35#include <wtf/NeverDestroyed.h> 36#include <wtf/text/StringBuilder.h> 37#include <wtf/text/StringHash.h> 38#include <wtf/text/WTFString.h> 39 40namespace WebCore { 41 42static HashMap<String, String>& keyMap() 43{ 44 static NeverDestroyed<HashMap<String, String>> keyMap; 45 return keyMap; 46} 47 48static HashMap<String, int>& windowsKeyMap() 49{ 50 static NeverDestroyed<HashMap<String, int>> windowsKeyMap; 51 return windowsKeyMap; 52} 53 54static HashMap<int, const char*>& keyDownCommandsMap() 55{ 56 static NeverDestroyed<HashMap<int, const char*>> keyDownCommandsMap; 57 return keyDownCommandsMap; 58} 59 60static HashMap<int, const char*>& keyPressCommandsMap() 61{ 62 static NeverDestroyed<HashMap<int, const char*>> keyPressCommandsMap; 63 return keyPressCommandsMap; 64} 65 66static inline void addCharactersToKeyMap(const char from, const char to) 67{ 68 for (char c = from; c <= to; c++) { 69 StringBuilder builder; 70 builder.appendLiteral("U+"); 71 appendUnsignedAsHexFixedSize(c, builder, 4, WTF::Uppercase); 72 keyMap().set(String(&c, 1), builder.toString()); 73 } 74} 75 76static void createKeyMap() 77{ 78 for (unsigned int i = 1; i < 25; i++) { 79 StringBuilder builder; 80 builder.append('F'); 81 builder.appendNumber(i); 82 String key = builder.toString(); 83 keyMap().set(key, key); 84 } 85 keyMap().set(ASCIILiteral("Alt_L"), ASCIILiteral("Alt")); 86 keyMap().set(ASCIILiteral("ISO_Level3_Shift"), ASCIILiteral("Alt")); 87 keyMap().set(ASCIILiteral("Menu"), ASCIILiteral("Alt")); 88 keyMap().set(ASCIILiteral("Shift_L"), ASCIILiteral("Shift")); 89 keyMap().set(ASCIILiteral("Shift_R"), ASCIILiteral("Shift")); 90 keyMap().set(ASCIILiteral("Down"), ASCIILiteral("Down")); 91 keyMap().set(ASCIILiteral("End"), ASCIILiteral("End")); 92 keyMap().set(ASCIILiteral("Return"), ASCIILiteral("Enter")); 93 keyMap().set(ASCIILiteral("KP_Enter"), ASCIILiteral("Enter")); 94 keyMap().set(ASCIILiteral("Home"), ASCIILiteral("Home")); 95 keyMap().set(ASCIILiteral("Insert"), ASCIILiteral("Insert")); 96 keyMap().set(ASCIILiteral("Left"), ASCIILiteral("Left")); 97 keyMap().set(ASCIILiteral("Next"), ASCIILiteral("PageDown")); 98 keyMap().set(ASCIILiteral("Prior"), ASCIILiteral("PageUp")); 99 keyMap().set(ASCIILiteral("Right"), ASCIILiteral("Right")); 100 keyMap().set(ASCIILiteral("Up"), ASCIILiteral("Up")); 101 keyMap().set(ASCIILiteral("Delete"), ASCIILiteral("U+007F")); 102 keyMap().set(ASCIILiteral("Tab"), ASCIILiteral("U+0009")); 103 keyMap().set(ASCIILiteral("ISO_Left_Tab"), ASCIILiteral("U+0009")); 104 keyMap().set(ASCIILiteral("BackSpace"), ASCIILiteral("U+0008")); 105 keyMap().set(ASCIILiteral("space"), ASCIILiteral("U+0020")); 106 keyMap().set(ASCIILiteral("Escape"), ASCIILiteral("U+001B")); 107 keyMap().set(ASCIILiteral("Print"), ASCIILiteral("PrintScreen")); 108 // Keypad location 109 keyMap().set(ASCIILiteral("KP_Left"), ASCIILiteral("Left")); 110 keyMap().set(ASCIILiteral("KP_Right"), ASCIILiteral("Right")); 111 keyMap().set(ASCIILiteral("KP_Up"), ASCIILiteral("Up")); 112 keyMap().set(ASCIILiteral("KP_Down"), ASCIILiteral("Down")); 113 keyMap().set(ASCIILiteral("KP_Prior"), ASCIILiteral("PageUp")); 114 keyMap().set(ASCIILiteral("KP_Next"), ASCIILiteral("PageDown")); 115 keyMap().set(ASCIILiteral("KP_Home"), ASCIILiteral("Home")); 116 keyMap().set(ASCIILiteral("KP_End"), ASCIILiteral("End")); 117 keyMap().set(ASCIILiteral("KP_Insert"), ASCIILiteral("Insert")); 118 keyMap().set(ASCIILiteral("KP_Delete"), ASCIILiteral("U+007F")); 119 120 addCharactersToKeyMap('a', 'z'); 121 addCharactersToKeyMap('A', 'Z'); 122 addCharactersToKeyMap('0', '9'); 123} 124 125static inline void addCharactersToWinKeyMap(const char from, const char to, const int baseCode) 126{ 127 int i = 0; 128 for (char c = from; c <= to; c++, i++) 129 windowsKeyMap().set(String(&c, 1), baseCode + i); 130} 131 132static void createWindowsKeyMap() 133{ 134 windowsKeyMap().set(ASCIILiteral("Return"), VK_RETURN); 135 windowsKeyMap().set(ASCIILiteral("KP_Return"), VK_RETURN); 136 windowsKeyMap().set(ASCIILiteral("Alt_L"), VK_LMENU); 137 windowsKeyMap().set(ASCIILiteral("Alt_R"), VK_RMENU); 138 windowsKeyMap().set(ASCIILiteral("ISO_Level3_Shift"), VK_MENU); 139 windowsKeyMap().set(ASCIILiteral("Menu"), VK_MENU); 140 windowsKeyMap().set(ASCIILiteral("Shift_L"), VK_LSHIFT); 141 windowsKeyMap().set(ASCIILiteral("Shift_R"), VK_RSHIFT); 142 windowsKeyMap().set(ASCIILiteral("Control_L"), VK_LCONTROL); 143 windowsKeyMap().set(ASCIILiteral("Control_R"), VK_RCONTROL); 144 windowsKeyMap().set(ASCIILiteral("Pause"), VK_PAUSE); 145 windowsKeyMap().set(ASCIILiteral("Break"), VK_PAUSE); 146 windowsKeyMap().set(ASCIILiteral("Caps_Lock"), VK_CAPITAL); 147 windowsKeyMap().set(ASCIILiteral("Scroll_Lock"), VK_SCROLL); 148 windowsKeyMap().set(ASCIILiteral("Num_Lock"), VK_NUMLOCK); 149 windowsKeyMap().set(ASCIILiteral("Escape"), VK_ESCAPE); 150 windowsKeyMap().set(ASCIILiteral("Tab"), VK_TAB); 151 windowsKeyMap().set(ASCIILiteral("ISO_Left_Tab"), VK_TAB); 152 windowsKeyMap().set(ASCIILiteral("BackSpace"), VK_BACK); 153 windowsKeyMap().set(ASCIILiteral("space"), VK_SPACE); 154 windowsKeyMap().set(ASCIILiteral("Next"), VK_NEXT); 155 windowsKeyMap().set(ASCIILiteral("Prior"), VK_PRIOR); 156 windowsKeyMap().set(ASCIILiteral("Home"), VK_HOME); 157 windowsKeyMap().set(ASCIILiteral("End"), VK_END); 158 windowsKeyMap().set(ASCIILiteral("Right"), VK_RIGHT); 159 windowsKeyMap().set(ASCIILiteral("Left"), VK_LEFT); 160 windowsKeyMap().set(ASCIILiteral("Up"), VK_UP); 161 windowsKeyMap().set(ASCIILiteral("Down"), VK_DOWN); 162 windowsKeyMap().set(ASCIILiteral("Print"), VK_SNAPSHOT); 163 windowsKeyMap().set(ASCIILiteral("Insert"), VK_INSERT); 164 windowsKeyMap().set(ASCIILiteral("Delete"), VK_DELETE); 165 166 windowsKeyMap().set(ASCIILiteral("comma"), VK_OEM_COMMA); 167 windowsKeyMap().set(ASCIILiteral("less"), VK_OEM_COMMA); 168 windowsKeyMap().set(ASCIILiteral("period"), VK_OEM_PERIOD); 169 windowsKeyMap().set(ASCIILiteral("greater"), VK_OEM_PERIOD); 170 windowsKeyMap().set(ASCIILiteral("semicolon"), VK_OEM_1); 171 windowsKeyMap().set(ASCIILiteral("colon"), VK_OEM_1); 172 windowsKeyMap().set(ASCIILiteral("slash"), VK_OEM_2); 173 windowsKeyMap().set(ASCIILiteral("question"), VK_OEM_2); 174 windowsKeyMap().set(ASCIILiteral("grave"), VK_OEM_3); 175 windowsKeyMap().set(ASCIILiteral("asciitilde"), VK_OEM_3); 176 windowsKeyMap().set(ASCIILiteral("bracketleft"), VK_OEM_4); 177 windowsKeyMap().set(ASCIILiteral("braceleft"), VK_OEM_4); 178 windowsKeyMap().set(ASCIILiteral("backslash"), VK_OEM_5); 179 windowsKeyMap().set(ASCIILiteral("bar"), VK_OEM_5); 180 windowsKeyMap().set(ASCIILiteral("bracketright"), VK_OEM_6); 181 windowsKeyMap().set(ASCIILiteral("braceright"), VK_OEM_6); 182 windowsKeyMap().set(ASCIILiteral("apostrophe"), VK_OEM_7); 183 windowsKeyMap().set(ASCIILiteral("quotedbl"), VK_OEM_7); 184 // Keypad location 185 windowsKeyMap().set(ASCIILiteral("KP_Left"), VK_LEFT); 186 windowsKeyMap().set(ASCIILiteral("KP_Right"), VK_RIGHT); 187 windowsKeyMap().set(ASCIILiteral("KP_Up"), VK_UP); 188 windowsKeyMap().set(ASCIILiteral("KP_Down"), VK_DOWN); 189 windowsKeyMap().set(ASCIILiteral("KP_Prior"), VK_PRIOR); 190 windowsKeyMap().set(ASCIILiteral("KP_Next"), VK_NEXT); 191 windowsKeyMap().set(ASCIILiteral("KP_Home"), VK_HOME); 192 windowsKeyMap().set(ASCIILiteral("KP_End"), VK_END); 193 windowsKeyMap().set(ASCIILiteral("KP_Insert"), VK_INSERT); 194 windowsKeyMap().set(ASCIILiteral("KP_Delete"), VK_DELETE); 195 windowsKeyMap().set(ASCIILiteral("KP_Multiply"), VK_MULTIPLY); 196 windowsKeyMap().set(ASCIILiteral("KP_Subtract"), VK_SUBTRACT); 197 windowsKeyMap().set(ASCIILiteral("KP_Decimal"), VK_DECIMAL); 198 windowsKeyMap().set(ASCIILiteral("KP_Devide"), VK_DIVIDE); 199 200 // Set alphabet to the windowsKeyMap. 201 addCharactersToWinKeyMap('a', 'z', VK_A); 202 addCharactersToWinKeyMap('A', 'Z', VK_A); 203 204 // Set digits to the windowsKeyMap. 205 addCharactersToWinKeyMap('0', '9', VK_0); 206 207 // Set digits of keypad to the windowsKeyMap. 208 for (unsigned i = 0; i < 10; ++i) { 209 StringBuilder builder; 210 builder.appendLiteral("KP_"); 211 builder.appendNumber(i); 212 windowsKeyMap().set(builder.toString(), VK_NUMPAD0 + i); 213 } 214 215 // Set shifted digits to the windowsKeyMap. 216 windowsKeyMap().set(ASCIILiteral("exclam"), VK_1); 217 windowsKeyMap().set(ASCIILiteral("at"), VK_2); 218 windowsKeyMap().set(ASCIILiteral("numbersign"), VK_3); 219 windowsKeyMap().set(ASCIILiteral("dollar"), VK_4); 220 windowsKeyMap().set(ASCIILiteral("percent"), VK_5); 221 windowsKeyMap().set(ASCIILiteral("asciicircum"), VK_6); 222 windowsKeyMap().set(ASCIILiteral("ampersand"), VK_7); 223 windowsKeyMap().set(ASCIILiteral("asterisk"), VK_8); 224 windowsKeyMap().set(ASCIILiteral("parenleft"), VK_9); 225 windowsKeyMap().set(ASCIILiteral("parenright"), VK_0); 226 windowsKeyMap().set(ASCIILiteral("minus"), VK_OEM_MINUS); 227 windowsKeyMap().set(ASCIILiteral("underscore"), VK_OEM_MINUS); 228 windowsKeyMap().set(ASCIILiteral("equal"), VK_OEM_PLUS); 229 windowsKeyMap().set(ASCIILiteral("plus"), VK_OEM_PLUS); 230 231 // Set F_XX keys to the windowsKeyMap. 232 for (unsigned int i = 1; i < 25; i++) { 233 StringBuilder builder; 234 builder.append('F'); 235 builder.appendNumber(i); 236 windowsKeyMap().set(builder.toString(), VK_F1 + i - 1); 237 } 238} 239 240static const unsigned CtrlKey = 1 << 0; 241static const unsigned AltKey = 1 << 1; 242static const unsigned ShiftKey = 1 << 2; 243 244struct KeyDownEntry { 245 unsigned virtualKey; 246 unsigned modifiers; 247 const char* name; 248}; 249 250struct KeyPressEntry { 251 unsigned charCode; 252 unsigned modifiers; 253 const char* name; 254}; 255 256static const KeyDownEntry keyDownEntries[] = { 257 { VK_LEFT, 0, "MoveLeft" }, 258 { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" }, 259 { VK_LEFT, CtrlKey, "MoveWordLeft" }, 260 { VK_LEFT, CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection" }, 261 { VK_RIGHT, 0, "MoveRight" }, 262 { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" }, 263 { VK_RIGHT, CtrlKey, "MoveWordRight" }, 264 { VK_RIGHT, CtrlKey | ShiftKey, "MoveWordRightAndModifySelection" }, 265 { VK_UP, 0, "MoveUp" }, 266 { VK_UP, ShiftKey, "MoveUpAndModifySelection" }, 267 { VK_PRIOR, ShiftKey, "MovePageUpAndModifySelection" }, 268 { VK_DOWN, 0, "MoveDown" }, 269 { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" }, 270 { VK_NEXT, ShiftKey, "MovePageDownAndModifySelection" }, 271 { VK_PRIOR, 0, "MovePageUp" }, 272 { VK_NEXT, 0, "MovePageDown" }, 273 { VK_HOME, 0, "MoveToBeginningOfLine" }, 274 { VK_HOME, ShiftKey, "MoveToBeginningOfLineAndModifySelection" }, 275 { VK_HOME, CtrlKey, "MoveToBeginningOfDocument" }, 276 { VK_HOME, CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" }, 277 278 { VK_END, 0, "MoveToEndOfLine" }, 279 { VK_END, ShiftKey, "MoveToEndOfLineAndModifySelection" }, 280 { VK_END, CtrlKey, "MoveToEndOfDocument" }, 281 { VK_END, CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection" }, 282 283 { VK_BACK, 0, "DeleteBackward" }, 284 { VK_BACK, ShiftKey, "DeleteBackward" }, 285 { VK_DELETE, 0, "DeleteForward" }, 286 { VK_BACK, CtrlKey, "DeleteWordBackward" }, 287 { VK_DELETE, CtrlKey, "DeleteWordForward" }, 288 289 { 'B', CtrlKey, "ToggleBold" }, 290 { 'I', CtrlKey, "ToggleItalic" }, 291 292 { VK_ESCAPE, 0, "Cancel" }, 293 { VK_OEM_PERIOD, CtrlKey, "Cancel" }, 294 { VK_TAB, 0, "InsertTab" }, 295 { VK_TAB, ShiftKey, "InsertBacktab" }, 296 { VK_RETURN, 0, "InsertNewline" }, 297 { VK_RETURN, CtrlKey, "InsertNewline" }, 298 { VK_RETURN, AltKey, "InsertNewline" }, 299 { VK_RETURN, AltKey | ShiftKey, "InsertNewline" }, 300 301 { 'C', CtrlKey, "Copy" }, 302 { 'V', CtrlKey, "Paste" }, 303 { 'X', CtrlKey, "Cut" }, 304 305 { 'A', CtrlKey, "SelectAll" }, 306 { 'Z', CtrlKey, "Undo" }, 307 { 'Z', CtrlKey | ShiftKey, "Redo" }, 308 { 'Y', CtrlKey, "Redo" }, 309}; 310 311static const KeyPressEntry keyPressEntries[] = { 312 { '\t', 0, "InsertTab" }, 313 { '\t', ShiftKey, "InsertBacktab" }, 314 { '\r', 0, "InsertNewline" }, 315 { '\r', CtrlKey, "InsertNewline" }, 316 { '\r', AltKey, "InsertNewline" }, 317 { '\r', AltKey | ShiftKey, "InsertNewline" }, 318}; 319 320static void createKeyDownCommandMap() 321{ 322 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyDownEntries); ++i) 323 keyDownCommandsMap().set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name); 324} 325 326static void createKeyPressCommandMap() 327{ 328 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyPressEntries); ++i) 329 keyPressCommandsMap().set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name); 330} 331 332String keyIdentifierForEvasKeyName(const String& keyName) 333{ 334 if (keyMap().isEmpty()) 335 createKeyMap(); 336 337 if (keyMap().contains(keyName)) 338 return keyMap().get(keyName); 339 340 return keyName; 341} 342 343int windowsKeyCodeForEvasKeyName(const String& keyName) 344{ 345 if (windowsKeyMap().isEmpty()) 346 createWindowsKeyMap(); 347 348 if (windowsKeyMap().contains(keyName)) 349 return windowsKeyMap().get(keyName); 350 351 return 0; 352} 353 354const char* getKeyDownCommandName(const KeyboardEvent* event) 355{ 356 unsigned modifiers = 0; 357 if (event->shiftKey()) 358 modifiers |= ShiftKey; 359 if (event->altKey()) 360 modifiers |= AltKey; 361 if (event->ctrlKey()) 362 modifiers |= CtrlKey; 363 364 int mapKey = modifiers << 16 | event->keyCode(); 365 if (!mapKey) 366 return 0; 367 368 if (keyDownCommandsMap().isEmpty()) 369 createKeyDownCommandMap(); 370 371 return keyDownCommandsMap().get(mapKey); 372} 373 374const char* getKeyPressCommandName(const KeyboardEvent* event) 375{ 376 unsigned modifiers = 0; 377 if (event->shiftKey()) 378 modifiers |= ShiftKey; 379 if (event->altKey()) 380 modifiers |= AltKey; 381 if (event->ctrlKey()) 382 modifiers |= CtrlKey; 383 384 int mapKey = modifiers << 16 | event->charCode(); 385 if (!mapKey) 386 return 0; 387 388 if (keyPressCommandsMap().isEmpty()) 389 createKeyPressCommandMap(); 390 391 return keyPressCommandsMap().get(mapKey); 392} 393 394} // namespace WebCore 395