📄 eventsendingcontroller.mm
字号:
/* * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2006 Jonas Witt <jonas.witt@gmail.com> * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com> * * 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. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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. */#import "EventSendingController.h"#import "DumpRenderTree.h"#import "DumpRenderTreeDraggingInfo.h"#import <Carbon/Carbon.h> // for GetCurrentEventTime()#import <WebKit/DOMPrivate.h>#import <WebKit/WebKit.h>#import <WebKit/WebViewPrivate.h>extern "C" void _NSNewKillRingSequence();enum MouseAction { MouseDown, MouseUp, MouseDragged};// Match the DOM spec (sadly the DOM spec does not provide an enum)enum MouseButton { LeftMouseButton = 0, MiddleMouseButton = 1, RightMouseButton = 2, NoMouseButton = -1};NSPoint lastMousePosition;NSPoint lastClickPosition;int lastClickButton = NoMouseButton;NSArray *webkitDomEventNames;NSMutableArray *savedMouseEvents; // mouse events sent between mouseDown and mouseUp are stored here, and then executed at once.BOOL replayingSavedEvents;@implementation EventSendingController+ (void)initialize{ webkitDomEventNames = [[NSArray alloc] initWithObjects: @"abort", @"beforecopy", @"beforecut", @"beforepaste", @"blur", @"change", @"click", @"contextmenu", @"copy", @"cut", @"dblclick", @"drag", @"dragend", @"dragenter", @"dragleave", @"dragover", @"dragstart", @"drop", @"error", @"focus", @"input", @"keydown", @"keypress", @"keyup", @"load", @"mousedown", @"mousemove", @"mouseout", @"mouseover", @"mouseup", @"mousewheel", @"beforeunload", @"paste", @"readystatechange", @"reset", @"resize", @"scroll", @"search", @"select", @"selectstart", @"submit", @"textInput", @"textzoomin", @"textzoomout", @"unload", @"zoom", nil];}+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector{ if (aSelector == @selector(mouseDown:) || aSelector == @selector(mouseUp:) || aSelector == @selector(contextClick) || aSelector == @selector(scheduleAsynchronousClick) || aSelector == @selector(mouseMoveToX:Y:) || aSelector == @selector(leapForward:) || aSelector == @selector(keyDown:withModifiers:) || aSelector == @selector(enableDOMUIEventLogging:) || aSelector == @selector(fireKeyboardEventsToElement:) || aSelector == @selector(clearKillRing) || aSelector == @selector(textZoomIn) || aSelector == @selector(textZoomOut) || aSelector == @selector(zoomPageIn) || aSelector == @selector(zoomPageOut)) return NO; return YES;}+ (BOOL)isKeyExcludedFromWebScript:(const char*)name{ if (strcmp(name, "dragMode") == 0) return NO; return YES;}+ (NSString *)webScriptNameForSelector:(SEL)aSelector{ if (aSelector == @selector(mouseDown:)) return @"mouseDown"; if (aSelector == @selector(mouseUp:)) return @"mouseUp"; if (aSelector == @selector(mouseMoveToX:Y:)) return @"mouseMoveTo"; if (aSelector == @selector(leapForward:)) return @"leapForward"; if (aSelector == @selector(keyDown:withModifiers:)) return @"keyDown"; if (aSelector == @selector(enableDOMUIEventLogging:)) return @"enableDOMUIEventLogging"; if (aSelector == @selector(fireKeyboardEventsToElement:)) return @"fireKeyboardEventsToElement"; if (aSelector == @selector(setDragMode:)) return @"setDragMode"; return nil;}- (id)init{ self = [super init]; if (self) dragMode = YES; return self;}- (void)dealloc{ [super dealloc];}- (double)currentEventTime{ return GetCurrentEventTime() + timeOffset;}- (void)leapForward:(int)milliseconds{ if (dragMode && leftMouseButtonDown && !replayingSavedEvents) { NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(leapForward:)]]; [invocation setTarget:self]; [invocation setSelector:@selector(leapForward:)]; [invocation setArgument:&milliseconds atIndex:2]; [EventSendingController saveEvent:invocation]; return; } timeOffset += milliseconds / 1000.0;}- (void)clearKillRing{ _NSNewKillRingSequence();}static NSEventType eventTypeForMouseButtonAndAction(int button, MouseAction action){ switch (button) { case LeftMouseButton: switch (action) { case MouseDown: return NSLeftMouseDown; case MouseUp: return NSLeftMouseUp; case MouseDragged: return NSLeftMouseDragged; } case RightMouseButton: switch (action) { case MouseDown: return NSRightMouseDown; case MouseUp: return NSRightMouseUp; case MouseDragged: return NSRightMouseDragged; } default: switch (action) { case MouseDown: return NSOtherMouseDown; case MouseUp: return NSOtherMouseUp; case MouseDragged: return NSOtherMouseDragged; } } assert(0); return static_cast<NSEventType>(0);}- (void)updateClickCountForButton:(int)buttonNumber{ if (([self currentEventTime] - lastClick >= 1) || !NSEqualPoints(lastMousePosition, lastClickPosition) || lastClickButton != buttonNumber) { clickCount = 1; lastClickButton = buttonNumber; } else clickCount++;}- (void)mouseDown:(int)buttonNumber{ [[[mainFrame frameView] documentView] layout]; [self updateClickCountForButton:buttonNumber]; NSEventType eventType = eventTypeForMouseButtonAndAction(buttonNumber, MouseDown); NSEvent *event = [NSEvent mouseEventWithType:eventType location:lastMousePosition modifierFlags:0 timestamp:[self currentEventTime] windowNumber:[[[mainFrame webView] window] windowNumber] context:[NSGraphicsContext currentContext] eventNumber:++eventNumber clickCount:clickCount pressure:0.0]; NSView *subView = [[mainFrame webView] hitTest:[event locationInWindow]]; if (subView) { [subView mouseDown:event]; if (buttonNumber == LeftMouseButton) leftMouseButtonDown = YES; }}- (void)textZoomIn{ [[mainFrame webView] makeTextLarger:self];}- (void)textZoomOut{ [[mainFrame webView] makeTextSmaller:self];}- (void)zoomPageIn{ [[mainFrame webView] zoomPageIn:self];}- (void)zoomPageOut{ [[mainFrame webView] zoomPageOut:self];}- (void)mouseUp:(int)buttonNumber{ if (dragMode && !replayingSavedEvents) { NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(mouseUp:)]]; [invocation setTarget:self]; [invocation setSelector:@selector(mouseUp:)]; [invocation setArgument:&buttonNumber atIndex:2]; [EventSendingController saveEvent:invocation]; [EventSendingController replaySavedEvents]; return; } [[[mainFrame frameView] documentView] layout]; NSEventType eventType = eventTypeForMouseButtonAndAction(buttonNumber, MouseUp); NSEvent *event = [NSEvent mouseEventWithType:eventType location:lastMousePosition modifierFlags:0 timestamp:[self currentEventTime] windowNumber:[[[mainFrame webView] window] windowNumber] context:[NSGraphicsContext currentContext] eventNumber:++eventNumber clickCount:clickCount pressure:0.0]; NSView *targetView = [[mainFrame webView] hitTest:[event locationInWindow]]; // FIXME: Silly hack to teach DRT to respect capturing mouse events outside the WebView. // The right solution is just to use NSApplication's built-in event sending methods, // instead of rolling our own algorithm for selecting an event target. targetView = targetView ? targetView : [[mainFrame frameView] documentView]; assert(targetView); [targetView mouseUp:event]; if (buttonNumber == LeftMouseButton) leftMouseButtonDown = NO; lastClick = [event timestamp]; lastClickPosition = lastMousePosition; if (draggingInfo) { WebView *webView = [mainFrame webView]; NSDragOperation dragOperation = [webView draggingUpdated:draggingInfo]; if (dragOperation != NSDragOperationNone)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -