/* * 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