WebKit2/Shared/win/WebEventFactory.cpp
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebKit2/Shared/win/WebEventFactory.cpp	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2009 Google 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 INC. 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 INC. 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 "WebEventFactory.h"
+
+#include <windowsx.h>
+#include <wtf/ASCIICType.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+static const unsigned short HIGH_BIT_MASK_SHORT = 0x8000;
+static const unsigned short SPI_GETWHEELSCROLLCHARS = 0x006C;
+
+static const unsigned WM_VISTA_MOUSEHWHEEL = 0x30E;
+
+static inline LPARAM relativeCursorPosition(HWND hwnd)
+{
+    POINT point = { -1, -1 };
+    ::GetCursorPos(&point);
+    ::ScreenToClient(hwnd, &point);
+    return MAKELPARAM(point.x, point.y);
+}
+
+static inline POINT positionForEvent(HWND hWnd, LPARAM lParam)
+{
+    POINT point = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+    return point;
+}
+
+static inline POINT globalPositionForEvent(HWND hWnd, LPARAM lParam)
+{
+    POINT point = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+    ::ClientToScreen(hWnd, &point);
+    return point;
+}
+
+static int horizontalScrollChars()
+{
+    static ULONG scrollChars;
+    if (!scrollChars && !::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &scrollChars, 0))
+        scrollChars = 1;
+    return scrollChars;
+}
+
+static int verticalScrollLines()
+{
+    static ULONG scrollLines;
+    if (!scrollLines && !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0))
+        scrollLines = 3;
+    return scrollLines;
+}
+
+static inline int clickCount(WebEvent::Type type, WebMouseEvent::Button button, int positionX, int positionY, double timeStampSeconds)
+{
+    static int gLastClickCount;
+    static double gLastClickTime;
+    static int lastClickPositionX;
+    static int lastClickPositionY;
+    static WebMouseEvent::Button lastClickButton = WebMouseEvent::LeftButton;
+
+    bool cancelPreviousClick = (abs(lastClickPositionX - positionX) > (::GetSystemMetrics(SM_CXDOUBLECLK) / 2))
+                            || (abs(lastClickPositionY - positionY) > (::GetSystemMetrics(SM_CYDOUBLECLK) / 2))
+                            || ((timeStampSeconds - gLastClickTime) * 1000.0 > ::GetDoubleClickTime());
+
+    if (type == WebEvent::MouseDown) {
+        if (!cancelPreviousClick && (button == lastClickButton))
+            ++gLastClickCount;
+        else {
+            gLastClickCount = 1;
+            lastClickPositionX = positionX;
+            lastClickPositionY = positionY;
+        }
+        gLastClickTime = timeStampSeconds;
+        lastClickButton = button;
+    } else if (type == WebEvent::MouseMove) {
+        if (cancelPreviousClick) {
+            gLastClickCount = 0;
+            lastClickPositionX = 0;
+            lastClickPositionY = 0;
+            gLastClickTime = 0;
+        }
+    }
+
+    return gLastClickCount;
+}
+
+static inline WebEvent::Modifiers modifiersForEvent(WPARAM wparam)
+{
+    unsigned modifiers = 0;
+    if (wparam & MK_CONTROL)
+        modifiers |= WebEvent::ControlKey;
+    if (wparam & MK_SHIFT)
+        modifiers |= WebEvent::ShiftKey;
+    if (::GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT)
+        modifiers |= WebEvent::AltKey;
+    return static_cast<WebEvent::Modifiers>(modifiers);
+}
+
+static inline WebEvent::Modifiers modifiersForCurrentKeyState()
+{
+    unsigned modifiers = 0;
+    if (::GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT)
+        modifiers |= WebEvent::ControlKey;
+    if (::GetKeyState(VK_SHIFT) & HIGH_BIT_MASK_SHORT)
+        modifiers |= WebEvent::ShiftKey;
+    if (::GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT)
+        modifiers |= WebEvent::AltKey;
+    return static_cast<WebEvent::Modifiers>(modifiers);
+}
+
+static inline WebEvent::Type keyboardEventTypeForEvent(UINT message)
+{
+    switch (message) {
+    case WM_SYSKEYDOWN:
+    case WM_KEYDOWN:
+        return WebEvent::RawKeyDown;
+        break;
+    case WM_SYSKEYUP:
+    case WM_KEYUP:
+        return WebEvent::KeyUp;
+        break;
+    case WM_IME_CHAR:
+    case WM_SYSCHAR:
+    case WM_CHAR:
+        return WebEvent::Char;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        return WebEvent::Char;
+    }
+}
+
+static inline bool isSystemKeyEvent(UINT message)
+{
+    switch (message) {
+    case WM_SYSKEYDOWN:
+    case WM_SYSKEYUP:
+    case WM_SYSCHAR:
+        return true;
+    default:
+        return false;
+    }
+}
+
+static bool isKeypadEvent(WPARAM wParam, LPARAM lParam, WebEvent::Type type)
+{
+    if (type != WebEvent::RawKeyDown && type != WebEvent::KeyUp)
+        return false;
+
+    switch (wParam) {
+    case VK_NUMLOCK:
+    case VK_NUMPAD0:
+    case VK_NUMPAD1:
+    case VK_NUMPAD2:
+    case VK_NUMPAD3:
+    case VK_NUMPAD4:
+    case VK_NUMPAD5:
+    case VK_NUMPAD6:
+    case VK_NUMPAD7:
+    case VK_NUMPAD8:
+    case VK_NUMPAD9:
+    case VK_MULTIPLY:
+    case VK_ADD:
+    case VK_SEPARATOR:
+    case VK_SUBTRACT:
+    case VK_DECIMAL:
+    case VK_DIVIDE:
+        return true;
+    case VK_RETURN:
+        return HIWORD(lParam) & KF_EXTENDED;
+    case VK_INSERT:
+    case VK_DELETE:
+    case VK_PRIOR:
+    case VK_NEXT:
+    case VK_END:
+    case VK_HOME:
+    case VK_LEFT:
+    case VK_UP:
+    case VK_RIGHT:
+    case VK_DOWN:
+        return !(HIWORD(lParam) & KF_EXTENDED);
+    default:
+        return false;
+    }
+}
+
+static String textFromEvent(WPARAM wparam, WebEvent::Type type)
+{
+    if (type != WebEvent::Char)
+        return String();
+
+    UChar c = static_cast<UChar>(wparam);
+    return String(&c, 1);
+}
+
+static String unmodifiedTextFromEvent(WPARAM wparam, WebEvent::Type type)
+{
+    if (type != WebEvent::Char)
+        return String();
+
+    UChar c = static_cast<UChar>(wparam);
+    return String(&c, 1);
+}
+
+static String keyIdentifierFromEvent(WPARAM wparam, WebEvent::Type type)
+{
+    if (type == WebEvent::Char)
+        return String();
+    
+    unsigned short keyCode = static_cast<unsigned short>(wparam);
+    switch (keyCode) {
+    case VK_MENU:
+        return String("Alt");
+    case VK_CONTROL:
+        return String("Control");
+    case VK_SHIFT:
+        return String("Shift");
+    case VK_CAPITAL:
+        return String("CapsLock");
+    case VK_LWIN:
+    case VK_RWIN:
+        return String("Win");
+    case VK_CLEAR:
+        return String("Clear");
+    case VK_DOWN:
+        return String("Down");
+    case VK_END:
+        return String("End");
+    case VK_RETURN:
+        return String("Enter");
+    case VK_EXECUTE:
+        return String("Execute");
+    case VK_F1:
+        return String("F1");
+    case VK_F2:
+        return String("F2");
+    case VK_F3:
+        return String("F3");
+    case VK_F4:
+        return String("F4");
+    case VK_F5:
+        return String("F5");
+    case VK_F6:
+        return String("F6");
+    case VK_F7:
+        return String("F7");
+    case VK_F8:
+        return String("F8");
+    case VK_F9:
+        return String("F9");
+    case VK_F10:
+        return String("F11");
+    case VK_F12:
+        return String("F12");
+    case VK_F13:
+        return String("F13");
+    case VK_F14:
+        return String("F14");
+    case VK_F15:
+        return String("F15");
+    case VK_F16:
+        return String("F16");
+    case VK_F17:
+        return String("F17");
+    case VK_F18:
+        return String("F18");
+    case VK_F19:
+        return String("F19");
+    case VK_F20:
+        return String("F20");
+    case VK_F21:
+        return String("F21");
+    case VK_F22:
+        return String("F22");
+    case VK_F23:
+        return String("F23");
+    case VK_F24:
+        return String("F24");
+    case VK_HELP:
+        return String("Help");
+    case VK_HOME:
+        return String("Home");
+    case VK_INSERT:
+        return String("Insert");
+    case VK_LEFT:
+        return String("Left");
+    case VK_NEXT:
+        return String("PageDown");
+    case VK_PRIOR:
+        return String("PageUp");
+    case VK_PAUSE:
+        return String("Pause");
+    case VK_SNAPSHOT:
+        return String("PrintScreen");
+    case VK_RIGHT:
+        return String("Right");
+    case VK_SCROLL:
+        return String("Scroll");
+    case VK_SELECT:
+        return String("Select");
+    case VK_UP:
+        return String("Up");
+    case VK_DELETE:
+        return String("U+007F"); // Standard says that DEL becomes U+007F.
+    default:
+        return String::format("U+%04X", toASCIIUpper(keyCode));
+    }
+}
+
+WebMouseEvent WebEventFactory::createWebMouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    WebEvent::Type type;
+    WebMouseEvent::Button button = WebMouseEvent::NoButton;
+    switch (message) {
+    case WM_MOUSEMOVE:
+        type = WebEvent::MouseMove;
+        if (wParam & MK_LBUTTON)
+            button = WebMouseEvent::LeftButton;
+        else if (wParam & MK_MBUTTON)
+            button = WebMouseEvent::MiddleButton;
+        else if (wParam & MK_RBUTTON)
+            button = WebMouseEvent::RightButton;
+        break;
+    case WM_MOUSELEAVE:
+        type = WebEvent::MouseMove;
+        if (wParam & MK_LBUTTON)
+            button = WebMouseEvent::LeftButton;
+        else if (wParam & MK_MBUTTON)
+            button = WebMouseEvent::MiddleButton;
+        else if (wParam & MK_RBUTTON)
+            button = WebMouseEvent::RightButton;
+
+        // Set the current mouse position (relative to the client area of the
+        // current window) since none is specified for this event.
+        lParam = relativeCursorPosition(hWnd);
+        break;
+    case WM_LBUTTONDOWN:
+    case WM_LBUTTONDBLCLK:
+        type = WebEvent::MouseDown;
+        button = WebMouseEvent::LeftButton;
+        break;
+    case WM_MBUTTONDOWN:
+    case WM_MBUTTONDBLCLK:
+        type = WebEvent::MouseDown;
+        button = WebMouseEvent::MiddleButton;
+        break;
+    case WM_RBUTTONDOWN:
+    case WM_RBUTTONDBLCLK:
+        type = WebEvent::MouseDown;
+        button = WebMouseEvent::RightButton;
+        break;
+    case WM_LBUTTONUP:
+        type = WebEvent::MouseUp;
+        button = WebMouseEvent::LeftButton;
+        break;
+    case WM_MBUTTONUP:
+        type = WebEvent::MouseUp;
+        button = WebMouseEvent::MiddleButton;
+        break;
+    case WM_RBUTTONUP:
+        type = WebEvent::MouseUp;
+        button = WebMouseEvent::RightButton;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        type = WebEvent::KeyDown;
+    }
+
+    POINT position = positionForEvent(hWnd, lParam);
+    POINT globalPosition = globalPositionForEvent(hWnd, lParam);
+
+    int positionX = position.x;
+    int positionY = position.y;
+    int globalPositionX = globalPosition.x;
+    int globalPositionY = globalPosition.y;
+    double timestamp = ::GetTickCount() * 0.001; // ::GetTickCount returns milliseconds (Chrome uses GetMessageTime() / 1000.0)
+
+    int clickCount = WebKit::clickCount(type, button, positionX, positionY, timestamp);
+    WebEvent::Modifiers modifiers = modifiersForEvent(wParam);
+
+    return WebMouseEvent(type, button, positionX, positionY, globalPositionX, globalPositionY, clickCount, modifiers, timestamp);
+}
+
+WebWheelEvent WebEventFactory::createWebWheelEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    // Taken from WebCore
+    static const float cScrollbarPixelsPerLine = 100.0f / 3.0f;
+
+    POINT position = positionForEvent(hWnd, lParam);
+    POINT globalPosition = globalPositionForEvent(hWnd, lParam);
+
+    int positionX = position.x;
+    int positionY = position.y;
+    int globalPositionX = globalPosition.x;
+    int globalPositionY = globalPosition.y;
+
+    WebWheelEvent::Granularity granularity  = WebWheelEvent::ScrollByPixelWheelEvent;
+
+    WebEvent::Modifiers modifiers = modifiersForEvent(wParam);
+    double timestamp = ::GetTickCount() * 0.001; // ::GetTickCount returns milliseconds (Chrome uses GetMessageTime() / 1000.0)
+
+    int deltaX = 0;
+    int deltaY = 0;
+    int wheelTicksX = 0;
+    int wheelTicksY = 0;
+
+    float delta = GET_WHEEL_DELTA_WPARAM(wParam) / static_cast<float>(WHEEL_DELTA);
+    bool isMouseHWheel = (message == WM_VISTA_MOUSEHWHEEL);
+    if (isMouseHWheel) {
+        wheelTicksX = delta;
+        wheelTicksY = 0;
+        delta = -delta;
+    } else {
+        wheelTicksX = 0;
+        wheelTicksY = delta;
+    }
+    if (isMouseHWheel || (modifiers & WebEvent::ShiftKey)) {
+        deltaX = delta * static_cast<float>(horizontalScrollChars()) * cScrollbarPixelsPerLine;
+        deltaY = 0;
+        granularity = WebWheelEvent::ScrollByPixelWheelEvent;
+    } else {
+        deltaX = 0;
+        deltaY = delta;
+        int verticalMultiplier = verticalScrollLines();
+        if (verticalMultiplier == WHEEL_PAGESCROLL)
+            granularity = WebWheelEvent::ScrollByPageWheelEvent;
+        else {
+            granularity = WebWheelEvent::ScrollByPixelWheelEvent;
+            deltaY *= static_cast<float>(verticalMultiplier) * cScrollbarPixelsPerLine;
+        }
+    }
+
+    return WebWheelEvent(WebEvent::Wheel, positionX, positionY, globalPositionX, globalPositionY, deltaX, deltaY, wheelTicksX, wheelTicksY, granularity, modifiers, timestamp);
+}
+
+WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
+{
+    WebEvent::Type type             = keyboardEventTypeForEvent(message);
+    String text                     = textFromEvent(wparam, type);
+    String unmodifiedText           = unmodifiedTextFromEvent(wparam, type);
+    String keyIdentifier            = keyIdentifierFromEvent(wparam, type);
+    int windowsVirtualKeyCode       = static_cast<int>(wparam);
+    int nativeVirtualKeyCode        = static_cast<int>(wparam);
+    bool autoRepeat                 = HIWORD(lparam) & KF_REPEAT;
+    bool isKeypad                   = isKeypadEvent(wparam, lparam, type);
+    bool isSystemKey                = isSystemKeyEvent(message);
+    WebEvent::Modifiers modifiers   = modifiersForCurrentKeyState();
+    double timestamp                = ::GetTickCount() * 0.001; // ::GetTickCount returns milliseconds (Chrome uses GetMessageTime() / 1000.0)
+
+    return WebKeyboardEvent(type, text, unmodifiedText, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, autoRepeat, isKeypad, isSystemKey, modifiers, timestamp);
+}
+
+} // namespace WebKit