1 // Copyright (c) 2012 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.
7 #include "ui/events/event_constants.h"
9 #include "base/logging.h"
10 #include "base/time/time.h"
11 #include "base/win/win_util.h"
12 #include "ui/events/event_utils.h"
13 #include "ui/events/keycodes/keyboard_code_conversion_win.h"
14 #include "ui/gfx/geometry/point.h"
15 #include "ui/gfx/win/dpi.h"
21 // From MSDN: "Mouse" events are flagged with 0xFF515700 if they come
22 // from a touch or stylus device. In Vista or later, they are also flagged
23 // with 0x80 if they come from touch.
24 #define MOUSEEVENTF_FROMTOUCH (0xFF515700 | 0x80)
26 // Get the native mouse key state from the native event message type.
27 int GetNativeMouseKey(const base::NativeEvent
& native_event
) {
28 switch (native_event
.message
) {
29 case WM_LBUTTONDBLCLK
:
32 case WM_NCLBUTTONDBLCLK
:
33 case WM_NCLBUTTONDOWN
:
36 case WM_MBUTTONDBLCLK
:
39 case WM_NCMBUTTONDBLCLK
:
40 case WM_NCMBUTTONDOWN
:
43 case WM_RBUTTONDBLCLK
:
46 case WM_NCRBUTTONDBLCLK
:
47 case WM_NCRBUTTONDOWN
:
50 case WM_NCXBUTTONDBLCLK
:
51 case WM_NCXBUTTONDOWN
:
53 case WM_XBUTTONDBLCLK
:
61 bool IsButtonDown(const base::NativeEvent
& native_event
) {
62 return ((MK_LBUTTON
| MK_MBUTTON
| MK_RBUTTON
| MK_XBUTTON1
| MK_XBUTTON2
) &
63 native_event
.wParam
) != 0;
66 bool IsClientMouseEvent(const base::NativeEvent
& native_event
) {
67 return native_event
.message
== WM_MOUSELEAVE
||
68 native_event
.message
== WM_MOUSEHOVER
||
69 (native_event
.message
>= WM_MOUSEFIRST
&&
70 native_event
.message
<= WM_MOUSELAST
);
73 bool IsNonClientMouseEvent(const base::NativeEvent
& native_event
) {
74 return native_event
.message
== WM_NCMOUSELEAVE
||
75 native_event
.message
== WM_NCMOUSEHOVER
||
76 (native_event
.message
>= WM_NCMOUSEMOVE
&&
77 native_event
.message
<= WM_NCXBUTTONDBLCLK
);
80 bool IsMouseEvent(const base::NativeEvent
& native_event
) {
81 return IsClientMouseEvent(native_event
) ||
82 IsNonClientMouseEvent(native_event
);
85 bool IsMouseWheelEvent(const base::NativeEvent
& native_event
) {
86 return native_event
.message
== WM_MOUSEWHEEL
||
87 native_event
.message
== WM_MOUSEHWHEEL
;
90 bool IsKeyEvent(const base::NativeEvent
& native_event
) {
91 return native_event
.message
== WM_KEYDOWN
||
92 native_event
.message
== WM_SYSKEYDOWN
||
93 native_event
.message
== WM_CHAR
||
94 native_event
.message
== WM_KEYUP
||
95 native_event
.message
== WM_SYSKEYUP
;
98 bool IsScrollEvent(const base::NativeEvent
& native_event
) {
99 return native_event
.message
== WM_VSCROLL
||
100 native_event
.message
== WM_HSCROLL
;
103 // Returns a mask corresponding to the set of pressed modifier keys.
104 // Checks the current global state and the state sent by client mouse messages.
105 int KeyStateFlagsFromNative(const base::NativeEvent
& native_event
) {
107 flags
|= base::win::IsAltPressed() ? EF_ALT_DOWN
: EF_NONE
;
108 flags
|= base::win::IsShiftPressed() ? EF_SHIFT_DOWN
: EF_NONE
;
109 flags
|= base::win::IsCtrlPressed() ? EF_CONTROL_DOWN
: EF_NONE
;
111 // Check key messages for the extended key flag.
112 if (IsKeyEvent(native_event
))
113 flags
|= (HIWORD(native_event
.lParam
) & KF_EXTENDED
) ? EF_EXTENDED
: 0;
115 // Most client mouse messages include key state information.
116 if (IsClientMouseEvent(native_event
)) {
117 int win_flags
= GET_KEYSTATE_WPARAM(native_event
.wParam
);
118 flags
|= (win_flags
& MK_SHIFT
) ? EF_SHIFT_DOWN
: 0;
119 flags
|= (win_flags
& MK_CONTROL
) ? EF_CONTROL_DOWN
: 0;
125 // Returns a mask corresponding to the set of pressed mouse buttons.
126 // This includes the button of the given message, even if it is being released.
127 int MouseStateFlagsFromNative(const base::NativeEvent
& native_event
) {
128 int win_flags
= GetNativeMouseKey(native_event
);
130 // Client mouse messages provide key states in their WPARAMs.
131 if (IsClientMouseEvent(native_event
))
132 win_flags
|= GET_KEYSTATE_WPARAM(native_event
.wParam
);
135 flags
|= (win_flags
& MK_LBUTTON
) ? EF_LEFT_MOUSE_BUTTON
: 0;
136 flags
|= (win_flags
& MK_MBUTTON
) ? EF_MIDDLE_MOUSE_BUTTON
: 0;
137 flags
|= (win_flags
& MK_RBUTTON
) ? EF_RIGHT_MOUSE_BUTTON
: 0;
138 flags
|= IsNonClientMouseEvent(native_event
) ? EF_IS_NON_CLIENT
: 0;
144 void UpdateDeviceList() {
148 EventType
EventTypeFromNative(const base::NativeEvent
& native_event
) {
149 switch (native_event
.message
) {
153 return ET_KEY_PRESSED
;
154 // The WM_DEADCHAR message is posted to the window with the keyboard focus
155 // when a WM_KEYUP message is translated. This happens for special keyboard
160 return ET_KEY_RELEASED
;
161 case WM_LBUTTONDBLCLK
:
163 case WM_MBUTTONDBLCLK
:
165 case WM_NCLBUTTONDBLCLK
:
166 case WM_NCLBUTTONDOWN
:
167 case WM_NCMBUTTONDBLCLK
:
168 case WM_NCMBUTTONDOWN
:
169 case WM_NCRBUTTONDBLCLK
:
170 case WM_NCRBUTTONDOWN
:
171 case WM_NCXBUTTONDBLCLK
:
172 case WM_NCXBUTTONDOWN
:
173 case WM_RBUTTONDBLCLK
:
175 case WM_XBUTTONDBLCLK
:
177 return ET_MOUSE_PRESSED
;
186 return ET_MOUSE_RELEASED
;
188 return IsButtonDown(native_event
) ? ET_MOUSE_DRAGGED
: ET_MOUSE_MOVED
;
190 return ET_MOUSE_MOVED
;
193 return ET_MOUSEWHEEL
;
195 case WM_NCMOUSELEAVE
:
196 return ET_MOUSE_EXITED
;
201 // We can't NOTREACHED() here, since this function can be called for any
208 int EventFlagsFromNative(const base::NativeEvent
& native_event
) {
209 int flags
= KeyStateFlagsFromNative(native_event
);
210 if (IsMouseEvent(native_event
))
211 flags
|= MouseStateFlagsFromNative(native_event
);
216 base::TimeDelta
EventTimeFromNative(const base::NativeEvent
& native_event
) {
217 return base::TimeDelta::FromMilliseconds(native_event
.time
);
220 gfx::Point
EventLocationFromNative(const base::NativeEvent
& native_event
) {
222 if ((native_event
.message
== WM_MOUSELEAVE
||
223 native_event
.message
== WM_NCMOUSELEAVE
) ||
224 IsScrollEvent(native_event
)) {
225 // These events have no coordinates. For sanity with rest of events grab
226 // coordinates from the OS.
227 ::GetCursorPos(&native_point
);
228 } else if (IsClientMouseEvent(native_event
) &&
229 !IsMouseWheelEvent(native_event
)) {
230 // Note: Wheel events are considered client, but their position is in screen
232 // Client message. The position is contained in the LPARAM.
233 return gfx::Point(native_event
.lParam
);
235 DCHECK(IsNonClientMouseEvent(native_event
) ||
236 IsMouseWheelEvent(native_event
) || IsScrollEvent(native_event
));
237 // Non-client message. The position is contained in a POINTS structure in
238 // LPARAM, and is in screen coordinates so we have to convert to client.
239 native_point
.x
= GET_X_LPARAM(native_event
.lParam
);
240 native_point
.y
= GET_Y_LPARAM(native_event
.lParam
);
242 ScreenToClient(native_event
.hwnd
, &native_point
);
243 return gfx::Point(native_point
);
246 gfx::Point
EventSystemLocationFromNative(
247 const base::NativeEvent
& native_event
) {
248 POINT global_point
= { static_cast<short>(LOWORD(native_event
.lParam
)),
249 static_cast<short>(HIWORD(native_event
.lParam
)) };
250 ClientToScreen(native_event
.hwnd
, &global_point
);
251 return gfx::Point(global_point
);
254 KeyboardCode
KeyboardCodeFromNative(const base::NativeEvent
& native_event
) {
255 return KeyboardCodeForWindowsKeyCode(static_cast<WORD
>(native_event
.wParam
));
258 DomCode
CodeFromNative(const base::NativeEvent
& native_event
) {
259 const uint16 scan_code
= GetScanCodeFromLParam(native_event
.lParam
);
260 return CodeForWindowsScanCode(scan_code
);
263 uint32
PlatformKeycodeFromNative(const base::NativeEvent
& native_event
) {
264 return static_cast<uint32
>(native_event
.wParam
);
267 bool IsCharFromNative(const base::NativeEvent
& native_event
) {
268 return native_event
.message
== WM_CHAR
;
271 int GetChangedMouseButtonFlagsFromNative(
272 const base::NativeEvent
& native_event
) {
273 switch (GetNativeMouseKey(native_event
)) {
275 return EF_LEFT_MOUSE_BUTTON
;
277 return EF_MIDDLE_MOUSE_BUTTON
;
279 return EF_RIGHT_MOUSE_BUTTON
;
280 // TODO: add support for MK_XBUTTON1.
287 gfx::Vector2d
GetMouseWheelOffset(const base::NativeEvent
& native_event
) {
288 DCHECK(native_event
.message
== WM_MOUSEWHEEL
||
289 native_event
.message
== WM_MOUSEHWHEEL
);
290 if (native_event
.message
== WM_MOUSEWHEEL
)
291 return gfx::Vector2d(0, GET_WHEEL_DELTA_WPARAM(native_event
.wParam
));
292 return gfx::Vector2d(GET_WHEEL_DELTA_WPARAM(native_event
.wParam
), 0);
295 base::NativeEvent
CopyNativeEvent(const base::NativeEvent
& event
) {
299 void ReleaseCopiedNativeEvent(const base::NativeEvent
& event
) {
302 void IncrementTouchIdRefCount(const base::NativeEvent
& event
) {
306 void ClearTouchIdIfReleased(const base::NativeEvent
& xev
) {
310 int GetTouchId(const base::NativeEvent
& xev
) {
315 float GetTouchRadiusX(const base::NativeEvent
& native_event
) {
320 float GetTouchRadiusY(const base::NativeEvent
& native_event
) {
325 float GetTouchAngle(const base::NativeEvent
& native_event
) {
330 float GetTouchForce(const base::NativeEvent
& native_event
) {
335 bool GetScrollOffsets(const base::NativeEvent
& native_event
,
338 float* x_offset_ordinal
,
339 float* y_offset_ordinal
,
342 // Support retrieving the scroll offsets from the scroll event.
343 if (native_event
.message
== WM_VSCROLL
|| native_event
.message
== WM_HSCROLL
)
348 bool GetFlingData(const base::NativeEvent
& native_event
,
354 // Not supported in Windows.
359 int GetModifiersFromACCEL(const ACCEL
& accel
) {
360 int modifiers
= EF_NONE
;
361 if (accel
.fVirt
& FSHIFT
)
362 modifiers
|= EF_SHIFT_DOWN
;
363 if (accel
.fVirt
& FCONTROL
)
364 modifiers
|= EF_CONTROL_DOWN
;
365 if (accel
.fVirt
& FALT
)
366 modifiers
|= EF_ALT_DOWN
;
370 int GetModifiersFromKeyState() {
371 int modifiers
= EF_NONE
;
372 if (base::win::IsShiftPressed())
373 modifiers
|= EF_SHIFT_DOWN
;
374 if (base::win::IsCtrlPressed())
375 modifiers
|= EF_CONTROL_DOWN
;
376 if (base::win::IsAltPressed())
377 modifiers
|= EF_ALT_DOWN
;
378 if (base::win::IsAltGrPressed())
379 modifiers
|= EF_ALTGR_DOWN
;
383 // Windows emulates mouse messages for touch events.
384 bool IsMouseEventFromTouch(UINT message
) {
385 return (message
>= WM_MOUSEFIRST
) && (message
<= WM_MOUSELAST
) &&
386 (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH
) ==
387 MOUSEEVENTF_FROMTOUCH
;
390 // Conversion scan_code and LParam each other.
392 // ui/events/keycodes/dom4/keycode_converter_data.h
393 // 0 - 15bits: represetns the scan code.
394 // 28 - 30 bits (0xE000): represents whether this is an extended key or not.
397 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms644984.aspx
398 // 16 - 23bits: represetns the scan code.
399 // 24bit (0x0100): represents whether this is an extended key or not.
400 uint16
GetScanCodeFromLParam(LPARAM l_param
) {
401 uint16 scan_code
= ((l_param
>> 16) & 0x00FF);
402 if (l_param
& (1 << 24))
407 LPARAM
GetLParamFromScanCode(uint16 scan_code
) {
408 LPARAM l_param
= static_cast<LPARAM
>(scan_code
& 0x00FF) << 16;
409 if ((scan_code
& 0xE000) == 0xE000)
410 l_param
|= (1 << 24);