2
* Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
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.
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.
27
#include "EventHandler.h"
29
#include "AXObjectCache.h"
30
#include "BlockExceptions.h"
32
#include "ChromeClient.h"
33
#include "ClipboardMac.h"
34
#include "DragController.h"
35
#include "EventNames.h"
36
#include "FocusController.h"
38
#include "FrameLoader.h"
39
#include "FrameView.h"
40
#include "KeyboardEvent.h"
41
#include "MouseEventWithHitTestResults.h"
42
#include "NotImplemented.h"
44
#include "Pasteboard.h"
45
#include "PlatformEventFactoryMac.h"
46
#include "RenderWidget.h"
47
#include "RuntimeApplicationChecks.h"
48
#include "Scrollbar.h"
50
#include "WebCoreSystemInterface.h"
51
#include <wtf/MainThread.h>
52
#include <wtf/ObjcRuntimeExtras.h>
53
#include <wtf/StdLibExtras.h>
57
#if ENABLE(DRAG_SUPPORT)
58
const double EventHandler::TextDragDelay = 0.15;
61
static RetainPtr<NSEvent>& currentNSEventSlot()
63
DEFINE_STATIC_LOCAL(RetainPtr<NSEvent>, event, ());
67
NSEvent *EventHandler::currentNSEvent()
69
return currentNSEventSlot().get();
72
class CurrentEventScope {
73
WTF_MAKE_NONCOPYABLE(CurrentEventScope);
75
CurrentEventScope(NSEvent *);
79
RetainPtr<NSEvent> m_savedCurrentEvent;
81
RetainPtr<NSEvent> m_event;
85
inline CurrentEventScope::CurrentEventScope(NSEvent *event)
86
: m_savedCurrentEvent(currentNSEventSlot())
91
currentNSEventSlot() = event;
94
inline CurrentEventScope::~CurrentEventScope()
96
ASSERT(currentNSEventSlot() == m_event);
97
currentNSEventSlot() = m_savedCurrentEvent;
100
bool EventHandler::wheelEvent(NSEvent *event)
102
Page* page = m_frame->page();
106
CurrentEventScope scope(event);
107
return handleWheelEvent(PlatformEventFactory::createPlatformWheelEvent(event, page->chrome()->platformPageClient()));
110
bool EventHandler::keyEvent(NSEvent *event)
112
BEGIN_BLOCK_OBJC_EXCEPTIONS;
114
ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
116
CurrentEventScope scope(event);
117
return keyEvent(PlatformEventFactory::createPlatformKeyboardEvent(event));
119
END_BLOCK_OBJC_EXCEPTIONS;
124
void EventHandler::focusDocumentView()
126
Page* page = m_frame->page();
130
if (FrameView* frameView = m_frame->view()) {
131
if (NSView *documentView = frameView->documentView())
132
page->chrome()->focusNSView(documentView);
135
page->focusController()->setFocusedFrame(m_frame);
138
bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
140
// Figure out which view to send the event to.
141
RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
142
if (!target || !target->isWidget())
145
// Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget will
146
// just pass currentEvent down to the widget, we don't want to call it for events that
147
// don't correspond to Cocoa events. The mousedown/ups will have already been passed on as
148
// part of the pressed/released handling.
149
return passMouseDownEventToWidget(toRenderWidget(target)->widget());
152
bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
154
return passMouseDownEventToWidget(renderWidget->widget());
157
static bool lastEventIsMouseUp()
159
// Many AppKit widgets run their own event loops and consume events while the mouse is down.
160
// When they finish, currentEvent is the mouseUp that they exited on. We need to update
161
// the WebCore state with this mouseUp, which we never saw. This method lets us detect
162
// that state. Handling this was critical when we used AppKit widgets for form elements.
163
// It's not clear in what cases this is helpful now -- it's possible it can be removed.
165
BEGIN_BLOCK_OBJC_EXCEPTIONS;
166
NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
167
return EventHandler::currentNSEvent() != currentEventAfterHandlingMouseDown
168
&& [currentEventAfterHandlingMouseDown type] == NSLeftMouseUp
169
&& [currentEventAfterHandlingMouseDown timestamp] >= [EventHandler::currentNSEvent() timestamp];
170
END_BLOCK_OBJC_EXCEPTIONS;
175
bool EventHandler::passMouseDownEventToWidget(Widget* pWidget)
177
// FIXME: This function always returns true. It should be changed either to return
178
// false in some cases or the return value should be removed.
180
RefPtr<Widget> widget = pWidget;
183
LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
187
// In WebKit2 we will never have an NSView. Just return early and let the regular event handler machinery take care of
188
// dispatching the event.
189
if (!widget->platformWidget())
192
BEGIN_BLOCK_OBJC_EXCEPTIONS;
194
NSView *nodeView = widget->platformWidget();
195
ASSERT([nodeView superview]);
196
NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
198
// We probably hit the border of a RenderWidget
202
Page* page = m_frame->page();
206
if (page->chrome()->client()->firstResponder() != view) {
207
// Normally [NSWindow sendEvent:] handles setting the first responder.
208
// But in our case, the event was sent to the view representing the entire web page.
209
if ([currentNSEvent() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey])
210
page->chrome()->client()->makeFirstResponder(view);
213
// We need to "defer loading" while tracking the mouse, because tearing down the
214
// page while an AppKit control is tracking the mouse can cause a crash.
216
// FIXME: In theory, WebCore now tolerates tear-down while tracking the
217
// mouse. We should confirm that, and then remove the deferrsLoading
220
bool wasDeferringLoading = page->defersLoading();
221
if (!wasDeferringLoading)
222
page->setDefersLoading(true);
224
ASSERT(!m_sendingEventToSubview);
225
m_sendingEventToSubview = true;
228
WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
229
[view mouseDown:currentNSEvent()];
232
m_sendingEventToSubview = false;
234
if (!wasDeferringLoading)
235
page->setDefersLoading(false);
237
// Remember which view we sent the event to, so we can direct the release event properly.
238
m_mouseDownView = view;
239
m_mouseDownWasInSubframe = false;
241
// Many AppKit widgets run their own event loops and consume events while the mouse is down.
242
// When they finish, currentEvent is the mouseUp that they exited on. We need to update
243
// the EventHandler state with this mouseUp, which we never saw.
244
// If this event isn't a mouseUp, we assume that the mouseUp will be coming later. There
245
// is a hole here if the widget consumes both the mouseUp and subsequent events.
246
if (lastEventIsMouseUp())
247
m_mousePressed = false;
249
END_BLOCK_OBJC_EXCEPTIONS;
254
// Note that this does the same kind of check as [target isDescendantOf:superview].
255
// There are two differences: This is a lot slower because it has to walk the whole
256
// tree, and this works in cases where the target has already been deallocated.
257
static bool findViewInSubviews(NSView *superview, NSView *target)
259
BEGIN_BLOCK_OBJC_EXCEPTIONS;
260
NSEnumerator *e = [[superview subviews] objectEnumerator];
262
while ((subview = [e nextObject])) {
263
if (subview == target || findViewInSubviews(subview, target)) {
267
END_BLOCK_OBJC_EXCEPTIONS;
272
NSView *EventHandler::mouseDownViewIfStillGood()
274
// Since we have no way of tracking the lifetime of m_mouseDownView, we have to assume that
275
// it could be deallocated already. We search for it in our subview tree; if we don't find
276
// it, we set it to nil.
277
NSView *mouseDownView = m_mouseDownView;
278
if (!mouseDownView) {
281
FrameView* topFrameView = m_frame->view();
282
NSView *topView = topFrameView ? topFrameView->platformWidget() : nil;
283
if (!topView || !findViewInSubviews(topView, mouseDownView)) {
284
m_mouseDownView = nil;
287
return mouseDownView;
290
#if ENABLE(DRAG_SUPPORT)
291
bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
293
NSView *view = mouseDownViewIfStillGood();
298
if (!m_mouseDownWasInSubframe) {
299
ASSERT(!m_sendingEventToSubview);
300
m_sendingEventToSubview = true;
301
BEGIN_BLOCK_OBJC_EXCEPTIONS;
302
[view mouseDragged:currentNSEvent()];
303
END_BLOCK_OBJC_EXCEPTIONS;
304
m_sendingEventToSubview = false;
309
#endif // ENABLE(DRAG_SUPPORT)
311
bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
313
NSView *view = mouseDownViewIfStillGood();
317
if (!m_mouseDownWasInSubframe) {
318
ASSERT(!m_sendingEventToSubview);
319
m_sendingEventToSubview = true;
320
BEGIN_BLOCK_OBJC_EXCEPTIONS;
321
[view mouseUp:currentNSEvent()];
322
END_BLOCK_OBJC_EXCEPTIONS;
323
m_sendingEventToSubview = false;
329
bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult* hoveredNode)
331
BEGIN_BLOCK_OBJC_EXCEPTIONS;
333
switch ([currentNSEvent() type]) {
334
case NSLeftMouseDragged:
335
case NSOtherMouseDragged:
336
case NSRightMouseDragged:
337
// This check is bogus and results in <rdar://6813830>, but removing it breaks a number of
339
if (!m_mouseDownWasInSubframe)
341
#if ENABLE(DRAG_SUPPORT)
342
if (subframe->page()->dragController()->didInitiateDrag())
346
// Since we're passing in currentNSEvent() here, we can call
347
// handleMouseMoveEvent() directly, since the save/restore of
348
// currentNSEvent() that mouseMoved() does would have no effect.
349
ASSERT(!m_sendingEventToSubview);
350
m_sendingEventToSubview = true;
351
subframe->eventHandler()->handleMouseMoveEvent(currentPlatformMouseEvent(), hoveredNode);
352
m_sendingEventToSubview = false;
355
case NSLeftMouseDown: {
356
Node* node = event.targetNode();
359
RenderObject* renderer = node->renderer();
360
if (!renderer || !renderer->isWidget())
362
Widget* widget = toRenderWidget(renderer)->widget();
363
if (!widget || !widget->isFrameView())
365
if (!passWidgetMouseDownEventToWidget(toRenderWidget(renderer)))
367
m_mouseDownWasInSubframe = true;
370
case NSLeftMouseUp: {
371
if (!m_mouseDownWasInSubframe)
373
ASSERT(!m_sendingEventToSubview);
374
m_sendingEventToSubview = true;
375
subframe->eventHandler()->handleMouseReleaseEvent(currentPlatformMouseEvent());
376
m_sendingEventToSubview = false;
382
END_BLOCK_OBJC_EXCEPTIONS;
387
static IMP originalNSScrollViewScrollWheel;
388
static bool _nsScrollViewScrollWheelShouldRetainSelf;
389
static void selfRetainingNSScrollViewScrollWheel(NSScrollView *, SEL, NSEvent *);
391
static bool nsScrollViewScrollWheelShouldRetainSelf()
393
ASSERT(isMainThread());
395
return _nsScrollViewScrollWheelShouldRetainSelf;
398
static void setNSScrollViewScrollWheelShouldRetainSelf(bool shouldRetain)
400
ASSERT(isMainThread());
402
if (!originalNSScrollViewScrollWheel) {
403
Method method = class_getInstanceMethod(objc_getRequiredClass("NSScrollView"), @selector(scrollWheel:));
404
originalNSScrollViewScrollWheel = method_setImplementation(method, reinterpret_cast<IMP>(selfRetainingNSScrollViewScrollWheel));
407
_nsScrollViewScrollWheelShouldRetainSelf = shouldRetain;
410
static void selfRetainingNSScrollViewScrollWheel(NSScrollView *self, SEL selector, NSEvent *event)
412
bool shouldRetainSelf = isMainThread() && nsScrollViewScrollWheelShouldRetainSelf();
414
if (shouldRetainSelf)
416
wtfCallIMP<void>(originalNSScrollViewScrollWheel, self, selector, event);
417
if (shouldRetainSelf)
421
bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget* widget)
423
BEGIN_BLOCK_OBJC_EXCEPTIONS;
428
NSView* nodeView = widget->platformWidget();
430
// WebKit2 code path.
431
if (!widget->isFrameView())
434
return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent);
437
if ([currentNSEvent() type] != NSScrollWheel || m_sendingEventToSubview)
441
ASSERT([nodeView superview]);
442
NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
444
// We probably hit the border of a RenderWidget
447
ASSERT(!m_sendingEventToSubview);
448
m_sendingEventToSubview = true;
449
// Work around <rdar://problem/6806810> which can cause -[NSScrollView scrollWheel:] to
450
// crash if the NSScrollView is released during timer or network callback dispatch
451
// in the nested tracking runloop that -[NSScrollView scrollWheel:] runs.
452
setNSScrollViewScrollWheelShouldRetainSelf(true);
453
[view scrollWheel:currentNSEvent()];
454
setNSScrollViewScrollWheelShouldRetainSelf(false);
455
m_sendingEventToSubview = false;
458
END_BLOCK_OBJC_EXCEPTIONS;
462
void EventHandler::mouseDown(NSEvent *event)
464
FrameView* v = m_frame->view();
465
if (!v || m_sendingEventToSubview)
468
BEGIN_BLOCK_OBJC_EXCEPTIONS;
470
m_mouseDownView = nil;
472
CurrentEventScope scope(event);
474
handleMousePressEvent(currentPlatformMouseEvent());
476
END_BLOCK_OBJC_EXCEPTIONS;
479
void EventHandler::mouseDragged(NSEvent *event)
481
FrameView* v = m_frame->view();
482
if (!v || m_sendingEventToSubview)
485
BEGIN_BLOCK_OBJC_EXCEPTIONS;
487
CurrentEventScope scope(event);
488
handleMouseMoveEvent(currentPlatformMouseEvent());
490
END_BLOCK_OBJC_EXCEPTIONS;
493
void EventHandler::mouseUp(NSEvent *event)
495
FrameView* v = m_frame->view();
496
if (!v || m_sendingEventToSubview)
499
BEGIN_BLOCK_OBJC_EXCEPTIONS;
501
CurrentEventScope scope(event);
503
// Our behavior here is a little different that Qt. Qt always sends
504
// a mouse release event, even for a double click. To correct problems
505
// in khtml's DOM click event handling we do not send a release here
506
// for a double click. Instead we send that event from FrameView's
507
// handleMouseDoubleClickEvent. Note also that the third click of
508
// a triple click is treated as a single click, but the fourth is then
509
// treated as another double click. Hence the "% 2" below.
510
int clickCount = [event clickCount];
511
if (clickCount > 0 && clickCount % 2 == 0)
512
handleMouseDoubleClickEvent(currentPlatformMouseEvent());
514
handleMouseReleaseEvent(currentPlatformMouseEvent());
516
m_mouseDownView = nil;
518
END_BLOCK_OBJC_EXCEPTIONS;
522
A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
523
eats all subsequent events after it is starts its modal tracking loop. After the interaction
524
is done, this routine is used to fix things up. When a mouse down started us tracking in
525
the widget, we post a fake mouse up to balance the mouse down we started with. When a
526
key down started us tracking in the widget, we post a fake key up to balance things out.
527
In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to
528
be over after the tracking is done.
530
void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
532
FrameView* view = m_frame->view();
536
BEGIN_BLOCK_OBJC_EXCEPTIONS;
538
m_sendingEventToSubview = false;
539
int eventType = [initiatingEvent type];
540
if (eventType == NSLeftMouseDown || eventType == NSKeyDown) {
541
NSEvent *fakeEvent = nil;
542
if (eventType == NSLeftMouseDown) {
543
fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
544
location:[initiatingEvent locationInWindow]
545
modifierFlags:[initiatingEvent modifierFlags]
546
timestamp:[initiatingEvent timestamp]
547
windowNumber:[initiatingEvent windowNumber]
548
context:[initiatingEvent context]
549
eventNumber:[initiatingEvent eventNumber]
550
clickCount:[initiatingEvent clickCount]
551
pressure:[initiatingEvent pressure]];
553
[NSApp postEvent:fakeEvent atStart:YES];
554
} else { // eventType == NSKeyDown
555
fakeEvent = [NSEvent keyEventWithType:NSKeyUp
556
location:[initiatingEvent locationInWindow]
557
modifierFlags:[initiatingEvent modifierFlags]
558
timestamp:[initiatingEvent timestamp]
559
windowNumber:[initiatingEvent windowNumber]
560
context:[initiatingEvent context]
561
characters:[initiatingEvent characters]
562
charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers]
563
isARepeat:[initiatingEvent isARepeat]
564
keyCode:[initiatingEvent keyCode]];
565
[NSApp postEvent:fakeEvent atStart:YES];
567
// FIXME: We should really get the current modifierFlags here, but there's no way to poll
568
// them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
569
// no up-to-date cache of them anywhere.
570
fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
571
location:[[view->platformWidget() window] convertScreenToBase:[NSEvent mouseLocation]]
572
modifierFlags:[initiatingEvent modifierFlags]
573
timestamp:[initiatingEvent timestamp]
574
windowNumber:[initiatingEvent windowNumber]
575
context:[initiatingEvent context]
579
[NSApp postEvent:fakeEvent atStart:YES];
582
END_BLOCK_OBJC_EXCEPTIONS;
585
void EventHandler::mouseMoved(NSEvent *event)
587
// Reject a mouse moved if the button is down - screws up tracking during autoscroll
588
// These happen because WebKit sometimes has to fake up moved events.
589
if (!m_frame->view() || m_mousePressed || m_sendingEventToSubview)
592
BEGIN_BLOCK_OBJC_EXCEPTIONS;
593
CurrentEventScope scope(event);
594
mouseMoved(currentPlatformMouseEvent());
595
END_BLOCK_OBJC_EXCEPTIONS;
598
void EventHandler::passMouseMovedEventToScrollbars(NSEvent *event)
600
// Reject a mouse moved if the button is down - screws up tracking during autoscroll
601
// These happen because WebKit sometimes has to fake up moved events.
602
if (!m_frame->view() || m_mousePressed || m_sendingEventToSubview)
605
BEGIN_BLOCK_OBJC_EXCEPTIONS;
606
CurrentEventScope scope(event);
607
passMouseMovedEventToScrollbars(currentPlatformMouseEvent());
608
END_BLOCK_OBJC_EXCEPTIONS;
611
static bool frameHasPlatformWidget(Frame* frame)
613
if (FrameView* frameView = frame->view()) {
614
if (frameView->platformWidget())
621
bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
623
// WebKit1 code path.
624
if (frameHasPlatformWidget(m_frame))
625
return passSubframeEventToSubframe(mev, subframe);
627
// WebKit2 code path.
628
subframe->eventHandler()->handleMousePressEvent(mev.event());
632
bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
634
// WebKit1 code path.
635
if (frameHasPlatformWidget(m_frame))
636
return passSubframeEventToSubframe(mev, subframe, hoveredNode);
638
#if ENABLE(DRAG_SUPPORT)
639
// WebKit2 code path.
640
if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
644
subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
648
bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
650
// WebKit1 code path.
651
if (frameHasPlatformWidget(m_frame))
652
return passSubframeEventToSubframe(mev, subframe);
654
// WebKit2 code path.
655
subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
659
PlatformMouseEvent EventHandler::currentPlatformMouseEvent() const
661
NSView *windowView = nil;
662
if (Page* page = m_frame->page())
663
windowView = page->chrome()->platformPageClient();
664
return PlatformEventFactory::createPlatformMouseEvent(currentNSEvent(), windowView);
667
bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
669
return m_activationEventNumber == event.eventNumber();
672
#if ENABLE(DRAG_SUPPORT)
674
PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
676
// Must be done before ondragstart adds types and data to the pboard,
677
// also done for security, as it erases data from the last drag
678
Pasteboard pasteboard(NSDragPboard);
680
return ClipboardMac::create(Clipboard::DragAndDrop, String(NSDragPboard), ClipboardWritable, ClipboardMac::DragAndDropData, m_frame);
685
bool EventHandler::tabsToAllFormControls(KeyboardEvent* event) const
687
Page* page = m_frame->page();
691
KeyboardUIMode keyboardUIMode = page->chrome()->client()->keyboardUIMode();
692
bool handlingOptionTab = isKeyboardOptionTab(event);
694
// If tab-to-links is off, option-tab always highlights all controls
695
if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab)
698
// If system preferences say to include all controls, we always include all controls
699
if (keyboardUIMode & KeyboardAccessFull)
702
// Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab.
703
if (keyboardUIMode & KeyboardAccessTabsToLinks)
704
return !handlingOptionTab;
706
return handlingOptionTab;
709
bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
711
Settings* settings = m_frame->settings();
715
#if ENABLE(DASHBOARD_SUPPORT)
716
if (settings->usesDashboardBackwardCompatibilityMode())
720
if (settings->needsKeyboardEventDisambiguationQuirks())
726
unsigned EventHandler::accessKeyModifiers()
728
// Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled.
729
// So, we use Control in this case, even though it conflicts with Emacs-style key bindings.
730
// See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail.
731
if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
732
return PlatformEvent::CtrlKey;
734
return PlatformEvent::CtrlKey | PlatformEvent::AltKey;