WebKit/chromium/src/win/WebInputEventFactory.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2006-2009 Google Inc. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions are
       
     6  * met:
       
     7  *
       
     8  *     * Redistributions of source code must retain the above copyright
       
     9  * notice, this list of conditions and the following disclaimer.
       
    10  *     * Redistributions in binary form must reproduce the above
       
    11  * copyright notice, this list of conditions and the following disclaimer
       
    12  * in the documentation and/or other materials provided with the
       
    13  * distribution.
       
    14  *     * Neither the name of Google Inc. nor the names of its
       
    15  * contributors may be used to endorse or promote products derived from
       
    16  * this software without specific prior written permission.
       
    17  *
       
    18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       
    19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       
    20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       
    21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       
    22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       
    23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       
    24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       
    25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       
    26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    29  */
       
    30 
       
    31 #include "config.h"
       
    32 #include "WebInputEventFactory.h"
       
    33 
       
    34 #include "WebInputEvent.h"
       
    35 
       
    36 #include <wtf/Assertions.h>
       
    37 
       
    38 namespace WebKit {
       
    39 
       
    40 static const unsigned long defaultScrollLinesPerWheelDelta = 3;
       
    41 static const unsigned long defaultScrollCharsPerWheelDelta = 1;
       
    42 
       
    43 // WebKeyboardEvent -----------------------------------------------------------
       
    44 
       
    45 static bool isKeyPad(WPARAM wparam, LPARAM lparam)
       
    46 {
       
    47     bool keypad = false;
       
    48     switch (wparam) {
       
    49     case VK_RETURN:
       
    50         keypad = (lparam >> 16) & KF_EXTENDED;
       
    51         break;
       
    52     case VK_INSERT:
       
    53     case VK_DELETE:
       
    54     case VK_HOME:
       
    55     case VK_END:
       
    56     case VK_PRIOR:
       
    57     case VK_NEXT:
       
    58     case VK_UP:
       
    59     case VK_DOWN:
       
    60     case VK_LEFT:
       
    61     case VK_RIGHT:
       
    62         keypad = !((lparam >> 16) & KF_EXTENDED);
       
    63         break;
       
    64     case VK_NUMLOCK:
       
    65     case VK_NUMPAD0:
       
    66     case VK_NUMPAD1:
       
    67     case VK_NUMPAD2:
       
    68     case VK_NUMPAD3:
       
    69     case VK_NUMPAD4:
       
    70     case VK_NUMPAD5:
       
    71     case VK_NUMPAD6:
       
    72     case VK_NUMPAD7:
       
    73     case VK_NUMPAD8:
       
    74     case VK_NUMPAD9:
       
    75     case VK_DIVIDE:
       
    76     case VK_MULTIPLY:
       
    77     case VK_SUBTRACT:
       
    78     case VK_ADD:
       
    79     case VK_DECIMAL:
       
    80     case VK_CLEAR:
       
    81         keypad = true;
       
    82         break;
       
    83     default:
       
    84         keypad = false;
       
    85     }
       
    86     return keypad;
       
    87 }
       
    88 
       
    89 WebKeyboardEvent WebInputEventFactory::keyboardEvent(HWND hwnd, UINT message,
       
    90                                                      WPARAM wparam, LPARAM lparam)
       
    91 {
       
    92     WebKeyboardEvent result;
       
    93 
       
    94     // TODO(pkasting): http://b/1117926 Are we guaranteed that the message that
       
    95     // GetMessageTime() refers to is the same one that we're passed in? Perhaps
       
    96     // one of the construction parameters should be the time passed by the
       
    97     // caller, who would know for sure.
       
    98     result.timeStampSeconds = GetMessageTime() / 1000.0;
       
    99 
       
   100     result.windowsKeyCode = result.nativeKeyCode = static_cast<int>(wparam);
       
   101 
       
   102     switch (message) {
       
   103     case WM_SYSKEYDOWN:
       
   104         result.isSystemKey = true;
       
   105     case WM_KEYDOWN:
       
   106         result.type = WebInputEvent::RawKeyDown;
       
   107         break;
       
   108     case WM_SYSKEYUP:
       
   109         result.isSystemKey = true;
       
   110     case WM_KEYUP:
       
   111         result.type = WebInputEvent::KeyUp;
       
   112         break;
       
   113     case WM_IME_CHAR:
       
   114         result.type = WebInputEvent::Char;
       
   115         break;
       
   116     case WM_SYSCHAR:
       
   117         result.isSystemKey = true;
       
   118         result.type = WebInputEvent::Char;
       
   119     case WM_CHAR:
       
   120         result.type = WebInputEvent::Char;
       
   121         break;
       
   122     default:
       
   123         ASSERT_NOT_REACHED();
       
   124     }
       
   125 
       
   126     if (result.type == WebInputEvent::Char || result.type == WebInputEvent::RawKeyDown) {
       
   127         result.text[0] = result.windowsKeyCode;
       
   128         result.unmodifiedText[0] = result.windowsKeyCode;
       
   129     }
       
   130     if (result.type != WebInputEvent::Char)
       
   131         result.setKeyIdentifierFromWindowsKeyCode();
       
   132 
       
   133     if (GetKeyState(VK_SHIFT) & 0x8000)
       
   134         result.modifiers |= WebInputEvent::ShiftKey;
       
   135     if (GetKeyState(VK_CONTROL) & 0x8000)
       
   136         result.modifiers |= WebInputEvent::ControlKey;
       
   137     if (GetKeyState(VK_MENU) & 0x8000)
       
   138         result.modifiers |= WebInputEvent::AltKey;
       
   139     // NOTE: There doesn't seem to be a way to query the mouse button state in
       
   140     // this case.
       
   141 
       
   142     if (LOWORD(lparam) > 1)
       
   143         result.modifiers |= WebInputEvent::IsAutoRepeat;
       
   144     if (isKeyPad(wparam, lparam))
       
   145         result.modifiers |= WebInputEvent::IsKeyPad;
       
   146 
       
   147     return result;
       
   148 }
       
   149 
       
   150 // WebMouseEvent --------------------------------------------------------------
       
   151 
       
   152 static int gLastClickCount;
       
   153 static double gLastClickTime;
       
   154 
       
   155 static LPARAM GetRelativeCursorPos(HWND hwnd)
       
   156 {
       
   157     POINT pos = {-1, -1};
       
   158     GetCursorPos(&pos);
       
   159     ScreenToClient(hwnd, &pos);
       
   160     return MAKELPARAM(pos.x, pos.y);
       
   161 }
       
   162 
       
   163 void WebInputEventFactory::resetLastClickState()
       
   164 {
       
   165     gLastClickTime = gLastClickCount = 0;
       
   166 }
       
   167 
       
   168 WebMouseEvent WebInputEventFactory::mouseEvent(HWND hwnd, UINT message,
       
   169                                                WPARAM wparam, LPARAM lparam)
       
   170 {
       
   171     WebMouseEvent result; //(WebInputEvent::Uninitialized());
       
   172 
       
   173     switch (message) {
       
   174     case WM_MOUSEMOVE:
       
   175         result.type = WebInputEvent::MouseMove;
       
   176         if (wparam & MK_LBUTTON)
       
   177             result.button = WebMouseEvent::ButtonLeft;
       
   178         else if (wparam & MK_MBUTTON)
       
   179             result.button = WebMouseEvent::ButtonMiddle;
       
   180         else if (wparam & MK_RBUTTON)
       
   181             result.button = WebMouseEvent::ButtonRight;
       
   182         else
       
   183             result.button = WebMouseEvent::ButtonNone;
       
   184         break;
       
   185     case WM_MOUSELEAVE:
       
   186         result.type = WebInputEvent::MouseLeave;
       
   187         result.button = WebMouseEvent::ButtonNone;
       
   188         // set the current mouse position (relative to the client area of the
       
   189         // current window) since none is specified for this event
       
   190         lparam = GetRelativeCursorPos(hwnd);
       
   191         break;
       
   192     case WM_LBUTTONDOWN:
       
   193     case WM_LBUTTONDBLCLK:
       
   194         result.type = WebInputEvent::MouseDown;
       
   195         result.button = WebMouseEvent::ButtonLeft;
       
   196         break;
       
   197     case WM_MBUTTONDOWN:
       
   198     case WM_MBUTTONDBLCLK:
       
   199         result.type = WebInputEvent::MouseDown;
       
   200         result.button = WebMouseEvent::ButtonMiddle;
       
   201         break;
       
   202     case WM_RBUTTONDOWN:
       
   203     case WM_RBUTTONDBLCLK:
       
   204         result.type = WebInputEvent::MouseDown;
       
   205         result.button = WebMouseEvent::ButtonRight;
       
   206         break;
       
   207     case WM_LBUTTONUP:
       
   208         result.type = WebInputEvent::MouseUp;
       
   209         result.button = WebMouseEvent::ButtonLeft;
       
   210         break;
       
   211     case WM_MBUTTONUP:
       
   212         result.type = WebInputEvent::MouseUp;
       
   213         result.button = WebMouseEvent::ButtonMiddle;
       
   214         break;
       
   215     case WM_RBUTTONUP:
       
   216         result.type = WebInputEvent::MouseUp;
       
   217         result.button = WebMouseEvent::ButtonRight;
       
   218         break;
       
   219     default:
       
   220         ASSERT_NOT_REACHED();
       
   221     }
       
   222 
       
   223     // TODO(pkasting): http://b/1117926 Are we guaranteed that the message that
       
   224     // GetMessageTime() refers to is the same one that we're passed in? Perhaps
       
   225     // one of the construction parameters should be the time passed by the
       
   226     // caller, who would know for sure.
       
   227     result.timeStampSeconds = GetMessageTime() / 1000.0;
       
   228 
       
   229     // set position fields:
       
   230 
       
   231     result.x = static_cast<short>(LOWORD(lparam));
       
   232     result.y = static_cast<short>(HIWORD(lparam));
       
   233     result.windowX = result.x;
       
   234     result.windowY = result.y;
       
   235 
       
   236     POINT globalPoint = { result.x, result.y };
       
   237     ClientToScreen(hwnd, &globalPoint);
       
   238 
       
   239     result.globalX = globalPoint.x;
       
   240     result.globalY = globalPoint.y;
       
   241 
       
   242     // calculate number of clicks:
       
   243 
       
   244     // This differs slightly from the WebKit code in WebKit/win/WebView.cpp
       
   245     // where their original code looks buggy.
       
   246     static int lastClickPositionX;
       
   247     static int lastClickPositionY;
       
   248     static WebMouseEvent::Button lastClickButton = WebMouseEvent::ButtonLeft;
       
   249 
       
   250     double currentTime = result.timeStampSeconds;
       
   251     bool cancelPreviousClick =
       
   252         (abs(lastClickPositionX - result.x) > (GetSystemMetrics(SM_CXDOUBLECLK) / 2))
       
   253         || (abs(lastClickPositionY - result.y) > (GetSystemMetrics(SM_CYDOUBLECLK) / 2))
       
   254         || ((currentTime - gLastClickTime) * 1000.0 > GetDoubleClickTime());
       
   255 
       
   256     if (result.type == WebInputEvent::MouseDown) {
       
   257         if (!cancelPreviousClick && (result.button == lastClickButton))
       
   258             ++gLastClickCount;
       
   259         else {
       
   260             gLastClickCount = 1;
       
   261             lastClickPositionX = result.x;
       
   262             lastClickPositionY = result.y;
       
   263         }
       
   264         gLastClickTime = currentTime;
       
   265         lastClickButton = result.button;
       
   266     } else if (result.type == WebInputEvent::MouseMove
       
   267                || result.type == WebInputEvent::MouseLeave) {
       
   268         if (cancelPreviousClick) {
       
   269             gLastClickCount = 0;
       
   270             lastClickPositionX = 0;
       
   271             lastClickPositionY = 0;
       
   272             gLastClickTime = 0;
       
   273         }
       
   274     }
       
   275     result.clickCount = gLastClickCount;
       
   276 
       
   277     // set modifiers:
       
   278 
       
   279     if (wparam & MK_CONTROL)
       
   280         result.modifiers |= WebInputEvent::ControlKey;
       
   281     if (wparam & MK_SHIFT)
       
   282         result.modifiers |= WebInputEvent::ShiftKey;
       
   283     if (GetKeyState(VK_MENU) & 0x8000)
       
   284         result.modifiers |= WebInputEvent::AltKey;
       
   285     if (wparam & MK_LBUTTON)
       
   286         result.modifiers |= WebInputEvent::LeftButtonDown;
       
   287     if (wparam & MK_MBUTTON)
       
   288         result.modifiers |= WebInputEvent::MiddleButtonDown;
       
   289     if (wparam & MK_RBUTTON)
       
   290         result.modifiers |= WebInputEvent::RightButtonDown;
       
   291 
       
   292     return result;
       
   293 }
       
   294 
       
   295 // WebMouseWheelEvent ---------------------------------------------------------
       
   296 
       
   297 WebMouseWheelEvent WebInputEventFactory::mouseWheelEvent(HWND hwnd, UINT message,
       
   298                                                          WPARAM wparam, LPARAM lparam)
       
   299 {
       
   300     WebMouseWheelEvent result; //(WebInputEvent::Uninitialized());
       
   301 
       
   302     result.type = WebInputEvent::MouseWheel;
       
   303 
       
   304     // TODO(pkasting): http://b/1117926 Are we guaranteed that the message that
       
   305     // GetMessageTime() refers to is the same one that we're passed in? Perhaps
       
   306     // one of the construction parameters should be the time passed by the
       
   307     // caller, who would know for sure.
       
   308     result.timeStampSeconds = GetMessageTime() / 1000.0;
       
   309 
       
   310     result.button = WebMouseEvent::ButtonNone;
       
   311 
       
   312     // Get key state, coordinates, and wheel delta from event.
       
   313     typedef SHORT (WINAPI *GetKeyStateFunction)(int key);
       
   314     GetKeyStateFunction getKeyState;
       
   315     UINT keyState;
       
   316     float wheelDelta;
       
   317     bool horizontalScroll = false;
       
   318     if ((message == WM_VSCROLL) || (message == WM_HSCROLL)) {
       
   319         // Synthesize mousewheel event from a scroll event.  This is needed to
       
   320         // simulate middle mouse scrolling in some laptops.  Use GetAsyncKeyState
       
   321         // for key state since we are synthesizing the input event.
       
   322         getKeyState = GetAsyncKeyState;
       
   323         keyState = 0;
       
   324         if (getKeyState(VK_SHIFT))
       
   325             keyState |= MK_SHIFT;
       
   326         if (getKeyState(VK_CONTROL))
       
   327             keyState |= MK_CONTROL;
       
   328         // NOTE: There doesn't seem to be a way to query the mouse button state
       
   329         // in this case.
       
   330 
       
   331         POINT cursorPosition = {0};
       
   332         GetCursorPos(&cursorPosition);
       
   333         result.globalX = cursorPosition.x;
       
   334         result.globalY = cursorPosition.y;
       
   335 
       
   336         switch (LOWORD(wparam)) {
       
   337         case SB_LINEUP:    // == SB_LINELEFT
       
   338             wheelDelta = WHEEL_DELTA;
       
   339             break;
       
   340         case SB_LINEDOWN:  // == SB_LINERIGHT
       
   341             wheelDelta = -WHEEL_DELTA;
       
   342             break;
       
   343         case SB_PAGEUP:
       
   344             wheelDelta = 1;
       
   345             result.scrollByPage = true;
       
   346             break;
       
   347         case SB_PAGEDOWN:
       
   348             wheelDelta = -1;
       
   349             result.scrollByPage = true;
       
   350             break;
       
   351         default:  // We don't supoprt SB_THUMBPOSITION or SB_THUMBTRACK here.
       
   352             wheelDelta = 0;
       
   353             break;
       
   354         }
       
   355 
       
   356         if (message == WM_HSCROLL)
       
   357             horizontalScroll = true;
       
   358     } else {
       
   359         // Non-synthesized event; we can just read data off the event.
       
   360         getKeyState = GetKeyState;
       
   361         keyState = GET_KEYSTATE_WPARAM(wparam);
       
   362 
       
   363         result.globalX = static_cast<short>(LOWORD(lparam));
       
   364         result.globalY = static_cast<short>(HIWORD(lparam));
       
   365 
       
   366         wheelDelta = static_cast<float>(GET_WHEEL_DELTA_WPARAM(wparam));
       
   367         if (message == WM_MOUSEHWHEEL) {
       
   368             horizontalScroll = true;
       
   369             wheelDelta = -wheelDelta;  // Windows is <- -/+ ->, WebKit <- +/- ->.
       
   370         }
       
   371     }
       
   372     if (keyState & MK_SHIFT)
       
   373         horizontalScroll = true;
       
   374 
       
   375     // Set modifiers based on key state.
       
   376     if (keyState & MK_SHIFT)
       
   377         result.modifiers |= WebInputEvent::ShiftKey;
       
   378     if (keyState & MK_CONTROL)
       
   379         result.modifiers |= WebInputEvent::ControlKey;
       
   380     if (getKeyState(VK_MENU) & 0x8000)
       
   381         result.modifiers |= WebInputEvent::AltKey;
       
   382     if (keyState & MK_LBUTTON)
       
   383         result.modifiers |= WebInputEvent::LeftButtonDown;
       
   384     if (keyState & MK_MBUTTON)
       
   385         result.modifiers |= WebInputEvent::MiddleButtonDown;
       
   386     if (keyState & MK_RBUTTON)
       
   387         result.modifiers |= WebInputEvent::RightButtonDown;
       
   388 
       
   389     // Set coordinates by translating event coordinates from screen to client.
       
   390     POINT clientPoint = { result.globalX, result.globalY };
       
   391     MapWindowPoints(0, hwnd, &clientPoint, 1);
       
   392     result.x = clientPoint.x;
       
   393     result.y = clientPoint.y;
       
   394     result.windowX = result.x;
       
   395     result.windowY = result.y;
       
   396 
       
   397     // Convert wheel delta amount to a number of pixels to scroll.
       
   398     //
       
   399     // How many pixels should we scroll per line?  Gecko uses the height of the
       
   400     // current line, which means scroll distance changes as you go through the
       
   401     // page or go to different pages.  IE 7 is ~50 px/line, although the value
       
   402     // seems to vary slightly by page and zoom level.  Since IE 7 has a smoothing
       
   403     // algorithm on scrolling, it can get away with slightly larger scroll values
       
   404     // without feeling jerky.  Here we use 100 px per three lines (the default
       
   405     // scroll amount is three lines per wheel tick).
       
   406     static const float scrollbarPixelsPerLine = 100.0f / 3.0f;
       
   407     wheelDelta /= WHEEL_DELTA;
       
   408     float scrollDelta = wheelDelta;
       
   409     if (horizontalScroll) {
       
   410         unsigned long scrollChars = defaultScrollCharsPerWheelDelta;
       
   411         SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &scrollChars, 0);
       
   412         // TODO(pkasting): Should probably have a different multiplier
       
   413         // scrollbarPixelsPerChar here.
       
   414         scrollDelta *= static_cast<float>(scrollChars) * scrollbarPixelsPerLine;
       
   415     } else {
       
   416         unsigned long scrollLines = defaultScrollLinesPerWheelDelta;
       
   417         SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0);
       
   418         if (scrollLines == WHEEL_PAGESCROLL)
       
   419             result.scrollByPage = true;
       
   420         if (!result.scrollByPage)
       
   421             scrollDelta *= static_cast<float>(scrollLines) * scrollbarPixelsPerLine;
       
   422     }
       
   423 
       
   424     // Set scroll amount based on above calculations.  WebKit expects positive
       
   425     // deltaY to mean "scroll up" and positive deltaX to mean "scroll left".
       
   426     if (horizontalScroll) {
       
   427         result.deltaX = scrollDelta;
       
   428         result.wheelTicksX = wheelDelta;
       
   429     } else {
       
   430         result.deltaY = scrollDelta;
       
   431         result.wheelTicksY = wheelDelta;
       
   432     }
       
   433 
       
   434     return result;
       
   435 }
       
   436 
       
   437 } // namespace WebKit