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 COMPUTER, 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 COMPUTER, 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/text/StringBuilder.h> 36#include <wtf/text/StringHash.h> 37#include <wtf/text/WTFString.h> 38 39namespace WebCore { 40 41typedef HashMap<String, String> KeyMap; 42typedef HashMap<String, int> WindowsKeyMap; 43typedef HashMap<int, const char*> KeyCommandMap; 44 45static KeyMap& keyMap() 46{ 47 DEFINE_STATIC_LOCAL(KeyMap, keyMap, ()); 48 return keyMap; 49} 50 51static WindowsKeyMap& windowsKeyMap() 52{ 53 DEFINE_STATIC_LOCAL(WindowsKeyMap, windowsKeyMap, ()); 54 return windowsKeyMap; 55} 56 57static KeyCommandMap& keyDownCommandsMap() 58{ 59 DEFINE_STATIC_LOCAL(KeyCommandMap, keyDownCommandsMap, ()); 60 return keyDownCommandsMap; 61} 62 63static KeyCommandMap& keyPressCommandsMap() 64{ 65 DEFINE_STATIC_LOCAL(KeyCommandMap, keyPressCommandsMap, ()); 66 return keyPressCommandsMap; 67} 68 69static inline void addCharactersToKeyMap(const char from, const char to) 70{ 71 for (char c = from; c <= to; c++) { 72 StringBuilder builder; 73 builder.appendLiteral("U+"); 74 appendUnsignedAsHexFixedSize(c, builder, 4, WTF::Uppercase); 75 keyMap().set(String(&c, 1), builder.toString()); 76 } 77} 78 79static void createKeyMap() 80{ 81 for (unsigned int i = 1; i < 25; i++) { 82 StringBuilder builder; 83 builder.append('F'); 84 builder.appendNumber(i); 85 String key = builder.toString(); 86 keyMap().set(key, key); 87 } 88 keyMap().set(ASCIILiteral("Alt_L"), ASCIILiteral("Alt")); 89 keyMap().set(ASCIILiteral("ISO_Level3_Shift"), ASCIILiteral("Alt")); 90 keyMap().set(ASCIILiteral("Menu"), ASCIILiteral("Alt")); 91 keyMap().set(ASCIILiteral("Shift_L"), ASCIILiteral("Shift")); 92 keyMap().set(ASCIILiteral("Shift_R"), ASCIILiteral("Shift")); 93 keyMap().set(ASCIILiteral("Down"), ASCIILiteral("Down")); 94 keyMap().set(ASCIILiteral("End"), ASCIILiteral("End")); 95 keyMap().set(ASCIILiteral("Return"), ASCIILiteral("Enter")); 96 keyMap().set(ASCIILiteral("KP_Enter"), ASCIILiteral("Enter")); 97 keyMap().set(ASCIILiteral("Home"), ASCIILiteral("Home")); 98 keyMap().set(ASCIILiteral("Insert"), ASCIILiteral("Insert")); 99 keyMap().set(ASCIILiteral("Left"), ASCIILiteral("Left")); 100 keyMap().set(ASCIILiteral("Down"), ASCIILiteral("Down")); 101 keyMap().set(ASCIILiteral("Next"), ASCIILiteral("PageDown")); 102 keyMap().set(ASCIILiteral("Prior"), ASCIILiteral("PageUp")); 103 keyMap().set(ASCIILiteral("Right"), ASCIILiteral("Right")); 104 keyMap().set(ASCIILiteral("Up"), ASCIILiteral("Up")); 105 keyMap().set(ASCIILiteral("Delete"), ASCIILiteral("U+007F")); 106 keyMap().set(ASCIILiteral("Tab"), ASCIILiteral("U+0009")); 107 keyMap().set(ASCIILiteral("ISO_Left_Tab"), ASCIILiteral("U+0009")); 108 keyMap().set(ASCIILiteral("BackSpace"), ASCIILiteral("U+0008")); 109 keyMap().set(ASCIILiteral("space"), ASCIILiteral("U+0020")); 110 keyMap().set(ASCIILiteral("Escape"), ASCIILiteral("U+001B")); 111 keyMap().set(ASCIILiteral("Print"), ASCIILiteral("PrintScreen")); 112 // Keypad location 113 keyMap().set(ASCIILiteral("KP_Left"), ASCIILiteral("Left")); 114 keyMap().set(ASCIILiteral("KP_Right"), ASCIILiteral("Right")); 115 keyMap().set(ASCIILiteral("KP_Up"), ASCIILiteral("Up")); 116 keyMap().set(ASCIILiteral("KP_Down"), ASCIILiteral("Down")); 117 keyMap().set(ASCIILiteral("KP_Prior"), ASCIILiteral("PageUp")); 118 keyMap().set(ASCIILiteral("KP_Next"), ASCIILiteral("PageDown")); 119 keyMap().set(ASCIILiteral("KP_Home"), ASCIILiteral("Home")); 120 keyMap().set(ASCIILiteral("KP_End"), ASCIILiteral("End")); 121 keyMap().set(ASCIILiteral("KP_Insert"), ASCIILiteral("Insert")); 122 keyMap().set(ASCIILiteral("KP_Delete"), ASCIILiteral("U+007F")); 123 124 addCharactersToKeyMap('a', 'z'); 125 addCharactersToKeyMap('A', 'Z'); 126 addCharactersToKeyMap('0', '9'); 127} 128 129static inline void addCharactersToWinKeyMap(const char from, const char to, const int baseCode) 130{ 131 int i = 0; 132 for (char c = from; c <= to; c++, i++) 133 windowsKeyMap().set(String(&c, 1), baseCode + i); 134} 135 136static void createWindowsKeyMap() 137{ 138 windowsKeyMap().set(ASCIILiteral("Return"), VK_RETURN); 139 windowsKeyMap().set(ASCIILiteral("KP_Return"), VK_RETURN); 140 windowsKeyMap().set(ASCIILiteral("Alt_L"), VK_LMENU); 141 windowsKeyMap().set(ASCIILiteral("Alt_R"), VK_RMENU); 142 windowsKeyMap().set(ASCIILiteral("ISO_Level3_Shift"), VK_MENU); 143 windowsKeyMap().set(ASCIILiteral("Menu"), VK_MENU); 144 windowsKeyMap().set(ASCIILiteral("Shift_L"), VK_LSHIFT); 145 windowsKeyMap().set(ASCIILiteral("Shift_R"), VK_RSHIFT); 146 windowsKeyMap().set(ASCIILiteral("Control_L"), VK_LCONTROL); 147 windowsKeyMap().set(ASCIILiteral("Control_R"), VK_RCONTROL); 148 windowsKeyMap().set(ASCIILiteral("Pause"), VK_PAUSE); 149 windowsKeyMap().set(ASCIILiteral("Break"), VK_PAUSE); 150 windowsKeyMap().set(ASCIILiteral("Caps_Lock"), VK_CAPITAL); 151 windowsKeyMap().set(ASCIILiteral("Scroll_Lock"), VK_SCROLL); 152 windowsKeyMap().set(ASCIILiteral("Num_Lock"), VK_NUMLOCK); 153 windowsKeyMap().set(ASCIILiteral("Escape"), VK_ESCAPE); 154 windowsKeyMap().set(ASCIILiteral("Tab"), VK_TAB); 155 windowsKeyMap().set(ASCIILiteral("ISO_Left_Tab"), VK_TAB); 156 windowsKeyMap().set(ASCIILiteral("BackSpace"), VK_BACK); 157 windowsKeyMap().set(ASCIILiteral("space"), VK_SPACE); 158 windowsKeyMap().set(ASCIILiteral("Next"), VK_NEXT); 159 windowsKeyMap().set(ASCIILiteral("Prior"), VK_PRIOR); 160 windowsKeyMap().set(ASCIILiteral("Home"), VK_HOME); 161 windowsKeyMap().set(ASCIILiteral("End"), VK_END); 162 windowsKeyMap().set(ASCIILiteral("Right"), VK_RIGHT); 163 windowsKeyMap().set(ASCIILiteral("Left"), VK_LEFT); 164 windowsKeyMap().set(ASCIILiteral("Up"), VK_UP); 165 windowsKeyMap().set(ASCIILiteral("Down"), VK_DOWN); 166 windowsKeyMap().set(ASCIILiteral("Print"), VK_SNAPSHOT); 167 windowsKeyMap().set(ASCIILiteral("Insert"), VK_INSERT); 168 windowsKeyMap().set(ASCIILiteral("Delete"), VK_DELETE); 169 170 windowsKeyMap().set(ASCIILiteral("comma"), VK_OEM_COMMA); 171 windowsKeyMap().set(ASCIILiteral("less"), VK_OEM_COMMA); 172 windowsKeyMap().set(ASCIILiteral("period"), VK_OEM_PERIOD); 173 windowsKeyMap().set(ASCIILiteral("greater"), VK_OEM_PERIOD); 174 windowsKeyMap().set(ASCIILiteral("semicolon"), VK_OEM_1); 175 windowsKeyMap().set(ASCIILiteral("colon"), VK_OEM_1); 176 windowsKeyMap().set(ASCIILiteral("slash"), VK_OEM_2); 177 windowsKeyMap().set(ASCIILiteral("question"), VK_OEM_2); 178 windowsKeyMap().set(ASCIILiteral("grave"), VK_OEM_3); 179 windowsKeyMap().set(ASCIILiteral("asciitilde"), VK_OEM_3); 180 windowsKeyMap().set(ASCIILiteral("bracketleft"), VK_OEM_4); 181 windowsKeyMap().set(ASCIILiteral("braceleft"), VK_OEM_4); 182 windowsKeyMap().set(ASCIILiteral("backslash"), VK_OEM_5); 183 windowsKeyMap().set(ASCIILiteral("bar"), VK_OEM_5); 184 windowsKeyMap().set(ASCIILiteral("bracketright"), VK_OEM_6); 185 windowsKeyMap().set(ASCIILiteral("braceright"), VK_OEM_6); 186 windowsKeyMap().set(ASCIILiteral("apostrophe"), VK_OEM_7); 187 windowsKeyMap().set(ASCIILiteral("quotedbl"), VK_OEM_7); 188 // Keypad location 189 windowsKeyMap().set(ASCIILiteral("KP_Left"), VK_LEFT); 190 windowsKeyMap().set(ASCIILiteral("KP_Right"), VK_RIGHT); 191 windowsKeyMap().set(ASCIILiteral("KP_Up"), VK_UP); 192 windowsKeyMap().set(ASCIILiteral("KP_Down"), VK_DOWN); 193 windowsKeyMap().set(ASCIILiteral("KP_Prior"), VK_PRIOR); 194 windowsKeyMap().set(ASCIILiteral("KP_Next"), VK_NEXT); 195 windowsKeyMap().set(ASCIILiteral("KP_Home"), VK_HOME); 196 windowsKeyMap().set(ASCIILiteral("KP_End"), VK_END); 197 windowsKeyMap().set(ASCIILiteral("KP_Insert"), VK_INSERT); 198 windowsKeyMap().set(ASCIILiteral("KP_Delete"), VK_DELETE); 199 windowsKeyMap().set(ASCIILiteral("KP_Multiply"), VK_MULTIPLY); 200 windowsKeyMap().set(ASCIILiteral("KP_Subtract"), VK_SUBTRACT); 201 windowsKeyMap().set(ASCIILiteral("KP_Decimal"), VK_DECIMAL); 202 windowsKeyMap().set(ASCIILiteral("KP_Devide"), VK_DIVIDE); 203 204 // Set alphabet to the windowsKeyMap. 205 addCharactersToWinKeyMap('a', 'z', VK_A); 206 addCharactersToWinKeyMap('A', 'Z', VK_A); 207 208 // Set digits to the windowsKeyMap. 209 addCharactersToWinKeyMap('0', '9', VK_0); 210 211 // Set digits of keypad to the windowsKeyMap. 212 for (unsigned i = 0; i < 10; ++i) { 213 StringBuilder builder; 214 builder.appendLiteral("KP_"); 215 builder.appendNumber(i); 216 windowsKeyMap().set(builder.toString(), VK_NUMPAD0 + i); 217 } 218 219 // Set shifted digits to the windowsKeyMap. 220 windowsKeyMap().set(ASCIILiteral("exclam"), VK_1); 221 windowsKeyMap().set(ASCIILiteral("at"), VK_2); 222 windowsKeyMap().set(ASCIILiteral("numbersign"), VK_3); 223 windowsKeyMap().set(ASCIILiteral("dollar"), VK_4); 224 windowsKeyMap().set(ASCIILiteral("percent"), VK_5); 225 windowsKeyMap().set(ASCIILiteral("asciicircum"), VK_6); 226 windowsKeyMap().set(ASCIILiteral("ampersand"), VK_7); 227 windowsKeyMap().set(ASCIILiteral("asterisk"), VK_8); 228 windowsKeyMap().set(ASCIILiteral("parenleft"), VK_9); 229 windowsKeyMap().set(ASCIILiteral("parenright"), VK_0); 230 windowsKeyMap().set(ASCIILiteral("minus"), VK_OEM_MINUS); 231 windowsKeyMap().set(ASCIILiteral("underscore"), VK_OEM_MINUS); 232 windowsKeyMap().set(ASCIILiteral("equal"), VK_OEM_PLUS); 233 windowsKeyMap().set(ASCIILiteral("plus"), VK_OEM_PLUS); 234 235 // Set F_XX keys to the windowsKeyMap. 236 for (unsigned int i = 1; i < 25; i++) { 237 StringBuilder builder; 238 builder.append('F'); 239 builder.appendNumber(i); 240 windowsKeyMap().set(builder.toString(), VK_F1 + i - 1); 241 } 242} 243 244static const unsigned CtrlKey = 1 << 0; 245static const unsigned AltKey = 1 << 1; 246static const unsigned ShiftKey = 1 << 2; 247 248struct KeyDownEntry { 249 unsigned virtualKey; 250 unsigned modifiers; 251 const char* name; 252}; 253 254struct KeyPressEntry { 255 unsigned charCode; 256 unsigned modifiers; 257 const char* name; 258}; 259 260static const KeyDownEntry keyDownEntries[] = { 261 { VK_LEFT, 0, "MoveLeft" }, 262 { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" }, 263 { VK_LEFT, CtrlKey, "MoveWordLeft" }, 264 { VK_LEFT, CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection" }, 265 { VK_RIGHT, 0, "MoveRight" }, 266 { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" }, 267 { VK_RIGHT, CtrlKey, "MoveWordRight" }, 268 { VK_RIGHT, CtrlKey | ShiftKey, "MoveWordRightAndModifySelection" }, 269 { VK_UP, 0, "MoveUp" }, 270 { VK_UP, ShiftKey, "MoveUpAndModifySelection" }, 271 { VK_PRIOR, ShiftKey, "MovePageUpAndModifySelection" }, 272 { VK_DOWN, 0, "MoveDown" }, 273 { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" }, 274 { VK_NEXT, ShiftKey, "MovePageDownAndModifySelection" }, 275 { VK_PRIOR, 0, "MovePageUp" }, 276 { VK_NEXT, 0, "MovePageDown" }, 277 { VK_HOME, 0, "MoveToBeginningOfLine" }, 278 { VK_HOME, ShiftKey, "MoveToBeginningOfLineAndModifySelection" }, 279 { VK_HOME, CtrlKey, "MoveToBeginningOfDocument" }, 280 { VK_HOME, CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" }, 281 282 { VK_END, 0, "MoveToEndOfLine" }, 283 { VK_END, ShiftKey, "MoveToEndOfLineAndModifySelection" }, 284 { VK_END, CtrlKey, "MoveToEndOfDocument" }, 285 { VK_END, CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection" }, 286 287 { VK_BACK, 0, "DeleteBackward" }, 288 { VK_BACK, ShiftKey, "DeleteBackward" }, 289 { VK_DELETE, 0, "DeleteForward" }, 290 { VK_BACK, CtrlKey, "DeleteWordBackward" }, 291 { VK_DELETE, CtrlKey, "DeleteWordForward" }, 292 293 { 'B', CtrlKey, "ToggleBold" }, 294 { 'I', CtrlKey, "ToggleItalic" }, 295 296 { VK_ESCAPE, 0, "Cancel" }, 297 { VK_OEM_PERIOD, CtrlKey, "Cancel" }, 298 { VK_TAB, 0, "InsertTab" }, 299 { VK_TAB, ShiftKey, "InsertBacktab" }, 300 { VK_RETURN, 0, "InsertNewline" }, 301 { VK_RETURN, CtrlKey, "InsertNewline" }, 302 { VK_RETURN, AltKey, "InsertNewline" }, 303 { VK_RETURN, AltKey | ShiftKey, "InsertNewline" }, 304}; 305 306static const KeyPressEntry keyPressEntries[] = { 307 { '\t', 0, "InsertTab" }, 308 { '\t', ShiftKey, "InsertBacktab" }, 309 { '\r', 0, "InsertNewline" }, 310 { '\r', CtrlKey, "InsertNewline" }, 311 { '\r', AltKey, "InsertNewline" }, 312 { '\r', AltKey | ShiftKey, "InsertNewline" }, 313}; 314 315static void createKeyDownCommandMap() 316{ 317 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyDownEntries); ++i) 318 keyDownCommandsMap().set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name); 319} 320 321static void createKeyPressCommandMap() 322{ 323 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyPressEntries); ++i) 324 keyPressCommandsMap().set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name); 325} 326 327String keyIdentifierForEvasKeyName(const String& keyName) 328{ 329 if (keyMap().isEmpty()) 330 createKeyMap(); 331 332 if (keyMap().contains(keyName)) 333 return keyMap().get(keyName); 334 335 return keyName; 336} 337 338int windowsKeyCodeForEvasKeyName(const String& keyName) 339{ 340 if (windowsKeyMap().isEmpty()) 341 createWindowsKeyMap(); 342 343 if (windowsKeyMap().contains(keyName)) 344 return windowsKeyMap().get(keyName); 345 346 return 0; 347} 348 349const char* getKeyDownCommandName(const KeyboardEvent* event) 350{ 351 unsigned modifiers = 0; 352 if (event->shiftKey()) 353 modifiers |= ShiftKey; 354 if (event->altKey()) 355 modifiers |= AltKey; 356 if (event->ctrlKey()) 357 modifiers |= CtrlKey; 358 359 int mapKey = modifiers << 16 | event->keyCode(); 360 if (!mapKey) 361 return 0; 362 363 if (keyDownCommandsMap().isEmpty()) 364 createKeyDownCommandMap(); 365 366 return keyDownCommandsMap().get(mapKey); 367} 368 369const char* getKeyPressCommandName(const KeyboardEvent* event) 370{ 371 unsigned modifiers = 0; 372 if (event->shiftKey()) 373 modifiers |= ShiftKey; 374 if (event->altKey()) 375 modifiers |= AltKey; 376 if (event->ctrlKey()) 377 modifiers |= CtrlKey; 378 379 int mapKey = modifiers << 16 | event->charCode(); 380 if (!mapKey) 381 return 0; 382 383 if (keyPressCommandsMap().isEmpty()) 384 createKeyPressCommandMap(); 385 386 return keyPressCommandsMap().get(mapKey); 387} 388 389} // namespace WebCore 390