WebKit/chromium/src/win/WebInputEventFactory.cpp
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebKit/chromium/src/win/WebInputEventFactory.cpp	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,437 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 "WebInputEventFactory.h"
+
+#include "WebInputEvent.h"
+
+#include <wtf/Assertions.h>
+
+namespace WebKit {
+
+static const unsigned long defaultScrollLinesPerWheelDelta = 3;
+static const unsigned long defaultScrollCharsPerWheelDelta = 1;
+
+// WebKeyboardEvent -----------------------------------------------------------
+
+static bool isKeyPad(WPARAM wparam, LPARAM lparam)
+{
+    bool keypad = false;
+    switch (wparam) {
+    case VK_RETURN:
+        keypad = (lparam >> 16) & KF_EXTENDED;
+        break;
+    case VK_INSERT:
+    case VK_DELETE:
+    case VK_HOME:
+    case VK_END:
+    case VK_PRIOR:
+    case VK_NEXT:
+    case VK_UP:
+    case VK_DOWN:
+    case VK_LEFT:
+    case VK_RIGHT:
+        keypad = !((lparam >> 16) & KF_EXTENDED);
+        break;
+    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_DIVIDE:
+    case VK_MULTIPLY:
+    case VK_SUBTRACT:
+    case VK_ADD:
+    case VK_DECIMAL:
+    case VK_CLEAR:
+        keypad = true;
+        break;
+    default:
+        keypad = false;
+    }
+    return keypad;
+}
+
+WebKeyboardEvent WebInputEventFactory::keyboardEvent(HWND hwnd, UINT message,
+                                                     WPARAM wparam, LPARAM lparam)
+{
+    WebKeyboardEvent result;
+
+    // TODO(pkasting): http://b/1117926 Are we guaranteed that the message that
+    // GetMessageTime() refers to is the same one that we're passed in? Perhaps
+    // one of the construction parameters should be the time passed by the
+    // caller, who would know for sure.
+    result.timeStampSeconds = GetMessageTime() / 1000.0;
+
+    result.windowsKeyCode = result.nativeKeyCode = static_cast<int>(wparam);
+
+    switch (message) {
+    case WM_SYSKEYDOWN:
+        result.isSystemKey = true;
+    case WM_KEYDOWN:
+        result.type = WebInputEvent::RawKeyDown;
+        break;
+    case WM_SYSKEYUP:
+        result.isSystemKey = true;
+    case WM_KEYUP:
+        result.type = WebInputEvent::KeyUp;
+        break;
+    case WM_IME_CHAR:
+        result.type = WebInputEvent::Char;
+        break;
+    case WM_SYSCHAR:
+        result.isSystemKey = true;
+        result.type = WebInputEvent::Char;
+    case WM_CHAR:
+        result.type = WebInputEvent::Char;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    if (result.type == WebInputEvent::Char || result.type == WebInputEvent::RawKeyDown) {
+        result.text[0] = result.windowsKeyCode;
+        result.unmodifiedText[0] = result.windowsKeyCode;
+    }
+    if (result.type != WebInputEvent::Char)
+        result.setKeyIdentifierFromWindowsKeyCode();
+
+    if (GetKeyState(VK_SHIFT) & 0x8000)
+        result.modifiers |= WebInputEvent::ShiftKey;
+    if (GetKeyState(VK_CONTROL) & 0x8000)
+        result.modifiers |= WebInputEvent::ControlKey;
+    if (GetKeyState(VK_MENU) & 0x8000)
+        result.modifiers |= WebInputEvent::AltKey;
+    // NOTE: There doesn't seem to be a way to query the mouse button state in
+    // this case.
+
+    if (LOWORD(lparam) > 1)
+        result.modifiers |= WebInputEvent::IsAutoRepeat;
+    if (isKeyPad(wparam, lparam))
+        result.modifiers |= WebInputEvent::IsKeyPad;
+
+    return result;
+}
+
+// WebMouseEvent --------------------------------------------------------------
+
+static int gLastClickCount;
+static double gLastClickTime;
+
+static LPARAM GetRelativeCursorPos(HWND hwnd)
+{
+    POINT pos = {-1, -1};
+    GetCursorPos(&pos);
+    ScreenToClient(hwnd, &pos);
+    return MAKELPARAM(pos.x, pos.y);
+}
+
+void WebInputEventFactory::resetLastClickState()
+{
+    gLastClickTime = gLastClickCount = 0;
+}
+
+WebMouseEvent WebInputEventFactory::mouseEvent(HWND hwnd, UINT message,
+                                               WPARAM wparam, LPARAM lparam)
+{
+    WebMouseEvent result; //(WebInputEvent::Uninitialized());
+
+    switch (message) {
+    case WM_MOUSEMOVE:
+        result.type = WebInputEvent::MouseMove;
+        if (wparam & MK_LBUTTON)
+            result.button = WebMouseEvent::ButtonLeft;
+        else if (wparam & MK_MBUTTON)
+            result.button = WebMouseEvent::ButtonMiddle;
+        else if (wparam & MK_RBUTTON)
+            result.button = WebMouseEvent::ButtonRight;
+        else
+            result.button = WebMouseEvent::ButtonNone;
+        break;
+    case WM_MOUSELEAVE:
+        result.type = WebInputEvent::MouseLeave;
+        result.button = WebMouseEvent::ButtonNone;
+        // set the current mouse position (relative to the client area of the
+        // current window) since none is specified for this event
+        lparam = GetRelativeCursorPos(hwnd);
+        break;
+    case WM_LBUTTONDOWN:
+    case WM_LBUTTONDBLCLK:
+        result.type = WebInputEvent::MouseDown;
+        result.button = WebMouseEvent::ButtonLeft;
+        break;
+    case WM_MBUTTONDOWN:
+    case WM_MBUTTONDBLCLK:
+        result.type = WebInputEvent::MouseDown;
+        result.button = WebMouseEvent::ButtonMiddle;
+        break;
+    case WM_RBUTTONDOWN:
+    case WM_RBUTTONDBLCLK:
+        result.type = WebInputEvent::MouseDown;
+        result.button = WebMouseEvent::ButtonRight;
+        break;
+    case WM_LBUTTONUP:
+        result.type = WebInputEvent::MouseUp;
+        result.button = WebMouseEvent::ButtonLeft;
+        break;
+    case WM_MBUTTONUP:
+        result.type = WebInputEvent::MouseUp;
+        result.button = WebMouseEvent::ButtonMiddle;
+        break;
+    case WM_RBUTTONUP:
+        result.type = WebInputEvent::MouseUp;
+        result.button = WebMouseEvent::ButtonRight;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    // TODO(pkasting): http://b/1117926 Are we guaranteed that the message that
+    // GetMessageTime() refers to is the same one that we're passed in? Perhaps
+    // one of the construction parameters should be the time passed by the
+    // caller, who would know for sure.
+    result.timeStampSeconds = GetMessageTime() / 1000.0;
+
+    // set position fields:
+
+    result.x = static_cast<short>(LOWORD(lparam));
+    result.y = static_cast<short>(HIWORD(lparam));
+    result.windowX = result.x;
+    result.windowY = result.y;
+
+    POINT globalPoint = { result.x, result.y };
+    ClientToScreen(hwnd, &globalPoint);
+
+    result.globalX = globalPoint.x;
+    result.globalY = globalPoint.y;
+
+    // calculate number of clicks:
+
+    // This differs slightly from the WebKit code in WebKit/win/WebView.cpp
+    // where their original code looks buggy.
+    static int lastClickPositionX;
+    static int lastClickPositionY;
+    static WebMouseEvent::Button lastClickButton = WebMouseEvent::ButtonLeft;
+
+    double currentTime = result.timeStampSeconds;
+    bool cancelPreviousClick =
+        (abs(lastClickPositionX - result.x) > (GetSystemMetrics(SM_CXDOUBLECLK) / 2))
+        || (abs(lastClickPositionY - result.y) > (GetSystemMetrics(SM_CYDOUBLECLK) / 2))
+        || ((currentTime - gLastClickTime) * 1000.0 > GetDoubleClickTime());
+
+    if (result.type == WebInputEvent::MouseDown) {
+        if (!cancelPreviousClick && (result.button == lastClickButton))
+            ++gLastClickCount;
+        else {
+            gLastClickCount = 1;
+            lastClickPositionX = result.x;
+            lastClickPositionY = result.y;
+        }
+        gLastClickTime = currentTime;
+        lastClickButton = result.button;
+    } else if (result.type == WebInputEvent::MouseMove
+               || result.type == WebInputEvent::MouseLeave) {
+        if (cancelPreviousClick) {
+            gLastClickCount = 0;
+            lastClickPositionX = 0;
+            lastClickPositionY = 0;
+            gLastClickTime = 0;
+        }
+    }
+    result.clickCount = gLastClickCount;
+
+    // set modifiers:
+
+    if (wparam & MK_CONTROL)
+        result.modifiers |= WebInputEvent::ControlKey;
+    if (wparam & MK_SHIFT)
+        result.modifiers |= WebInputEvent::ShiftKey;
+    if (GetKeyState(VK_MENU) & 0x8000)
+        result.modifiers |= WebInputEvent::AltKey;
+    if (wparam & MK_LBUTTON)
+        result.modifiers |= WebInputEvent::LeftButtonDown;
+    if (wparam & MK_MBUTTON)
+        result.modifiers |= WebInputEvent::MiddleButtonDown;
+    if (wparam & MK_RBUTTON)
+        result.modifiers |= WebInputEvent::RightButtonDown;
+
+    return result;
+}
+
+// WebMouseWheelEvent ---------------------------------------------------------
+
+WebMouseWheelEvent WebInputEventFactory::mouseWheelEvent(HWND hwnd, UINT message,
+                                                         WPARAM wparam, LPARAM lparam)
+{
+    WebMouseWheelEvent result; //(WebInputEvent::Uninitialized());
+
+    result.type = WebInputEvent::MouseWheel;
+
+    // TODO(pkasting): http://b/1117926 Are we guaranteed that the message that
+    // GetMessageTime() refers to is the same one that we're passed in? Perhaps
+    // one of the construction parameters should be the time passed by the
+    // caller, who would know for sure.
+    result.timeStampSeconds = GetMessageTime() / 1000.0;
+
+    result.button = WebMouseEvent::ButtonNone;
+
+    // Get key state, coordinates, and wheel delta from event.
+    typedef SHORT (WINAPI *GetKeyStateFunction)(int key);
+    GetKeyStateFunction getKeyState;
+    UINT keyState;
+    float wheelDelta;
+    bool horizontalScroll = false;
+    if ((message == WM_VSCROLL) || (message == WM_HSCROLL)) {
+        // Synthesize mousewheel event from a scroll event.  This is needed to
+        // simulate middle mouse scrolling in some laptops.  Use GetAsyncKeyState
+        // for key state since we are synthesizing the input event.
+        getKeyState = GetAsyncKeyState;
+        keyState = 0;
+        if (getKeyState(VK_SHIFT))
+            keyState |= MK_SHIFT;
+        if (getKeyState(VK_CONTROL))
+            keyState |= MK_CONTROL;
+        // NOTE: There doesn't seem to be a way to query the mouse button state
+        // in this case.
+
+        POINT cursorPosition = {0};
+        GetCursorPos(&cursorPosition);
+        result.globalX = cursorPosition.x;
+        result.globalY = cursorPosition.y;
+
+        switch (LOWORD(wparam)) {
+        case SB_LINEUP:    // == SB_LINELEFT
+            wheelDelta = WHEEL_DELTA;
+            break;
+        case SB_LINEDOWN:  // == SB_LINERIGHT
+            wheelDelta = -WHEEL_DELTA;
+            break;
+        case SB_PAGEUP:
+            wheelDelta = 1;
+            result.scrollByPage = true;
+            break;
+        case SB_PAGEDOWN:
+            wheelDelta = -1;
+            result.scrollByPage = true;
+            break;
+        default:  // We don't supoprt SB_THUMBPOSITION or SB_THUMBTRACK here.
+            wheelDelta = 0;
+            break;
+        }
+
+        if (message == WM_HSCROLL)
+            horizontalScroll = true;
+    } else {
+        // Non-synthesized event; we can just read data off the event.
+        getKeyState = GetKeyState;
+        keyState = GET_KEYSTATE_WPARAM(wparam);
+
+        result.globalX = static_cast<short>(LOWORD(lparam));
+        result.globalY = static_cast<short>(HIWORD(lparam));
+
+        wheelDelta = static_cast<float>(GET_WHEEL_DELTA_WPARAM(wparam));
+        if (message == WM_MOUSEHWHEEL) {
+            horizontalScroll = true;
+            wheelDelta = -wheelDelta;  // Windows is <- -/+ ->, WebKit <- +/- ->.
+        }
+    }
+    if (keyState & MK_SHIFT)
+        horizontalScroll = true;
+
+    // Set modifiers based on key state.
+    if (keyState & MK_SHIFT)
+        result.modifiers |= WebInputEvent::ShiftKey;
+    if (keyState & MK_CONTROL)
+        result.modifiers |= WebInputEvent::ControlKey;
+    if (getKeyState(VK_MENU) & 0x8000)
+        result.modifiers |= WebInputEvent::AltKey;
+    if (keyState & MK_LBUTTON)
+        result.modifiers |= WebInputEvent::LeftButtonDown;
+    if (keyState & MK_MBUTTON)
+        result.modifiers |= WebInputEvent::MiddleButtonDown;
+    if (keyState & MK_RBUTTON)
+        result.modifiers |= WebInputEvent::RightButtonDown;
+
+    // Set coordinates by translating event coordinates from screen to client.
+    POINT clientPoint = { result.globalX, result.globalY };
+    MapWindowPoints(0, hwnd, &clientPoint, 1);
+    result.x = clientPoint.x;
+    result.y = clientPoint.y;
+    result.windowX = result.x;
+    result.windowY = result.y;
+
+    // Convert wheel delta amount to a number of pixels to scroll.
+    //
+    // How many pixels should we scroll per line?  Gecko uses the height of the
+    // current line, which means scroll distance changes as you go through the
+    // page or go to different pages.  IE 7 is ~50 px/line, although the value
+    // seems to vary slightly by page and zoom level.  Since IE 7 has a smoothing
+    // algorithm on scrolling, it can get away with slightly larger scroll values
+    // without feeling jerky.  Here we use 100 px per three lines (the default
+    // scroll amount is three lines per wheel tick).
+    static const float scrollbarPixelsPerLine = 100.0f / 3.0f;
+    wheelDelta /= WHEEL_DELTA;
+    float scrollDelta = wheelDelta;
+    if (horizontalScroll) {
+        unsigned long scrollChars = defaultScrollCharsPerWheelDelta;
+        SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &scrollChars, 0);
+        // TODO(pkasting): Should probably have a different multiplier
+        // scrollbarPixelsPerChar here.
+        scrollDelta *= static_cast<float>(scrollChars) * scrollbarPixelsPerLine;
+    } else {
+        unsigned long scrollLines = defaultScrollLinesPerWheelDelta;
+        SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0);
+        if (scrollLines == WHEEL_PAGESCROLL)
+            result.scrollByPage = true;
+        if (!result.scrollByPage)
+            scrollDelta *= static_cast<float>(scrollLines) * scrollbarPixelsPerLine;
+    }
+
+    // Set scroll amount based on above calculations.  WebKit expects positive
+    // deltaY to mean "scroll up" and positive deltaX to mean "scroll left".
+    if (horizontalScroll) {
+        result.deltaX = scrollDelta;
+        result.wheelTicksX = wheelDelta;
+    } else {
+        result.deltaY = scrollDelta;
+        result.wheelTicksY = wheelDelta;
+    }
+
+    return result;
+}
+
+} // namespace WebKit