Index: content/browser/renderer_host/input/web_input_event_builders_win.cc |
diff --git a/content/browser/renderer_host/input/web_input_event_builders_win.cc b/content/browser/renderer_host/input/web_input_event_builders_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e376d5ee82f3a08bed79ee476b568981d672dd65 |
--- /dev/null |
+++ b/content/browser/renderer_host/input/web_input_event_builders_win.cc |
@@ -0,0 +1,456 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/renderer_host/input/web_input_event_builders_win.h" |
+ |
+#include "base/logging.h" |
+ |
+using WebKit::WebInputEvent; |
+using WebKit::WebKeyboardEvent; |
+using WebKit::WebMouseEvent; |
+using WebKit::WebMouseWheelEvent; |
+ |
+namespace content { |
+ |
+static const unsigned long kDefaultScrollLinesPerWheelDelta = 3; |
+static const unsigned long kDefaultScrollCharsPerWheelDelta = 1; |
+ |
+static bool IsKeyDown(WPARAM wparam) { |
+ return (GetKeyState(wparam) & 0x8000) != 0; |
+} |
+ |
+static int GetLocationModifier(WPARAM wparam, LPARAM lparam) { |
+ int modifier = 0; |
+ switch (wparam) { |
+ case VK_RETURN: |
+ if ((lparam >> 16) & KF_EXTENDED) |
+ modifier = WebInputEvent::IsKeyPad; |
+ break; |
+ case VK_INSERT: |
+ case VK_DELETE: |
+ case VK_HOME: |
+ case VK_END: |
+ case VK_PRIOR: |
+ case VK_NEXT: |
+ case VK_UP: |
+ case VK_DOWN: |
+ case VK_LEFT: |
+ case VK_RIGHT: |
+ if (!((lparam >> 16) & KF_EXTENDED)) |
+ modifier = WebInputEvent::IsKeyPad; |
+ break; |
+ case VK_NUMLOCK: |
+ case VK_NUMPAD0: |
+ case VK_NUMPAD1: |
+ case VK_NUMPAD2: |
+ case VK_NUMPAD3: |
+ case VK_NUMPAD4: |
+ case VK_NUMPAD5: |
+ case VK_NUMPAD6: |
+ case VK_NUMPAD7: |
+ case VK_NUMPAD8: |
+ case VK_NUMPAD9: |
+ case VK_DIVIDE: |
+ case VK_MULTIPLY: |
+ case VK_SUBTRACT: |
+ case VK_ADD: |
+ case VK_DECIMAL: |
+ case VK_CLEAR: |
+ modifier = WebInputEvent::IsKeyPad; |
+ break; |
+ case VK_SHIFT: |
+ if (IsKeyDown(VK_LSHIFT)) |
+ modifier = WebInputEvent::IsLeft; |
+ else if (IsKeyDown(VK_RSHIFT)) |
+ modifier = WebInputEvent::IsRight; |
+ break; |
+ case VK_CONTROL: |
+ if (IsKeyDown(VK_LCONTROL)) |
+ modifier = WebInputEvent::IsLeft; |
+ else if (IsKeyDown(VK_RCONTROL)) |
+ modifier = WebInputEvent::IsRight; |
+ break; |
+ case VK_MENU: |
+ if (IsKeyDown(VK_LMENU)) |
+ modifier = WebInputEvent::IsLeft; |
+ else if (IsKeyDown(VK_RMENU)) |
+ modifier = WebInputEvent::IsRight; |
+ break; |
+ case VK_LWIN: |
+ modifier = WebInputEvent::IsLeft; |
+ break; |
+ case VK_RWIN: |
+ modifier = WebInputEvent::IsRight; |
+ break; |
+ } |
+ |
+ DCHECK(!modifier |
+ || modifier == WebInputEvent::IsKeyPad |
+ || modifier == WebInputEvent::IsLeft |
+ || modifier == WebInputEvent::IsRight); |
+ return modifier; |
+} |
+ |
+// Loads the state for toggle keys into the event. |
+static void SetToggleKeyState(WebInputEvent* event) { |
+ // Low bit set from GetKeyState indicates "toggled". |
+ if (::GetKeyState(VK_NUMLOCK) & 1) |
+ event->modifiers |= WebInputEvent::NumLockOn; |
+ if (::GetKeyState(VK_CAPITAL) & 1) |
+ event->modifiers |= WebInputEvent::CapsLockOn; |
+} |
+ |
+WebKeyboardEvent WebKeyboardEventBuilder::Build(HWND hwnd, UINT message, |
+ WPARAM wparam, LPARAM lparam) { |
+ WebKeyboardEvent result; |
+ |
+ // TODO(pkasting): http://b/1117926 Are we guaranteed that the message that |
+ // GetMessageTime() refers to is the same one that we're passed in? Perhaps |
+ // one of the construction parameters should be the time passed by the |
+ // caller, who would know for sure. |
+ result.timeStampSeconds = ::GetMessageTime() / 1000.0; |
+ |
+ result.windowsKeyCode = static_cast<int>(wparam); |
+ // Record the scan code (along with other context bits) for this key event. |
+ result.nativeKeyCode = static_cast<int>(lparam); |
+ |
+ switch (message) { |
+ case WM_SYSKEYDOWN: |
+ result.isSystemKey = true; |
+ case WM_KEYDOWN: |
+ result.type = WebInputEvent::RawKeyDown; |
+ break; |
+ case WM_SYSKEYUP: |
+ result.isSystemKey = true; |
+ case WM_KEYUP: |
+ result.type = WebInputEvent::KeyUp; |
+ break; |
+ case WM_IME_CHAR: |
+ result.type = WebInputEvent::Char; |
+ break; |
+ case WM_SYSCHAR: |
+ result.isSystemKey = true; |
+ result.type = WebInputEvent::Char; |
+ case WM_CHAR: |
+ result.type = WebInputEvent::Char; |
+ break; |
+ default: |
+ NOTREACHED(); |
+ } |
+ |
+ if (result.type == WebInputEvent::Char |
+ || result.type == WebInputEvent::RawKeyDown) { |
+ result.text[0] = result.windowsKeyCode; |
+ result.unmodifiedText[0] = result.windowsKeyCode; |
+ } |
+ if (result.type != WebInputEvent::Char) |
+ result.setKeyIdentifierFromWindowsKeyCode(); |
+ |
+ if (::GetKeyState(VK_SHIFT) & 0x8000) |
+ result.modifiers |= WebInputEvent::ShiftKey; |
+ if (::GetKeyState(VK_CONTROL) & 0x8000) |
+ result.modifiers |= WebInputEvent::ControlKey; |
+ if (::GetKeyState(VK_MENU) & 0x8000) |
+ result.modifiers |= WebInputEvent::AltKey; |
+ // NOTE: There doesn't seem to be a way to query the mouse button state in |
+ // this case. |
+ |
+ if (LOWORD(lparam) > 1) |
+ result.modifiers |= WebInputEvent::IsAutoRepeat; |
+ |
+ result.modifiers |= GetLocationModifier(wparam, lparam); |
+ |
+ SetToggleKeyState(&result); |
+ return result; |
+} |
+ |
+// WebMouseEvent -------------------------------------------------------------- |
+ |
+static int g_last_click_count = 0; |
+static double g_last_click_time = 0; |
+ |
+static LPARAM GetRelativeCursorPos(HWND hwnd) { |
+ POINT pos = {-1, -1}; |
+ GetCursorPos(&pos); |
+ ScreenToClient(hwnd, &pos); |
+ return MAKELPARAM(pos.x, pos.y); |
+} |
+ |
+WebMouseEvent WebMouseEventBuilder::Build(HWND hwnd, UINT message, |
+ WPARAM wparam, LPARAM lparam) { |
+ WebMouseEvent result; |
+ |
+ switch (message) { |
+ case WM_MOUSEMOVE: |
+ result.type = WebInputEvent::MouseMove; |
+ if (wparam & MK_LBUTTON) |
+ result.button = WebMouseEvent::ButtonLeft; |
+ else if (wparam & MK_MBUTTON) |
+ result.button = WebMouseEvent::ButtonMiddle; |
+ else if (wparam & MK_RBUTTON) |
+ result.button = WebMouseEvent::ButtonRight; |
+ else |
+ result.button = WebMouseEvent::ButtonNone; |
+ break; |
+ case WM_MOUSELEAVE: |
+ result.type = WebInputEvent::MouseLeave; |
+ result.button = WebMouseEvent::ButtonNone; |
+ // set the current mouse position (relative to the client area of the |
+ // current window) since none is specified for this event |
+ lparam = GetRelativeCursorPos(hwnd); |
+ break; |
+ case WM_LBUTTONDOWN: |
+ case WM_LBUTTONDBLCLK: |
+ result.type = WebInputEvent::MouseDown; |
+ result.button = WebMouseEvent::ButtonLeft; |
+ break; |
+ case WM_MBUTTONDOWN: |
+ case WM_MBUTTONDBLCLK: |
+ result.type = WebInputEvent::MouseDown; |
+ result.button = WebMouseEvent::ButtonMiddle; |
+ break; |
+ case WM_RBUTTONDOWN: |
+ case WM_RBUTTONDBLCLK: |
+ result.type = WebInputEvent::MouseDown; |
+ result.button = WebMouseEvent::ButtonRight; |
+ break; |
+ case WM_LBUTTONUP: |
+ result.type = WebInputEvent::MouseUp; |
+ result.button = WebMouseEvent::ButtonLeft; |
+ break; |
+ case WM_MBUTTONUP: |
+ result.type = WebInputEvent::MouseUp; |
+ result.button = WebMouseEvent::ButtonMiddle; |
+ break; |
+ case WM_RBUTTONUP: |
+ result.type = WebInputEvent::MouseUp; |
+ result.button = WebMouseEvent::ButtonRight; |
+ break; |
+ default: |
+ NOTREACHED(); |
+ } |
+ |
+ // TODO(pkasting): http://b/1117926 Are we guaranteed that the message that |
+ // GetMessageTime() refers to is the same one that we're passed in? Perhaps |
+ // one of the construction parameters should be the time passed by the |
+ // caller, who would know for sure. |
+ result.timeStampSeconds = ::GetMessageTime() / 1000.0; |
+ |
+ // set position fields: |
+ |
+ result.x = static_cast<short>(LOWORD(lparam)); |
+ result.y = static_cast<short>(HIWORD(lparam)); |
+ result.windowX = result.x; |
+ result.windowY = result.y; |
+ |
+ POINT global_point = { result.x, result.y }; |
+ ClientToScreen(hwnd, &global_point); |
+ |
+ result.globalX = global_point.x; |
+ result.globalY = global_point.y; |
+ |
+ // calculate number of clicks: |
+ |
+ // This differs slightly from the WebKit code in WebKit/win/WebView.cpp |
+ // where their original code looks buggy. |
+ static int last_click_position_x; |
+ static int last_click_position_Y; |
+ static WebMouseEvent::Button last_click_button = WebMouseEvent::ButtonLeft; |
+ |
+ double current_time = result.timeStampSeconds; |
+ bool cancel_previous_click = |
+ (abs(last_click_position_x - result.x) > |
+ (::GetSystemMetrics(SM_CXDOUBLECLK) / 2)) |
+ || (abs(last_click_position_x - result.y) > |
+ (::GetSystemMetrics(SM_CYDOUBLECLK) / 2)) |
+ || ((current_time - g_last_click_time) * 1000.0 > ::GetDoubleClickTime()); |
+ |
+ if (result.type == WebInputEvent::MouseDown) { |
+ if (!cancel_previous_click && (result.button == last_click_button)) { |
+ ++g_last_click_count; |
+ } else { |
+ g_last_click_count = 1; |
+ last_click_position_x = result.x; |
+ last_click_position_x = result.y; |
+ } |
+ g_last_click_time = current_time; |
+ last_click_button = result.button; |
+ } else if (result.type == WebInputEvent::MouseMove |
+ || result.type == WebInputEvent::MouseLeave) { |
+ if (cancel_previous_click) { |
+ g_last_click_count = 0; |
+ last_click_position_x = 0; |
+ last_click_position_x = 0; |
+ g_last_click_time = 0; |
+ } |
+ } |
+ result.clickCount = g_last_click_count; |
+ |
+ // set modifiers: |
+ |
+ if (wparam & MK_CONTROL) |
+ result.modifiers |= WebInputEvent::ControlKey; |
+ if (wparam & MK_SHIFT) |
+ result.modifiers |= WebInputEvent::ShiftKey; |
+ if (::GetKeyState(VK_MENU) & 0x8000) |
+ result.modifiers |= WebInputEvent::AltKey; |
+ if (wparam & MK_LBUTTON) |
+ result.modifiers |= WebInputEvent::LeftButtonDown; |
+ if (wparam & MK_MBUTTON) |
+ result.modifiers |= WebInputEvent::MiddleButtonDown; |
+ if (wparam & MK_RBUTTON) |
+ result.modifiers |= WebInputEvent::RightButtonDown; |
+ |
+ SetToggleKeyState(&result); |
+ return result; |
+} |
+ |
+// WebMouseWheelEvent --------------------------------------------------------- |
+ |
+WebMouseWheelEvent |
+WebMouseWheelEventBuilder::Build(HWND hwnd, UINT message, |
+ WPARAM wparam, LPARAM lparam) { |
+ WebMouseWheelEvent result; |
+ |
+ result.type = WebInputEvent::MouseWheel; |
+ |
+ // TODO(pkasting): http://b/1117926 Are we guaranteed that the message that |
+ // GetMessageTime() refers to is the same one that we're passed in? Perhaps |
+ // one of the construction parameters should be the time passed by the |
+ // caller, who would know for sure. |
+ result.timeStampSeconds = ::GetMessageTime() / 1000.0; |
+ |
+ result.button = WebMouseEvent::ButtonNone; |
+ |
+ // Get key state, coordinates, and wheel delta from event. |
+ typedef SHORT (WINAPI *GetKeyStateFunction)(int key); |
+ GetKeyStateFunction get_key_state_func; |
+ UINT key_state; |
+ float wheel_delta; |
+ bool horizontal_scroll = false; |
+ if ((message == WM_VSCROLL) || (message == WM_HSCROLL)) { |
+ // Synthesize mousewheel event from a scroll event. This is needed to |
+ // simulate middle mouse scrolling in some laptops. Use GetAsyncKeyState |
+ // for key state since we are synthesizing the input event. |
+ get_key_state_func = GetAsyncKeyState; |
+ key_state = 0; |
+ if (get_key_state_func(VK_SHIFT)) |
+ key_state |= MK_SHIFT; |
+ if (get_key_state_func(VK_CONTROL)) |
+ key_state |= MK_CONTROL; |
+ // NOTE: There doesn't seem to be a way to query the mouse button state |
+ // in this case. |
+ |
+ POINT cursor_position = {0}; |
+ GetCursorPos(&cursor_position); |
+ result.globalX = cursor_position.x; |
+ result.globalY = cursor_position.y; |
+ |
+ switch (LOWORD(wparam)) { |
+ case SB_LINEUP: // == SB_LINELEFT |
+ wheel_delta = WHEEL_DELTA; |
+ break; |
+ case SB_LINEDOWN: // == SB_LINERIGHT |
+ wheel_delta = -WHEEL_DELTA; |
+ break; |
+ case SB_PAGEUP: |
+ wheel_delta = 1; |
+ result.scrollByPage = true; |
+ break; |
+ case SB_PAGEDOWN: |
+ wheel_delta = -1; |
+ result.scrollByPage = true; |
+ break; |
+ default: // We don't supoprt SB_THUMBPOSITION or SB_THUMBTRACK here. |
+ wheel_delta = 0; |
+ break; |
+ } |
+ |
+ if (message == WM_HSCROLL) |
+ horizontal_scroll = true; |
+ } else { |
+ // Non-synthesized event; we can just read data off the event. |
+ get_key_state_func = ::GetKeyState; |
+ key_state = GET_KEYSTATE_WPARAM(wparam); |
+ |
+ result.globalX = static_cast<short>(LOWORD(lparam)); |
+ result.globalY = static_cast<short>(HIWORD(lparam)); |
+ |
+ wheel_delta = static_cast<float>(GET_WHEEL_DELTA_WPARAM(wparam)); |
+ if (message == WM_MOUSEHWHEEL) { |
+ horizontal_scroll = true; |
+ wheel_delta = -wheel_delta; // Windows is <- -/+ ->, WebKit <- +/- ->. |
+ } |
+ } |
+ if (key_state & MK_SHIFT) |
+ horizontal_scroll = true; |
+ |
+ // Set modifiers based on key state. |
+ if (key_state & MK_SHIFT) |
+ result.modifiers |= WebInputEvent::ShiftKey; |
+ if (key_state & MK_CONTROL) |
+ result.modifiers |= WebInputEvent::ControlKey; |
+ if (get_key_state_func(VK_MENU) & 0x8000) |
+ result.modifiers |= WebInputEvent::AltKey; |
+ if (key_state & MK_LBUTTON) |
+ result.modifiers |= WebInputEvent::LeftButtonDown; |
+ if (key_state & MK_MBUTTON) |
+ result.modifiers |= WebInputEvent::MiddleButtonDown; |
+ if (key_state & MK_RBUTTON) |
+ result.modifiers |= WebInputEvent::RightButtonDown; |
+ |
+ SetToggleKeyState(&result); |
+ |
+ // Set coordinates by translating event coordinates from screen to client. |
+ POINT client_point = { result.globalX, result.globalY }; |
+ MapWindowPoints(0, hwnd, &client_point, 1); |
+ result.x = client_point.x; |
+ result.y = client_point.y; |
+ result.windowX = result.x; |
+ result.windowY = result.y; |
+ |
+ // Convert wheel delta amount to a number of pixels to scroll. |
+ // |
+ // How many pixels should we scroll per line? Gecko uses the height of the |
+ // current line, which means scroll distance changes as you go through the |
+ // page or go to different pages. IE 8 is ~60 px/line, although the value |
+ // seems to vary slightly by page and zoom level. Also, IE defaults to |
+ // smooth scrolling while Firefox doesn't, so it can get away with somewhat |
+ // larger scroll values without feeling as jerky. Here we use 100 px per |
+ // three lines (the default scroll amount is three lines per wheel tick). |
+ // Even though we have smooth scrolling, we don't make this as large as IE |
+ // because subjectively IE feels like it scrolls farther than you want while |
+ // reading articles. |
+ static const float kScrollbarPixelsPerLine = 100.0f / 3.0f; |
+ wheel_delta /= WHEEL_DELTA; |
+ float scroll_delta = wheel_delta * kScrollbarPixelsPerLine; |
+ if (horizontal_scroll) { |
+ unsigned long scroll_chars = kDefaultScrollCharsPerWheelDelta; |
+ SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &scroll_chars, 0); |
+ // TODO(pkasting): Should probably have a different multiplier |
+ // scrollbarPixelsPerChar here. |
+ scroll_delta *= static_cast<float>(scroll_chars); |
+ } else { |
+ unsigned long scroll_lines = kDefaultScrollLinesPerWheelDelta; |
+ SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0); |
+ if (scroll_lines == WHEEL_PAGESCROLL) |
+ result.scrollByPage = true; |
+ if (!result.scrollByPage) |
+ scroll_delta *= static_cast<float>(scroll_lines); |
+ } |
+ |
+ // Set scroll amount based on above calculations. WebKit expects positive |
+ // deltaY to mean "scroll up" and positive deltaX to mean "scroll left". |
+ if (horizontal_scroll) { |
+ result.deltaX = scroll_delta; |
+ result.wheelTicksX = wheel_delta; |
+ } else { |
+ result.deltaY = scroll_delta; |
+ result.wheelTicksY = wheel_delta; |
+ } |
+ |
+ return result; |
+} |
+ |
+} // namespace content |