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