diff -r 000000000000 -r 4f2f89ce4247 WebKit2/Shared/win/WebEventFactory.cpp --- /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 +#include + +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(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(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(wparam); + return String(&c, 1); +} + +static String unmodifiedTextFromEvent(WPARAM wparam, WebEvent::Type type) +{ + if (type != WebEvent::Char) + return String(); + + UChar c = static_cast(wparam); + return String(&c, 1); +} + +static String keyIdentifierFromEvent(WPARAM wparam, WebEvent::Type type) +{ + if (type == WebEvent::Char) + return String(); + + unsigned short keyCode = static_cast(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(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(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(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(wparam); + int nativeVirtualKeyCode = static_cast(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