• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IsMouseEvent(const base::NativeEvent & native_event)80 bool IsMouseEvent(const base::NativeEvent& native_event) {
81   return IsClientMouseEvent(native_event) ||
82          IsNonClientMouseEvent(native_event);
83 }
84 
IsMouseWheelEvent(const base::NativeEvent & native_event)85 bool IsMouseWheelEvent(const base::NativeEvent& native_event) {
86   return native_event.message == WM_MOUSEWHEEL ||
87          native_event.message == WM_MOUSEHWHEEL;
88 }
89 
IsKeyEvent(const base::NativeEvent & native_event)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;
96 }
97 
IsScrollEvent(const base::NativeEvent & native_event)98 bool IsScrollEvent(const base::NativeEvent& native_event) {
99   return native_event.message == WM_VSCROLL ||
100          native_event.message == WM_HSCROLL;
101 }
102 
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.
KeyStateFlagsFromNative(const base::NativeEvent & native_event)105 int KeyStateFlagsFromNative(const base::NativeEvent& native_event) {
106   int flags = 0;
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;
110 
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;
114 
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;
120   }
121 
122   return flags;
123 }
124 
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.
MouseStateFlagsFromNative(const base::NativeEvent & native_event)127 int MouseStateFlagsFromNative(const base::NativeEvent& native_event) {
128   int win_flags = GetNativeMouseKey(native_event);
129 
130   // Client mouse messages provide key states in their WPARAMs.
131   if (IsClientMouseEvent(native_event))
132     win_flags |= GET_KEYSTATE_WPARAM(native_event.wParam);
133 
134   int flags = 0;
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;
139   return flags;
140 }
141 
142 }  // namespace
143 
UpdateDeviceList()144 void UpdateDeviceList() {
145   NOTIMPLEMENTED();
146 }
147 
EventTypeFromNative(const base::NativeEvent & native_event)148 EventType EventTypeFromNative(const base::NativeEvent& native_event) {
149   switch (native_event.message) {
150     case WM_KEYDOWN:
151     case WM_SYSKEYDOWN:
152     case WM_CHAR:
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
156     // sequences.
157     case WM_DEADCHAR:
158     case WM_KEYUP:
159     case WM_SYSKEYUP:
160       return ET_KEY_RELEASED;
161     case WM_LBUTTONDBLCLK:
162     case WM_LBUTTONDOWN:
163     case WM_MBUTTONDBLCLK:
164     case WM_MBUTTONDOWN:
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:
174     case WM_RBUTTONDOWN:
175     case WM_XBUTTONDBLCLK:
176     case WM_XBUTTONDOWN:
177       return ET_MOUSE_PRESSED;
178     case WM_LBUTTONUP:
179     case WM_MBUTTONUP:
180     case WM_NCLBUTTONUP:
181     case WM_NCMBUTTONUP:
182     case WM_NCRBUTTONUP:
183     case WM_NCXBUTTONUP:
184     case WM_RBUTTONUP:
185     case WM_XBUTTONUP:
186       return ET_MOUSE_RELEASED;
187     case WM_MOUSEMOVE:
188       return IsButtonDown(native_event) ? ET_MOUSE_DRAGGED : ET_MOUSE_MOVED;
189     case WM_NCMOUSEMOVE:
190       return ET_MOUSE_MOVED;
191     case WM_MOUSEWHEEL:
192     case WM_MOUSEHWHEEL:
193       return ET_MOUSEWHEEL;
194     case WM_MOUSELEAVE:
195     case WM_NCMOUSELEAVE:
196       return ET_MOUSE_EXITED;
197     case WM_VSCROLL:
198     case WM_HSCROLL:
199       return ET_SCROLL;
200     default:
201       // We can't NOTREACHED() here, since this function can be called for any
202       // message.
203       break;
204   }
205   return ET_UNKNOWN;
206 }
207 
EventFlagsFromNative(const base::NativeEvent & native_event)208 int EventFlagsFromNative(const base::NativeEvent& native_event) {
209   int flags = KeyStateFlagsFromNative(native_event);
210   if (IsMouseEvent(native_event))
211     flags |= MouseStateFlagsFromNative(native_event);
212 
213   return flags;
214 }
215 
EventTimeFromNative(const base::NativeEvent & native_event)216 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
217   return base::TimeDelta::FromMilliseconds(native_event.time);
218 }
219 
EventLocationFromNative(const base::NativeEvent & native_event)220 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
221   POINT native_point;
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
231     //       coordinates.
232     // Client message. The position is contained in the LPARAM.
233     return gfx::Point(native_event.lParam);
234   } else {
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);
241   }
242   ScreenToClient(native_event.hwnd, &native_point);
243   return gfx::Point(native_point);
244 }
245 
EventSystemLocationFromNative(const base::NativeEvent & native_event)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);
252 }
253 
KeyboardCodeFromNative(const base::NativeEvent & native_event)254 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
255   return KeyboardCodeForWindowsKeyCode(native_event.wParam);
256 }
257 
CodeFromNative(const base::NativeEvent & native_event)258 const char* CodeFromNative(const base::NativeEvent& native_event) {
259   const uint16 scan_code = GetScanCodeFromLParam(native_event.lParam);
260   return CodeForWindowsScanCode(scan_code);
261 }
262 
PlatformKeycodeFromNative(const base::NativeEvent & native_event)263 uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) {
264   return static_cast<uint32>(native_event.wParam);
265 }
266 
IsCharFromNative(const base::NativeEvent & native_event)267 bool IsCharFromNative(const base::NativeEvent& native_event) {
268   return native_event.message == WM_CHAR;
269 }
270 
GetChangedMouseButtonFlagsFromNative(const base::NativeEvent & native_event)271 int GetChangedMouseButtonFlagsFromNative(
272     const base::NativeEvent& native_event) {
273   switch (GetNativeMouseKey(native_event)) {
274     case MK_LBUTTON:
275       return EF_LEFT_MOUSE_BUTTON;
276     case MK_MBUTTON:
277       return EF_MIDDLE_MOUSE_BUTTON;
278     case MK_RBUTTON:
279       return EF_RIGHT_MOUSE_BUTTON;
280     // TODO: add support for MK_XBUTTON1.
281     default:
282       break;
283   }
284   return 0;
285 }
286 
GetMouseWheelOffset(const base::NativeEvent & native_event)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);
293 }
294 
CopyNativeEvent(const base::NativeEvent & event)295 base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
296   return event;
297 }
298 
ReleaseCopiedNativeEvent(const base::NativeEvent & event)299 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
300 }
301 
IncrementTouchIdRefCount(const base::NativeEvent & event)302 void IncrementTouchIdRefCount(const base::NativeEvent& event) {
303   NOTIMPLEMENTED();
304 }
305 
ClearTouchIdIfReleased(const base::NativeEvent & xev)306 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
307   NOTIMPLEMENTED();
308 }
309 
GetTouchId(const base::NativeEvent & xev)310 int GetTouchId(const base::NativeEvent& xev) {
311   NOTIMPLEMENTED();
312   return 0;
313 }
314 
GetTouchRadiusX(const base::NativeEvent & native_event)315 float GetTouchRadiusX(const base::NativeEvent& native_event) {
316   NOTIMPLEMENTED();
317   return 1.0;
318 }
319 
GetTouchRadiusY(const base::NativeEvent & native_event)320 float GetTouchRadiusY(const base::NativeEvent& native_event) {
321   NOTIMPLEMENTED();
322   return 1.0;
323 }
324 
GetTouchAngle(const base::NativeEvent & native_event)325 float GetTouchAngle(const base::NativeEvent& native_event) {
326   NOTIMPLEMENTED();
327   return 0.0;
328 }
329 
GetTouchForce(const base::NativeEvent & native_event)330 float GetTouchForce(const base::NativeEvent& native_event) {
331   NOTIMPLEMENTED();
332   return 0.0;
333 }
334 
GetScrollOffsets(const base::NativeEvent & native_event,float * x_offset,float * y_offset,float * x_offset_ordinal,float * y_offset_ordinal,int * finger_count)335 bool GetScrollOffsets(const base::NativeEvent& native_event,
336                       float* x_offset,
337                       float* y_offset,
338                       float* x_offset_ordinal,
339                       float* y_offset_ordinal,
340                       int* finger_count) {
341   // TODO(ananta)
342   // Support retrieving the scroll offsets from the scroll event.
343   if (native_event.message == WM_VSCROLL || native_event.message == WM_HSCROLL)
344     return true;
345   return false;
346 }
347 
GetFlingData(const base::NativeEvent & native_event,float * vx,float * vy,float * vx_ordinal,float * vy_ordinal,bool * is_cancel)348 bool GetFlingData(const base::NativeEvent& native_event,
349                   float* vx,
350                   float* vy,
351                   float* vx_ordinal,
352                   float* vy_ordinal,
353                   bool* is_cancel) {
354   // Not supported in Windows.
355   NOTIMPLEMENTED();
356   return false;
357 }
358 
GetModifiersFromACCEL(const ACCEL & accel)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;
367   return modifiers;
368 }
369 
GetModifiersFromKeyState()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;
380   return modifiers;
381 }
382 
383 // Windows emulates mouse messages for touch events.
IsMouseEventFromTouch(UINT message)384 bool IsMouseEventFromTouch(UINT message) {
385   return (message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST) &&
386       (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) ==
387       MOUSEEVENTF_FROMTOUCH;
388 }
389 
390 // Conversion scan_code and LParam each other.
391 // uint16 scan_code:
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.
395 //
396 // LPARAM lParam:
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.
GetScanCodeFromLParam(LPARAM l_param)400 uint16 GetScanCodeFromLParam(LPARAM l_param) {
401   uint16 scan_code = ((l_param >> 16) & 0x00FF);
402   if (l_param & (1 << 24))
403     scan_code |= 0xE000;
404   return scan_code;
405 }
406 
GetLParamFromScanCode(uint16 scan_code)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);
411   return l_param;
412 }
413 
414 }  // namespace ui
415