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