eventhandlermac.mm
来自「linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自Web」· MM 代码 · 共 656 行 · 第 1/2 页
MM
656 行
/* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "EventHandler.h"#include "AXObjectCache.h"#include "BlockExceptions.h"#include "ChromeClient.h"#include "ClipboardMac.h"#include "EventNames.h"#include "FocusController.h"#include "FrameLoader.h"#include "Frame.h"#include "FrameView.h"#include "KeyboardEvent.h"#include "MouseEventWithHitTestResults.h"#include "Page.h"#include "PlatformKeyboardEvent.h"#include "PlatformWheelEvent.h"#include "RenderWidget.h"#include "Scrollbar.h"#include "Settings.h"#include <wtf/StdLibExtras.h>namespace WebCore {const double EventHandler::TextDragDelay = 0.15;static RetainPtr<NSEvent>& currentEvent(){ DEFINE_STATIC_LOCAL(RetainPtr<NSEvent>, event, ()); return event;}NSEvent *EventHandler::currentNSEvent(){ return currentEvent().get();}bool EventHandler::wheelEvent(NSEvent *event){ RetainPtr<NSEvent> oldCurrentEvent = currentEvent(); currentEvent() = event; PlatformWheelEvent wheelEvent(event); handleWheelEvent(wheelEvent); ASSERT(currentEvent() == event); currentEvent() = oldCurrentEvent; return wheelEvent.isAccepted();}PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const{ NSEvent *event = [NSApp currentEvent]; if (!event) return 0; switch ([event type]) { case NSKeyDown: { PlatformKeyboardEvent platformEvent(event); platformEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown); return KeyboardEvent::create(platformEvent, m_frame->document()->defaultView()); } case NSKeyUp: return KeyboardEvent::create(event, m_frame->document()->defaultView()); default: return 0; }}static inline bool isKeyboardOptionTab(KeyboardEvent* event){ return event && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent) && event->altKey() && event->keyIdentifier() == "U+0009"; }bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const{ return isKeyboardOptionTab(event);}bool EventHandler::tabsToAllControls(KeyboardEvent* event) const{ Page* page = m_frame->page(); if (!page) return false; KeyboardUIMode keyboardUIMode = page->chrome()->client()->keyboardUIMode(); bool handlingOptionTab = isKeyboardOptionTab(event); // If tab-to-links is off, option-tab always highlights all controls if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab) return true; // If system preferences say to include all controls, we always include all controls if (keyboardUIMode & KeyboardAccessFull) return true; // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab. if (keyboardUIMode & KeyboardAccessTabsToLinks) return !handlingOptionTab; return handlingOptionTab;}bool EventHandler::needsKeyboardEventDisambiguationQuirks() const{ static BOOL checkedSafari = NO; static BOOL isSafari = NO; if (!checkedSafari) { isSafari = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"]; checkedSafari = YES; } Document* document = m_frame->document(); // RSS view needs arrow key keypress events. if (isSafari && document->url().protocolIs("feed") || document->url().protocolIs("feeds")) return true; Settings* settings = m_frame->settings(); if (!settings) return false;#if ENABLE(DASHBOARD_SUPPORT) if (settings->usesDashboardBackwardCompatibilityMode()) return true;#endif if (settings->needsKeyboardEventDisambiguationQuirks()) return true; return false;}bool EventHandler::keyEvent(NSEvent *event){ bool result; BEGIN_BLOCK_OBJC_EXCEPTIONS; ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp); RetainPtr<NSEvent> oldCurrentEvent = currentEvent(); currentEvent() = event; result = keyEvent(PlatformKeyboardEvent(event)); ASSERT(currentEvent() == event); currentEvent() = oldCurrentEvent; return result; END_BLOCK_OBJC_EXCEPTIONS; return false;}void EventHandler::focusDocumentView(){ Page* page = m_frame->page(); if (!page) return; if (FrameView* frameView = m_frame->view()) { if (NSView *documentView = frameView->documentView()) page->chrome()->focusNSView(documentView); } page->focusController()->setFocusedFrame(m_frame);}bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event){ // Figure out which view to send the event to. RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0; if (!target || !target->isWidget()) return false; // Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget will // just pass currentEvent down to the widget, we don't want to call it for events that // don't correspond to Cocoa events. The mousedown/ups will have already been passed on as // part of the pressed/released handling. return passMouseDownEventToWidget(static_cast<RenderWidget*>(target)->widget());}bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget){ return passMouseDownEventToWidget(renderWidget->widget());}static bool lastEventIsMouseUp(){ // Many AK widgets run their own event loops and consume events while the mouse is down. // When they finish, currentEvent is the mouseUp that they exited on. We need to update // the khtml state with this mouseUp, which khtml never saw. This method lets us detect // that state. BEGIN_BLOCK_OBJC_EXCEPTIONS; NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent]; if (currentEvent() != currentEventAfterHandlingMouseDown && [currentEventAfterHandlingMouseDown type] == NSLeftMouseUp && [currentEventAfterHandlingMouseDown timestamp] >= [currentEvent().get() timestamp]) return true; END_BLOCK_OBJC_EXCEPTIONS; return false;}bool EventHandler::passMouseDownEventToWidget(Widget* widget){ // FIXME: this method always returns true if (!widget) { LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed"); return true; } BEGIN_BLOCK_OBJC_EXCEPTIONS; NSView *nodeView = widget->platformWidget(); ASSERT(nodeView); ASSERT([nodeView superview]); NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentEvent().get() locationInWindow] fromView:nil]]; if (!view) { // We probably hit the border of a RenderWidget return true; } Page* page = m_frame->page(); if (!page) return true; if (page->chrome()->client()->firstResponder() != view) { // Normally [NSWindow sendEvent:] handles setting the first responder. // But in our case, the event was sent to the view representing the entire web page. if ([currentEvent().get() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey]) page->chrome()->client()->makeFirstResponder(view); } // We need to "defer loading" while tracking the mouse, because tearing down the // page while an AppKit control is tracking the mouse can cause a crash. // FIXME: In theory, WebCore now tolerates tear-down while tracking the // mouse. We should confirm that, and then remove the deferrsLoading // hack entirely. bool wasDeferringLoading = page->defersLoading(); if (!wasDeferringLoading) page->setDefersLoading(true); ASSERT(!m_sendingEventToSubview); m_sendingEventToSubview = true; [view mouseDown:currentEvent().get()]; m_sendingEventToSubview = false; if (!wasDeferringLoading) page->setDefersLoading(false); // Remember which view we sent the event to, so we can direct the release event properly. m_mouseDownView = view; m_mouseDownWasInSubframe = false; // Many AppKit widgets run their own event loops and consume events while the mouse is down. // When they finish, currentEvent is the mouseUp that they exited on. We need to update // the EventHandler state with this mouseUp, which we never saw. // If this event isn't a mouseUp, we assume that the mouseUp will be coming later. There // is a hole here if the widget consumes both the mouseUp and subsequent events. if (lastEventIsMouseUp()) m_mousePressed = false; END_BLOCK_OBJC_EXCEPTIONS; return true;} // Note that this does the same kind of check as [target isDescendantOf:superview].// There are two differences: This is a lot slower because it has to walk the whole// tree, and this works in cases where the target has already been deallocated.static bool findViewInSubviews(NSView *superview, NSView *target){ BEGIN_BLOCK_OBJC_EXCEPTIONS; NSEnumerator *e = [[superview subviews] objectEnumerator]; NSView *subview; while ((subview = [e nextObject])) { if (subview == target || findViewInSubviews(subview, target)) { return true; } } END_BLOCK_OBJC_EXCEPTIONS; return false;}NSView *EventHandler::mouseDownViewIfStillGood(){ // Since we have no way of tracking the lifetime of m_mouseDownView, we have to assume that // it could be deallocated already. We search for it in our subview tree; if we don't find // it, we set it to nil. NSView *mouseDownView = m_mouseDownView; if (!mouseDownView) { return nil; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?