| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/browser/renderer_host/input/web_input_event_builders_win.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "content/browser/renderer_host/input/web_input_event_util.h" | |
| 9 #include "ui/display/win/screen_win.h" | |
| 10 #include "ui/events/blink/blink_event_util.h" | |
| 11 #include "ui/events/event_utils.h" | |
| 12 | |
| 13 using blink::WebInputEvent; | |
| 14 using blink::WebKeyboardEvent; | |
| 15 using blink::WebMouseEvent; | |
| 16 using blink::WebMouseWheelEvent; | |
| 17 | |
| 18 namespace content { | |
| 19 | |
| 20 static const unsigned long kDefaultScrollLinesPerWheelDelta = 3; | |
| 21 static const unsigned long kDefaultScrollCharsPerWheelDelta = 1; | |
| 22 | |
| 23 WebKeyboardEvent WebKeyboardEventBuilder::Build(HWND hwnd, | |
| 24 UINT message, | |
| 25 WPARAM wparam, | |
| 26 LPARAM lparam, | |
| 27 double time_stamp) { | |
| 28 WebKeyboardEvent result; | |
| 29 | |
| 30 result.timeStampSeconds = time_stamp; | |
| 31 | |
| 32 result.windowsKeyCode = static_cast<int>(wparam); | |
| 33 // Record the scan code (along with other context bits) for this key event. | |
| 34 result.nativeKeyCode = static_cast<int>(lparam); | |
| 35 | |
| 36 switch (message) { | |
| 37 case WM_SYSKEYDOWN: | |
| 38 result.isSystemKey = true; | |
| 39 case WM_KEYDOWN: | |
| 40 result.type = WebInputEvent::RawKeyDown; | |
| 41 break; | |
| 42 case WM_SYSKEYUP: | |
| 43 result.isSystemKey = true; | |
| 44 case WM_KEYUP: | |
| 45 result.type = WebInputEvent::KeyUp; | |
| 46 break; | |
| 47 case WM_IME_CHAR: | |
| 48 result.type = WebInputEvent::Char; | |
| 49 break; | |
| 50 case WM_SYSCHAR: | |
| 51 result.isSystemKey = true; | |
| 52 result.type = WebInputEvent::Char; | |
| 53 case WM_CHAR: | |
| 54 result.type = WebInputEvent::Char; | |
| 55 break; | |
| 56 default: | |
| 57 NOTREACHED(); | |
| 58 } | |
| 59 | |
| 60 if (result.type == WebInputEvent::Char | |
| 61 || result.type == WebInputEvent::RawKeyDown) { | |
| 62 result.text[0] = result.windowsKeyCode; | |
| 63 result.unmodifiedText[0] = result.windowsKeyCode; | |
| 64 } | |
| 65 result.modifiers = | |
| 66 ui::EventFlagsToWebEventModifiers(ui::GetModifiersFromKeyState()); | |
| 67 // NOTE: There doesn't seem to be a way to query the mouse button state in | |
| 68 // this case. | |
| 69 | |
| 70 // Bit 30 of lParam represents the "previous key state". If set, the key was | |
| 71 // already down, therefore this is an auto-repeat. Only apply this to key | |
| 72 // down events, to match DOM semantics. | |
| 73 if ((result.type == WebInputEvent::RawKeyDown) && (lparam & 0x40000000)) | |
| 74 result.modifiers |= WebInputEvent::IsAutoRepeat; | |
| 75 | |
| 76 return result; | |
| 77 } | |
| 78 | |
| 79 // WebMouseEvent -------------------------------------------------------------- | |
| 80 | |
| 81 static int g_last_click_count = 0; | |
| 82 static double g_last_click_time = 0; | |
| 83 | |
| 84 static LPARAM GetRelativeCursorPos(HWND hwnd) { | |
| 85 POINT pos = {-1, -1}; | |
| 86 GetCursorPos(&pos); | |
| 87 ScreenToClient(hwnd, &pos); | |
| 88 return MAKELPARAM(pos.x, pos.y); | |
| 89 } | |
| 90 | |
| 91 WebMouseEvent WebMouseEventBuilder::Build( | |
| 92 HWND hwnd, | |
| 93 UINT message, | |
| 94 WPARAM wparam, | |
| 95 LPARAM lparam, | |
| 96 double time_stamp, | |
| 97 blink::WebPointerProperties::PointerType pointer_type) { | |
| 98 WebMouseEvent result; | |
| 99 | |
| 100 switch (message) { | |
| 101 case WM_MOUSEMOVE: | |
| 102 result.type = WebInputEvent::MouseMove; | |
| 103 if (wparam & MK_LBUTTON) | |
| 104 result.button = WebMouseEvent::ButtonLeft; | |
| 105 else if (wparam & MK_MBUTTON) | |
| 106 result.button = WebMouseEvent::ButtonMiddle; | |
| 107 else if (wparam & MK_RBUTTON) | |
| 108 result.button = WebMouseEvent::ButtonRight; | |
| 109 else | |
| 110 result.button = WebMouseEvent::ButtonNone; | |
| 111 break; | |
| 112 case WM_MOUSELEAVE: | |
| 113 case WM_NCMOUSELEAVE: | |
| 114 // TODO(rbyers): This should be MouseLeave but is disabled temporarily. | |
| 115 // See http://crbug.com/450631 | |
| 116 result.type = WebInputEvent::MouseMove; | |
| 117 result.button = WebMouseEvent::ButtonNone; | |
| 118 // set the current mouse position (relative to the client area of the | |
| 119 // current window) since none is specified for this event | |
| 120 lparam = GetRelativeCursorPos(hwnd); | |
| 121 break; | |
| 122 case WM_LBUTTONDOWN: | |
| 123 case WM_LBUTTONDBLCLK: | |
| 124 result.type = WebInputEvent::MouseDown; | |
| 125 result.button = WebMouseEvent::ButtonLeft; | |
| 126 break; | |
| 127 case WM_MBUTTONDOWN: | |
| 128 case WM_MBUTTONDBLCLK: | |
| 129 result.type = WebInputEvent::MouseDown; | |
| 130 result.button = WebMouseEvent::ButtonMiddle; | |
| 131 break; | |
| 132 case WM_RBUTTONDOWN: | |
| 133 case WM_RBUTTONDBLCLK: | |
| 134 result.type = WebInputEvent::MouseDown; | |
| 135 result.button = WebMouseEvent::ButtonRight; | |
| 136 break; | |
| 137 case WM_LBUTTONUP: | |
| 138 result.type = WebInputEvent::MouseUp; | |
| 139 result.button = WebMouseEvent::ButtonLeft; | |
| 140 break; | |
| 141 case WM_MBUTTONUP: | |
| 142 result.type = WebInputEvent::MouseUp; | |
| 143 result.button = WebMouseEvent::ButtonMiddle; | |
| 144 break; | |
| 145 case WM_RBUTTONUP: | |
| 146 result.type = WebInputEvent::MouseUp; | |
| 147 result.button = WebMouseEvent::ButtonRight; | |
| 148 break; | |
| 149 default: | |
| 150 NOTREACHED(); | |
| 151 } | |
| 152 | |
| 153 result.timeStampSeconds = time_stamp; | |
| 154 result.pointerType = pointer_type; | |
| 155 | |
| 156 // set position fields: | |
| 157 | |
| 158 result.x = static_cast<short>(LOWORD(lparam)); | |
| 159 result.y = static_cast<short>(HIWORD(lparam)); | |
| 160 result.windowX = result.x; | |
| 161 result.windowY = result.y; | |
| 162 | |
| 163 POINT global_point = { result.x, result.y }; | |
| 164 ClientToScreen(hwnd, &global_point); | |
| 165 | |
| 166 // We need to convert the global point back to DIP before using it. | |
| 167 gfx::Point dip_global_point = display::win::ScreenWin::ScreenToDIPPoint( | |
| 168 gfx::Point(global_point.x, global_point.y)); | |
| 169 | |
| 170 result.globalX = dip_global_point.x(); | |
| 171 result.globalY = dip_global_point.y(); | |
| 172 | |
| 173 // calculate number of clicks: | |
| 174 | |
| 175 // This differs slightly from the WebKit code in WebKit/win/WebView.cpp | |
| 176 // where their original code looks buggy. | |
| 177 static int last_click_position_x; | |
| 178 static int last_click_position_y; | |
| 179 static WebMouseEvent::Button last_click_button = WebMouseEvent::ButtonLeft; | |
| 180 | |
| 181 double current_time = result.timeStampSeconds; | |
| 182 bool cancel_previous_click = | |
| 183 (abs(last_click_position_x - result.x) > | |
| 184 (::GetSystemMetrics(SM_CXDOUBLECLK) / 2)) | |
| 185 || (abs(last_click_position_y - result.y) > | |
| 186 (::GetSystemMetrics(SM_CYDOUBLECLK) / 2)) | |
| 187 || ((current_time - g_last_click_time) * 1000.0 > ::GetDoubleClickTime()); | |
| 188 | |
| 189 if (result.type == WebInputEvent::MouseDown) { | |
| 190 if (!cancel_previous_click && (result.button == last_click_button)) { | |
| 191 ++g_last_click_count; | |
| 192 } else { | |
| 193 g_last_click_count = 1; | |
| 194 last_click_position_x = result.x; | |
| 195 last_click_position_y = result.y; | |
| 196 } | |
| 197 g_last_click_time = current_time; | |
| 198 last_click_button = result.button; | |
| 199 } else if (result.type == WebInputEvent::MouseMove | |
| 200 || result.type == WebInputEvent::MouseLeave) { | |
| 201 if (cancel_previous_click) { | |
| 202 g_last_click_count = 0; | |
| 203 last_click_position_x = 0; | |
| 204 last_click_position_y = 0; | |
| 205 g_last_click_time = 0; | |
| 206 } | |
| 207 } | |
| 208 result.clickCount = g_last_click_count; | |
| 209 | |
| 210 // set modifiers: | |
| 211 result.modifiers = | |
| 212 ui::EventFlagsToWebEventModifiers(ui::GetModifiersFromKeyState()); | |
| 213 if (wparam & MK_CONTROL) | |
| 214 result.modifiers |= WebInputEvent::ControlKey; | |
| 215 if (wparam & MK_SHIFT) | |
| 216 result.modifiers |= WebInputEvent::ShiftKey; | |
| 217 if (wparam & MK_LBUTTON) | |
| 218 result.modifiers |= WebInputEvent::LeftButtonDown; | |
| 219 if (wparam & MK_MBUTTON) | |
| 220 result.modifiers |= WebInputEvent::MiddleButtonDown; | |
| 221 if (wparam & MK_RBUTTON) | |
| 222 result.modifiers |= WebInputEvent::RightButtonDown; | |
| 223 | |
| 224 return result; | |
| 225 } | |
| 226 | |
| 227 // WebMouseWheelEvent --------------------------------------------------------- | |
| 228 | |
| 229 WebMouseWheelEvent WebMouseWheelEventBuilder::Build( | |
| 230 HWND hwnd, | |
| 231 UINT message, | |
| 232 WPARAM wparam, | |
| 233 LPARAM lparam, | |
| 234 double time_stamp, | |
| 235 blink::WebPointerProperties::PointerType pointer_type) { | |
| 236 WebMouseWheelEvent result; | |
| 237 | |
| 238 result.type = WebInputEvent::MouseWheel; | |
| 239 | |
| 240 result.timeStampSeconds = time_stamp; | |
| 241 | |
| 242 result.button = WebMouseEvent::ButtonNone; | |
| 243 | |
| 244 result.pointerType = pointer_type; | |
| 245 | |
| 246 // Get key state, coordinates, and wheel delta from event. | |
| 247 UINT key_state; | |
| 248 float wheel_delta; | |
| 249 bool horizontal_scroll = false; | |
| 250 if ((message == WM_VSCROLL) || (message == WM_HSCROLL)) { | |
| 251 // Synthesize mousewheel event from a scroll event. This is needed to | |
| 252 // simulate middle mouse scrolling in some laptops. Use GetAsyncKeyState | |
| 253 // for key state since we are synthesizing the input event. | |
| 254 key_state = 0; | |
| 255 if (GetAsyncKeyState(VK_SHIFT) & 0x8000) | |
| 256 key_state |= MK_SHIFT; | |
| 257 if (GetAsyncKeyState(VK_CONTROL) & 0x8000) | |
| 258 key_state |= MK_CONTROL; | |
| 259 // NOTE: There doesn't seem to be a way to query the mouse button state | |
| 260 // in this case. | |
| 261 | |
| 262 POINT cursor_position = {0}; | |
| 263 GetCursorPos(&cursor_position); | |
| 264 result.globalX = cursor_position.x; | |
| 265 result.globalY = cursor_position.y; | |
| 266 | |
| 267 switch (LOWORD(wparam)) { | |
| 268 case SB_LINEUP: // == SB_LINELEFT | |
| 269 wheel_delta = WHEEL_DELTA; | |
| 270 break; | |
| 271 case SB_LINEDOWN: // == SB_LINERIGHT | |
| 272 wheel_delta = -WHEEL_DELTA; | |
| 273 break; | |
| 274 case SB_PAGEUP: | |
| 275 wheel_delta = 1; | |
| 276 result.scrollByPage = true; | |
| 277 break; | |
| 278 case SB_PAGEDOWN: | |
| 279 wheel_delta = -1; | |
| 280 result.scrollByPage = true; | |
| 281 break; | |
| 282 default: // We don't supoprt SB_THUMBPOSITION or SB_THUMBTRACK here. | |
| 283 wheel_delta = 0; | |
| 284 break; | |
| 285 } | |
| 286 | |
| 287 if (message == WM_HSCROLL) | |
| 288 horizontal_scroll = true; | |
| 289 } else { | |
| 290 // Non-synthesized event; we can just read data off the event. | |
| 291 key_state = GET_KEYSTATE_WPARAM(wparam); | |
| 292 | |
| 293 result.globalX = static_cast<short>(LOWORD(lparam)); | |
| 294 result.globalY = static_cast<short>(HIWORD(lparam)); | |
| 295 | |
| 296 // Currently we leave hasPreciseScrollingDeltas false, even for trackpad | |
| 297 // scrolls that generate WM_MOUSEWHEEL, since we don't have a good way to | |
| 298 // distinguish these from real mouse wheels (crbug.com/545234). | |
| 299 wheel_delta = static_cast<float>(GET_WHEEL_DELTA_WPARAM(wparam)); | |
| 300 | |
| 301 if (message == WM_MOUSEHWHEEL) { | |
| 302 horizontal_scroll = true; | |
| 303 wheel_delta = -wheel_delta; // Windows is <- -/+ ->, WebKit <- +/- ->. | |
| 304 } | |
| 305 } | |
| 306 if (key_state & MK_SHIFT) | |
| 307 horizontal_scroll = true; | |
| 308 | |
| 309 // Set modifiers based on key state. | |
| 310 result.modifiers = | |
| 311 ui::EventFlagsToWebEventModifiers(ui::GetModifiersFromKeyState()); | |
| 312 if (key_state & MK_SHIFT) | |
| 313 result.modifiers |= WebInputEvent::ShiftKey; | |
| 314 if (key_state & MK_CONTROL) | |
| 315 result.modifiers |= WebInputEvent::ControlKey; | |
| 316 if (key_state & MK_LBUTTON) | |
| 317 result.modifiers |= WebInputEvent::LeftButtonDown; | |
| 318 if (key_state & MK_MBUTTON) | |
| 319 result.modifiers |= WebInputEvent::MiddleButtonDown; | |
| 320 if (key_state & MK_RBUTTON) | |
| 321 result.modifiers |= WebInputEvent::RightButtonDown; | |
| 322 | |
| 323 // Set coordinates by translating event coordinates from screen to client. | |
| 324 POINT client_point = { result.globalX, result.globalY }; | |
| 325 MapWindowPoints(0, hwnd, &client_point, 1); | |
| 326 result.x = client_point.x; | |
| 327 result.y = client_point.y; | |
| 328 result.windowX = result.x; | |
| 329 result.windowY = result.y; | |
| 330 | |
| 331 // Convert wheel delta amount to a number of pixels to scroll. | |
| 332 // | |
| 333 // How many pixels should we scroll per line? Gecko uses the height of the | |
| 334 // current line, which means scroll distance changes as you go through the | |
| 335 // page or go to different pages. IE 8 is ~60 px/line, although the value | |
| 336 // seems to vary slightly by page and zoom level. Also, IE defaults to | |
| 337 // smooth scrolling while Firefox doesn't, so it can get away with somewhat | |
| 338 // larger scroll values without feeling as jerky. Here we use 100 px per | |
| 339 // three lines (the default scroll amount is three lines per wheel tick). | |
| 340 // Even though we have smooth scrolling, we don't make this as large as IE | |
| 341 // because subjectively IE feels like it scrolls farther than you want while | |
| 342 // reading articles. | |
| 343 static const float kScrollbarPixelsPerLine = 100.0f / 3.0f; | |
| 344 wheel_delta /= WHEEL_DELTA; | |
| 345 float scroll_delta = wheel_delta; | |
| 346 if (horizontal_scroll) { | |
| 347 unsigned long scroll_chars = kDefaultScrollCharsPerWheelDelta; | |
| 348 SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &scroll_chars, 0); | |
| 349 // TODO(pkasting): Should probably have a different multiplier | |
| 350 // scrollbarPixelsPerChar here. | |
| 351 scroll_delta *= static_cast<float>(scroll_chars) * kScrollbarPixelsPerLine; | |
| 352 } else { | |
| 353 unsigned long scroll_lines = kDefaultScrollLinesPerWheelDelta; | |
| 354 SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0); | |
| 355 if (scroll_lines == WHEEL_PAGESCROLL) | |
| 356 result.scrollByPage = true; | |
| 357 if (!result.scrollByPage) { | |
| 358 scroll_delta *= | |
| 359 static_cast<float>(scroll_lines) * kScrollbarPixelsPerLine; | |
| 360 } | |
| 361 } | |
| 362 | |
| 363 // Set scroll amount based on above calculations. WebKit expects positive | |
| 364 // deltaY to mean "scroll up" and positive deltaX to mean "scroll left". | |
| 365 if (horizontal_scroll) { | |
| 366 result.deltaX = scroll_delta; | |
| 367 result.wheelTicksX = wheel_delta; | |
| 368 } else { | |
| 369 result.deltaY = scroll_delta; | |
| 370 result.wheelTicksY = wheel_delta; | |
| 371 } | |
| 372 | |
| 373 return result; | |
| 374 } | |
| 375 | |
| 376 } // namespace content | |
| OLD | NEW |