|  | // Copyright (c) 2012 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 <windowsx.h> | 
|  |  | 
|  | #include "ui/events/event_constants.h" | 
|  |  | 
|  | #include "base/logging.h" | 
|  | #include "base/time/time.h" | 
|  | #include "base/win/win_util.h" | 
|  | #include "ui/events/event_utils.h" | 
|  | #include "ui/events/keycodes/keyboard_code_conversion_win.h" | 
|  | #include "ui/gfx/point.h" | 
|  | #include "ui/gfx/win/dpi.h" | 
|  |  | 
|  | namespace ui { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // From MSDN: "Mouse" events are flagged with 0xFF515700 if they come | 
|  | // from a touch or stylus device.  In Vista or later, they are also flagged | 
|  | // with 0x80 if they come from touch. | 
|  | #define MOUSEEVENTF_FROMTOUCH (0xFF515700 | 0x80) | 
|  |  | 
|  | // Get the native mouse key state from the native event message type. | 
|  | int GetNativeMouseKey(const base::NativeEvent& native_event) { | 
|  | switch (native_event.message) { | 
|  | case WM_LBUTTONDBLCLK: | 
|  | case WM_LBUTTONDOWN: | 
|  | case WM_LBUTTONUP: | 
|  | case WM_NCLBUTTONDBLCLK: | 
|  | case WM_NCLBUTTONDOWN: | 
|  | case WM_NCLBUTTONUP: | 
|  | return MK_LBUTTON; | 
|  | case WM_MBUTTONDBLCLK: | 
|  | case WM_MBUTTONDOWN: | 
|  | case WM_MBUTTONUP: | 
|  | case WM_NCMBUTTONDBLCLK: | 
|  | case WM_NCMBUTTONDOWN: | 
|  | case WM_NCMBUTTONUP: | 
|  | return MK_MBUTTON; | 
|  | case WM_RBUTTONDBLCLK: | 
|  | case WM_RBUTTONDOWN: | 
|  | case WM_RBUTTONUP: | 
|  | case WM_NCRBUTTONDBLCLK: | 
|  | case WM_NCRBUTTONDOWN: | 
|  | case WM_NCRBUTTONUP: | 
|  | return MK_RBUTTON; | 
|  | case WM_NCXBUTTONDBLCLK: | 
|  | case WM_NCXBUTTONDOWN: | 
|  | case WM_NCXBUTTONUP: | 
|  | case WM_XBUTTONDBLCLK: | 
|  | case WM_XBUTTONDOWN: | 
|  | case WM_XBUTTONUP: | 
|  | return MK_XBUTTON1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | bool IsButtonDown(const base::NativeEvent& native_event) { | 
|  | return ((MK_LBUTTON | MK_MBUTTON | MK_RBUTTON | MK_XBUTTON1 | MK_XBUTTON2) & | 
|  | native_event.wParam) != 0; | 
|  | } | 
|  |  | 
|  | bool IsClientMouseEvent(const base::NativeEvent& native_event) { | 
|  | return native_event.message == WM_MOUSELEAVE || | 
|  | native_event.message == WM_MOUSEHOVER || | 
|  | (native_event.message >= WM_MOUSEFIRST && | 
|  | native_event.message <= WM_MOUSELAST); | 
|  | } | 
|  |  | 
|  | bool IsNonClientMouseEvent(const base::NativeEvent& native_event) { | 
|  | return native_event.message == WM_NCMOUSELEAVE || | 
|  | native_event.message == WM_NCMOUSEHOVER || | 
|  | (native_event.message >= WM_NCMOUSEMOVE && | 
|  | native_event.message <= WM_NCXBUTTONDBLCLK); | 
|  | } | 
|  |  | 
|  | bool IsMouseEvent(const base::NativeEvent& native_event) { | 
|  | return IsClientMouseEvent(native_event) || | 
|  | IsNonClientMouseEvent(native_event); | 
|  | } | 
|  |  | 
|  | bool IsMouseWheelEvent(const base::NativeEvent& native_event) { | 
|  | return native_event.message == WM_MOUSEWHEEL || | 
|  | native_event.message == WM_MOUSEHWHEEL; | 
|  | } | 
|  |  | 
|  | bool IsKeyEvent(const base::NativeEvent& native_event) { | 
|  | return native_event.message == WM_KEYDOWN || | 
|  | native_event.message == WM_SYSKEYDOWN || | 
|  | native_event.message == WM_CHAR || | 
|  | native_event.message == WM_KEYUP || | 
|  | native_event.message == WM_SYSKEYUP; | 
|  | } | 
|  |  | 
|  | bool IsScrollEvent(const base::NativeEvent& native_event) { | 
|  | return native_event.message == WM_VSCROLL || | 
|  | native_event.message == WM_HSCROLL; | 
|  | } | 
|  |  | 
|  | // Returns a mask corresponding to the set of pressed modifier keys. | 
|  | // Checks the current global state and the state sent by client mouse messages. | 
|  | int KeyStateFlagsFromNative(const base::NativeEvent& native_event) { | 
|  | int flags = 0; | 
|  | flags |= base::win::IsAltPressed() ? EF_ALT_DOWN : EF_NONE; | 
|  | flags |= base::win::IsShiftPressed() ? EF_SHIFT_DOWN : EF_NONE; | 
|  | flags |= base::win::IsCtrlPressed() ? EF_CONTROL_DOWN : EF_NONE; | 
|  |  | 
|  | // Check key messages for the extended key flag. | 
|  | if (IsKeyEvent(native_event)) | 
|  | flags |= (HIWORD(native_event.lParam) & KF_EXTENDED) ? EF_EXTENDED : 0; | 
|  |  | 
|  | // Most client mouse messages include key state information. | 
|  | if (IsClientMouseEvent(native_event)) { | 
|  | int win_flags = GET_KEYSTATE_WPARAM(native_event.wParam); | 
|  | flags |= (win_flags & MK_SHIFT) ? EF_SHIFT_DOWN : 0; | 
|  | flags |= (win_flags & MK_CONTROL) ? EF_CONTROL_DOWN : 0; | 
|  | } | 
|  |  | 
|  | return flags; | 
|  | } | 
|  |  | 
|  | // Returns a mask corresponding to the set of pressed mouse buttons. | 
|  | // This includes the button of the given message, even if it is being released. | 
|  | int MouseStateFlagsFromNative(const base::NativeEvent& native_event) { | 
|  | int win_flags = GetNativeMouseKey(native_event); | 
|  |  | 
|  | // Client mouse messages provide key states in their WPARAMs. | 
|  | if (IsClientMouseEvent(native_event)) | 
|  | win_flags |= GET_KEYSTATE_WPARAM(native_event.wParam); | 
|  |  | 
|  | int flags = 0; | 
|  | flags |= (win_flags & MK_LBUTTON) ? EF_LEFT_MOUSE_BUTTON : 0; | 
|  | flags |= (win_flags & MK_MBUTTON) ? EF_MIDDLE_MOUSE_BUTTON : 0; | 
|  | flags |= (win_flags & MK_RBUTTON) ? EF_RIGHT_MOUSE_BUTTON : 0; | 
|  | flags |= IsNonClientMouseEvent(native_event) ? EF_IS_NON_CLIENT : 0; | 
|  | return flags; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | void UpdateDeviceList() { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | EventType EventTypeFromNative(const base::NativeEvent& native_event) { | 
|  | switch (native_event.message) { | 
|  | case WM_KEYDOWN: | 
|  | case WM_SYSKEYDOWN: | 
|  | case WM_CHAR: | 
|  | return ET_KEY_PRESSED; | 
|  | // The WM_DEADCHAR message is posted to the window with the keyboard focus | 
|  | // when a WM_KEYUP message is translated. This happens for special keyboard | 
|  | // sequences. | 
|  | case WM_DEADCHAR: | 
|  | case WM_KEYUP: | 
|  | case WM_SYSKEYUP: | 
|  | return ET_KEY_RELEASED; | 
|  | case WM_LBUTTONDBLCLK: | 
|  | case WM_LBUTTONDOWN: | 
|  | case WM_MBUTTONDBLCLK: | 
|  | case WM_MBUTTONDOWN: | 
|  | case WM_NCLBUTTONDBLCLK: | 
|  | case WM_NCLBUTTONDOWN: | 
|  | case WM_NCMBUTTONDBLCLK: | 
|  | case WM_NCMBUTTONDOWN: | 
|  | case WM_NCRBUTTONDBLCLK: | 
|  | case WM_NCRBUTTONDOWN: | 
|  | case WM_NCXBUTTONDBLCLK: | 
|  | case WM_NCXBUTTONDOWN: | 
|  | case WM_RBUTTONDBLCLK: | 
|  | case WM_RBUTTONDOWN: | 
|  | case WM_XBUTTONDBLCLK: | 
|  | case WM_XBUTTONDOWN: | 
|  | return ET_MOUSE_PRESSED; | 
|  | case WM_LBUTTONUP: | 
|  | case WM_MBUTTONUP: | 
|  | case WM_NCLBUTTONUP: | 
|  | case WM_NCMBUTTONUP: | 
|  | case WM_NCRBUTTONUP: | 
|  | case WM_NCXBUTTONUP: | 
|  | case WM_RBUTTONUP: | 
|  | case WM_XBUTTONUP: | 
|  | return ET_MOUSE_RELEASED; | 
|  | case WM_MOUSEMOVE: | 
|  | return IsButtonDown(native_event) ? ET_MOUSE_DRAGGED : ET_MOUSE_MOVED; | 
|  | case WM_NCMOUSEMOVE: | 
|  | return ET_MOUSE_MOVED; | 
|  | case WM_MOUSEWHEEL: | 
|  | case WM_MOUSEHWHEEL: | 
|  | return ET_MOUSEWHEEL; | 
|  | case WM_MOUSELEAVE: | 
|  | case WM_NCMOUSELEAVE: | 
|  | return ET_MOUSE_EXITED; | 
|  | case WM_VSCROLL: | 
|  | case WM_HSCROLL: | 
|  | return ET_SCROLL; | 
|  | default: | 
|  | // We can't NOTREACHED() here, since this function can be called for any | 
|  | // message. | 
|  | break; | 
|  | } | 
|  | return ET_UNKNOWN; | 
|  | } | 
|  |  | 
|  | int EventFlagsFromNative(const base::NativeEvent& native_event) { | 
|  | int flags = KeyStateFlagsFromNative(native_event); | 
|  | if (IsMouseEvent(native_event)) | 
|  | flags |= MouseStateFlagsFromNative(native_event); | 
|  |  | 
|  | return flags; | 
|  | } | 
|  |  | 
|  | base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) { | 
|  | return base::TimeDelta::FromMilliseconds(native_event.time); | 
|  | } | 
|  |  | 
|  | gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) { | 
|  | POINT native_point; | 
|  | if ((native_event.message == WM_MOUSELEAVE || | 
|  | native_event.message == WM_NCMOUSELEAVE) || | 
|  | IsScrollEvent(native_event)) { | 
|  | // These events have no coordinates. For sanity with rest of events grab | 
|  | // coordinates from the OS. | 
|  | ::GetCursorPos(&native_point); | 
|  | } else if (IsClientMouseEvent(native_event) && | 
|  | !IsMouseWheelEvent(native_event)) { | 
|  | // Note: Wheel events are considered client, but their position is in screen | 
|  | //       coordinates. | 
|  | // Client message. The position is contained in the LPARAM. | 
|  | return gfx::Point(native_event.lParam); | 
|  | } else { | 
|  | DCHECK(IsNonClientMouseEvent(native_event) || | 
|  | IsMouseWheelEvent(native_event) || IsScrollEvent(native_event)); | 
|  | // Non-client message. The position is contained in a POINTS structure in | 
|  | // LPARAM, and is in screen coordinates so we have to convert to client. | 
|  | native_point.x = GET_X_LPARAM(native_event.lParam); | 
|  | native_point.y = GET_Y_LPARAM(native_event.lParam); | 
|  | } | 
|  | ScreenToClient(native_event.hwnd, &native_point); | 
|  | return gfx::Point(native_point); | 
|  | } | 
|  |  | 
|  | gfx::Point EventSystemLocationFromNative( | 
|  | const base::NativeEvent& native_event) { | 
|  | POINT global_point = { static_cast<short>(LOWORD(native_event.lParam)), | 
|  | static_cast<short>(HIWORD(native_event.lParam)) }; | 
|  | ClientToScreen(native_event.hwnd, &global_point); | 
|  | return gfx::Point(global_point); | 
|  | } | 
|  |  | 
|  | KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) { | 
|  | return KeyboardCodeForWindowsKeyCode(static_cast<WORD>(native_event.wParam)); | 
|  | } | 
|  |  | 
|  | const char* CodeFromNative(const base::NativeEvent& native_event) { | 
|  | const uint16 scan_code = GetScanCodeFromLParam(native_event.lParam); | 
|  | return CodeForWindowsScanCode(scan_code); | 
|  | } | 
|  |  | 
|  | uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) { | 
|  | return static_cast<uint32>(native_event.wParam); | 
|  | } | 
|  |  | 
|  | bool IsCharFromNative(const base::NativeEvent& native_event) { | 
|  | return native_event.message == WM_CHAR; | 
|  | } | 
|  |  | 
|  | int GetChangedMouseButtonFlagsFromNative( | 
|  | const base::NativeEvent& native_event) { | 
|  | switch (GetNativeMouseKey(native_event)) { | 
|  | case MK_LBUTTON: | 
|  | return EF_LEFT_MOUSE_BUTTON; | 
|  | case MK_MBUTTON: | 
|  | return EF_MIDDLE_MOUSE_BUTTON; | 
|  | case MK_RBUTTON: | 
|  | return EF_RIGHT_MOUSE_BUTTON; | 
|  | // TODO: add support for MK_XBUTTON1. | 
|  | default: | 
|  | break; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) { | 
|  | DCHECK(native_event.message == WM_MOUSEWHEEL || | 
|  | native_event.message == WM_MOUSEHWHEEL); | 
|  | if (native_event.message == WM_MOUSEWHEEL) | 
|  | return gfx::Vector2d(0, GET_WHEEL_DELTA_WPARAM(native_event.wParam)); | 
|  | return gfx::Vector2d(GET_WHEEL_DELTA_WPARAM(native_event.wParam), 0); | 
|  | } | 
|  |  | 
|  | base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) { | 
|  | return event; | 
|  | } | 
|  |  | 
|  | void ReleaseCopiedNativeEvent(const base::NativeEvent& event) { | 
|  | } | 
|  |  | 
|  | void IncrementTouchIdRefCount(const base::NativeEvent& event) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void ClearTouchIdIfReleased(const base::NativeEvent& xev) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | int GetTouchId(const base::NativeEvent& xev) { | 
|  | NOTIMPLEMENTED(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | float GetTouchRadiusX(const base::NativeEvent& native_event) { | 
|  | NOTIMPLEMENTED(); | 
|  | return 1.0; | 
|  | } | 
|  |  | 
|  | float GetTouchRadiusY(const base::NativeEvent& native_event) { | 
|  | NOTIMPLEMENTED(); | 
|  | return 1.0; | 
|  | } | 
|  |  | 
|  | float GetTouchAngle(const base::NativeEvent& native_event) { | 
|  | NOTIMPLEMENTED(); | 
|  | return 0.0; | 
|  | } | 
|  |  | 
|  | float GetTouchForce(const base::NativeEvent& native_event) { | 
|  | NOTIMPLEMENTED(); | 
|  | return 0.0; | 
|  | } | 
|  |  | 
|  | bool GetScrollOffsets(const base::NativeEvent& native_event, | 
|  | float* x_offset, | 
|  | float* y_offset, | 
|  | float* x_offset_ordinal, | 
|  | float* y_offset_ordinal, | 
|  | int* finger_count) { | 
|  | // TODO(ananta) | 
|  | // Support retrieving the scroll offsets from the scroll event. | 
|  | if (native_event.message == WM_VSCROLL || native_event.message == WM_HSCROLL) | 
|  | return true; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GetFlingData(const base::NativeEvent& native_event, | 
|  | float* vx, | 
|  | float* vy, | 
|  | float* vx_ordinal, | 
|  | float* vy_ordinal, | 
|  | bool* is_cancel) { | 
|  | // Not supported in Windows. | 
|  | NOTIMPLEMENTED(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | int GetModifiersFromACCEL(const ACCEL& accel) { | 
|  | int modifiers = EF_NONE; | 
|  | if (accel.fVirt & FSHIFT) | 
|  | modifiers |= EF_SHIFT_DOWN; | 
|  | if (accel.fVirt & FCONTROL) | 
|  | modifiers |= EF_CONTROL_DOWN; | 
|  | if (accel.fVirt & FALT) | 
|  | modifiers |= EF_ALT_DOWN; | 
|  | return modifiers; | 
|  | } | 
|  |  | 
|  | int GetModifiersFromKeyState() { | 
|  | int modifiers = EF_NONE; | 
|  | if (base::win::IsShiftPressed()) | 
|  | modifiers |= EF_SHIFT_DOWN; | 
|  | if (base::win::IsCtrlPressed()) | 
|  | modifiers |= EF_CONTROL_DOWN; | 
|  | if (base::win::IsAltPressed()) | 
|  | modifiers |= EF_ALT_DOWN; | 
|  | if (base::win::IsAltGrPressed()) | 
|  | modifiers |= EF_ALTGR_DOWN; | 
|  | return modifiers; | 
|  | } | 
|  |  | 
|  | // Windows emulates mouse messages for touch events. | 
|  | bool IsMouseEventFromTouch(UINT message) { | 
|  | return (message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST) && | 
|  | (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == | 
|  | MOUSEEVENTF_FROMTOUCH; | 
|  | } | 
|  |  | 
|  | // Conversion scan_code and LParam each other. | 
|  | // uint16 scan_code: | 
|  | //     ui/events/keycodes/dom4/keycode_converter_data.h | 
|  | // 0 - 15bits: represetns the scan code. | 
|  | // 28 - 30 bits (0xE000): represents whether this is an extended key or not. | 
|  | // | 
|  | // LPARAM lParam: | 
|  | //     http://msdn.microsoft.com/en-us/library/windows/desktop/ms644984.aspx | 
|  | // 16 - 23bits: represetns the scan code. | 
|  | // 24bit (0x0100): represents whether this is an extended key or not. | 
|  | uint16 GetScanCodeFromLParam(LPARAM l_param) { | 
|  | uint16 scan_code = ((l_param >> 16) & 0x00FF); | 
|  | if (l_param & (1 << 24)) | 
|  | scan_code |= 0xE000; | 
|  | return scan_code; | 
|  | } | 
|  |  | 
|  | LPARAM GetLParamFromScanCode(uint16 scan_code) { | 
|  | LPARAM l_param = static_cast<LPARAM>(scan_code & 0x00FF) << 16; | 
|  | if ((scan_code & 0xE000) == 0xE000) | 
|  | l_param |= (1 << 24); | 
|  | return l_param; | 
|  | } | 
|  |  | 
|  | }  // namespace ui |