Replace OptionSet |= and -= operators with add() and remove() functions
[WebKit-https.git] / Source / WebCore / platform / mac / PlatformEventFactoryMac.mm
1 /*
2  * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "PlatformEventFactoryMac.h"
28
29 #if PLATFORM(MAC)
30
31 #import "KeyEventCocoa.h"
32 #import "Logging.h"
33 #import "PlatformScreen.h"
34 #import "Scrollbar.h"
35 #import "WindowsKeyboardCodes.h"
36 #import <HIToolbox/CarbonEvents.h>
37 #import <HIToolbox/Events.h>
38 #import <mach/mach_time.h>
39 #import <pal/spi/mac/HIToolboxSPI.h>
40 #import <pal/spi/mac/NSEventSPI.h>
41 #import <pal/spi/mac/NSMenuSPI.h>
42 #import <wtf/ASCIICType.h>
43 #import <wtf/WallTime.h>
44
45 namespace WebCore {
46
47 NSPoint globalPoint(const NSPoint& windowPoint, NSWindow *window)
48 {
49 #pragma clang diagnostic push
50 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
51     return flipScreenPoint([window convertBaseToScreen:windowPoint], screen(window));
52 #pragma clang diagnostic pop
53 }
54
55 static NSPoint globalPointForEvent(NSEvent *event)
56 {
57     switch ([event type]) {
58 #if defined(__LP64__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101003
59     case NSEventTypePressure:
60 #endif
61     case NSEventTypeLeftMouseDown:
62     case NSEventTypeLeftMouseDragged:
63     case NSEventTypeLeftMouseUp:
64     case NSEventTypeMouseEntered:
65     case NSEventTypeMouseExited:
66     case NSEventTypeMouseMoved:
67     case NSEventTypeOtherMouseDown:
68     case NSEventTypeOtherMouseDragged:
69     case NSEventTypeOtherMouseUp:
70     case NSEventTypeRightMouseDown:
71     case NSEventTypeRightMouseDragged:
72     case NSEventTypeRightMouseUp:
73     case NSEventTypeScrollWheel:
74         return globalPoint([event locationInWindow], [event window]);
75     default:
76         return { 0, 0 };
77     }
78 }
79
80 static IntPoint pointForEvent(NSEvent *event, NSView *windowView)
81 {
82     switch ([event type]) {
83 #if defined(__LP64__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101003
84     case NSEventTypePressure:
85 #endif
86     case NSEventTypeLeftMouseDown:
87     case NSEventTypeLeftMouseDragged:
88     case NSEventTypeLeftMouseUp:
89     case NSEventTypeMouseEntered:
90     case NSEventTypeMouseExited:
91     case NSEventTypeMouseMoved:
92     case NSEventTypeOtherMouseDown:
93     case NSEventTypeOtherMouseDragged:
94     case NSEventTypeOtherMouseUp:
95     case NSEventTypeRightMouseDown:
96     case NSEventTypeRightMouseDragged:
97     case NSEventTypeRightMouseUp:
98     case NSEventTypeScrollWheel: {
99         // Note: This will have its origin at the bottom left of the window unless windowView is flipped.
100         // In those cases, the Y coordinate gets flipped by Widget::convertFromContainingWindow.
101         NSPoint location = [event locationInWindow];
102         if (windowView)
103             location = [windowView convertPoint:location fromView:nil];
104         return IntPoint(location);
105     }
106     default:
107         return IntPoint();
108     }
109 }
110
111 static MouseButton mouseButtonForEvent(NSEvent *event)
112 {
113     switch ([event type]) {
114 #if defined(__LP64__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101003
115     case NSEventTypePressure:
116 #endif
117     case NSEventTypeLeftMouseDown:
118     case NSEventTypeLeftMouseUp:
119     case NSEventTypeLeftMouseDragged:
120         return LeftButton;
121     case NSEventTypeRightMouseDown:
122     case NSEventTypeRightMouseUp:
123     case NSEventTypeRightMouseDragged:
124         return RightButton;
125     case NSEventTypeOtherMouseDown:
126     case NSEventTypeOtherMouseUp:
127     case NSEventTypeOtherMouseDragged:
128         return MiddleButton;
129     default:
130         return NoButton;
131     }
132 }
133
134 static unsigned short currentlyPressedMouseButtons()
135 {
136     return static_cast<unsigned short>([NSEvent pressedMouseButtons]);
137 }
138
139 static PlatformEvent::Type mouseEventTypeForEvent(NSEvent* event)
140 {
141     switch ([event type]) {
142     case NSEventTypeLeftMouseDragged:
143     case NSEventTypeMouseEntered:
144     case NSEventTypeMouseExited:
145     case NSEventTypeMouseMoved:
146     case NSEventTypeOtherMouseDragged:
147     case NSEventTypeRightMouseDragged:
148         return PlatformEvent::MouseMoved;
149     case NSEventTypeLeftMouseDown:
150     case NSEventTypeRightMouseDown:
151     case NSEventTypeOtherMouseDown:
152         return PlatformEvent::MousePressed;
153     case NSEventTypeLeftMouseUp:
154     case NSEventTypeRightMouseUp:
155     case NSEventTypeOtherMouseUp:
156         return PlatformEvent::MouseReleased;
157     default:
158         return PlatformEvent::MouseMoved;
159     }
160 }
161
162 static int clickCountForEvent(NSEvent *event)
163 {
164     switch ([event type]) {
165     case NSEventTypeLeftMouseDown:
166     case NSEventTypeLeftMouseUp:
167     case NSEventTypeLeftMouseDragged:
168     case NSEventTypeRightMouseDown:
169     case NSEventTypeRightMouseUp:
170     case NSEventTypeRightMouseDragged:
171     case NSEventTypeOtherMouseDown:
172     case NSEventTypeOtherMouseUp:
173     case NSEventTypeOtherMouseDragged:
174         return [event clickCount];
175     default:
176         return 0;
177     }
178 }
179
180 static PlatformWheelEventPhase momentumPhaseForEvent(NSEvent *event)
181 {
182     uint32_t phase = PlatformWheelEventPhaseNone;
183
184     if ([event momentumPhase] & NSEventPhaseBegan)
185         phase |= PlatformWheelEventPhaseBegan;
186     if ([event momentumPhase] & NSEventPhaseStationary)
187         phase |= PlatformWheelEventPhaseStationary;
188     if ([event momentumPhase] & NSEventPhaseChanged)
189         phase |= PlatformWheelEventPhaseChanged;
190     if ([event momentumPhase] & NSEventPhaseEnded)
191         phase |= PlatformWheelEventPhaseEnded;
192     if ([event momentumPhase] & NSEventPhaseCancelled)
193         phase |= PlatformWheelEventPhaseCancelled;
194
195     return static_cast<PlatformWheelEventPhase>(phase);
196 }
197
198 static PlatformWheelEventPhase phaseForEvent(NSEvent *event)
199 {
200     uint32_t phase = PlatformWheelEventPhaseNone; 
201     if ([event phase] & NSEventPhaseBegan)
202         phase |= PlatformWheelEventPhaseBegan;
203     if ([event phase] & NSEventPhaseStationary)
204         phase |= PlatformWheelEventPhaseStationary;
205     if ([event phase] & NSEventPhaseChanged)
206         phase |= PlatformWheelEventPhaseChanged;
207     if ([event phase] & NSEventPhaseEnded)
208         phase |= PlatformWheelEventPhaseEnded;
209     if ([event phase] & NSEventPhaseCancelled)
210         phase |= PlatformWheelEventPhaseCancelled;
211     if ([event momentumPhase] & NSEventPhaseMayBegin)
212         phase |= PlatformWheelEventPhaseMayBegin;
213
214     return static_cast<PlatformWheelEventPhase>(phase);
215 }
216
217 static inline String textFromEvent(NSEvent* event)
218 {
219     if ([event type] == NSEventTypeFlagsChanged)
220         return emptyString();
221     return String([event characters]);
222 }
223
224 static inline String unmodifiedTextFromEvent(NSEvent* event)
225 {
226     if ([event type] == NSEventTypeFlagsChanged)
227         return emptyString();
228     return String([event charactersIgnoringModifiers]);
229 }
230
231 String keyForKeyEvent(NSEvent *event)
232 {
233     // This constant was missing before OS X Sierra.
234 #ifndef kVK_RightCommand
235 #define kVK_RightCommand 0x36
236 #endif
237     switch ([event keyCode]) {
238     case kVK_RightCommand:
239     case kVK_Command:
240         return "Meta"_s;
241     case kVK_Shift:
242     case kVK_RightShift:
243         return "Shift"_s;
244     case kVK_CapsLock:
245         return "CapsLock"_s;
246     case kVK_Option: // Left Alt.
247     case kVK_RightOption: // Right Alt.
248         return "Alt"_s;
249     case kVK_Control:
250     case kVK_RightControl:
251         return "Control"_s;
252     }
253
254     // If the event is an NSEventTypeFlagsChanged events and we have not returned yet then this means we could not
255     // identify the modifier key. We return now and report the key as "Unidentified".
256     // Note that [event characters] below raises an exception if called on an NSEventTypeFlagsChanged event.
257     if ([event type] == NSEventTypeFlagsChanged)
258         return "Unidentified"_s;
259
260     // If more than one key is being pressed and the key combination includes one or more modifier keys
261     // that result in the key no longer producing a printable character (e.g., Control + a), then the
262     // key value should be the printable key value that would have been produced if the key had been
263     // typed with the default keyboard layout with no modifier keys except for Shift and AltGr applied.
264     // https://w3c.github.io/uievents/#keys-guidelines
265     bool isControlDown = ([event modifierFlags] & NSEventModifierFlagControl);
266     NSString *s = isControlDown ? [event charactersIgnoringModifiers] : [event characters];
267     auto length = [s length];
268     // characters / charactersIgnoringModifiers return an empty string for dead keys.
269     // https://developer.apple.com/reference/appkit/nsevent/1534183-characters
270     if (!length)
271         return "Dead"_s;
272     // High unicode codepoints are coded with a character sequence in Mac OS X.
273     if (length > 1)
274         return s;
275     return keyForCharCode([s characterAtIndex:0]);
276 }
277
278 // https://w3c.github.io/uievents-code/
279 String codeForKeyEvent(NSEvent *event)
280 {
281     switch ([event keyCode]) {
282     // Keys in the alphanumeric section.
283     case kVK_ANSI_Grave: return "Backquote"_s;
284     case kVK_ANSI_Backslash: return "Backslash"_s;
285     case kVK_Delete: return "Backspace"_s;
286     case kVK_ANSI_LeftBracket: return "BracketLeft"_s;
287     case kVK_ANSI_RightBracket: return "BracketRight"_s;
288     case kVK_ANSI_Comma: return "Comma"_s;
289     case kVK_ANSI_0: return "Digit0"_s;
290     case kVK_ANSI_1: return "Digit1"_s;
291     case kVK_ANSI_2: return "Digit2"_s;
292     case kVK_ANSI_3: return "Digit3"_s;
293     case kVK_ANSI_4: return "Digit4"_s;
294     case kVK_ANSI_5: return "Digit5"_s;
295     case kVK_ANSI_6: return "Digit6"_s;
296     case kVK_ANSI_7: return "Digit7"_s;
297     case kVK_ANSI_8: return "Digit8"_s;
298     case kVK_ANSI_9: return "Digit9"_s;
299     case kVK_ANSI_Equal: return "Equal"_s;
300     case kVK_ISO_Section: return "IntlBackslash"_s;
301     case kVK_JIS_Underscore: return "IntlRo"_s;
302     case kVK_JIS_Yen: return "IntlYen"_s;
303     case kVK_ANSI_A: return "KeyA"_s;
304     case kVK_ANSI_B: return "KeyB"_s;
305     case kVK_ANSI_C: return "KeyC"_s;
306     case kVK_ANSI_D: return "KeyD"_s;
307     case kVK_ANSI_E: return "KeyE"_s;
308     case kVK_ANSI_F: return "KeyF"_s;
309     case kVK_ANSI_G: return "KeyG"_s;
310     case kVK_ANSI_H: return "KeyH"_s;
311     case kVK_ANSI_I: return "KeyI"_s;
312     case kVK_ANSI_J: return "KeyJ"_s;
313     case kVK_ANSI_K: return "KeyK"_s;
314     case kVK_ANSI_L: return "KeyL"_s;
315     case kVK_ANSI_M: return "KeyM"_s;
316     case kVK_ANSI_N: return "KeyN"_s;
317     case kVK_ANSI_O: return "KeyO"_s;
318     case kVK_ANSI_P: return "KeyP"_s;
319     case kVK_ANSI_Q: return "KeyQ"_s;
320     case kVK_ANSI_R: return "KeyR"_s;
321     case kVK_ANSI_S: return "KeyS"_s;
322     case kVK_ANSI_T: return "KeyT"_s;
323     case kVK_ANSI_U: return "KeyU"_s;
324     case kVK_ANSI_V: return "KeyV"_s;
325     case kVK_ANSI_W: return "KeyW"_s;
326     case kVK_ANSI_X: return "KeyX"_s;
327     case kVK_ANSI_Y: return "KeyY"_s;
328     case kVK_ANSI_Z: return "KeyZ"_s;
329     case kVK_ANSI_Minus: return "Minus"_s;
330     case kVK_ANSI_Period: return "Period"_s;
331     case kVK_ANSI_Quote: return "Quote"_s;
332     case kVK_ANSI_Semicolon: return "Semicolon"_s;
333     case kVK_ANSI_Slash: return "Slash"_s;
334
335     // Functional keys in alphanumeric section.
336     case kVK_Option: return "AltLeft"_s;
337     case kVK_RightOption: return "AltRight"_s;
338     case kVK_CapsLock: return "CapsLock"_s;
339     // ContextMenu.
340     case kVK_Control: return "ControlLeft"_s;
341     case kVK_RightControl: return "ControlRight"_s;
342     case kVK_Return: return "Enter"_s; //  Labeled Return on Apple keyboards.
343     case kVK_Command: return "MetaLeft"_s;
344     case kVK_RightCommand: return "MetaRight"_s;
345     case kVK_Shift: return "ShiftLeft"_s;
346     case kVK_RightShift: return "ShiftRight"_s;
347     case kVK_Space: return "Space"_s;
348     case kVK_Tab: return "Tab"_s;
349
350     // Functional keys found on Japanese and Korean keyboards.
351     // Convert.
352     case kVK_JIS_Kana: return "KanaMode"_s;
353     // Lang1.
354     case kVK_JIS_Eisu: return "Lang2"_s; // Japanese (Mac keyboard): eisu.
355     // Lang3.
356     // Lang4.
357     // Lang5.
358     // NonConvert.
359
360     // Keys in the ControlPad section.
361     case kVK_ForwardDelete: return "Delete"_s;
362     case kVK_End: return "End"_s;
363     case kVK_Help: return "Help"_s;
364     case kVK_Home: return "Home"_s;
365     // Insert: Not present on Apple keyboards.
366     case kVK_PageDown: return "PageDown"_s;
367     case kVK_PageUp: return "PageUp"_s;
368
369     // Keys in the ArrowPad section.
370     case kVK_DownArrow: return "ArrowDown"_s;
371     case kVK_LeftArrow: return "ArrowLeft"_s;
372     case kVK_RightArrow: return "ArrowRight"_s;
373     case kVK_UpArrow: return "ArrowUp"_s;
374
375     // Keys in the Numpad section.
376     case kVK_ANSI_KeypadClear: return "NumLock"_s; // The specification says to use "NumLock" on Mac for the numpad Clear key.
377     case kVK_ANSI_Keypad0: return "Numpad0"_s;
378     case kVK_ANSI_Keypad1: return "Numpad1"_s;
379     case kVK_ANSI_Keypad2: return "Numpad2"_s;
380     case kVK_ANSI_Keypad3: return "Numpad3"_s;
381     case kVK_ANSI_Keypad4: return "Numpad4"_s;
382     case kVK_ANSI_Keypad5: return "Numpad5"_s;
383     case kVK_ANSI_Keypad6: return "Numpad6"_s;
384     case kVK_ANSI_Keypad7: return "Numpad7"_s;
385     case kVK_ANSI_Keypad8: return "Numpad8"_s;
386     case kVK_ANSI_Keypad9: return "Numpad9"_s;
387     case kVK_ANSI_KeypadPlus: return "NumpadAdd"_s;
388     // NumpadBackspace.
389     // NumpadClear: The specification says that the numpad Clear key should always be encoded as "NumLock" on Mac.
390     // NumpadClearEntry.
391     case kVK_JIS_KeypadComma: return "NumpadComma"_s;
392     case kVK_ANSI_KeypadDecimal: return "NumpadDecimal"_s;
393     case kVK_ANSI_KeypadDivide: return "NumpadDivide"_s;
394     case kVK_ANSI_KeypadEnter: return "NumpadEnter"_s;
395     case kVK_ANSI_KeypadEquals: return "NumpadEqual"_s;
396     // NumpadHash.
397     // NumpadMemoryAdd.
398     // NumpadMemoryClear.
399     // NumpadMemoryRecall.
400     // NumpadMemoryStore.
401     // NumpadMemorySubtract.
402     case kVK_ANSI_KeypadMultiply: return "NumpadMultiply"_s;
403     // NumpadParenLeft.
404     // NumpadParenRight.
405     // NumpadStar: The specification says to use "NumpadMultiply" for the * key on numeric keypads.
406     case kVK_ANSI_KeypadMinus: return "NumpadSubtract"_s;
407
408     // Keys in the Function section.
409     case kVK_Escape: return "Escape"_s;
410     case kVK_F1: return "F1"_s;
411     case kVK_F2: return "F2"_s;
412     case kVK_F3: return "F3"_s;
413     case kVK_F4: return "F4"_s;
414     case kVK_F5: return "F5"_s;
415     case kVK_F6: return "F6"_s;
416     case kVK_F7: return "F7"_s;
417     case kVK_F8: return "F8"_s;
418     case kVK_F9: return "F9"_s;
419     case kVK_F10: return "F10"_s;
420     case kVK_F11: return "F11"_s;
421     case kVK_F12: return "F12"_s;
422     case kVK_F13: return "F13"_s;
423     case kVK_F14: return "F14"_s;
424     case kVK_F15: return "F15"_s;
425     case kVK_F16: return "F16"_s;
426     case kVK_F17: return "F17"_s;
427     case kVK_F18: return "F18"_s;
428     case kVK_F19: return "F19"_s;
429     case kVK_F20: return "F20"_s;
430     // Fn: This is typically a hardware key that does not generate a separate code.
431     // FnLock.
432     // PrintScreen.
433     // ScrollLock.
434     // Pause.
435
436     // Media keys.
437     // BrowserBack.
438     // BrowserFavorites.
439     // BrowserForward.
440     // BrowserHome.
441     // BrowserRefresh.
442     // BrowserSearch.
443     // BrowserStop.
444     // Eject.
445     // LaunchApp1.
446     // LaunchApp2.
447     // LaunchMail.
448     // MediaPlayPause.
449     // MediaSelect.
450     // MediaStop.
451     // MediaTrackNext.
452     // MediaTrackPrevious.
453     // Power.
454     // Sleep.
455     case kVK_VolumeDown: return "AudioVolumeDown"_s;
456     case kVK_Mute: return "AudioVolumeMute"_s;
457     case kVK_VolumeUp: return "AudioVolumeUp"_s;
458     // WakeUp.
459
460     // Legacy modifier keys.
461     // Hyper.
462     // Super.
463     // Turbo.
464
465     // Legacy process control keys.
466     // Abort.
467     // Resume.
468     // Suspend.
469
470     // Legacy editing keys.
471     // Again.
472     // Copy.
473     // Cut.
474     // Find.
475     // Open.
476     // Paste.
477     // Props.
478     // Select.
479     // Undo.
480
481     // Keys found on international keyboards.
482     // Hiragana.
483     // Katakana.
484
485     default:
486         return "Unidentified"_s;
487     }
488 }
489
490 String keyIdentifierForKeyEvent(NSEvent* event)
491 {
492     if ([event type] == NSEventTypeFlagsChanged) {
493         switch ([event keyCode]) {
494         case 54: // Right Command
495         case 55: // Left Command
496             return String("Meta");
497
498         case 57: // Capslock
499             return String("CapsLock");
500
501         case 56: // Left Shift
502         case 60: // Right Shift
503             return String("Shift");
504
505         case 58: // Left Alt
506         case 61: // Right Alt
507             return String("Alt");
508
509         case 59: // Left Ctrl
510         case 62: // Right Ctrl
511             return String("Control");
512
513         default:
514             ASSERT_NOT_REACHED();
515             return emptyString();
516         }
517     }
518     
519     NSString *s = [event charactersIgnoringModifiers];
520     if ([s length] != 1) {
521         LOG(Events, "received an unexpected number of characters in key event: %u", [s length]);
522         return "Unidentified";
523     }
524     return keyIdentifierForCharCode([s characterAtIndex:0]);
525 }
526
527 static bool isKeypadEvent(NSEvent* event)
528 {
529     // Check that this is the type of event that has a keyCode.
530     switch ([event type]) {
531     case NSEventTypeKeyDown:
532     case NSEventTypeKeyUp:
533     case NSEventTypeFlagsChanged:
534         break;
535     default:
536         return false;
537     }
538
539     if ([event modifierFlags] & NSEventModifierFlagNumericPad)
540         return true;
541
542     switch ([event keyCode]) {
543     case 71: // Clear
544     case 81: // =
545     case 75: // /
546     case 67: // *
547     case 78: // -
548     case 69: // +
549     case 76: // Enter
550     case 65: // .
551     case 82: // 0
552     case 83: // 1
553     case 84: // 2
554     case 85: // 3
555     case 86: // 4
556     case 87: // 5
557     case 88: // 6
558     case 89: // 7
559     case 91: // 8
560     case 92: // 9
561         return true;
562     }
563      
564      return false;
565 }
566
567 int windowsKeyCodeForKeyEvent(NSEvent* event)
568 {
569     int code = 0;
570     // There are several kinds of characters for which we produce key code from char code:
571     // 1. Roman letters. Windows keyboard layouts affect both virtual key codes and character codes for these,
572     //    so e.g. 'A' gets the same keyCode on QWERTY, AZERTY or Dvorak layouts.
573     // 2. Keys for which there is no known Mac virtual key codes, like PrintScreen.
574     // 3. Certain punctuation keys. On Windows, these are also remapped depending on current keyboard layout,
575     //    but see comment in windowsKeyCodeForCharCode().
576     if (!isKeypadEvent(event) && ([event type] == NSEventTypeKeyDown || [event type] == NSEventTypeKeyUp)) {
577         // Cmd switches Roman letters for Dvorak-QWERTY layout, so try modified characters first.
578         NSString* s = [event characters];
579         code = [s length] > 0 ? windowsKeyCodeForCharCode([s characterAtIndex:0]) : 0;
580         if (code)
581             return code;
582
583         // Ctrl+A on an AZERTY keyboard would get VK_Q keyCode if we relied on -[NSEvent keyCode] below.
584         s = [event charactersIgnoringModifiers];
585         code = [s length] > 0 ? windowsKeyCodeForCharCode([s characterAtIndex:0]) : 0;
586         if (code)
587             return code;
588     }
589
590     // Map Mac virtual key code directly to Windows one for any keys not handled above.
591     // 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).
592     return windowsKeyCodeForKeyCode([event keyCode]);
593 }
594
595 static CFAbsoluteTime systemStartupTime;
596
597 static void updateSystemStartupTimeIntervalSince1970()
598 {
599     // CFAbsoluteTimeGetCurrent() provides the absolute time in seconds since 2001.
600     // mach_absolute_time() provides a relative system time since startup minus the time the computer was suspended.
601     mach_timebase_info_data_t timebase_info;
602     mach_timebase_info(&timebase_info);
603     double elapsedTimeSinceStartup = static_cast<double>(mach_absolute_time()) * timebase_info.numer / timebase_info.denom / 1e9;
604     systemStartupTime = kCFAbsoluteTimeIntervalSince1970 + CFAbsoluteTimeGetCurrent() - elapsedTimeSinceStartup;
605 }
606
607 static CFTimeInterval cachedStartupTimeIntervalSince1970()
608 {
609     static dispatch_once_t once;
610     dispatch_once(&once, ^{
611         void (^updateBlock)(NSNotification *) = Block_copy(^(NSNotification *){ updateSystemStartupTimeIntervalSince1970(); });
612         [[[NSWorkspace sharedWorkspace] notificationCenter] addObserverForName:NSWorkspaceDidWakeNotification
613                                                                         object:nil
614                                                                          queue:nil
615                                                                     usingBlock:updateBlock];
616         [[NSNotificationCenter defaultCenter] addObserverForName:NSSystemClockDidChangeNotification
617                                                           object:nil
618                                                            queue:nil
619                                                       usingBlock:updateBlock];
620         Block_release(updateBlock);
621
622         updateSystemStartupTimeIntervalSince1970();
623     });
624     return systemStartupTime;
625 }
626
627 WallTime eventTimeStampSince1970(NSEvent* event)
628 {
629     return WallTime::fromRawSeconds(static_cast<double>(cachedStartupTimeIntervalSince1970() + [event timestamp]));
630 }
631
632 static inline bool isKeyUpEvent(NSEvent *event)
633 {
634     if ([event type] != NSEventTypeFlagsChanged)
635         return [event type] == NSEventTypeKeyUp;
636     // FIXME: This logic fails if the user presses both Shift keys at once, for example:
637     // we treat releasing one of them as keyDown.
638     switch ([event keyCode]) {
639     case 54: // Right Command
640     case 55: // Left Command
641         return !([event modifierFlags] & NSEventModifierFlagCommand);
642
643     case 57: // Capslock
644         return !([event modifierFlags] & NSEventModifierFlagCapsLock);
645
646     case 56: // Left Shift
647     case 60: // Right Shift
648         return !([event modifierFlags] & NSEventModifierFlagShift);
649
650     case 58: // Left Alt
651     case 61: // Right Alt
652         return !([event modifierFlags] & NSEventModifierFlagOption);
653
654     case 59: // Left Ctrl
655     case 62: // Right Ctrl
656         return !([event modifierFlags] & NSEventModifierFlagControl);
657
658     case 63: // Function
659         return !([event modifierFlags] & NSEventModifierFlagFunction);
660     }
661     return false;
662 }
663
664 OptionSet<PlatformEvent::Modifier> modifiersForEvent(NSEvent *event)
665 {
666     OptionSet<PlatformEvent::Modifier> modifiers;
667
668     if (event.modifierFlags & NSEventModifierFlagShift)
669         modifiers.add(PlatformEvent::Modifier::ShiftKey);
670     if (event.modifierFlags & NSEventModifierFlagControl)
671         modifiers.add(PlatformEvent::Modifier::CtrlKey);
672     if (event.modifierFlags & NSEventModifierFlagOption)
673         modifiers.add(PlatformEvent::Modifier::AltKey);
674     if (event.modifierFlags & NSEventModifierFlagCommand)
675         modifiers.add(PlatformEvent::Modifier::MetaKey);
676     if (event.modifierFlags & NSEventModifierFlagCapsLock)
677         modifiers.add(PlatformEvent::Modifier::CapsLockKey);
678
679     return modifiers;
680 }
681
682 static int typeForEvent(NSEvent *event)
683 {
684     return static_cast<int>([NSMenu menuTypeForEvent:event]);
685 }
686
687 void getWheelEventDeltas(NSEvent *event, float& deltaX, float& deltaY, BOOL& continuous)
688 {
689     ASSERT(event);
690     if (event.hasPreciseScrollingDeltas) {
691         deltaX = event.scrollingDeltaX;
692         deltaY = event.scrollingDeltaY;
693         continuous = YES;
694     } else {
695         deltaX = event.deltaX;
696         deltaY = event.deltaY;
697         continuous = NO;
698     }
699 }
700
701 UInt8 keyCharForEvent(NSEvent *event)
702 {
703     EventRef eventRef = (EventRef)[event _eventRef];
704     if (!eventRef)
705         return 0;
706
707     ByteCount keyCharCount = 0;
708     if (GetEventParameter(eventRef, kEventParamKeyMacCharCodes, typeChar, 0, 0, &keyCharCount, 0) != noErr)
709         return 0;
710     if (keyCharCount != 1)
711         return 0;
712
713     UInt8 keyChar = 0;
714     if (GetEventParameter(eventRef, kEventParamKeyMacCharCodes, typeChar, 0, sizeof(keyChar), &keyCharCount, &keyChar) != noErr)
715         return 0;
716     
717     return keyChar;
718 }
719
720 class PlatformMouseEventBuilder : public PlatformMouseEvent {
721 public:
722     PlatformMouseEventBuilder(NSEvent *event, NSEvent *correspondingPressureEvent, NSView *windowView)
723     {
724         // PlatformEvent
725         m_type = mouseEventTypeForEvent(event);
726
727 #if defined(__LP64__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101003
728         BOOL eventIsPressureEvent = [event type] == NSEventTypePressure;
729         if (eventIsPressureEvent) {
730             // Since AppKit doesn't send mouse events for force down or force up, we have to use the current pressure
731             // event and correspondingPressureEvent to detect if this is MouseForceDown, MouseForceUp, or just MouseForceChanged.
732             if (correspondingPressureEvent.stage == 1 && event.stage == 2)
733                 m_type = PlatformEvent::MouseForceDown;
734             else if (correspondingPressureEvent.stage == 2 && event.stage == 1)
735                 m_type = PlatformEvent::MouseForceUp;
736             else
737                 m_type = PlatformEvent::MouseForceChanged;
738         }
739 #else
740         UNUSED_PARAM(correspondingPressureEvent);
741 #endif
742
743         m_modifiers = modifiersForEvent(event);
744         m_timestamp = eventTimeStampSince1970(event);
745
746         // PlatformMouseEvent
747         m_position = pointForEvent(event, windowView);
748         m_globalPosition = IntPoint(globalPointForEvent(event));
749         m_button = mouseButtonForEvent(event);
750         m_buttons = currentlyPressedMouseButtons();
751         m_clickCount = clickCountForEvent(event);
752 #if ENABLE(POINTER_LOCK)
753         m_movementDelta = IntPoint(event.deltaX, event.deltaY);
754 #endif
755
756         m_force = 0;
757 #if defined(__LP64__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101003
758         int stage = eventIsPressureEvent ? event.stage : correspondingPressureEvent.stage;
759         double pressure = eventIsPressureEvent ? event.pressure : correspondingPressureEvent.pressure;
760         m_force = pressure + stage;
761 #endif
762
763         // Mac specific
764         m_modifierFlags = [event modifierFlags];
765         m_eventNumber = [event eventNumber];
766         m_menuTypeForEvent = typeForEvent(event);
767     }
768 };
769
770 PlatformMouseEvent PlatformEventFactory::createPlatformMouseEvent(NSEvent *event, NSEvent *correspondingPressureEvent, NSView *windowView)
771 {
772     return PlatformMouseEventBuilder(event, correspondingPressureEvent, windowView);
773 }
774
775
776 class PlatformWheelEventBuilder : public PlatformWheelEvent {
777 public:
778     PlatformWheelEventBuilder(NSEvent *event, NSView *windowView)
779     {
780         // PlatformEvent
781         m_type = PlatformEvent::Wheel;
782         m_modifiers = modifiersForEvent(event);
783         m_timestamp = eventTimeStampSince1970(event);
784
785         // PlatformWheelEvent
786         m_position = pointForEvent(event, windowView);
787         m_globalPosition = IntPoint(globalPointForEvent(event));
788         m_granularity = ScrollByPixelWheelEvent;
789
790         BOOL continuous;
791         getWheelEventDeltas(event, m_deltaX, m_deltaY, continuous);
792         if (continuous) {
793             m_wheelTicksX = m_deltaX / static_cast<float>(Scrollbar::pixelsPerLineStep());
794             m_wheelTicksY = m_deltaY / static_cast<float>(Scrollbar::pixelsPerLineStep());
795         } else {
796             m_wheelTicksX = m_deltaX;
797             m_wheelTicksY = m_deltaY;
798             m_deltaX *= static_cast<float>(Scrollbar::pixelsPerLineStep());
799             m_deltaY *= static_cast<float>(Scrollbar::pixelsPerLineStep());
800         }
801
802         m_phase = phaseForEvent(event);
803         m_momentumPhase = momentumPhaseForEvent(event);
804         m_hasPreciseScrollingDeltas = continuous;
805         m_directionInvertedFromDevice = [event isDirectionInvertedFromDevice];
806     }
807 };
808
809 PlatformWheelEvent PlatformEventFactory::createPlatformWheelEvent(NSEvent *event, NSView *windowView)
810 {
811     return PlatformWheelEventBuilder(event, windowView);
812 }
813
814
815 class PlatformKeyboardEventBuilder : public PlatformKeyboardEvent {
816 public:
817     PlatformKeyboardEventBuilder(NSEvent *event)
818     {
819         // PlatformEvent
820         m_type = isKeyUpEvent(event) ? PlatformEvent::KeyUp : PlatformEvent::KeyDown;
821         m_modifiers = modifiersForEvent(event);
822         m_timestamp = eventTimeStampSince1970(event);
823
824         // PlatformKeyboardEvent
825         m_text = textFromEvent(event);
826         m_unmodifiedText = unmodifiedTextFromEvent(event);
827         m_keyIdentifier = keyIdentifierForKeyEvent(event);
828         m_key = keyForKeyEvent(event);
829         m_code = codeForKeyEvent(event);
830         m_windowsVirtualKeyCode = windowsKeyCodeForKeyEvent(event);
831         m_autoRepeat = [event type] != NSEventTypeFlagsChanged && [event isARepeat];
832         m_isKeypad = isKeypadEvent(event);
833         m_isSystemKey = false; // SystemKey is always false on the Mac.
834
835         // Always use 13 for Enter/Return -- we don't want to use AppKit's different character for Enter.
836         if (m_windowsVirtualKeyCode == VK_RETURN) {
837             m_text = "\r";
838             m_unmodifiedText = "\r";
839         }
840
841         // AppKit sets text to "\x7F" for backspace, but the correct KeyboardEvent character code is 8.
842         if (m_windowsVirtualKeyCode == VK_BACK) {
843             m_text = "\x8";
844             m_unmodifiedText = "\x8";
845         }
846
847         // Always use 9 for Tab -- we don't want to use AppKit's different character for shift-tab.
848         if (m_windowsVirtualKeyCode == VK_TAB) {
849             m_text = "\x9";
850             m_unmodifiedText = "\x9";
851         }
852
853         // Mac specific.
854         m_macEvent = event;
855     }
856 };
857
858 PlatformKeyboardEvent PlatformEventFactory::createPlatformKeyboardEvent(NSEvent *event)
859 {
860     return PlatformKeyboardEventBuilder(event);
861 }
862
863 } // namespace WebCore
864
865 #endif // PLATFORM(MAC)