| OLD | NEW |
| (Empty) |
| 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 | |
| OLD | NEW |