diff options
Diffstat (limited to 'Source/WebKit2/Shared/win/WebEventFactory.cpp')
| -rw-r--r-- | Source/WebKit2/Shared/win/WebEventFactory.cpp | 463 |
1 files changed, 463 insertions, 0 deletions
diff --git a/Source/WebKit2/Shared/win/WebEventFactory.cpp b/Source/WebKit2/Shared/win/WebEventFactory.cpp new file mode 100644 index 0000000..a4081fc --- /dev/null +++ b/Source/WebKit2/Shared/win/WebEventFactory.cpp @@ -0,0 +1,463 @@ +/* + * 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 = 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 |
