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.
4
5 #include <windowsx.h>
6
7 #include "ui/events/event_constants.h"
8
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/point.h"
15 #include "ui/gfx/win/dpi.h"
16
17 namespace ui {
18
19 namespace {
20
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)
25
26 // Get the native mouse key state from the native event message type.
GetNativeMouseKey(const base::NativeEvent & native_event)27 int GetNativeMouseKey(const base::NativeEvent& native_event) {
28 switch (native_event.message) {
29 case WM_LBUTTONDBLCLK:
30 case WM_LBUTTONDOWN:
31 case WM_LBUTTONUP:
32 case WM_NCLBUTTONDBLCLK:
33 case WM_NCLBUTTONDOWN:
34 case WM_NCLBUTTONUP:
35 return MK_LBUTTON;
36 case WM_MBUTTONDBLCLK:
37 case WM_MBUTTONDOWN:
38 case WM_MBUTTONUP:
39 case WM_NCMBUTTONDBLCLK:
40 case WM_NCMBUTTONDOWN:
41 case WM_NCMBUTTONUP:
42 return MK_MBUTTON;
43 case WM_RBUTTONDBLCLK:
44 case WM_RBUTTONDOWN:
45 case WM_RBUTTONUP:
46 case WM_NCRBUTTONDBLCLK:
47 case WM_NCRBUTTONDOWN:
48 case WM_NCRBUTTONUP:
49 return MK_RBUTTON;
50 case WM_NCXBUTTONDBLCLK:
51 case WM_NCXBUTTONDOWN:
52 case WM_NCXBUTTONUP:
53 case WM_XBUTTONDBLCLK:
54 case WM_XBUTTONDOWN:
55 case WM_XBUTTONUP:
56 return MK_XBUTTON1;
57 }
58 return 0;
59 }
60
IsButtonDown(const base::NativeEvent & native_event)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;
64 }
65
IsClientMouseEvent(const base::NativeEvent & native_event)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);
71 }
72
IsNonClientMouseEvent(const base::NativeEvent & native_event)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);
78 }
79
IsMouseWheelEvent(const base::NativeEvent & native_event)80 bool IsMouseWheelEvent(const base::NativeEvent& native_event) {
81 return native_event.message == WM_MOUSEWHEEL ||
82 native_event.message == WM_MOUSEHWHEEL;
83 }
84
IsKeyEvent(const base::NativeEvent & native_event)85 bool IsKeyEvent(const base::NativeEvent& native_event) {
86 return native_event.message == WM_KEYDOWN ||
87 native_event.message == WM_SYSKEYDOWN ||
88 native_event.message == WM_CHAR ||
89 native_event.message == WM_KEYUP ||
90 native_event.message == WM_SYSKEYUP;
91 }
92
IsScrollEvent(const base::NativeEvent & native_event)93 bool IsScrollEvent(const base::NativeEvent& native_event) {
94 return native_event.message == WM_VSCROLL ||
95 native_event.message == WM_HSCROLL;
96 }
97
98 // Returns a mask corresponding to the set of pressed modifier keys.
99 // Checks the current global state and the state sent by client mouse messages.
KeyStateFlagsFromNative(const base::NativeEvent & native_event)100 int KeyStateFlagsFromNative(const base::NativeEvent& native_event) {
101 int flags = 0;
102 flags |= base::win::IsAltPressed() ? EF_ALT_DOWN : EF_NONE;
103 flags |= base::win::IsShiftPressed() ? EF_SHIFT_DOWN : EF_NONE;
104 flags |= base::win::IsCtrlPressed() ? EF_CONTROL_DOWN : EF_NONE;
105
106 // Check key messages for the extended key flag.
107 if (IsKeyEvent(native_event))
108 flags |= (HIWORD(native_event.lParam) & KF_EXTENDED) ? EF_EXTENDED : 0;
109
110 // Most client mouse messages include key state information.
111 if (IsClientMouseEvent(native_event)) {
112 int win_flags = GET_KEYSTATE_WPARAM(native_event.wParam);
113 flags |= (win_flags & MK_SHIFT) ? EF_SHIFT_DOWN : 0;
114 flags |= (win_flags & MK_CONTROL) ? EF_CONTROL_DOWN : 0;
115 }
116
117 return flags;
118 }
119
120 // Returns a mask corresponding to the set of pressed mouse buttons.
121 // This includes the button of the given message, even if it is being released.
MouseStateFlagsFromNative(const base::NativeEvent & native_event)122 int MouseStateFlagsFromNative(const base::NativeEvent& native_event) {
123 int win_flags = GetNativeMouseKey(native_event);
124
125 // Client mouse messages provide key states in their WPARAMs.
126 if (IsClientMouseEvent(native_event))
127 win_flags |= GET_KEYSTATE_WPARAM(native_event.wParam);
128
129 int flags = 0;
130 flags |= (win_flags & MK_LBUTTON) ? EF_LEFT_MOUSE_BUTTON : 0;
131 flags |= (win_flags & MK_MBUTTON) ? EF_MIDDLE_MOUSE_BUTTON : 0;
132 flags |= (win_flags & MK_RBUTTON) ? EF_RIGHT_MOUSE_BUTTON : 0;
133 flags |= IsNonClientMouseEvent(native_event) ? EF_IS_NON_CLIENT : 0;
134 return flags;
135 }
136
137 } // namespace
138
UpdateDeviceList()139 void UpdateDeviceList() {
140 NOTIMPLEMENTED();
141 }
142
EventTypeFromNative(const base::NativeEvent & native_event)143 EventType EventTypeFromNative(const base::NativeEvent& native_event) {
144 switch (native_event.message) {
145 case WM_KEYDOWN:
146 case WM_SYSKEYDOWN:
147 case WM_CHAR:
148 return ET_KEY_PRESSED;
149 case WM_KEYUP:
150 case WM_SYSKEYUP:
151 return ET_KEY_RELEASED;
152 case WM_LBUTTONDBLCLK:
153 case WM_LBUTTONDOWN:
154 case WM_MBUTTONDBLCLK:
155 case WM_MBUTTONDOWN:
156 case WM_NCLBUTTONDBLCLK:
157 case WM_NCLBUTTONDOWN:
158 case WM_NCMBUTTONDBLCLK:
159 case WM_NCMBUTTONDOWN:
160 case WM_NCRBUTTONDBLCLK:
161 case WM_NCRBUTTONDOWN:
162 case WM_NCXBUTTONDBLCLK:
163 case WM_NCXBUTTONDOWN:
164 case WM_RBUTTONDBLCLK:
165 case WM_RBUTTONDOWN:
166 case WM_XBUTTONDBLCLK:
167 case WM_XBUTTONDOWN:
168 return ET_MOUSE_PRESSED;
169 case WM_LBUTTONUP:
170 case WM_MBUTTONUP:
171 case WM_NCLBUTTONUP:
172 case WM_NCMBUTTONUP:
173 case WM_NCRBUTTONUP:
174 case WM_NCXBUTTONUP:
175 case WM_RBUTTONUP:
176 case WM_XBUTTONUP:
177 return ET_MOUSE_RELEASED;
178 case WM_MOUSEMOVE:
179 return IsButtonDown(native_event) ? ET_MOUSE_DRAGGED : ET_MOUSE_MOVED;
180 case WM_NCMOUSEMOVE:
181 return ET_MOUSE_MOVED;
182 case WM_MOUSEWHEEL:
183 case WM_MOUSEHWHEEL:
184 return ET_MOUSEWHEEL;
185 case WM_MOUSELEAVE:
186 case WM_NCMOUSELEAVE:
187 return ET_MOUSE_EXITED;
188 case WM_VSCROLL:
189 case WM_HSCROLL:
190 return ET_SCROLL;
191 default:
192 // We can't NOTREACHED() here, since this function can be called for any
193 // message.
194 break;
195 }
196 return ET_UNKNOWN;
197 }
198
EventFlagsFromNative(const base::NativeEvent & native_event)199 int EventFlagsFromNative(const base::NativeEvent& native_event) {
200 int flags = KeyStateFlagsFromNative(native_event);
201 if (IsMouseEvent(native_event))
202 flags |= MouseStateFlagsFromNative(native_event);
203
204 return flags;
205 }
206
EventTimeFromNative(const base::NativeEvent & native_event)207 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
208 return base::TimeDelta::FromMilliseconds(native_event.time);
209 }
210
EventLocationFromNative(const base::NativeEvent & native_event)211 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
212 POINT native_point;
213 if ((native_event.message == WM_MOUSELEAVE ||
214 native_event.message == WM_NCMOUSELEAVE) ||
215 IsScrollEvent(native_event)) {
216 // These events have no coordinates. For sanity with rest of events grab
217 // coordinates from the OS.
218 ::GetCursorPos(&native_point);
219 } else if (IsClientMouseEvent(native_event) &&
220 !IsMouseWheelEvent(native_event)) {
221 // Note: Wheel events are considered client, but their position is in screen
222 // coordinates.
223 // Client message. The position is contained in the LPARAM.
224 return gfx::Point(native_event.lParam);
225 } else {
226 DCHECK(IsNonClientMouseEvent(native_event) ||
227 IsMouseWheelEvent(native_event) || IsScrollEvent(native_event));
228 // Non-client message. The position is contained in a POINTS structure in
229 // LPARAM, and is in screen coordinates so we have to convert to client.
230 native_point.x = GET_X_LPARAM(native_event.lParam);
231 native_point.y = GET_Y_LPARAM(native_event.lParam);
232 }
233 ScreenToClient(native_event.hwnd, &native_point);
234 return gfx::win::ScreenToDIPPoint(gfx::Point(native_point));
235 }
236
EventSystemLocationFromNative(const base::NativeEvent & native_event)237 gfx::Point EventSystemLocationFromNative(
238 const base::NativeEvent& native_event) {
239 // TODO(ben): Needs to always return screen position here. Returning normal
240 // origin for now since that's obviously wrong.
241 return gfx::Point(0, 0);
242 }
243
KeyboardCodeFromNative(const base::NativeEvent & native_event)244 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
245 return KeyboardCodeForWindowsKeyCode(native_event.wParam);
246 }
247
CodeFromNative(const base::NativeEvent & native_event)248 const char* CodeFromNative(const base::NativeEvent& native_event) {
249 const uint16 scan_code = GetScanCodeFromLParam(native_event.lParam);
250 return CodeForWindowsScanCode(scan_code);
251 }
252
IsMouseEvent(const base::NativeEvent & native_event)253 bool IsMouseEvent(const base::NativeEvent& native_event) {
254 return IsClientMouseEvent(native_event) ||
255 IsNonClientMouseEvent(native_event);
256 }
257
GetChangedMouseButtonFlagsFromNative(const base::NativeEvent & native_event)258 int GetChangedMouseButtonFlagsFromNative(
259 const base::NativeEvent& native_event) {
260 switch (GetNativeMouseKey(native_event)) {
261 case MK_LBUTTON:
262 return EF_LEFT_MOUSE_BUTTON;
263 case MK_MBUTTON:
264 return EF_MIDDLE_MOUSE_BUTTON;
265 case MK_RBUTTON:
266 return EF_RIGHT_MOUSE_BUTTON;
267 // TODO: add support for MK_XBUTTON1.
268 default:
269 break;
270 }
271 return 0;
272 }
273
GetMouseWheelOffset(const base::NativeEvent & native_event)274 gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
275 DCHECK(native_event.message == WM_MOUSEWHEEL ||
276 native_event.message == WM_MOUSEHWHEEL);
277 if (native_event.message == WM_MOUSEWHEEL)
278 return gfx::Vector2d(0, GET_WHEEL_DELTA_WPARAM(native_event.wParam));
279 return gfx::Vector2d(GET_WHEEL_DELTA_WPARAM(native_event.wParam), 0);
280 }
281
ClearTouchIdIfReleased(const base::NativeEvent & xev)282 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
283 NOTIMPLEMENTED();
284 }
285
GetTouchId(const base::NativeEvent & xev)286 int GetTouchId(const base::NativeEvent& xev) {
287 NOTIMPLEMENTED();
288 return 0;
289 }
290
GetTouchRadiusX(const base::NativeEvent & native_event)291 float GetTouchRadiusX(const base::NativeEvent& native_event) {
292 NOTIMPLEMENTED();
293 return 1.0;
294 }
295
GetTouchRadiusY(const base::NativeEvent & native_event)296 float GetTouchRadiusY(const base::NativeEvent& native_event) {
297 NOTIMPLEMENTED();
298 return 1.0;
299 }
300
GetTouchAngle(const base::NativeEvent & native_event)301 float GetTouchAngle(const base::NativeEvent& native_event) {
302 NOTIMPLEMENTED();
303 return 0.0;
304 }
305
GetTouchForce(const base::NativeEvent & native_event)306 float GetTouchForce(const base::NativeEvent& native_event) {
307 NOTIMPLEMENTED();
308 return 0.0;
309 }
310
GetScrollOffsets(const base::NativeEvent & native_event,float * x_offset,float * y_offset,float * x_offset_ordinal,float * y_offset_ordinal,int * finger_count)311 bool GetScrollOffsets(const base::NativeEvent& native_event,
312 float* x_offset,
313 float* y_offset,
314 float* x_offset_ordinal,
315 float* y_offset_ordinal,
316 int* finger_count) {
317 // TODO(ananta)
318 // Support retrieving the scroll offsets from the scroll event.
319 if (native_event.message == WM_VSCROLL || native_event.message == WM_HSCROLL)
320 return true;
321 return false;
322 }
323
GetFlingData(const base::NativeEvent & native_event,float * vx,float * vy,float * vx_ordinal,float * vy_ordinal,bool * is_cancel)324 bool GetFlingData(const base::NativeEvent& native_event,
325 float* vx,
326 float* vy,
327 float* vx_ordinal,
328 float* vy_ordinal,
329 bool* is_cancel) {
330 // Not supported in Windows.
331 NOTIMPLEMENTED();
332 return false;
333 }
334
GetGestureTimes(const base::NativeEvent & native_event,double * start_time,double * end_time)335 bool GetGestureTimes(const base::NativeEvent& native_event,
336 double* start_time,
337 double* end_time) {
338 // Not supported in Windows.
339 *start_time = 0;
340 *end_time = 0;
341 return false;
342 }
343
SetNaturalScroll(bool enabled)344 void SetNaturalScroll(bool enabled) {
345 NOTIMPLEMENTED();
346 }
347
IsNaturalScrollEnabled()348 bool IsNaturalScrollEnabled() {
349 NOTIMPLEMENTED();
350 return false;
351 }
352
IsTouchpadEvent(const base::NativeEvent & event)353 bool IsTouchpadEvent(const base::NativeEvent& event) {
354 NOTIMPLEMENTED();
355 return false;
356 }
357
IsNoopEvent(const base::NativeEvent & event)358 bool IsNoopEvent(const base::NativeEvent& event) {
359 return event.message == WM_USER + 310;
360 }
361
CreateNoopEvent()362 base::NativeEvent CreateNoopEvent() {
363 MSG event = { NULL };
364 event.message = WM_USER + 310;
365 return event;
366 }
367
GetModifiersFromACCEL(const ACCEL & accel)368 int GetModifiersFromACCEL(const ACCEL& accel) {
369 int modifiers = EF_NONE;
370 if (accel.fVirt & FSHIFT)
371 modifiers |= EF_SHIFT_DOWN;
372 if (accel.fVirt & FCONTROL)
373 modifiers |= EF_CONTROL_DOWN;
374 if (accel.fVirt & FALT)
375 modifiers |= EF_ALT_DOWN;
376 return modifiers;
377 }
378
GetModifiersFromKeyState()379 int GetModifiersFromKeyState() {
380 int modifiers = EF_NONE;
381 if (base::win::IsShiftPressed())
382 modifiers |= EF_SHIFT_DOWN;
383 if (base::win::IsCtrlPressed())
384 modifiers |= EF_CONTROL_DOWN;
385 if (base::win::IsAltPressed())
386 modifiers |= EF_ALT_DOWN;
387 if (base::win::IsAltGrPressed())
388 modifiers |= EF_ALTGR_DOWN;
389 return modifiers;
390 }
391
392 // Windows emulates mouse messages for touch events.
IsMouseEventFromTouch(UINT message)393 bool IsMouseEventFromTouch(UINT message) {
394 return (message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST) &&
395 (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) ==
396 MOUSEEVENTF_FROMTOUCH;
397 }
398
399 // Conversion scan_code and LParam each other.
400 // uint16 scan_code:
401 // ui/events/keycodes/dom4/keycode_converter_data.h
402 // 0 - 15bits: represetns the scan code.
403 // 28 - 30 bits (0xE000): represents whether this is an extended key or not.
404 //
405 // LPARAM lParam:
406 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms644984.aspx
407 // 16 - 23bits: represetns the scan code.
408 // 24bit (0x0100): represents whether this is an extended key or not.
GetScanCodeFromLParam(LPARAM l_param)409 uint16 GetScanCodeFromLParam(LPARAM l_param) {
410 uint16 scan_code = ((l_param >> 16) & 0x00FF);
411 if (l_param & (1 << 24))
412 scan_code |= 0xE000;
413 return scan_code;
414 }
415
GetLParamFromScanCode(uint16 scan_code)416 LPARAM GetLParamFromScanCode(uint16 scan_code) {
417 LPARAM l_param = static_cast<LPARAM>(scan_code & 0x00FF) << 16;
418 if ((scan_code & 0xE000) == 0xE000)
419 l_param |= (1 << 24);
420 return l_param;
421 }
422
423 } // namespace ui
424