📄 eventsender.cpp
字号:
/* * Copyright (C) 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. * 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. */#include "config.h"#include "EventSender.h"#include "DraggingInfo.h"#include "DumpRenderTree.h"#include <WebCore/COMPtr.h>#include <wtf/ASCIICType.h>#include <wtf/Platform.h>#include <JavaScriptCore/JavaScriptCore.h>#include <JavaScriptCore/Assertions.h>#include <WebKit/WebKit.h>#include <windows.h>#define WM_DRT_SEND_QUEUED_EVENT (WM_APP+1)static bool down;static bool dragMode = true;static bool replayingSavedEvents;static int timeOffset;static POINT lastMousePosition;struct DelayedMessage { MSG msg; unsigned delay;};static DelayedMessage msgQueue[1024];static unsigned endOfQueue;static unsigned startOfQueue;static bool didDragEnter;DraggingInfo* draggingInfo = 0;static JSValueRef getDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception){ return JSValueMakeBoolean(context, dragMode);}static bool setDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception){ dragMode = JSValueToBoolean(context, value); return true;}static JSValueRef getConstantCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception){ if (JSStringIsEqualToUTF8CString(propertyName, "WM_KEYDOWN")) return JSValueMakeNumber(context, WM_KEYDOWN); if (JSStringIsEqualToUTF8CString(propertyName, "WM_KEYUP")) return JSValueMakeNumber(context, WM_KEYUP); if (JSStringIsEqualToUTF8CString(propertyName, "WM_CHAR")) return JSValueMakeNumber(context, WM_CHAR); if (JSStringIsEqualToUTF8CString(propertyName, "WM_DEADCHAR")) return JSValueMakeNumber(context, WM_DEADCHAR); if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSKEYDOWN")) return JSValueMakeNumber(context, WM_SYSKEYDOWN); if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSKEYUP")) return JSValueMakeNumber(context, WM_SYSKEYUP); if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSCHAR")) return JSValueMakeNumber(context, WM_SYSCHAR); if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSDEADCHAR")) return JSValueMakeNumber(context, WM_SYSDEADCHAR); ASSERT_NOT_REACHED(); return JSValueMakeUndefined(context);}static JSValueRef leapForwardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){ if (argumentCount > 0) { msgQueue[endOfQueue].delay = JSValueToNumber(context, arguments[0], exception); ASSERT(!exception || !*exception); } return JSValueMakeUndefined(context);}static DWORD currentEventTime(){ return ::GetTickCount() + timeOffset;}static MSG makeMsg(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ MSG result = {0}; result.hwnd = hwnd; result.message = message; result.wParam = wParam; result.lParam = lParam; result.time = currentEventTime(); result.pt = lastMousePosition; return result;}static LRESULT dispatchMessage(const MSG* msg){ ASSERT(msg); ::TranslateMessage(msg); return ::DispatchMessage(msg);}static JSValueRef contextClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){ COMPtr<IWebFramePrivate> framePrivate; if (SUCCEEDED(frame->QueryInterface(&framePrivate))) framePrivate->layout(); down = true; MSG msg = makeMsg(webViewWindow, WM_RBUTTONDOWN, 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y)); dispatchMessage(&msg); down = false; msg = makeMsg(webViewWindow, WM_RBUTTONUP, 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y)); dispatchMessage(&msg); return JSValueMakeUndefined(context);}static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){ COMPtr<IWebFramePrivate> framePrivate; if (SUCCEEDED(frame->QueryInterface(&framePrivate))) framePrivate->layout(); down = true; MSG msg = makeMsg(webViewWindow, WM_LBUTTONDOWN, 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y)); if (!msgQueue[endOfQueue].delay) dispatchMessage(&msg); else { // replaySavedEvents has the required logic to make leapForward delays work msgQueue[endOfQueue++].msg = msg; replaySavedEvents(); } return JSValueMakeUndefined(context);}static inline POINTL pointl(const POINT& point){ POINTL result; result.x = point.x; result.y = point.y; return result;}static void doMouseUp(MSG msg){ COMPtr<IWebFramePrivate> framePrivate; if (SUCCEEDED(frame->QueryInterface(&framePrivate))) framePrivate->layout(); dispatchMessage(&msg); down = false; if (draggingInfo) { COMPtr<IWebView> webView; COMPtr<IDropTarget> webViewDropTarget; if (SUCCEEDED(frame->webView(&webView)) && SUCCEEDED(webView->QueryInterface(IID_IDropTarget, (void**)&webViewDropTarget))) { POINT screenPoint = msg.pt; DWORD effect = 0; ::ClientToScreen(webViewWindow, &screenPoint); if (!didDragEnter) { webViewDropTarget->DragEnter(draggingInfo->dataObject(), 0, pointl(screenPoint), &effect); didDragEnter = true; } HRESULT hr = draggingInfo->dropSource()->QueryContinueDrag(0, 0); webViewDropTarget->DragOver(0, pointl(screenPoint), &effect); if (hr == DRAGDROP_S_DROP && effect != DROPEFFECT_NONE) { DWORD effect = 0; webViewDropTarget->Drop(draggingInfo->dataObject(), 0, pointl(screenPoint), &effect); } else webViewDropTarget->DragLeave(); delete draggingInfo; draggingInfo = 0; } }}static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){ MSG msg = makeMsg(webViewWindow, WM_LBUTTONUP, 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y)); if ((dragMode && !replayingSavedEvents) || msgQueue[endOfQueue].delay) { msgQueue[endOfQueue++].msg = msg; replaySavedEvents(); } else doMouseUp(msg); return JSValueMakeUndefined(context);}static void doMouseMove(MSG msg){ COMPtr<IWebFramePrivate> framePrivate; if (SUCCEEDED(frame->QueryInterface(&framePrivate))) framePrivate->layout(); dispatchMessage(&msg); if (down && draggingInfo) { POINT screenPoint = msg.pt; ::ClientToScreen(webViewWindow, &screenPoint); IWebView* webView; COMPtr<IDropTarget> webViewDropTarget; if (SUCCEEDED(frame->webView(&webView)) && SUCCEEDED(webView->QueryInterface(IID_IDropTarget, (void**)&webViewDropTarget))) { DWORD effect = 0; if (didDragEnter) webViewDropTarget->DragOver(MK_LBUTTON, pointl(screenPoint), &effect); else { webViewDropTarget->DragEnter(draggingInfo->dataObject(), 0, pointl(screenPoint), &effect); didDragEnter = true; } draggingInfo->dropSource()->GiveFeedback(effect); } }}static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){ if (argumentCount < 2) return JSValueMakeUndefined(context); lastMousePosition.x = (int)JSValueToNumber(context, arguments[0], exception); ASSERT(!exception || !*exception); lastMousePosition.y = (int)JSValueToNumber(context, arguments[1], exception); ASSERT(!exception || !*exception); MSG msg = makeMsg(webViewWindow, WM_MOUSEMOVE, down ? MK_LBUTTON : 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y)); if (dragMode && down && !replayingSavedEvents) { msgQueue[endOfQueue++].msg = msg; return JSValueMakeUndefined(context); } doMouseMove(msg); return JSValueMakeUndefined(context);}void replaySavedEvents(){ replayingSavedEvents = true; MSG msg = { 0 }; while (startOfQueue < endOfQueue && !msgQueue[startOfQueue].delay) { msg = msgQueue[startOfQueue++].msg; switch (msg.message) { case WM_LBUTTONUP: doMouseUp(msg); break; case WM_MOUSEMOVE: doMouseMove(msg); break; case WM_LBUTTONDOWN: dispatchMessage(&msg); break; default: // Not reached break; } } int numQueuedMessages = endOfQueue - startOfQueue; if (!numQueuedMessages) { startOfQueue = 0; endOfQueue = 0; replayingSavedEvents = false; ASSERT(!down);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -