Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2010 Apple Inc. All rights reserved.
      3  * Copyright (C) 2006-2009 Google Inc. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     24  * THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "WebEventFactory.h"
     29 
     30 #include <windowsx.h>
     31 #include <wtf/ASCIICType.h>
     32 
     33 using namespace WebCore;
     34 
     35 namespace WebKit {
     36 
     37 static const unsigned short HIGH_BIT_MASK_SHORT = 0x8000;
     38 static const unsigned short SPI_GETWHEELSCROLLCHARS = 0x006C;
     39 
     40 static const unsigned WM_VISTA_MOUSEHWHEEL = 0x20E;
     41 
     42 static inline LPARAM relativeCursorPosition(HWND hwnd)
     43 {
     44     POINT point = { -1, -1 };
     45     ::GetCursorPos(&point);
     46     ::ScreenToClient(hwnd, &point);
     47     return MAKELPARAM(point.x, point.y);
     48 }
     49 
     50 static inline POINT point(LPARAM lParam)
     51 {
     52     POINT point = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
     53     return point;
     54 }
     55 
     56 static int horizontalScrollChars()
     57 {
     58     static ULONG scrollChars;
     59     if (!scrollChars && !::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &scrollChars, 0))
     60         scrollChars = 1;
     61     return scrollChars;
     62 }
     63 
     64 static int verticalScrollLines()
     65 {
     66     static ULONG scrollLines;
     67     if (!scrollLines && !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0))
     68         scrollLines = 3;
     69     return scrollLines;
     70 }
     71 
     72 static inline int clickCount(WebEvent::Type type, WebMouseEvent::Button button, const POINT& position, double timeStampSeconds)
     73 {
     74     static int gLastClickCount;
     75     static double gLastClickTime;
     76     static POINT lastClickPosition;
     77     static WebMouseEvent::Button lastClickButton = WebMouseEvent::LeftButton;
     78 
     79     bool cancelPreviousClick = (abs(lastClickPosition.x - position.x) > (::GetSystemMetrics(SM_CXDOUBLECLK) / 2))
     80                             || (abs(lastClickPosition.y - position.y) > (::GetSystemMetrics(SM_CYDOUBLECLK) / 2))
     81                             || ((timeStampSeconds - gLastClickTime) * 1000.0 > ::GetDoubleClickTime());
     82 
     83     if (type == WebEvent::MouseDown) {
     84         if (!cancelPreviousClick && (button == lastClickButton))
     85             ++gLastClickCount;
     86         else {
     87             gLastClickCount = 1;
     88             lastClickPosition = position;
     89         }
     90         gLastClickTime = timeStampSeconds;
     91         lastClickButton = button;
     92     } else if (type == WebEvent::MouseMove) {
     93         if (cancelPreviousClick) {
     94             gLastClickCount = 0;
     95             lastClickPosition.x = 0;
     96             lastClickPosition.y = 0;
     97             gLastClickTime = 0;
     98         }
     99     }
    100 
    101     return gLastClickCount;
    102 }
    103 
    104 static inline WebEvent::Modifiers modifiersForEvent(WPARAM wparam)
    105 {
    106     unsigned modifiers = 0;
    107     if (wparam & MK_CONTROL)
    108         modifiers |= WebEvent::ControlKey;
    109     if (wparam & MK_SHIFT)
    110         modifiers |= WebEvent::ShiftKey;
    111     if (::GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT)
    112         modifiers |= WebEvent::AltKey;
    113     return static_cast<WebEvent::Modifiers>(modifiers);
    114 }
    115 
    116 static inline WebEvent::Modifiers modifiersForCurrentKeyState()
    117 {
    118     unsigned modifiers = 0;
    119     if (::GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT)
    120         modifiers |= WebEvent::ControlKey;
    121     if (::GetKeyState(VK_SHIFT) & HIGH_BIT_MASK_SHORT)
    122         modifiers |= WebEvent::ShiftKey;
    123     if (::GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT)
    124         modifiers |= WebEvent::AltKey;
    125     return static_cast<WebEvent::Modifiers>(modifiers);
    126 }
    127 
    128 static inline WebEvent::Type keyboardEventTypeForEvent(UINT message)
    129 {
    130     switch (message) {
    131     case WM_SYSKEYDOWN:
    132     case WM_KEYDOWN:
    133         return WebEvent::RawKeyDown;
    134         break;
    135     case WM_SYSKEYUP:
    136     case WM_KEYUP:
    137         return WebEvent::KeyUp;
    138         break;
    139     case WM_IME_CHAR:
    140     case WM_SYSCHAR:
    141     case WM_CHAR:
    142         return WebEvent::Char;
    143         break;
    144     default:
    145         ASSERT_NOT_REACHED();
    146         return WebEvent::Char;
    147     }
    148 }
    149 
    150 static inline bool isSystemKeyEvent(UINT message)
    151 {
    152     switch (message) {
    153     case WM_SYSKEYDOWN:
    154     case WM_SYSKEYUP:
    155     case WM_SYSCHAR:
    156         return true;
    157     default:
    158         return false;
    159     }
    160 }
    161 
    162 static bool isKeypadEvent(WPARAM wParam, LPARAM lParam, WebEvent::Type type)
    163 {
    164     if (type != WebEvent::RawKeyDown && type != WebEvent::KeyUp)
    165         return false;
    166 
    167     switch (wParam) {
    168     case VK_NUMLOCK:
    169     case VK_NUMPAD0:
    170     case VK_NUMPAD1:
    171     case VK_NUMPAD2:
    172     case VK_NUMPAD3:
    173     case VK_NUMPAD4:
    174     case VK_NUMPAD5:
    175     case VK_NUMPAD6:
    176     case VK_NUMPAD7:
    177     case VK_NUMPAD8:
    178     case VK_NUMPAD9:
    179     case VK_MULTIPLY:
    180     case VK_ADD:
    181     case VK_SEPARATOR:
    182     case VK_SUBTRACT:
    183     case VK_DECIMAL:
    184     case VK_DIVIDE:
    185         return true;
    186     case VK_RETURN:
    187         return HIWORD(lParam) & KF_EXTENDED;
    188     case VK_INSERT:
    189     case VK_DELETE:
    190     case VK_PRIOR:
    191     case VK_NEXT:
    192     case VK_END:
    193     case VK_HOME:
    194     case VK_LEFT:
    195     case VK_UP:
    196     case VK_RIGHT:
    197     case VK_DOWN:
    198         return !(HIWORD(lParam) & KF_EXTENDED);
    199     default:
    200         return false;
    201     }
    202 }
    203 
    204 static String textFromEvent(WPARAM wparam, WebEvent::Type type)
    205 {
    206     if (type != WebEvent::Char)
    207         return String();
    208 
    209     UChar c = static_cast<UChar>(wparam);
    210     return String(&c, 1);
    211 }
    212 
    213 static String unmodifiedTextFromEvent(WPARAM wparam, WebEvent::Type type)
    214 {
    215     if (type != WebEvent::Char)
    216         return String();
    217 
    218     UChar c = static_cast<UChar>(wparam);
    219     return String(&c, 1);
    220 }
    221 
    222 static String keyIdentifierFromEvent(WPARAM wparam, WebEvent::Type type)
    223 {
    224     if (type == WebEvent::Char)
    225         return String();
    226 
    227     unsigned short keyCode = static_cast<unsigned short>(wparam);
    228     switch (keyCode) {
    229     case VK_MENU:
    230         return String("Alt");
    231     case VK_CONTROL:
    232         return String("Control");
    233     case VK_SHIFT:
    234         return String("Shift");
    235     case VK_CAPITAL:
    236         return String("CapsLock");
    237     case VK_LWIN:
    238     case VK_RWIN:
    239         return String("Win");
    240     case VK_CLEAR:
    241         return String("Clear");
    242     case VK_DOWN:
    243         return String("Down");
    244     case VK_END:
    245         return String("End");
    246     case VK_RETURN:
    247         return String("Enter");
    248     case VK_EXECUTE:
    249         return String("Execute");
    250     case VK_F1:
    251         return String("F1");
    252     case VK_F2:
    253         return String("F2");
    254     case VK_F3:
    255         return String("F3");
    256     case VK_F4:
    257         return String("F4");
    258     case VK_F5:
    259         return String("F5");
    260     case VK_F6:
    261         return String("F6");
    262     case VK_F7:
    263         return String("F7");
    264     case VK_F8:
    265         return String("F8");
    266     case VK_F9:
    267         return String("F9");
    268     case VK_F10:
    269         return String("F11");
    270     case VK_F12:
    271         return String("F12");
    272     case VK_F13:
    273         return String("F13");
    274     case VK_F14:
    275         return String("F14");
    276     case VK_F15:
    277         return String("F15");
    278     case VK_F16:
    279         return String("F16");
    280     case VK_F17:
    281         return String("F17");
    282     case VK_F18:
    283         return String("F18");
    284     case VK_F19:
    285         return String("F19");
    286     case VK_F20:
    287         return String("F20");
    288     case VK_F21:
    289         return String("F21");
    290     case VK_F22:
    291         return String("F22");
    292     case VK_F23:
    293         return String("F23");
    294     case VK_F24:
    295         return String("F24");
    296     case VK_HELP:
    297         return String("Help");
    298     case VK_HOME:
    299         return String("Home");
    300     case VK_INSERT:
    301         return String("Insert");
    302     case VK_LEFT:
    303         return String("Left");
    304     case VK_NEXT:
    305         return String("PageDown");
    306     case VK_PRIOR:
    307         return String("PageUp");
    308     case VK_PAUSE:
    309         return String("Pause");
    310     case VK_SNAPSHOT:
    311         return String("PrintScreen");
    312     case VK_RIGHT:
    313         return String("Right");
    314     case VK_SCROLL:
    315         return String("Scroll");
    316     case VK_SELECT:
    317         return String("Select");
    318     case VK_UP:
    319         return String("Up");
    320     case VK_DELETE:
    321         return String("U+007F"); // Standard says that DEL becomes U+007F.
    322     default:
    323         return String::format("U+%04X", toASCIIUpper(keyCode));
    324     }
    325 }
    326 
    327 WebMouseEvent WebEventFactory::createWebMouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool didActivateWebView)
    328 {
    329     WebEvent::Type type;
    330     WebMouseEvent::Button button = WebMouseEvent::NoButton;
    331     switch (message) {
    332     case WM_MOUSEMOVE:
    333         type = WebEvent::MouseMove;
    334         if (wParam & MK_LBUTTON)
    335             button = WebMouseEvent::LeftButton;
    336         else if (wParam & MK_MBUTTON)
    337             button = WebMouseEvent::MiddleButton;
    338         else if (wParam & MK_RBUTTON)
    339             button = WebMouseEvent::RightButton;
    340         break;
    341     case WM_MOUSELEAVE:
    342         type = WebEvent::MouseMove;
    343         if (wParam & MK_LBUTTON)
    344             button = WebMouseEvent::LeftButton;
    345         else if (wParam & MK_MBUTTON)
    346             button = WebMouseEvent::MiddleButton;
    347         else if (wParam & MK_RBUTTON)
    348             button = WebMouseEvent::RightButton;
    349 
    350         // Set the current mouse position (relative to the client area of the
    351         // current window) since none is specified for this event.
    352         lParam = relativeCursorPosition(hWnd);
    353         break;
    354     case WM_LBUTTONDOWN:
    355     case WM_LBUTTONDBLCLK:
    356         type = WebEvent::MouseDown;
    357         button = WebMouseEvent::LeftButton;
    358         break;
    359     case WM_MBUTTONDOWN:
    360     case WM_MBUTTONDBLCLK:
    361         type = WebEvent::MouseDown;
    362         button = WebMouseEvent::MiddleButton;
    363         break;
    364     case WM_RBUTTONDOWN:
    365     case WM_RBUTTONDBLCLK:
    366         type = WebEvent::MouseDown;
    367         button = WebMouseEvent::RightButton;
    368         break;
    369     case WM_LBUTTONUP:
    370         type = WebEvent::MouseUp;
    371         button = WebMouseEvent::LeftButton;
    372         break;
    373     case WM_MBUTTONUP:
    374         type = WebEvent::MouseUp;
    375         button = WebMouseEvent::MiddleButton;
    376         break;
    377     case WM_RBUTTONUP:
    378         type = WebEvent::MouseUp;
    379         button = WebMouseEvent::RightButton;
    380         break;
    381     default:
    382         ASSERT_NOT_REACHED();
    383         type = WebEvent::KeyDown;
    384     }
    385 
    386     POINT position = point(lParam);
    387     POINT globalPosition = position;
    388     ::ClientToScreen(hWnd, &globalPosition);
    389 
    390     double timestamp = ::GetTickCount() * 0.001; // ::GetTickCount returns milliseconds (Chrome uses GetMessageTime() / 1000.0)
    391 
    392     int clickCount = WebKit::clickCount(type, button, position, timestamp);
    393     WebEvent::Modifiers modifiers = modifiersForEvent(wParam);
    394 
    395     return WebMouseEvent(type, button, position, globalPosition, 0, 0, 0, clickCount, modifiers, timestamp, didActivateWebView);
    396 }
    397 
    398 WebWheelEvent WebEventFactory::createWebWheelEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    399 {
    400     // Taken from WebCore
    401     static const float cScrollbarPixelsPerLine = 100.0f / 3.0f;
    402 
    403     POINT globalPosition = point(lParam);
    404     POINT position = globalPosition;
    405     ::ScreenToClient(hWnd, &position);
    406 
    407     WebWheelEvent::Granularity granularity  = WebWheelEvent::ScrollByPixelWheelEvent;
    408 
    409     WebEvent::Modifiers modifiers = modifiersForEvent(wParam);
    410     double timestamp = ::GetTickCount() * 0.001; // ::GetTickCount returns milliseconds (Chrome uses GetMessageTime() / 1000.0)
    411 
    412     int deltaX = 0;
    413     int deltaY = 0;
    414     int wheelTicksX = 0;
    415     int wheelTicksY = 0;
    416 
    417     float delta = GET_WHEEL_DELTA_WPARAM(wParam) / static_cast<float>(WHEEL_DELTA);
    418     bool isMouseHWheel = (message == WM_VISTA_MOUSEHWHEEL);
    419     if (isMouseHWheel) {
    420         wheelTicksX = delta;
    421         wheelTicksY = 0;
    422         delta = -delta;
    423     } else {
    424         wheelTicksX = 0;
    425         wheelTicksY = delta;
    426     }
    427     if (isMouseHWheel || (modifiers & WebEvent::ShiftKey)) {
    428         deltaX = delta * static_cast<float>(horizontalScrollChars()) * cScrollbarPixelsPerLine;
    429         deltaY = 0;
    430         granularity = WebWheelEvent::ScrollByPixelWheelEvent;
    431     } else {
    432         deltaX = 0;
    433         deltaY = delta;
    434         int verticalMultiplier = verticalScrollLines();
    435         if (verticalMultiplier == WHEEL_PAGESCROLL)
    436             granularity = WebWheelEvent::ScrollByPageWheelEvent;
    437         else {
    438             granularity = WebWheelEvent::ScrollByPixelWheelEvent;
    439             deltaY *= static_cast<float>(verticalMultiplier) * cScrollbarPixelsPerLine;
    440         }
    441     }
    442 
    443     return WebWheelEvent(WebEvent::Wheel, position, globalPosition, FloatSize(deltaX, deltaY), FloatSize(wheelTicksX, wheelTicksY), granularity, modifiers, timestamp);
    444 }
    445 
    446 WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
    447 {
    448     WebEvent::Type type             = keyboardEventTypeForEvent(message);
    449     String text                     = textFromEvent(wparam, type);
    450     String unmodifiedText           = unmodifiedTextFromEvent(wparam, type);
    451     String keyIdentifier            = keyIdentifierFromEvent(wparam, type);
    452     int windowsVirtualKeyCode       = static_cast<int>(wparam);
    453     int nativeVirtualKeyCode        = static_cast<int>(wparam);
    454     int macCharCode                 = 0;
    455     bool autoRepeat                 = HIWORD(lparam) & KF_REPEAT;
    456     bool isKeypad                   = isKeypadEvent(wparam, lparam, type);
    457     bool isSystemKey                = isSystemKeyEvent(message);
    458     WebEvent::Modifiers modifiers   = modifiersForCurrentKeyState();
    459     double timestamp                = ::GetTickCount() * 0.001; // ::GetTickCount returns milliseconds (Chrome uses GetMessageTime() / 1000.0)
    460 
    461     return WebKeyboardEvent(type, text, unmodifiedText, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, macCharCode, autoRepeat, isKeypad, isSystemKey, modifiers, timestamp);
    462 }
    463 
    464 } // namespace WebKit
    465