| /* |
| * 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 "config.h" |
| #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 = 0x20E; |
| |
| static inline LPARAM relativeCursorPosition(HWND hwnd) |
| { |
| POINT point = { -1, -1 }; |
| ::GetCursorPos(&point); |
| ::ScreenToClient(hwnd, &point); |
| return MAKELPARAM(point.x, point.y); |
| } |
| |
| static inline POINT point(LPARAM lParam) |
| { |
| POINT point = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; |
| 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, const POINT& position, double timeStampSeconds) |
| { |
| static int gLastClickCount; |
| static double gLastClickTime; |
| static POINT lastClickPosition; |
| static WebMouseEvent::Button lastClickButton = WebMouseEvent::LeftButton; |
| |
| bool cancelPreviousClick = (abs(lastClickPosition.x - position.x) > (::GetSystemMetrics(SM_CXDOUBLECLK) / 2)) |
| || (abs(lastClickPosition.y - position.y) > (::GetSystemMetrics(SM_CYDOUBLECLK) / 2)) |
| || ((timeStampSeconds - gLastClickTime) * 1000.0 > ::GetDoubleClickTime()); |
| |
| if (type == WebEvent::MouseDown) { |
| if (!cancelPreviousClick && (button == lastClickButton)) |
| ++gLastClickCount; |
| else { |
| gLastClickCount = 1; |
| lastClickPosition = position; |
| } |
| gLastClickTime = timeStampSeconds; |
| lastClickButton = button; |
| } else if (type == WebEvent::MouseMove) { |
| if (cancelPreviousClick) { |
| gLastClickCount = 0; |
| lastClickPosition.x = 0; |
| lastClickPosition.y = 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, bool didActivateWebView) |
| { |
| 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 = point(lParam); |
| POINT globalPosition = position; |
| ::ClientToScreen(hWnd, &globalPosition); |
| |
| double timestamp = ::GetTickCount() * 0.001; // ::GetTickCount returns milliseconds (Chrome uses GetMessageTime() / 1000.0) |
| |
| int clickCount = WebKit::clickCount(type, button, position, timestamp); |
| WebEvent::Modifiers modifiers = modifiersForEvent(wParam); |
| |
| return WebMouseEvent(type, button, position, globalPosition, 0, 0, 0, clickCount, modifiers, timestamp, didActivateWebView); |
| } |
| |
| WebWheelEvent WebEventFactory::createWebWheelEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
| { |
| // Taken from WebCore |
| static const float cScrollbarPixelsPerLine = 100.0f / 3.0f; |
| |
| POINT globalPosition = point(lParam); |
| POINT position = globalPosition; |
| ::ScreenToClient(hWnd, &position); |
| |
| 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, position, globalPosition, FloatSize(deltaX, deltaY), FloatSize(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); |
| int macCharCode = 0; |
| 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, macCharCode, autoRepeat, isKeypad, isSystemKey, modifiers, timestamp); |
| } |
| |
| } // namespace WebKit |