Safari clears selection when its window gets activated via mouse down
[WebKit-https.git] / Source / WebKit2 / Shared / mac / WebEventFactory.mm
1 /*
2  * Copyright (C) 2010, 2011, 2013 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 #import "config.h"
27 #import "WebEventFactory.h"
28
29 #if USE(APPKIT)
30
31 #import "WebKitSystemInterface.h"
32 #import <WebCore/KeyboardEvent.h>
33 #import <WebCore/PlatformEventFactoryMac.h>
34 #import <WebCore/Scrollbar.h>
35 #import <WebCore/WindowsKeyboardCodes.h>
36 #import <wtf/ASCIICType.h>
37
38
39 using namespace WebCore;
40
41 @interface NSEvent (WebNSEventDetails)
42 - (NSInteger)_scrollCount;
43 - (CGFloat)_unacceleratedScrollingDeltaX;
44 - (CGFloat)_unacceleratedScrollingDeltaY;
45 @end
46
47 namespace WebKit {
48
49 // FIXME: This is a huge copy/paste from WebCore/PlatformEventFactoryMac.mm. The code should be merged.
50
51 static WebMouseEvent::Button currentMouseButton()
52 {
53     NSUInteger pressedMouseButtons = [NSEvent pressedMouseButtons];
54     if (!pressedMouseButtons)
55         return WebMouseEvent::NoButton;
56     if (pressedMouseButtons == 1 << 0)
57         return WebMouseEvent::LeftButton;
58     if (pressedMouseButtons == 1 << 1)
59         return WebMouseEvent::RightButton;
60     return WebMouseEvent::MiddleButton;
61 }
62
63 static WebMouseEvent::Button mouseButtonForEvent(NSEvent *event)
64 {
65     switch ([event type]) {
66         case NSLeftMouseDown:
67         case NSLeftMouseUp:
68         case NSLeftMouseDragged:
69             return WebMouseEvent::LeftButton;
70         case NSRightMouseDown:
71         case NSRightMouseUp:
72         case NSRightMouseDragged:
73             return WebMouseEvent::RightButton;
74         case NSOtherMouseDown:
75         case NSOtherMouseUp:
76         case NSOtherMouseDragged:
77             return WebMouseEvent::MiddleButton;
78         case NSMouseEntered:
79         case NSMouseExited:
80             return currentMouseButton();
81         default:
82             return WebMouseEvent::NoButton;
83     }
84 }
85
86 static WebEvent::Type mouseEventTypeForEvent(NSEvent* event)
87 {
88     switch ([event type]) {
89         case NSLeftMouseDragged:
90         case NSMouseEntered:
91         case NSMouseExited:
92         case NSMouseMoved:
93         case NSOtherMouseDragged:
94         case NSRightMouseDragged:
95             return WebEvent::MouseMove;
96         case NSLeftMouseDown:
97         case NSRightMouseDown:
98         case NSOtherMouseDown:
99             return WebEvent::MouseDown;
100         case NSLeftMouseUp:
101         case NSRightMouseUp:
102         case NSOtherMouseUp:
103             return WebEvent::MouseUp;
104         default:
105             return WebEvent::MouseMove;
106     }
107 }
108
109 static int clickCountForEvent(NSEvent *event)
110 {
111     switch ([event type]) {
112         case NSLeftMouseDown:
113         case NSLeftMouseUp:
114         case NSLeftMouseDragged:
115         case NSRightMouseDown:
116         case NSRightMouseUp:
117         case NSRightMouseDragged:
118         case NSOtherMouseDown:
119         case NSOtherMouseUp:
120         case NSOtherMouseDragged:
121             return [event clickCount];
122         default:
123             return 0;
124     }
125 }
126
127 static NSScreen *screenForWindow(NSWindow *window)
128 {
129     NSScreen *screen = [window screen]; // nil if the window is off-screen
130     if (screen)
131         return screen;
132     
133     NSArray *screens = [NSScreen screens];
134     if ([screens count] > 0)
135         return [screens objectAtIndex:0]; // screen containing the menubar
136     
137     return nil;
138 }
139
140 static NSPoint flipScreenPoint(const NSPoint& screenPoint, NSScreen *screen)
141 {
142     NSPoint flippedPoint = screenPoint;
143     flippedPoint.y = NSMaxY([screen frame]) - flippedPoint.y;
144     return flippedPoint;
145 }
146
147 static NSPoint globalPoint(const NSPoint& windowPoint, NSWindow *window)
148 {
149 #pragma clang diagnostic push
150 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
151     return flipScreenPoint([window convertBaseToScreen:windowPoint], screenForWindow(window));
152 #pragma clang diagnostic pop
153 }
154
155 static NSPoint globalPointForEvent(NSEvent *event)
156 {
157     switch ([event type]) {
158         case NSLeftMouseDown:
159         case NSLeftMouseDragged:
160         case NSLeftMouseUp:
161         case NSMouseEntered:
162         case NSMouseExited:
163         case NSMouseMoved:
164         case NSOtherMouseDown:
165         case NSOtherMouseDragged:
166         case NSOtherMouseUp:
167         case NSRightMouseDown:
168         case NSRightMouseDragged:
169         case NSRightMouseUp:
170         case NSScrollWheel:
171             return globalPoint([event locationInWindow], [event window]);
172         default:
173             return NSZeroPoint;
174     }
175 }
176
177 static NSPoint pointForEvent(NSEvent *event, NSView *windowView)
178 {
179     switch ([event type]) {
180         case NSLeftMouseDown:
181         case NSLeftMouseDragged:
182         case NSLeftMouseUp:
183         case NSMouseEntered:
184         case NSMouseExited:
185         case NSMouseMoved:
186         case NSOtherMouseDown:
187         case NSOtherMouseDragged:
188         case NSOtherMouseUp:
189         case NSRightMouseDown:
190         case NSRightMouseDragged:
191         case NSRightMouseUp:
192         case NSScrollWheel: {
193             // Note: This will have its origin at the bottom left of the window unless windowView is flipped.
194             // In those cases, the Y coordinate gets flipped by Widget::convertFromContainingWindow.
195             NSPoint location = [event locationInWindow];
196             if (windowView)
197                 location = [windowView convertPoint:location fromView:nil];
198             return location;
199         }
200         default:
201             return NSZeroPoint;
202     }
203 }
204
205 static WebWheelEvent::Phase phaseForEvent(NSEvent *event)
206 {
207     uint32_t phase = WebWheelEvent::PhaseNone;
208     if ([event phase] & NSEventPhaseBegan)
209         phase |= WebWheelEvent::PhaseBegan;
210     if ([event phase] & NSEventPhaseStationary)
211         phase |= WebWheelEvent::PhaseStationary;
212     if ([event phase] & NSEventPhaseChanged)
213         phase |= WebWheelEvent::PhaseChanged;
214     if ([event phase] & NSEventPhaseEnded)
215         phase |= WebWheelEvent::PhaseEnded;
216     if ([event phase] & NSEventPhaseCancelled)
217         phase |= WebWheelEvent::PhaseCancelled;
218     if ([event phase] & NSEventPhaseMayBegin)
219         phase |= WebWheelEvent::PhaseMayBegin;
220
221     return static_cast<WebWheelEvent::Phase>(phase);
222 }
223
224 static WebWheelEvent::Phase momentumPhaseForEvent(NSEvent *event)
225 {
226     uint32_t phase = WebWheelEvent::PhaseNone; 
227
228     if ([event momentumPhase] & NSEventPhaseBegan)
229         phase |= WebWheelEvent::PhaseBegan;
230     if ([event momentumPhase] & NSEventPhaseStationary)
231         phase |= WebWheelEvent::PhaseStationary;
232     if ([event momentumPhase] & NSEventPhaseChanged)
233         phase |= WebWheelEvent::PhaseChanged;
234     if ([event momentumPhase] & NSEventPhaseEnded)
235         phase |= WebWheelEvent::PhaseEnded;
236     if ([event momentumPhase] & NSEventPhaseCancelled)
237         phase |= WebWheelEvent::PhaseCancelled;
238
239     return static_cast<WebWheelEvent::Phase>(phase);
240 }
241
242 static inline String textFromEvent(NSEvent* event)
243 {
244     if ([event type] == NSFlagsChanged)
245         return emptyString();
246     return String([event characters]);
247 }
248
249 static inline String unmodifiedTextFromEvent(NSEvent* event)
250 {
251     if ([event type] == NSFlagsChanged)
252         return emptyString();
253     return String([event charactersIgnoringModifiers]);
254 }
255
256 static bool isKeypadEvent(NSEvent* event)
257 {
258     // Check that this is the type of event that has a keyCode.
259     switch ([event type]) {
260         case NSKeyDown:
261         case NSKeyUp:
262         case NSFlagsChanged:
263             break;
264         default:
265             return false;
266     }
267
268     switch ([event keyCode]) {
269         case 71: // Clear
270         case 81: // =
271         case 75: // /
272         case 67: // *
273         case 78: // -
274         case 69: // +
275         case 76: // Enter
276         case 65: // .
277         case 82: // 0
278         case 83: // 1
279         case 84: // 2
280         case 85: // 3
281         case 86: // 4
282         case 87: // 5
283         case 88: // 6
284         case 89: // 7
285         case 91: // 8
286         case 92: // 9
287             return true;
288      }
289      
290      return false;
291 }
292
293 static inline bool isKeyUpEvent(NSEvent *event)
294 {
295     if ([event type] != NSFlagsChanged)
296         return [event type] == NSKeyUp;
297     // FIXME: This logic fails if the user presses both Shift keys at once, for example:
298     // we treat releasing one of them as keyDown.
299     switch ([event keyCode]) {
300         case 54: // Right Command
301         case 55: // Left Command
302             return ([event modifierFlags] & NSCommandKeyMask) == 0;
303             
304         case 57: // Capslock
305             return ([event modifierFlags] & NSAlphaShiftKeyMask) == 0;
306             
307         case 56: // Left Shift
308         case 60: // Right Shift
309             return ([event modifierFlags] & NSShiftKeyMask) == 0;
310             
311         case 58: // Left Alt
312         case 61: // Right Alt
313             return ([event modifierFlags] & NSAlternateKeyMask) == 0;
314             
315         case 59: // Left Ctrl
316         case 62: // Right Ctrl
317             return ([event modifierFlags] & NSControlKeyMask) == 0;
318             
319         case 63: // Function
320             return ([event modifierFlags] & NSFunctionKeyMask) == 0;
321     }
322     return false;
323 }
324
325 static inline WebEvent::Modifiers modifiersForEvent(NSEvent *event)
326 {
327     unsigned modifiers = 0;
328     if ([event modifierFlags] & NSAlphaShiftKeyMask)
329         modifiers |= WebEvent::CapsLockKey;
330     if ([event modifierFlags] & NSShiftKeyMask)
331         modifiers |= WebEvent::ShiftKey;
332     if ([event modifierFlags] & NSControlKeyMask)
333         modifiers |= WebEvent::ControlKey;
334     if ([event modifierFlags] & NSAlternateKeyMask)
335         modifiers |= WebEvent::AltKey;
336     if ([event modifierFlags] & NSCommandKeyMask)
337         modifiers |= WebEvent::MetaKey;
338     return (WebEvent::Modifiers)modifiers;
339 }
340
341 WebMouseEvent WebEventFactory::createWebMouseEvent(NSEvent *event, NSView *windowView)
342 {
343     NSPoint position = pointForEvent(event, windowView);
344     NSPoint globalPosition = globalPointForEvent(event);
345
346     WebEvent::Type type                     = mouseEventTypeForEvent(event);
347     WebMouseEvent::Button button            = mouseButtonForEvent(event);
348     float deltaX                            = [event deltaX];
349     float deltaY                            = [event deltaY];
350     float deltaZ                            = [event deltaZ];
351     int clickCount                          = clickCountForEvent(event);
352     WebEvent::Modifiers modifiers           = modifiersForEvent(event);
353     double timestamp                        = eventTimeStampSince1970(event);
354     int eventNumber                         = [event eventNumber];
355
356     return WebMouseEvent(type, button, IntPoint(position), IntPoint(globalPosition), deltaX, deltaY, deltaZ, clickCount, modifiers, timestamp, eventNumber);
357 }
358
359 WebWheelEvent WebEventFactory::createWebWheelEvent(NSEvent *event, NSView *windowView)
360 {
361     NSPoint position = pointForEvent(event, windowView);
362     NSPoint globalPosition = globalPointForEvent(event);
363
364     BOOL continuous;
365     float deltaX = 0;
366     float deltaY = 0;
367     float wheelTicksX = 0;
368     float wheelTicksY = 0;
369
370     WKGetWheelEventDeltas(event, &deltaX, &deltaY, &continuous);
371     
372     if (continuous) {
373         // smooth scroll events
374         wheelTicksX = deltaX / static_cast<float>(Scrollbar::pixelsPerLineStep());
375         wheelTicksY = deltaY / static_cast<float>(Scrollbar::pixelsPerLineStep());
376     } else {
377         // plain old wheel events
378         wheelTicksX = deltaX;
379         wheelTicksY = deltaY;
380         deltaX *= static_cast<float>(Scrollbar::pixelsPerLineStep());
381         deltaY *= static_cast<float>(Scrollbar::pixelsPerLineStep());
382     }
383
384     WebWheelEvent::Granularity granularity  = WebWheelEvent::ScrollByPixelWheelEvent;
385     bool directionInvertedFromDevice        = [event isDirectionInvertedFromDevice];
386     WebWheelEvent::Phase phase              = phaseForEvent(event);
387     WebWheelEvent::Phase momentumPhase      = momentumPhaseForEvent(event);
388     bool hasPreciseScrollingDeltas          = continuous;
389
390     uint32_t scrollCount;
391     FloatSize unacceleratedScrollingDelta;
392
393     static bool nsEventSupportsScrollCount = [NSEvent instancesRespondToSelector:@selector(_scrollCount)];
394     if (nsEventSupportsScrollCount) {
395         scrollCount = [event _scrollCount];
396         unacceleratedScrollingDelta = FloatSize([event _unacceleratedScrollingDeltaX], [event _unacceleratedScrollingDeltaY]);
397     } else {
398         scrollCount = 0;
399         unacceleratedScrollingDelta = FloatSize(deltaX, deltaY);
400     }
401
402     WebEvent::Modifiers modifiers           = modifiersForEvent(event);
403     double timestamp                        = eventTimeStampSince1970(event);
404     
405     return WebWheelEvent(WebEvent::Wheel, IntPoint(position), IntPoint(globalPosition), FloatSize(deltaX, deltaY), FloatSize(wheelTicksX, wheelTicksY), granularity, directionInvertedFromDevice, phase, momentumPhase, hasPreciseScrollingDeltas, scrollCount, unacceleratedScrollingDelta, modifiers, timestamp);
406 }
407
408 WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(NSEvent *event, bool handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands)
409 {
410     WebEvent::Type type             = isKeyUpEvent(event) ? WebEvent::KeyUp : WebEvent::KeyDown;
411     String text                     = textFromEvent(event);
412     String unmodifiedText           = unmodifiedTextFromEvent(event);
413     String keyIdentifier            = keyIdentifierForKeyEvent(event);
414     int windowsVirtualKeyCode       = windowsKeyCodeForKeyEvent(event);
415     int nativeVirtualKeyCode        = [event keyCode];
416     int macCharCode                 = WKGetNSEventKeyChar(event);
417     bool autoRepeat                 = ([event type] != NSFlagsChanged) && [event isARepeat];
418     bool isKeypad                   = isKeypadEvent(event);
419     bool isSystemKey                = false; // SystemKey is always false on the Mac.
420     WebEvent::Modifiers modifiers   = modifiersForEvent(event);
421     double timestamp                = eventTimeStampSince1970(event);
422
423     // Always use 13 for Enter/Return -- we don't want to use AppKit's different character for Enter.
424     if (windowsVirtualKeyCode == VK_RETURN) {
425         text = "\r";
426         unmodifiedText = "\r";
427     }
428
429     // AppKit sets text to "\x7F" for backspace, but the correct KeyboardEvent character code is 8.
430     if (windowsVirtualKeyCode == VK_BACK) {
431         text = "\x8";
432         unmodifiedText = "\x8";
433     }
434
435     // Always use 9 for Tab -- we don't want to use AppKit's different character for shift-tab.
436     if (windowsVirtualKeyCode == VK_TAB) {
437         text = "\x9";
438         unmodifiedText = "\x9";
439     }
440
441     return WebKeyboardEvent(type, text, unmodifiedText, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, macCharCode, handledByInputMethod, commands, autoRepeat, isKeypad, isSystemKey, modifiers, timestamp);
442 }
443
444 } // namespace WebKit
445
446 #endif // USE(APPKIT)