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 + -
显示快捷键?