• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2006, 2007, 2008, 2009 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 COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "EventHandler.h"
28
29#include "AXObjectCache.h"
30#include "BlockExceptions.h"
31#include "ChromeClient.h"
32#include "ClipboardMac.h"
33#include "DragController.h"
34#include "EventNames.h"
35#include "FocusController.h"
36#include "FrameLoader.h"
37#include "Frame.h"
38#include "FrameView.h"
39#include "KeyboardEvent.h"
40#include "MouseEventWithHitTestResults.h"
41#include "Page.h"
42#include "PlatformKeyboardEvent.h"
43#include "PlatformWheelEvent.h"
44#include "RenderWidget.h"
45#include "RuntimeApplicationChecks.h"
46#include "Scrollbar.h"
47#include "Settings.h"
48#include "WebCoreSystemInterface.h"
49#include <objc/objc-runtime.h>
50#include <wtf/StdLibExtras.h>
51
52#if !(defined(OBJC_API_VERSION) && OBJC_API_VERSION > 0)
53static inline IMP method_setImplementation(Method m, IMP i)
54{
55    IMP oi = m->method_imp;
56    m->method_imp = i;
57    return oi;
58}
59#endif
60
61namespace WebCore {
62
63const double EventHandler::TextDragDelay = 0.15;
64
65static RetainPtr<NSEvent>& currentNSEventSlot()
66{
67    DEFINE_STATIC_LOCAL(RetainPtr<NSEvent>, event, ());
68    return event;
69}
70
71NSEvent *EventHandler::currentNSEvent()
72{
73    return currentNSEventSlot().get();
74}
75
76class CurrentEventScope : public Noncopyable {
77public:
78    CurrentEventScope(NSEvent *);
79    ~CurrentEventScope();
80
81private:
82    RetainPtr<NSEvent> m_savedCurrentEvent;
83#ifndef NDEBUG
84    RetainPtr<NSEvent> m_event;
85#endif
86};
87
88inline CurrentEventScope::CurrentEventScope(NSEvent *event)
89    : m_savedCurrentEvent(currentNSEventSlot())
90#ifndef NDEBUG
91    , m_event(event)
92#endif
93{
94    currentNSEventSlot() = event;
95}
96
97inline CurrentEventScope::~CurrentEventScope()
98{
99    ASSERT(currentNSEventSlot() == m_event);
100    currentNSEventSlot() = m_savedCurrentEvent;
101}
102
103bool EventHandler::wheelEvent(NSEvent *event)
104{
105    Page* page = m_frame->page();
106    if (!page)
107        return false;
108
109    CurrentEventScope scope(event);
110
111    m_useLatchedWheelEventNode = wkIsLatchingWheelEvent(event);
112
113    PlatformWheelEvent wheelEvent(event, page->chrome()->platformWindow());
114    handleWheelEvent(wheelEvent);
115
116    return wheelEvent.isAccepted();
117}
118
119PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const
120{
121    NSEvent *event = [NSApp currentEvent];
122    if (!event)
123        return 0;
124    switch ([event type]) {
125        case NSKeyDown: {
126            PlatformKeyboardEvent platformEvent(event);
127            platformEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown);
128            return KeyboardEvent::create(platformEvent, m_frame->document()->defaultView());
129        }
130        case NSKeyUp:
131            return KeyboardEvent::create(event, m_frame->document()->defaultView());
132        default:
133            return 0;
134    }
135}
136
137static inline bool isKeyboardOptionTab(KeyboardEvent* event)
138{
139    return event
140        && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
141        && event->altKey()
142        && event->keyIdentifier() == "U+0009";
143}
144
145bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const
146{
147    return isKeyboardOptionTab(event);
148}
149
150bool EventHandler::tabsToAllControls(KeyboardEvent* event) const
151{
152    Page* page = m_frame->page();
153    if (!page)
154        return false;
155
156    KeyboardUIMode keyboardUIMode = page->chrome()->client()->keyboardUIMode();
157    bool handlingOptionTab = isKeyboardOptionTab(event);
158
159    // If tab-to-links is off, option-tab always highlights all controls
160    if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab)
161        return true;
162
163    // If system preferences say to include all controls, we always include all controls
164    if (keyboardUIMode & KeyboardAccessFull)
165        return true;
166
167    // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab.
168    if (keyboardUIMode & KeyboardAccessTabsToLinks)
169        return !handlingOptionTab;
170
171    return handlingOptionTab;
172}
173
174bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
175{
176    Document* document = m_frame->document();
177
178    // RSS view needs arrow key keypress events.
179    if (applicationIsSafari() && document->url().protocolIs("feed") || document->url().protocolIs("feeds"))
180        return true;
181    Settings* settings = m_frame->settings();
182    if (!settings)
183        return false;
184
185#if ENABLE(DASHBOARD_SUPPORT)
186    if (settings->usesDashboardBackwardCompatibilityMode())
187        return true;
188#endif
189
190    if (settings->needsKeyboardEventDisambiguationQuirks())
191        return true;
192
193    return false;
194}
195
196bool EventHandler::keyEvent(NSEvent *event)
197{
198    BEGIN_BLOCK_OBJC_EXCEPTIONS;
199
200    ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
201
202    CurrentEventScope scope(event);
203    return keyEvent(PlatformKeyboardEvent(event));
204
205    END_BLOCK_OBJC_EXCEPTIONS;
206
207    return false;
208}
209
210void EventHandler::focusDocumentView()
211{
212    Page* page = m_frame->page();
213    if (!page)
214        return;
215
216    if (FrameView* frameView = m_frame->view()) {
217        if (NSView *documentView = frameView->documentView())
218            page->chrome()->focusNSView(documentView);
219    }
220
221    page->focusController()->setFocusedFrame(m_frame);
222}
223
224bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
225{
226    // Figure out which view to send the event to.
227    RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
228    if (!target || !target->isWidget())
229        return false;
230
231    // Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget will
232    // just pass currentEvent down to the widget, we don't want to call it for events that
233    // don't correspond to Cocoa events.  The mousedown/ups will have already been passed on as
234    // part of the pressed/released handling.
235    return passMouseDownEventToWidget(toRenderWidget(target)->widget());
236}
237
238bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
239{
240    return passMouseDownEventToWidget(renderWidget->widget());
241}
242
243static bool lastEventIsMouseUp()
244{
245    // Many AppKit widgets run their own event loops and consume events while the mouse is down.
246    // When they finish, currentEvent is the mouseUp that they exited on. We need to update
247    // the WebCore state with this mouseUp, which we never saw. This method lets us detect
248    // that state. Handling this was critical when we used AppKit widgets for form elements.
249    // It's not clear in what cases this is helpful now -- it's possible it can be removed.
250
251    BEGIN_BLOCK_OBJC_EXCEPTIONS;
252    NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
253    return EventHandler::currentNSEvent() != currentEventAfterHandlingMouseDown
254        && [currentEventAfterHandlingMouseDown type] == NSLeftMouseUp
255        && [currentEventAfterHandlingMouseDown timestamp] >= [EventHandler::currentNSEvent() timestamp];
256    END_BLOCK_OBJC_EXCEPTIONS;
257
258    return false;
259}
260
261bool EventHandler::passMouseDownEventToWidget(Widget* pWidget)
262{
263    // FIXME: This function always returns true. It should be changed either to return
264    // false in some cases or the return value should be removed.
265
266    RefPtr<Widget> widget = pWidget;
267
268    if (!widget) {
269        LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
270        return true;
271    }
272
273    BEGIN_BLOCK_OBJC_EXCEPTIONS;
274
275    NSView *nodeView = widget->platformWidget();
276    ASSERT(nodeView);
277    ASSERT([nodeView superview]);
278    NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
279    if (!view) {
280        // We probably hit the border of a RenderWidget
281        return true;
282    }
283
284    Page* page = m_frame->page();
285    if (!page)
286        return true;
287
288    if (page->chrome()->client()->firstResponder() != view) {
289        // Normally [NSWindow sendEvent:] handles setting the first responder.
290        // But in our case, the event was sent to the view representing the entire web page.
291        if ([currentNSEvent() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey])
292            page->chrome()->client()->makeFirstResponder(view);
293    }
294
295    // We need to "defer loading" while tracking the mouse, because tearing down the
296    // page while an AppKit control is tracking the mouse can cause a crash.
297
298    // FIXME: In theory, WebCore now tolerates tear-down while tracking the
299    // mouse. We should confirm that, and then remove the deferrsLoading
300    // hack entirely.
301
302    bool wasDeferringLoading = page->defersLoading();
303    if (!wasDeferringLoading)
304        page->setDefersLoading(true);
305
306    ASSERT(!m_sendingEventToSubview);
307    m_sendingEventToSubview = true;
308    NSView *outerView = widget->getOuterView();
309    widget->beforeMouseDown(outerView, widget.get());
310    [view mouseDown:currentNSEvent()];
311    widget->afterMouseDown(outerView, widget.get());
312    m_sendingEventToSubview = false;
313
314    if (!wasDeferringLoading)
315        page->setDefersLoading(false);
316
317    // Remember which view we sent the event to, so we can direct the release event properly.
318    m_mouseDownView = view;
319    m_mouseDownWasInSubframe = false;
320
321    // Many AppKit widgets run their own event loops and consume events while the mouse is down.
322    // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
323    // the EventHandler state with this mouseUp, which we never saw.
324    // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There
325    // is a hole here if the widget consumes both the mouseUp and subsequent events.
326    if (lastEventIsMouseUp())
327        m_mousePressed = false;
328
329    END_BLOCK_OBJC_EXCEPTIONS;
330
331    return true;
332}
333
334// Note that this does the same kind of check as [target isDescendantOf:superview].
335// There are two differences: This is a lot slower because it has to walk the whole
336// tree, and this works in cases where the target has already been deallocated.
337static bool findViewInSubviews(NSView *superview, NSView *target)
338{
339    BEGIN_BLOCK_OBJC_EXCEPTIONS;
340    NSEnumerator *e = [[superview subviews] objectEnumerator];
341    NSView *subview;
342    while ((subview = [e nextObject])) {
343        if (subview == target || findViewInSubviews(subview, target)) {
344            return true;
345        }
346    }
347    END_BLOCK_OBJC_EXCEPTIONS;
348
349    return false;
350}
351
352NSView *EventHandler::mouseDownViewIfStillGood()
353{
354    // Since we have no way of tracking the lifetime of m_mouseDownView, we have to assume that
355    // it could be deallocated already. We search for it in our subview tree; if we don't find
356    // it, we set it to nil.
357    NSView *mouseDownView = m_mouseDownView;
358    if (!mouseDownView) {
359        return nil;
360    }
361    FrameView* topFrameView = m_frame->view();
362    NSView *topView = topFrameView ? topFrameView->platformWidget() : nil;
363    if (!topView || !findViewInSubviews(topView, mouseDownView)) {
364        m_mouseDownView = nil;
365        return nil;
366    }
367    return mouseDownView;
368}
369
370bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
371{
372    return m_activationEventNumber == event.eventNumber();
373}
374
375bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
376{
377    NSView *view = mouseDownViewIfStillGood();
378
379    if (!view)
380        return false;
381
382    if (!m_mouseDownWasInSubframe) {
383        ASSERT(!m_sendingEventToSubview);
384        m_sendingEventToSubview = true;
385        BEGIN_BLOCK_OBJC_EXCEPTIONS;
386        [view mouseDragged:currentNSEvent()];
387        END_BLOCK_OBJC_EXCEPTIONS;
388        m_sendingEventToSubview = false;
389    }
390
391    return true;
392}
393
394PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
395{
396    NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
397    // Must be done before ondragstart adds types and data to the pboard,
398    // also done for security, as it erases data from the last drag
399    [pasteboard declareTypes:[NSArray array] owner:nil];
400    return ClipboardMac::create(true, pasteboard, ClipboardWritable, m_frame);
401}
402
403bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
404{
405    NSView *view = mouseDownViewIfStillGood();
406    if (!view)
407        return false;
408
409    if (!m_mouseDownWasInSubframe) {
410        ASSERT(!m_sendingEventToSubview);
411        m_sendingEventToSubview = true;
412        BEGIN_BLOCK_OBJC_EXCEPTIONS;
413        [view mouseUp:currentNSEvent()];
414        END_BLOCK_OBJC_EXCEPTIONS;
415        m_sendingEventToSubview = false;
416    }
417
418    return true;
419}
420
421bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult* hoveredNode)
422{
423    BEGIN_BLOCK_OBJC_EXCEPTIONS;
424
425    switch ([currentNSEvent() type]) {
426        case NSLeftMouseDragged:
427        case NSOtherMouseDragged:
428        case NSRightMouseDragged:
429            // This check is bogus and results in <rdar://6813830>, but removing it breaks a number of
430            // layout tests.
431            if (!m_mouseDownWasInSubframe)
432                return false;
433            if (subframe->page()->dragController()->didInitiateDrag())
434                return false;
435        case NSMouseMoved:
436            // Since we're passing in currentNSEvent() here, we can call
437            // handleMouseMoveEvent() directly, since the save/restore of
438            // currentNSEvent() that mouseMoved() does would have no effect.
439            ASSERT(!m_sendingEventToSubview);
440            m_sendingEventToSubview = true;
441            subframe->eventHandler()->handleMouseMoveEvent(currentPlatformMouseEvent(), hoveredNode);
442            m_sendingEventToSubview = false;
443            return true;
444
445        case NSLeftMouseDown: {
446            Node* node = event.targetNode();
447            if (!node)
448                return false;
449            RenderObject* renderer = node->renderer();
450            if (!renderer || !renderer->isWidget())
451                return false;
452            Widget* widget = toRenderWidget(renderer)->widget();
453            if (!widget || !widget->isFrameView())
454                return false;
455            if (!passWidgetMouseDownEventToWidget(toRenderWidget(renderer)))
456                return false;
457            m_mouseDownWasInSubframe = true;
458            return true;
459        }
460        case NSLeftMouseUp: {
461            if (!m_mouseDownWasInSubframe)
462                return false;
463            ASSERT(!m_sendingEventToSubview);
464            m_sendingEventToSubview = true;
465            subframe->eventHandler()->handleMouseReleaseEvent(currentPlatformMouseEvent());
466            m_sendingEventToSubview = false;
467            return true;
468        }
469        default:
470            return false;
471    }
472    END_BLOCK_OBJC_EXCEPTIONS;
473
474    return false;
475}
476
477static IMP originalNSScrollViewScrollWheel;
478static bool _nsScrollViewScrollWheelShouldRetainSelf;
479static void selfRetainingNSScrollViewScrollWheel(NSScrollView *, SEL, NSEvent *);
480
481static bool nsScrollViewScrollWheelShouldRetainSelf()
482{
483    ASSERT(isMainThread());
484
485    return _nsScrollViewScrollWheelShouldRetainSelf;
486}
487
488static void setNSScrollViewScrollWheelShouldRetainSelf(bool shouldRetain)
489{
490    ASSERT(isMainThread());
491
492    if (!originalNSScrollViewScrollWheel) {
493        Method method = class_getInstanceMethod(objc_getRequiredClass("NSScrollView"), @selector(scrollWheel:));
494        originalNSScrollViewScrollWheel = method_setImplementation(method, reinterpret_cast<IMP>(selfRetainingNSScrollViewScrollWheel));
495    }
496
497    _nsScrollViewScrollWheelShouldRetainSelf = shouldRetain;
498}
499
500static void selfRetainingNSScrollViewScrollWheel(NSScrollView *self, SEL selector, NSEvent *event)
501{
502    bool shouldRetainSelf = isMainThread() && nsScrollViewScrollWheelShouldRetainSelf();
503
504    if (shouldRetainSelf)
505        [self retain];
506    originalNSScrollViewScrollWheel(self, selector, event);
507    if (shouldRetainSelf)
508        [self release];
509}
510
511bool EventHandler::passWheelEventToWidget(PlatformWheelEvent&, Widget* widget)
512{
513    BEGIN_BLOCK_OBJC_EXCEPTIONS;
514
515    if ([currentNSEvent() type] != NSScrollWheel || m_sendingEventToSubview || !widget)
516        return false;
517
518    NSView* nodeView = widget->platformWidget();
519    ASSERT(nodeView);
520    ASSERT([nodeView superview]);
521    NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
522    if (!view)
523        // We probably hit the border of a RenderWidget
524        return false;
525
526    ASSERT(!m_sendingEventToSubview);
527    m_sendingEventToSubview = true;
528    // Work around <rdar://problem/6806810> which can cause -[NSScrollView scrollWheel:] to
529    // crash if the NSScrollView is released during timer or network callback dispatch
530    // in the nested tracking runloop that -[NSScrollView scrollWheel:] runs.
531    setNSScrollViewScrollWheelShouldRetainSelf(true);
532    [view scrollWheel:currentNSEvent()];
533    setNSScrollViewScrollWheelShouldRetainSelf(false);
534    m_sendingEventToSubview = false;
535    return true;
536
537    END_BLOCK_OBJC_EXCEPTIONS;
538    return false;
539}
540
541void EventHandler::mouseDown(NSEvent *event)
542{
543    FrameView* v = m_frame->view();
544    if (!v || m_sendingEventToSubview)
545        return;
546
547    BEGIN_BLOCK_OBJC_EXCEPTIONS;
548
549    m_frame->loader()->resetMultipleFormSubmissionProtection();
550
551    m_mouseDownView = nil;
552
553    CurrentEventScope scope(event);
554
555    handleMousePressEvent(currentPlatformMouseEvent());
556
557    END_BLOCK_OBJC_EXCEPTIONS;
558}
559
560void EventHandler::mouseDragged(NSEvent *event)
561{
562    FrameView* v = m_frame->view();
563    if (!v || m_sendingEventToSubview)
564        return;
565
566    BEGIN_BLOCK_OBJC_EXCEPTIONS;
567
568    CurrentEventScope scope(event);
569    handleMouseMoveEvent(currentPlatformMouseEvent());
570
571    END_BLOCK_OBJC_EXCEPTIONS;
572}
573
574void EventHandler::mouseUp(NSEvent *event)
575{
576    FrameView* v = m_frame->view();
577    if (!v || m_sendingEventToSubview)
578        return;
579
580    BEGIN_BLOCK_OBJC_EXCEPTIONS;
581
582    CurrentEventScope scope(event);
583
584    // Our behavior here is a little different that Qt. Qt always sends
585    // a mouse release event, even for a double click. To correct problems
586    // in khtml's DOM click event handling we do not send a release here
587    // for a double click. Instead we send that event from FrameView's
588    // handleMouseDoubleClickEvent. Note also that the third click of
589    // a triple click is treated as a single click, but the fourth is then
590    // treated as another double click. Hence the "% 2" below.
591    int clickCount = [event clickCount];
592    if (clickCount > 0 && clickCount % 2 == 0)
593        handleMouseDoubleClickEvent(currentPlatformMouseEvent());
594    else
595        handleMouseReleaseEvent(currentPlatformMouseEvent());
596
597    m_mouseDownView = nil;
598
599    END_BLOCK_OBJC_EXCEPTIONS;
600}
601
602/*
603 A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
604 eats all subsequent events after it is starts its modal tracking loop.  After the interaction
605 is done, this routine is used to fix things up.  When a mouse down started us tracking in
606 the widget, we post a fake mouse up to balance the mouse down we started with. When a
607 key down started us tracking in the widget, we post a fake key up to balance things out.
608 In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to
609 be over after the tracking is done.
610 */
611void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
612{
613    FrameView* view = m_frame->view();
614    if (!view)
615        return;
616
617    BEGIN_BLOCK_OBJC_EXCEPTIONS;
618
619    m_sendingEventToSubview = false;
620    int eventType = [initiatingEvent type];
621    if (eventType == NSLeftMouseDown || eventType == NSKeyDown) {
622        NSEvent *fakeEvent = nil;
623        if (eventType == NSLeftMouseDown) {
624            fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
625                                           location:[initiatingEvent locationInWindow]
626                                      modifierFlags:[initiatingEvent modifierFlags]
627                                          timestamp:[initiatingEvent timestamp]
628                                       windowNumber:[initiatingEvent windowNumber]
629                                            context:[initiatingEvent context]
630                                        eventNumber:[initiatingEvent eventNumber]
631                                         clickCount:[initiatingEvent clickCount]
632                                           pressure:[initiatingEvent pressure]];
633
634            [NSApp postEvent:fakeEvent atStart:YES];
635        } else { // eventType == NSKeyDown
636            fakeEvent = [NSEvent keyEventWithType:NSKeyUp
637                                         location:[initiatingEvent locationInWindow]
638                                    modifierFlags:[initiatingEvent modifierFlags]
639                                        timestamp:[initiatingEvent timestamp]
640                                     windowNumber:[initiatingEvent windowNumber]
641                                          context:[initiatingEvent context]
642                                       characters:[initiatingEvent characters]
643                      charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers]
644                                        isARepeat:[initiatingEvent isARepeat]
645                                          keyCode:[initiatingEvent keyCode]];
646            [NSApp postEvent:fakeEvent atStart:YES];
647        }
648        // FIXME: We should really get the current modifierFlags here, but there's no way to poll
649        // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
650        // no up-to-date cache of them anywhere.
651        fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
652                                       location:[[view->platformWidget() window] convertScreenToBase:[NSEvent mouseLocation]]
653                                  modifierFlags:[initiatingEvent modifierFlags]
654                                      timestamp:[initiatingEvent timestamp]
655                                   windowNumber:[initiatingEvent windowNumber]
656                                        context:[initiatingEvent context]
657                                    eventNumber:0
658                                     clickCount:0
659                                       pressure:0];
660        [NSApp postEvent:fakeEvent atStart:YES];
661    }
662
663    END_BLOCK_OBJC_EXCEPTIONS;
664}
665
666void EventHandler::mouseMoved(NSEvent *event)
667{
668    // Reject a mouse moved if the button is down - screws up tracking during autoscroll
669    // These happen because WebKit sometimes has to fake up moved events.
670    if (!m_frame->view() || m_mousePressed || m_sendingEventToSubview)
671        return;
672
673    BEGIN_BLOCK_OBJC_EXCEPTIONS;
674    CurrentEventScope scope(event);
675    mouseMoved(currentPlatformMouseEvent());
676    END_BLOCK_OBJC_EXCEPTIONS;
677}
678
679bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
680{
681    return passSubframeEventToSubframe(mev, subframe);
682}
683
684bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
685{
686    return passSubframeEventToSubframe(mev, subframe, hoveredNode);
687}
688
689bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
690{
691    return passSubframeEventToSubframe(mev, subframe);
692}
693
694unsigned EventHandler::accessKeyModifiers()
695{
696    // Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled.
697    // So, we use Control in this case, even though it conflicts with Emacs-style key bindings.
698    // See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail.
699    if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
700        return PlatformKeyboardEvent::CtrlKey;
701
702    return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey;
703}
704
705PlatformMouseEvent EventHandler::currentPlatformMouseEvent() const
706{
707    NSView *windowView = nil;
708    if (Page* page = m_frame->page())
709        windowView = page->chrome()->platformWindow();
710    return PlatformMouseEvent(currentNSEvent(), windowView);
711}
712
713bool EventHandler::sendContextMenuEvent(NSEvent *event)
714{
715    Page* page = m_frame->page();
716    if (!page)
717        return false;
718    return sendContextMenuEvent(PlatformMouseEvent(event, page->chrome()->platformWindow()));
719}
720
721bool EventHandler::eventMayStartDrag(NSEvent *event)
722{
723    Page* page = m_frame->page();
724    if (!page)
725        return false;
726    return eventMayStartDrag(PlatformMouseEvent(event, page->chrome()->platformWindow()));
727}
728
729}
730