1/*
2 * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2006-2009 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "public/web/mac/WebInputEventFactory.h"
29
30#include <ApplicationServices/ApplicationServices.h>
31#import <AvailabilityMacros.h>
32#import <Cocoa/Cocoa.h>
33
34#include "platform/WindowsKeyboardCodes.h"
35#include "public/web/WebInputEvent.h"
36#include "wtf/ASCIICType.h"
37
38#if __MAC_OS_X_VERSION_MAX_ALLOWED == 1060
39
40// Additional Lion APIs.
41enum {
42    NSEventPhaseNone        = 0,
43    NSEventPhaseBegan       = 0x1 << 0,
44    NSEventPhaseStationary  = 0x1 << 1,
45    NSEventPhaseChanged     = 0x1 << 2,
46    NSEventPhaseEnded       = 0x1 << 3,
47    NSEventPhaseCancelled   = 0x1 << 4
48};
49typedef NSUInteger NSEventPhase;
50
51@interface NSEvent (LionSDKDeclarations)
52- (NSEventPhase)phase;
53- (NSEventPhase)momentumPhase;
54@end
55
56#endif  // __MAC_OS_X_VERSION_MAX_ALLOWED == 1060
57
58#if __MAC_OS_X_VERSION_MAX_ALLOWED < 1080
59
60// Additional Mountain Lion APIs.
61enum {
62    NSEventPhaseMayBegin    = 0x1 << 5
63};
64
65#endif  // __MAC_OS_X_VERSION_MAX_ALLOWED < 1080
66
67namespace blink {
68
69static int windowsKeyCodeForKeyCode(uint16_t keyCode)
70{
71    static const int windowsKeyCode[] = {
72        /* 0 */ VK_A,
73        /* 1 */ VK_S,
74        /* 2 */ VK_D,
75        /* 3 */ VK_F,
76        /* 4 */ VK_H,
77        /* 5 */ VK_G,
78        /* 6 */ VK_Z,
79        /* 7 */ VK_X,
80        /* 8 */ VK_C,
81        /* 9 */ VK_V,
82        /* 0x0A */ VK_OEM_3, // "Section" - key to the left from 1 (ISO Keyboard Only)
83        /* 0x0B */ VK_B,
84        /* 0x0C */ VK_Q,
85        /* 0x0D */ VK_W,
86        /* 0x0E */ VK_E,
87        /* 0x0F */ VK_R,
88        /* 0x10 */ VK_Y,
89        /* 0x11 */ VK_T,
90        /* 0x12 */ VK_1,
91        /* 0x13 */ VK_2,
92        /* 0x14 */ VK_3,
93        /* 0x15 */ VK_4,
94        /* 0x16 */ VK_6,
95        /* 0x17 */ VK_5,
96        /* 0x18 */ VK_OEM_PLUS, // =+
97        /* 0x19 */ VK_9,
98        /* 0x1A */ VK_7,
99        /* 0x1B */ VK_OEM_MINUS, // -_
100        /* 0x1C */ VK_8,
101        /* 0x1D */ VK_0,
102        /* 0x1E */ VK_OEM_6, // ]}
103        /* 0x1F */ VK_O,
104        /* 0x20 */ VK_U,
105        /* 0x21 */ VK_OEM_4, // {[
106        /* 0x22 */ VK_I,
107        /* 0x23 */ VK_P,
108        /* 0x24 */ VK_RETURN, // Return
109        /* 0x25 */ VK_L,
110        /* 0x26 */ VK_J,
111        /* 0x27 */ VK_OEM_7, // '"
112        /* 0x28 */ VK_K,
113        /* 0x29 */ VK_OEM_1, // ;:
114        /* 0x2A */ VK_OEM_5, // \|
115        /* 0x2B */ VK_OEM_COMMA, // ,<
116        /* 0x2C */ VK_OEM_2, // /?
117        /* 0x2D */ VK_N,
118        /* 0x2E */ VK_M,
119        /* 0x2F */ VK_OEM_PERIOD, // .>
120        /* 0x30 */ VK_TAB,
121        /* 0x31 */ VK_SPACE,
122        /* 0x32 */ VK_OEM_3, // `~
123        /* 0x33 */ VK_BACK, // Backspace
124        /* 0x34 */ 0, // n/a
125        /* 0x35 */ VK_ESCAPE,
126        /* 0x36 */ VK_APPS, // Right Command
127        /* 0x37 */ VK_LWIN, // Left Command
128        /* 0x38 */ VK_LSHIFT, // Left Shift
129        /* 0x39 */ VK_CAPITAL, // Caps Lock
130        /* 0x3A */ VK_LMENU, // Left Option
131        /* 0x3B */ VK_LCONTROL, // Left Ctrl
132        /* 0x3C */ VK_RSHIFT, // Right Shift
133        /* 0x3D */ VK_RMENU, // Right Option
134        /* 0x3E */ VK_RCONTROL, // Right Ctrl
135        /* 0x3F */ 0, // fn
136        /* 0x40 */ VK_F17,
137        /* 0x41 */ VK_DECIMAL, // Num Pad .
138        /* 0x42 */ 0, // n/a
139        /* 0x43 */ VK_MULTIPLY, // Num Pad *
140        /* 0x44 */ 0, // n/a
141        /* 0x45 */ VK_ADD, // Num Pad +
142        /* 0x46 */ 0, // n/a
143        /* 0x47 */ VK_CLEAR, // Num Pad Clear
144        /* 0x48 */ VK_VOLUME_UP,
145        /* 0x49 */ VK_VOLUME_DOWN,
146        /* 0x4A */ VK_VOLUME_MUTE,
147        /* 0x4B */ VK_DIVIDE, // Num Pad /
148        /* 0x4C */ VK_RETURN, // Num Pad Enter
149        /* 0x4D */ 0, // n/a
150        /* 0x4E */ VK_SUBTRACT, // Num Pad -
151        /* 0x4F */ VK_F18,
152        /* 0x50 */ VK_F19,
153        /* 0x51 */ VK_OEM_PLUS, // Num Pad =. There is no such key on common PC keyboards, mapping to normal "+=".
154        /* 0x52 */ VK_NUMPAD0,
155        /* 0x53 */ VK_NUMPAD1,
156        /* 0x54 */ VK_NUMPAD2,
157        /* 0x55 */ VK_NUMPAD3,
158        /* 0x56 */ VK_NUMPAD4,
159        /* 0x57 */ VK_NUMPAD5,
160        /* 0x58 */ VK_NUMPAD6,
161        /* 0x59 */ VK_NUMPAD7,
162        /* 0x5A */ VK_F20,
163        /* 0x5B */ VK_NUMPAD8,
164        /* 0x5C */ VK_NUMPAD9,
165        /* 0x5D */ 0, // Yen (JIS Keyboard Only)
166        /* 0x5E */ 0, // Underscore (JIS Keyboard Only)
167        /* 0x5F */ 0, // KeypadComma (JIS Keyboard Only)
168        /* 0x60 */ VK_F5,
169        /* 0x61 */ VK_F6,
170        /* 0x62 */ VK_F7,
171        /* 0x63 */ VK_F3,
172        /* 0x64 */ VK_F8,
173        /* 0x65 */ VK_F9,
174        /* 0x66 */ 0, // Eisu (JIS Keyboard Only)
175        /* 0x67 */ VK_F11,
176        /* 0x68 */ 0, // Kana (JIS Keyboard Only)
177        /* 0x69 */ VK_F13,
178        /* 0x6A */ VK_F16,
179        /* 0x6B */ VK_F14,
180        /* 0x6C */ 0, // n/a
181        /* 0x6D */ VK_F10,
182        /* 0x6E */ 0, // n/a (Windows95 key?)
183        /* 0x6F */ VK_F12,
184        /* 0x70 */ 0, // n/a
185        /* 0x71 */ VK_F15,
186        /* 0x72 */ VK_INSERT, // Help
187        /* 0x73 */ VK_HOME, // Home
188        /* 0x74 */ VK_PRIOR, // Page Up
189        /* 0x75 */ VK_DELETE, // Forward Delete
190        /* 0x76 */ VK_F4,
191        /* 0x77 */ VK_END, // End
192        /* 0x78 */ VK_F2,
193        /* 0x79 */ VK_NEXT, // Page Down
194        /* 0x7A */ VK_F1,
195        /* 0x7B */ VK_LEFT, // Left Arrow
196        /* 0x7C */ VK_RIGHT, // Right Arrow
197        /* 0x7D */ VK_DOWN, // Down Arrow
198        /* 0x7E */ VK_UP, // Up Arrow
199        /* 0x7F */ 0 // n/a
200    };
201
202    if (keyCode >= 0x80)
203        return 0;
204
205     return windowsKeyCode[keyCode];
206}
207
208static int windowsKeyCodeForCharCode(unichar charCode)
209{
210    switch (charCode) {
211
212        case 'a': case 'A': return VK_A;
213        case 'b': case 'B': return VK_B;
214        case 'c': case 'C': return VK_C;
215        case 'd': case 'D': return VK_D;
216        case 'e': case 'E': return VK_E;
217        case 'f': case 'F': return VK_F;
218        case 'g': case 'G': return VK_G;
219        case 'h': case 'H': return VK_H;
220        case 'i': case 'I': return VK_I;
221        case 'j': case 'J': return VK_J;
222        case 'k': case 'K': return VK_K;
223        case 'l': case 'L': return VK_L;
224        case 'm': case 'M': return VK_M;
225        case 'n': case 'N': return VK_N;
226        case 'o': case 'O': return VK_O;
227        case 'p': case 'P': return VK_P;
228        case 'q': case 'Q': return VK_Q;
229        case 'r': case 'R': return VK_R;
230        case 's': case 'S': return VK_S;
231        case 't': case 'T': return VK_T;
232        case 'u': case 'U': return VK_U;
233        case 'v': case 'V': return VK_V;
234        case 'w': case 'W': return VK_W;
235        case 'x': case 'X': return VK_X;
236        case 'y': case 'Y': return VK_Y;
237        case 'z': case 'Z': return VK_Z;
238
239        // AppKit generates Unicode PUA character codes for some function keys; using these when key code is not known.
240        case NSPauseFunctionKey: return VK_PAUSE;
241        case NSSelectFunctionKey: return VK_SELECT;
242        case NSPrintFunctionKey: return VK_PRINT;
243        case NSExecuteFunctionKey: return VK_EXECUTE;
244        case NSPrintScreenFunctionKey: return VK_SNAPSHOT;
245        case NSInsertFunctionKey: return VK_INSERT;
246
247        case NSF21FunctionKey: return VK_F21;
248        case NSF22FunctionKey: return VK_F22;
249        case NSF23FunctionKey: return VK_F23;
250        case NSF24FunctionKey: return VK_F24;
251        case NSScrollLockFunctionKey: return VK_SCROLL;
252
253        // This is for U.S. keyboard mapping, and doesn't necessarily make sense for different keyboard layouts.
254        // For example, '"' on Windows Russian layout is VK_2, not VK_OEM_7.
255        case ';': case ':': return VK_OEM_1;
256        case '=': case '+': return VK_OEM_PLUS;
257        case ',': case '<': return VK_OEM_COMMA;
258        case '-': case '_': return VK_OEM_MINUS;
259        case '.': case '>': return VK_OEM_PERIOD;
260        case '/': case '?': return VK_OEM_2;
261        case '`': case '~': return VK_OEM_3;
262        case '[': case '{': return VK_OEM_4;
263        case '\\': case '|': return VK_OEM_5;
264        case ']': case '}': return VK_OEM_6;
265        case '\'': case '"': return VK_OEM_7;
266
267    }
268
269    return 0;
270}
271
272static inline bool isKeyUpEvent(NSEvent* event)
273{
274    if ([event type] != NSFlagsChanged)
275        return [event type] == NSKeyUp;
276    // FIXME: This logic fails if the user presses both Shift keys at once, for example:
277    // we treat releasing one of them as keyDown.
278    switch ([event keyCode]) {
279    case 54: // Right Command
280    case 55: // Left Command
281        return ([event modifierFlags] & NSCommandKeyMask) == 0;
282
283    case 57: // Capslock
284        return ([event modifierFlags] & NSAlphaShiftKeyMask) == 0;
285
286    case 56: // Left Shift
287    case 60: // Right Shift
288        return ([event modifierFlags] & NSShiftKeyMask) == 0;
289
290    case 58: // Left Alt
291    case 61: // Right Alt
292        return ([event modifierFlags] & NSAlternateKeyMask) == 0;
293
294    case 59: // Left Ctrl
295    case 62: // Right Ctrl
296        return ([event modifierFlags] & NSControlKeyMask) == 0;
297
298    case 63: // Function
299        return ([event modifierFlags] & NSFunctionKeyMask) == 0;
300    }
301    return false;
302}
303
304static bool isKeypadEvent(NSEvent* event)
305{
306    // Check that this is the type of event that has a keyCode.
307    switch ([event type]) {
308    case NSKeyDown:
309    case NSKeyUp:
310    case NSFlagsChanged:
311        break;
312    default:
313        return false;
314    }
315
316    switch ([event keyCode]) {
317    case 71: // Clear
318    case 81: // =
319    case 75: // /
320    case 67: // *
321    case 78: // -
322    case 69: // +
323    case 76: // Enter
324    case 65: // .
325    case 82: // 0
326    case 83: // 1
327    case 84: // 2
328    case 85: // 3
329    case 86: // 4
330    case 87: // 5
331    case 88: // 6
332    case 89: // 7
333    case 91: // 8
334    case 92: // 9
335        return true;
336    }
337
338    return false;
339}
340
341static int windowsKeyCodeForKeyEvent(NSEvent* event)
342{
343    int code = 0;
344    // There are several kinds of characters for which we produce key code from char code:
345    // 1. Roman letters. Windows keyboard layouts affect both virtual key codes and character codes for these,
346    //    so e.g. 'A' gets the same keyCode on QWERTY, AZERTY or Dvorak layouts.
347    // 2. Keys for which there is no known Mac virtual key codes, like PrintScreen.
348    // 3. Certain punctuation keys. On Windows, these are also remapped depending on current keyboard layout,
349    //    but see comment in windowsKeyCodeForCharCode().
350    if (!isKeypadEvent(event) && ([event type] == NSKeyDown || [event type] == NSKeyUp)) {
351        // Cmd switches Roman letters for Dvorak-QWERTY layout, so try modified characters first.
352        NSString* s = [event characters];
353        code = [s length] > 0 ? windowsKeyCodeForCharCode([s characterAtIndex:0]) : 0;
354        if (code)
355            return code;
356
357        // Ctrl+A on an AZERTY keyboard would get VK_Q keyCode if we relied on -[NSEvent keyCode] below.
358        s = [event charactersIgnoringModifiers];
359        code = [s length] > 0 ? windowsKeyCodeForCharCode([s characterAtIndex:0]) : 0;
360        if (code)
361            return code;
362    }
363
364    // Map Mac virtual key code directly to Windows one for any keys not handled above.
365    // E.g. the key next to Caps Lock has the same Event.keyCode on U.S. keyboard ('A') and on Russian keyboard (CYRILLIC LETTER EF).
366    return windowsKeyCodeForKeyCode([event keyCode]);
367}
368
369static inline NSString* textFromEvent(NSEvent* event)
370{
371    if ([event type] == NSFlagsChanged)
372        return @"";
373    return [event characters];
374}
375
376static inline NSString* unmodifiedTextFromEvent(NSEvent* event)
377{
378    if ([event type] == NSFlagsChanged)
379        return @"";
380    return [event charactersIgnoringModifiers];
381}
382
383static NSString* keyIdentifierForKeyEvent(NSEvent* event)
384{
385    if ([event type] == NSFlagsChanged) {
386        switch ([event keyCode]) {
387        case 54: // Right Command
388        case 55: // Left Command
389            return @"Meta";
390
391        case 57: // Capslock
392            return @"CapsLock";
393
394        case 56: // Left Shift
395        case 60: // Right Shift
396            return @"Shift";
397
398        case 58: // Left Alt
399        case 61: // Right Alt
400            return @"Alt";
401
402        case 59: // Left Ctrl
403        case 62: // Right Ctrl
404            return @"Control";
405
406// Begin non-Apple addition/modification --------------------------------------
407        case 63: // Function
408            return @"Function";
409
410        default: // Unknown, but this may be a strange/new keyboard.
411            return @"Unidentified";
412// End non-Apple addition/modification ----------------------------------------
413        }
414    }
415
416    NSString* s = [event charactersIgnoringModifiers];
417    if ([s length] != 1)
418        return @"Unidentified";
419
420    unichar c = [s characterAtIndex:0];
421    switch (c) {
422    // Each identifier listed in the DOM spec is listed here.
423    // Many are simply commented out since they do not appear on standard Macintosh keyboards
424    // or are on a key that doesn't have a corresponding character.
425
426    // "Accept"
427    // "AllCandidates"
428
429    // "Alt"
430    case NSMenuFunctionKey:
431        return @"Alt";
432
433    // "Apps"
434    // "BrowserBack"
435    // "BrowserForward"
436    // "BrowserHome"
437    // "BrowserRefresh"
438    // "BrowserSearch"
439    // "BrowserStop"
440    // "CapsLock"
441
442    // "Clear"
443    case NSClearLineFunctionKey:
444        return @"Clear";
445
446    // "CodeInput"
447    // "Compose"
448    // "Control"
449    // "Crsel"
450    // "Convert"
451    // "Copy"
452    // "Cut"
453
454    // "Down"
455    case NSDownArrowFunctionKey:
456        return @"Down";
457    // "End"
458    case NSEndFunctionKey:
459        return @"End";
460    // "Enter"
461    case 0x3: case 0xA: case 0xD: // Macintosh calls the one on the main keyboard Return, but Windows calls it Enter, so we'll do the same for the DOM
462        return @"Enter";
463
464    // "EraseEof"
465
466    // "Execute"
467    case NSExecuteFunctionKey:
468        return @"Execute";
469
470    // "Exsel"
471
472    // "F1"
473    case NSF1FunctionKey:
474        return @"F1";
475    // "F2"
476    case NSF2FunctionKey:
477        return @"F2";
478    // "F3"
479    case NSF3FunctionKey:
480        return @"F3";
481    // "F4"
482    case NSF4FunctionKey:
483        return @"F4";
484    // "F5"
485    case NSF5FunctionKey:
486        return @"F5";
487    // "F6"
488    case NSF6FunctionKey:
489        return @"F6";
490    // "F7"
491    case NSF7FunctionKey:
492        return @"F7";
493    // "F8"
494    case NSF8FunctionKey:
495        return @"F8";
496    // "F9"
497    case NSF9FunctionKey:
498        return @"F9";
499    // "F10"
500    case NSF10FunctionKey:
501        return @"F10";
502    // "F11"
503    case NSF11FunctionKey:
504        return @"F11";
505    // "F12"
506    case NSF12FunctionKey:
507        return @"F12";
508    // "F13"
509    case NSF13FunctionKey:
510        return @"F13";
511    // "F14"
512    case NSF14FunctionKey:
513        return @"F14";
514    // "F15"
515    case NSF15FunctionKey:
516        return @"F15";
517    // "F16"
518    case NSF16FunctionKey:
519        return @"F16";
520    // "F17"
521    case NSF17FunctionKey:
522        return @"F17";
523    // "F18"
524    case NSF18FunctionKey:
525        return @"F18";
526    // "F19"
527    case NSF19FunctionKey:
528        return @"F19";
529    // "F20"
530    case NSF20FunctionKey:
531        return @"F20";
532    // "F21"
533    case NSF21FunctionKey:
534        return @"F21";
535    // "F22"
536    case NSF22FunctionKey:
537        return @"F22";
538    // "F23"
539    case NSF23FunctionKey:
540        return @"F23";
541    // "F24"
542    case NSF24FunctionKey:
543        return @"F24";
544
545    // "FinalMode"
546
547    // "Find"
548    case NSFindFunctionKey:
549        return @"Find";
550
551    // "FullWidth"
552    // "HalfWidth"
553    // "HangulMode"
554    // "HanjaMode"
555
556    // "Help"
557    case NSHelpFunctionKey:
558        return @"Help";
559
560    // "Hiragana"
561
562    // "Home"
563    case NSHomeFunctionKey:
564        return @"Home";
565    // "Insert"
566    case NSInsertFunctionKey:
567        return @"Insert";
568
569    // "JapaneseHiragana"
570    // "JapaneseKatakana"
571    // "JapaneseRomaji"
572    // "JunjaMode"
573    // "KanaMode"
574    // "KanjiMode"
575    // "Katakana"
576    // "LaunchApplication1"
577    // "LaunchApplication2"
578    // "LaunchMail"
579
580    // "Left"
581    case NSLeftArrowFunctionKey:
582        return @"Left";
583
584    // "Meta"
585    // "MediaNextTrack"
586    // "MediaPlayPause"
587    // "MediaPreviousTrack"
588    // "MediaStop"
589
590    // "ModeChange"
591    case NSModeSwitchFunctionKey:
592        return @"ModeChange";
593
594    // "Nonconvert"
595    // "NumLock"
596
597    // "PageDown"
598    case NSPageDownFunctionKey:
599        return @"PageDown";
600    // "PageUp"
601    case NSPageUpFunctionKey:
602        return @"PageUp";
603
604    // "Paste"
605
606    // "Pause"
607    case NSPauseFunctionKey:
608        return @"Pause";
609
610    // "Play"
611    // "PreviousCandidate"
612
613    // "PrintScreen"
614    case NSPrintScreenFunctionKey:
615        return @"PrintScreen";
616
617    // "Process"
618    // "Props"
619
620    // "Right"
621    case NSRightArrowFunctionKey:
622        return @"Right";
623
624    // "RomanCharacters"
625
626    // "Scroll"
627    case NSScrollLockFunctionKey:
628        return @"Scroll";
629    // "Select"
630    case NSSelectFunctionKey:
631        return @"Select";
632
633    // "SelectMedia"
634    // "Shift"
635
636    // "Stop"
637    case NSStopFunctionKey:
638        return @"Stop";
639    // "Up"
640    case NSUpArrowFunctionKey:
641        return @"Up";
642    // "Undo"
643    case NSUndoFunctionKey:
644        return @"Undo";
645
646    // "VolumeDown"
647    // "VolumeMute"
648    // "VolumeUp"
649    // "Win"
650    // "Zoom"
651
652    // More function keys, not in the key identifier specification.
653    case NSF25FunctionKey:
654        return @"F25";
655    case NSF26FunctionKey:
656        return @"F26";
657    case NSF27FunctionKey:
658        return @"F27";
659    case NSF28FunctionKey:
660        return @"F28";
661    case NSF29FunctionKey:
662        return @"F29";
663    case NSF30FunctionKey:
664        return @"F30";
665    case NSF31FunctionKey:
666        return @"F31";
667    case NSF32FunctionKey:
668        return @"F32";
669    case NSF33FunctionKey:
670        return @"F33";
671    case NSF34FunctionKey:
672        return @"F34";
673    case NSF35FunctionKey:
674        return @"F35";
675
676    // Turn 0x7F into 0x08, because backspace needs to always be 0x08.
677    case 0x7F:
678        return @"U+0008";
679    // Standard says that DEL becomes U+007F.
680    case NSDeleteFunctionKey:
681        return @"U+007F";
682
683    // Always use 0x09 for tab instead of AppKit's backtab character.
684    case NSBackTabCharacter:
685        return @"U+0009";
686
687    case NSBeginFunctionKey:
688    case NSBreakFunctionKey:
689    case NSClearDisplayFunctionKey:
690    case NSDeleteCharFunctionKey:
691    case NSDeleteLineFunctionKey:
692    case NSInsertCharFunctionKey:
693    case NSInsertLineFunctionKey:
694    case NSNextFunctionKey:
695    case NSPrevFunctionKey:
696    case NSPrintFunctionKey:
697    case NSRedoFunctionKey:
698    case NSResetFunctionKey:
699    case NSSysReqFunctionKey:
700    case NSSystemFunctionKey:
701    case NSUserFunctionKey:
702        // FIXME: We should use something other than the vendor-area Unicode values for the above keys.
703        // For now, just fall through to the default.
704    default:
705        return [NSString stringWithFormat:@"U+%04X", WTF::toASCIIUpper(c)];
706    }
707}
708
709// End Apple code.
710// ----------------------------------------------------------------------------
711
712static inline int modifiersFromEvent(NSEvent* event) {
713    int modifiers = 0;
714
715    if ([event modifierFlags] & NSControlKeyMask)
716        modifiers |= WebInputEvent::ControlKey;
717    if ([event modifierFlags] & NSShiftKeyMask)
718        modifiers |= WebInputEvent::ShiftKey;
719    if ([event modifierFlags] & NSAlternateKeyMask)
720        modifiers |= WebInputEvent::AltKey;
721    if ([event modifierFlags] & NSCommandKeyMask)
722        modifiers |= WebInputEvent::MetaKey;
723    if ([event modifierFlags] & NSAlphaShiftKeyMask)
724        modifiers |= WebInputEvent::CapsLockOn;
725    // TODO(port): Set mouse button states
726
727    return modifiers;
728}
729
730static inline void setWebEventLocationFromEventInView(WebMouseEvent* result,
731                                                      NSEvent* event,
732                                                      NSView* view) {
733    NSPoint windowLocal = [event locationInWindow];
734
735    NSPoint screenLocal = [[view window] convertBaseToScreen:windowLocal];
736    result->globalX = screenLocal.x;
737    // Flip y.
738    NSScreen* primaryScreen = ([[NSScreen screens] count] > 0) ?
739        [[NSScreen screens] objectAtIndex:0] : nil;
740    if (primaryScreen)
741        result->globalY = [primaryScreen frame].size.height - screenLocal.y;
742    else
743        result->globalY = screenLocal.y;
744
745    NSPoint contentLocal = [view convertPoint:windowLocal fromView:nil];
746    result->x = contentLocal.x;
747    result->y = [view frame].size.height - contentLocal.y;  // Flip y.
748
749    result->windowX = result->x;
750    result->windowY = result->y;
751
752    result->movementX = [event deltaX];
753    result->movementY = [event deltaY];
754}
755
756bool WebInputEventFactory::isSystemKeyEvent(const WebKeyboardEvent& event)
757{
758    // Windows and Linux set |isSystemKey| if alt is down. Blink looks at this
759    // flag to decide if it should handle a key or not. E.g. alt-left/right
760    // shouldn't be used by Blink to scroll the current page, because we want
761    // to get that key back for it to do history navigation. Hence, the
762    // corresponding situation on OS X is to set this for cmd key presses.
763    // cmd-b and and cmd-i are system wide key bindings that OS X doesn't
764    // handle for us, so the editor handles them.
765    return event.modifiers & WebInputEvent::MetaKey
766           && event.windowsKeyCode != VK_B
767           && event.windowsKeyCode != VK_I;
768}
769
770WebKeyboardEvent WebInputEventFactory::keyboardEvent(NSEvent* event)
771{
772    WebKeyboardEvent result;
773
774    result.type =
775        isKeyUpEvent(event) ? WebInputEvent::KeyUp : WebInputEvent::RawKeyDown;
776
777    result.modifiers = modifiersFromEvent(event);
778
779    if (isKeypadEvent(event))
780        result.modifiers |= WebInputEvent::IsKeyPad;
781
782    if (([event type] != NSFlagsChanged) && [event isARepeat])
783        result.modifiers |= WebInputEvent::IsAutoRepeat;
784
785    int windowsKeyCode = windowsKeyCodeForKeyEvent(event);
786    result.windowsKeyCode = WebKeyboardEvent::windowsKeyCodeWithoutLocation(windowsKeyCode);
787    result.modifiers |= WebKeyboardEvent::locationModifiersFromWindowsKeyCode(windowsKeyCode);
788    result.nativeKeyCode = [event keyCode];
789
790    NSString* textStr = textFromEvent(event);
791    NSString* unmodifiedStr = unmodifiedTextFromEvent(event);
792    NSString* identifierStr = keyIdentifierForKeyEvent(event);
793
794    // Begin Apple code, copied from KeyEventMac.mm
795
796    // Always use 13 for Enter/Return -- we don't want to use AppKit's
797    // different character for Enter.
798    if (result.windowsKeyCode == '\r') {
799        textStr = @"\r";
800        unmodifiedStr = @"\r";
801    }
802
803    // The adjustments below are only needed in backward compatibility mode,
804    // but we cannot tell what mode we are in from here.
805
806    // Turn 0x7F into 8, because backspace needs to always be 8.
807    if ([textStr isEqualToString:@"\x7F"])
808        textStr = @"\x8";
809    if ([unmodifiedStr isEqualToString:@"\x7F"])
810        unmodifiedStr = @"\x8";
811    // Always use 9 for tab -- we don't want to use AppKit's different character
812    // for shift-tab.
813    if (result.windowsKeyCode == 9) {
814        textStr = @"\x9";
815        unmodifiedStr = @"\x9";
816    }
817
818    // End Apple code.
819
820    if ([textStr length] < WebKeyboardEvent::textLengthCap &&
821        [unmodifiedStr length] < WebKeyboardEvent::textLengthCap) {
822        [textStr getCharacters:&result.text[0]];
823        [unmodifiedStr getCharacters:&result.unmodifiedText[0]];
824    } else
825        ASSERT_NOT_REACHED();
826
827    [identifierStr getCString:&result.keyIdentifier[0]
828                    maxLength:sizeof(result.keyIdentifier)
829                     encoding:NSASCIIStringEncoding];
830
831    result.timeStampSeconds = [event timestamp];
832    result.isSystemKey = isSystemKeyEvent(result);
833
834    return result;
835}
836
837WebKeyboardEvent WebInputEventFactory::keyboardEvent(wchar_t character,
838                                                     int modifiers,
839                                                     double timeStampSeconds)
840{
841    // keyboardEvent(NSEvent*) depends on the NSEvent object and
842    // it is hard to use it from methods of the NSTextInput protocol. For
843    // such methods, this function creates a WebInputEvent::Char event without
844    // using a NSEvent object.
845    WebKeyboardEvent result;
846    result.type = blink::WebInputEvent::Char;
847    result.timeStampSeconds = timeStampSeconds;
848    result.modifiers = modifiers;
849    result.windowsKeyCode = character;
850    result.nativeKeyCode = character;
851    result.text[0] = character;
852    result.unmodifiedText[0] = character;
853    result.isSystemKey = isSystemKeyEvent(result);
854
855    return result;
856}
857
858// WebMouseEvent --------------------------------------------------------------
859
860WebMouseEvent WebInputEventFactory::mouseEvent(NSEvent* event, NSView* view)
861{
862    WebMouseEvent result;
863
864    result.clickCount = 0;
865
866    switch ([event type]) {
867    case NSMouseExited:
868        result.type = WebInputEvent::MouseLeave;
869        result.button = WebMouseEvent::ButtonNone;
870        break;
871    case NSLeftMouseDown:
872        result.type = WebInputEvent::MouseDown;
873        result.clickCount = [event clickCount];
874        result.button = WebMouseEvent::ButtonLeft;
875        break;
876    case NSOtherMouseDown:
877        result.type = WebInputEvent::MouseDown;
878        result.clickCount = [event clickCount];
879        result.button = WebMouseEvent::ButtonMiddle;
880        break;
881    case NSRightMouseDown:
882        result.type = WebInputEvent::MouseDown;
883        result.clickCount = [event clickCount];
884        result.button = WebMouseEvent::ButtonRight;
885        break;
886    case NSLeftMouseUp:
887        result.type = WebInputEvent::MouseUp;
888        result.clickCount = [event clickCount];
889        result.button = WebMouseEvent::ButtonLeft;
890        break;
891    case NSOtherMouseUp:
892        result.type = WebInputEvent::MouseUp;
893        result.clickCount = [event clickCount];
894        result.button = WebMouseEvent::ButtonMiddle;
895        break;
896    case NSRightMouseUp:
897        result.type = WebInputEvent::MouseUp;
898        result.clickCount = [event clickCount];
899        result.button = WebMouseEvent::ButtonRight;
900        break;
901    case NSMouseMoved:
902    case NSMouseEntered:
903        result.type = WebInputEvent::MouseMove;
904        break;
905    case NSLeftMouseDragged:
906        result.type = WebInputEvent::MouseMove;
907        result.button = WebMouseEvent::ButtonLeft;
908        break;
909    case NSOtherMouseDragged:
910        result.type = WebInputEvent::MouseMove;
911        result.button = WebMouseEvent::ButtonMiddle;
912        break;
913    case NSRightMouseDragged:
914        result.type = WebInputEvent::MouseMove;
915        result.button = WebMouseEvent::ButtonRight;
916        break;
917    default:
918        ASSERT_NOT_REACHED();
919    }
920
921    setWebEventLocationFromEventInView(&result, event, view);
922
923    result.modifiers = modifiersFromEvent(event);
924
925    result.timeStampSeconds = [event timestamp];
926
927    return result;
928}
929
930// WebMouseWheelEvent ---------------------------------------------------------
931
932static WebMouseWheelEvent::Phase phaseForNSEventPhase(NSEventPhase eventPhase)
933{
934    uint32_t phase = WebMouseWheelEvent::PhaseNone;
935    if (eventPhase & NSEventPhaseBegan)
936        phase |= WebMouseWheelEvent::PhaseBegan;
937    if (eventPhase & NSEventPhaseStationary)
938        phase |= WebMouseWheelEvent::PhaseStationary;
939    if (eventPhase & NSEventPhaseChanged)
940        phase |= WebMouseWheelEvent::PhaseChanged;
941    if (eventPhase & NSEventPhaseEnded)
942        phase |= WebMouseWheelEvent::PhaseEnded;
943    if (eventPhase & NSEventPhaseCancelled)
944        phase |= WebMouseWheelEvent::PhaseCancelled;
945    if (eventPhase & NSEventPhaseMayBegin)
946        phase |= WebMouseWheelEvent::PhaseMayBegin;
947    return static_cast<WebMouseWheelEvent::Phase>(phase);
948}
949
950static WebMouseWheelEvent::Phase phaseForEvent(NSEvent *event)
951{
952    if (![event respondsToSelector:@selector(phase)])
953        return WebMouseWheelEvent::PhaseNone;
954
955    NSEventPhase eventPhase = [event phase];
956    return phaseForNSEventPhase(eventPhase);
957}
958
959static WebMouseWheelEvent::Phase momentumPhaseForEvent(NSEvent *event)
960{
961    if (![event respondsToSelector:@selector(momentumPhase)])
962        return WebMouseWheelEvent::PhaseNone;
963
964    NSEventPhase eventMomentumPhase = [event momentumPhase];
965    return phaseForNSEventPhase(eventMomentumPhase);
966}
967
968WebMouseWheelEvent WebInputEventFactory::mouseWheelEvent(NSEvent* event, NSView* view, bool canRubberbandLeft, bool canRubberbandRight)
969{
970    WebMouseWheelEvent result;
971
972    result.type = WebInputEvent::MouseWheel;
973    result.button = WebMouseEvent::ButtonNone;
974
975    result.modifiers = modifiersFromEvent(event);
976
977    setWebEventLocationFromEventInView(&result, event, view);
978
979    result.canRubberbandLeft = canRubberbandLeft;
980    result.canRubberbandRight = canRubberbandRight;
981
982    // Of Mice and Men
983    // ---------------
984    //
985    // There are three types of scroll data available on a scroll wheel CGEvent.
986    // Apple's documentation ([1]) is rather vague in their differences, and not
987    // terribly helpful in deciding which to use. This is what's really going on.
988    //
989    // First, these events behave very differently depending on whether a standard
990    // wheel mouse is used (one that scrolls in discrete units) or a
991    // trackpad/Mighty Mouse is used (which both provide continuous scrolling).
992    // You must check to see which was used for the event by testing the
993    // kCGScrollWheelEventIsContinuous field.
994    //
995    // Second, these events refer to "axes". Axis 1 is the y-axis, and axis 2 is
996    // the x-axis.
997    //
998    // Third, there is a concept of mouse acceleration. Scrolling the same amount
999    // of physical distance will give you different results logically depending on
1000    // whether you scrolled a little at a time or in one continuous motion. Some
1001    // fields account for this while others do not.
1002    //
1003    // Fourth, for trackpads there is a concept of chunkiness. When scrolling
1004    // continuously, events can be delivered in chunks. That is to say, lots of
1005    // scroll events with delta 0 will be delivered, and every so often an event
1006    // with a non-zero delta will be delivered, containing the accumulated deltas
1007    // from all the intermediate moves. [2]
1008    //
1009    // For notchy wheel mice (kCGScrollWheelEventIsContinuous == 0)
1010    // ------------------------------------------------------------
1011    //
1012    // kCGScrollWheelEventDeltaAxis*
1013    //   This is the rawest of raw events. For each mouse notch you get a value of
1014    //   +1/-1. This does not take acceleration into account and thus is less
1015    //   useful for building UIs.
1016    //
1017    // kCGScrollWheelEventPointDeltaAxis*
1018    //   This is smarter. In general, for each mouse notch you get a value of
1019    //   +1/-1, but this _does_ take acceleration into account, so you will get
1020    //   larger values on longer scrolls. This field would be ideal for building
1021    //   UIs except for one nasty bug: when the shift key is pressed, this set of
1022    //   fields fails to move the value into the axis2 field (the other two types
1023    //   of data do). This wouldn't be so bad except for the fact that while the
1024    //   number of axes is used in the creation of a CGScrollWheelEvent, there is
1025    //   no way to get that information out of the event once created.
1026    //
1027    // kCGScrollWheelEventFixedPtDeltaAxis*
1028    //   This is a fixed value, and for each mouse notch you get a value of
1029    //   +0.1/-0.1 (but, like above, scaled appropriately for acceleration). This
1030    //   value takes acceleration into account, and in fact is identical to the
1031    //   results you get from -[NSEvent delta*]. (That is, if you linked on Tiger
1032    //   or greater; see [2] for details.)
1033    //
1034    // A note about continuous devices
1035    // -------------------------------
1036    //
1037    // There are two devices that provide continuous scrolling events (trackpads
1038    // and Mighty Mouses) and they behave rather differently. The Mighty Mouse
1039    // behaves a lot like a regular mouse. There is no chunking, and the
1040    // FixedPtDelta values are the PointDelta values multiplied by 0.1. With the
1041    // trackpad, though, there is chunking. While the FixedPtDelta values are
1042    // reasonable (they occur about every fifth event but have values five times
1043    // larger than usual) the Delta values are unreasonable. They don't appear to
1044    // accumulate properly.
1045    //
1046    // For continuous devices (kCGScrollWheelEventIsContinuous != 0)
1047    // -------------------------------------------------------------
1048    //
1049    // kCGScrollWheelEventDeltaAxis*
1050    //   This provides values with no acceleration. With a trackpad, these values
1051    //   are chunked but each non-zero value does not appear to be cumulative.
1052    //   This seems to be a bug.
1053    //
1054    // kCGScrollWheelEventPointDeltaAxis*
1055    //   This provides values with acceleration. With a trackpad, these values are
1056    //   not chunked and are highly accurate.
1057    //
1058    // kCGScrollWheelEventFixedPtDeltaAxis*
1059    //   This provides values with acceleration. With a trackpad, these values are
1060    //   chunked but unlike Delta events are properly cumulative.
1061    //
1062    // Summary
1063    // -------
1064    //
1065    // In general the best approach to take is: determine if the event is
1066    // continuous. If it is not, then use the FixedPtDelta events (or just stick
1067    // with Cocoa events). They provide both acceleration and proper horizontal
1068    // scrolling. If the event is continuous, then doing pixel scrolling with the
1069    // PointDelta is the way to go. In general, avoid the Delta events. They're
1070    // the oldest (dating back to 10.4, before CGEvents were public) but they lack
1071    // acceleration and precision, making them useful only in specific edge cases.
1072    //
1073    // References
1074    // ----------
1075    //
1076    // [1] <http://developer.apple.com/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html>
1077    // [2] <http://developer.apple.com/releasenotes/Cocoa/AppKitOlderNotes.html>
1078    //     Scroll to the section headed "NSScrollWheel events".
1079    //
1080    // P.S. The "smooth scrolling" option in the system preferences is utterly
1081    // unrelated to any of this.
1082
1083    CGEventRef cgEvent = [event CGEvent];
1084    ASSERT(cgEvent);
1085
1086    // Wheel ticks are supposed to be raw, unaccelerated values, one per physical
1087    // mouse wheel notch. The delta event is perfect for this (being a good
1088    // "specific edge case" as mentioned above). Trackpads, unfortunately, do
1089    // event chunking, and sending mousewheel events with 0 ticks causes some
1090    // websites to malfunction. Therefore, for all continuous input devices we use
1091    // the point delta data instead, since we cannot distinguish trackpad data
1092    // from data from any other continuous device.
1093
1094    // Conversion between wheel delta amounts and number of pixels to scroll.
1095    static const double scrollbarPixelsPerCocoaTick = 40.0;
1096
1097    if (CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventIsContinuous)) {
1098        result.deltaX = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis2);
1099        result.deltaY = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1);
1100        result.wheelTicksX = result.deltaX / scrollbarPixelsPerCocoaTick;
1101        result.wheelTicksY = result.deltaY / scrollbarPixelsPerCocoaTick;
1102        result.hasPreciseScrollingDeltas = true;
1103    } else {
1104        result.deltaX = [event deltaX] * scrollbarPixelsPerCocoaTick;
1105        result.deltaY = [event deltaY] * scrollbarPixelsPerCocoaTick;
1106        result.wheelTicksY = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventDeltaAxis1);
1107        result.wheelTicksX = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventDeltaAxis2);
1108    }
1109
1110    result.timeStampSeconds = [event timestamp];
1111
1112    result.phase              = phaseForEvent(event);
1113    result.momentumPhase      = momentumPhaseForEvent(event);
1114
1115    return result;
1116}
1117
1118WebGestureEvent WebInputEventFactory::gestureEvent(NSEvent *event, NSView *view)
1119{
1120    WebGestureEvent result;
1121
1122    // Use a temporary WebMouseEvent to get the location.
1123    WebMouseEvent temp;
1124
1125    setWebEventLocationFromEventInView(&temp, event, view);
1126    result.x = temp.x;
1127    result.y = temp.y;
1128    result.globalX = temp.globalX;
1129    result.globalY = temp.globalY;
1130
1131    result.modifiers = modifiersFromEvent(event);
1132    result.timeStampSeconds = [event timestamp];
1133
1134    // MacOS X gestures are used only for pinch support.
1135    result.sourceDevice = WebGestureDeviceTouchpad;
1136    switch ([event type]) {
1137    case NSEventTypeMagnify:
1138        result.type = WebInputEvent::GesturePinchUpdate;
1139        result.data.pinchUpdate.scale = [event magnification] + 1.0;
1140        break;
1141    default:
1142        ASSERT_NOT_REACHED();
1143        result.type = WebInputEvent::Undefined;
1144    }
1145
1146    return result;
1147}
1148
1149} // namespace blink
1150