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/base/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/base/events/event_utils.h" 13 #include "ui/base/keycodes/keyboard_code_conversion_win.h" 14 #include "ui/base/win/dpi.h" 15 #include "ui/gfx/point.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. 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 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 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 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 80 bool IsMouseWheelEvent(const base::NativeEvent& native_event) { 81 return native_event.message == WM_MOUSEWHEEL || 82 native_event.message == WM_MOUSEHWHEEL; 83 } 84 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 93 // Returns a mask corresponding to the set of pressed modifier keys. 94 // Checks the current global state and the state sent by client mouse messages. 95 int KeyStateFlagsFromNative(const base::NativeEvent& native_event) { 96 int flags = 0; 97 flags |= base::win::IsAltPressed() ? EF_ALT_DOWN : EF_NONE; 98 flags |= base::win::IsShiftPressed() ? EF_SHIFT_DOWN : EF_NONE; 99 flags |= base::win::IsCtrlPressed() ? EF_CONTROL_DOWN : EF_NONE; 100 101 // Check key messages for the extended key flag. 102 if (IsKeyEvent(native_event)) 103 flags |= (HIWORD(native_event.lParam) & KF_EXTENDED) ? EF_EXTENDED : 0; 104 105 // Most client mouse messages include key state information. 106 if (IsClientMouseEvent(native_event)) { 107 int win_flags = GET_KEYSTATE_WPARAM(native_event.wParam); 108 flags |= (win_flags & MK_SHIFT) ? EF_SHIFT_DOWN : 0; 109 flags |= (win_flags & MK_CONTROL) ? EF_CONTROL_DOWN : 0; 110 } 111 112 return flags; 113 } 114 115 // Returns a mask corresponding to the set of pressed mouse buttons. 116 // This includes the button of the given message, even if it is being released. 117 int MouseStateFlagsFromNative(const base::NativeEvent& native_event) { 118 int win_flags = GetNativeMouseKey(native_event); 119 120 // Client mouse messages provide key states in their WPARAMs. 121 if (IsClientMouseEvent(native_event)) 122 win_flags |= GET_KEYSTATE_WPARAM(native_event.wParam); 123 124 int flags = 0; 125 flags |= (win_flags & MK_LBUTTON) ? EF_LEFT_MOUSE_BUTTON : 0; 126 flags |= (win_flags & MK_MBUTTON) ? EF_MIDDLE_MOUSE_BUTTON : 0; 127 flags |= (win_flags & MK_RBUTTON) ? EF_RIGHT_MOUSE_BUTTON : 0; 128 flags |= IsNonClientMouseEvent(native_event) ? EF_IS_NON_CLIENT : 0; 129 return flags; 130 } 131 132 } // namespace 133 134 void UpdateDeviceList() { 135 NOTIMPLEMENTED(); 136 } 137 138 EventType EventTypeFromNative(const base::NativeEvent& native_event) { 139 switch (native_event.message) { 140 case WM_KEYDOWN: 141 case WM_SYSKEYDOWN: 142 case WM_CHAR: 143 return ET_KEY_PRESSED; 144 case WM_KEYUP: 145 case WM_SYSKEYUP: 146 return ET_KEY_RELEASED; 147 case WM_LBUTTONDBLCLK: 148 case WM_LBUTTONDOWN: 149 case WM_MBUTTONDBLCLK: 150 case WM_MBUTTONDOWN: 151 case WM_NCLBUTTONDBLCLK: 152 case WM_NCLBUTTONDOWN: 153 case WM_NCMBUTTONDBLCLK: 154 case WM_NCMBUTTONDOWN: 155 case WM_NCRBUTTONDBLCLK: 156 case WM_NCRBUTTONDOWN: 157 case WM_NCXBUTTONDBLCLK: 158 case WM_NCXBUTTONDOWN: 159 case WM_RBUTTONDBLCLK: 160 case WM_RBUTTONDOWN: 161 case WM_XBUTTONDBLCLK: 162 case WM_XBUTTONDOWN: 163 return ET_MOUSE_PRESSED; 164 case WM_LBUTTONUP: 165 case WM_MBUTTONUP: 166 case WM_NCLBUTTONUP: 167 case WM_NCMBUTTONUP: 168 case WM_NCRBUTTONUP: 169 case WM_NCXBUTTONUP: 170 case WM_RBUTTONUP: 171 case WM_XBUTTONUP: 172 return ET_MOUSE_RELEASED; 173 case WM_MOUSEMOVE: 174 return IsButtonDown(native_event) ? ET_MOUSE_DRAGGED : ET_MOUSE_MOVED; 175 case WM_NCMOUSEMOVE: 176 return ET_MOUSE_MOVED; 177 case WM_MOUSEWHEEL: 178 return ET_MOUSEWHEEL; 179 case WM_MOUSELEAVE: 180 case WM_NCMOUSELEAVE: 181 return ET_MOUSE_EXITED; 182 default: 183 // We can't NOTREACHED() here, since this function can be called for any 184 // message. 185 break; 186 } 187 return ET_UNKNOWN; 188 } 189 190 int EventFlagsFromNative(const base::NativeEvent& native_event) { 191 int flags = KeyStateFlagsFromNative(native_event); 192 if (IsMouseEvent(native_event)) 193 flags |= MouseStateFlagsFromNative(native_event); 194 195 return flags; 196 } 197 198 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) { 199 return base::TimeDelta::FromMilliseconds(native_event.time); 200 } 201 202 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) { 203 // Note: Wheel events are considered client, but their position is in screen 204 // coordinates. 205 // Client message. The position is contained in the LPARAM. 206 if (IsClientMouseEvent(native_event) && !IsMouseWheelEvent(native_event)) 207 return gfx::Point(native_event.lParam); 208 DCHECK(IsNonClientMouseEvent(native_event) || 209 IsMouseWheelEvent(native_event)); 210 // Non-client message. The position is contained in a POINTS structure in 211 // LPARAM, and is in screen coordinates so we have to convert to client. 212 POINT native_point = { GET_X_LPARAM(native_event.lParam), 213 GET_Y_LPARAM(native_event.lParam) }; 214 ScreenToClient(native_event.hwnd, &native_point); 215 gfx::Point location(native_point); 216 location = ui::win::ScreenToDIPPoint(location); 217 return location; 218 } 219 220 gfx::Point EventSystemLocationFromNative( 221 const base::NativeEvent& native_event) { 222 // TODO(ben): Needs to always return screen position here. Returning normal 223 // origin for now since that's obviously wrong. 224 return gfx::Point(0, 0); 225 } 226 227 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) { 228 return KeyboardCodeForWindowsKeyCode(native_event.wParam); 229 } 230 231 bool IsMouseEvent(const base::NativeEvent& native_event) { 232 return IsClientMouseEvent(native_event) || 233 IsNonClientMouseEvent(native_event); 234 } 235 236 int GetChangedMouseButtonFlagsFromNative( 237 const base::NativeEvent& native_event) { 238 switch (GetNativeMouseKey(native_event)) { 239 case MK_LBUTTON: 240 return EF_LEFT_MOUSE_BUTTON; 241 case MK_MBUTTON: 242 return EF_MIDDLE_MOUSE_BUTTON; 243 case MK_RBUTTON: 244 return EF_RIGHT_MOUSE_BUTTON; 245 // TODO: add support for MK_XBUTTON1. 246 default: 247 break; 248 } 249 return 0; 250 } 251 252 gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) { 253 DCHECK(native_event.message == WM_MOUSEWHEEL); 254 return gfx::Vector2d(0, GET_WHEEL_DELTA_WPARAM(native_event.wParam)); 255 } 256 257 void ClearTouchIdIfReleased(const base::NativeEvent& xev) { 258 NOTIMPLEMENTED(); 259 } 260 261 int GetTouchId(const base::NativeEvent& xev) { 262 NOTIMPLEMENTED(); 263 return 0; 264 } 265 266 float GetTouchRadiusX(const base::NativeEvent& native_event) { 267 NOTIMPLEMENTED(); 268 return 1.0; 269 } 270 271 float GetTouchRadiusY(const base::NativeEvent& native_event) { 272 NOTIMPLEMENTED(); 273 return 1.0; 274 } 275 276 float GetTouchAngle(const base::NativeEvent& native_event) { 277 NOTIMPLEMENTED(); 278 return 0.0; 279 } 280 281 float GetTouchForce(const base::NativeEvent& native_event) { 282 NOTIMPLEMENTED(); 283 return 0.0; 284 } 285 286 bool GetScrollOffsets(const base::NativeEvent& native_event, 287 float* x_offset, 288 float* y_offset, 289 float* x_offset_ordinal, 290 float* y_offset_ordinal, 291 int* finger_count) { 292 // Not supported in Windows. 293 NOTIMPLEMENTED(); 294 return false; 295 } 296 297 bool GetFlingData(const base::NativeEvent& native_event, 298 float* vx, 299 float* vy, 300 float* vx_ordinal, 301 float* vy_ordinal, 302 bool* is_cancel) { 303 // Not supported in Windows. 304 NOTIMPLEMENTED(); 305 return false; 306 } 307 308 bool GetGestureTimes(const base::NativeEvent& native_event, 309 double* start_time, 310 double* end_time) { 311 // Not supported in Windows. 312 *start_time = 0; 313 *end_time = 0; 314 return false; 315 } 316 317 void SetNaturalScroll(bool enabled) { 318 NOTIMPLEMENTED(); 319 } 320 321 bool IsNaturalScrollEnabled() { 322 NOTIMPLEMENTED(); 323 return false; 324 } 325 326 bool IsTouchpadEvent(const base::NativeEvent& event) { 327 NOTIMPLEMENTED(); 328 return false; 329 } 330 331 bool IsNoopEvent(const base::NativeEvent& event) { 332 return event.message == WM_USER + 310; 333 } 334 335 base::NativeEvent CreateNoopEvent() { 336 MSG event = { NULL }; 337 event.message = WM_USER + 310; 338 return event; 339 } 340 341 int GetModifiersFromACCEL(const ACCEL& accel) { 342 int modifiers = EF_NONE; 343 if (accel.fVirt & FSHIFT) 344 modifiers |= EF_SHIFT_DOWN; 345 if (accel.fVirt & FCONTROL) 346 modifiers |= EF_CONTROL_DOWN; 347 if (accel.fVirt & FALT) 348 modifiers |= EF_ALT_DOWN; 349 return modifiers; 350 } 351 352 int GetModifiersFromKeyState() { 353 int modifiers = EF_NONE; 354 if (base::win::IsShiftPressed()) 355 modifiers |= EF_SHIFT_DOWN; 356 if (base::win::IsCtrlPressed()) 357 modifiers |= EF_CONTROL_DOWN; 358 if (base::win::IsAltPressed()) 359 modifiers |= EF_ALT_DOWN; 360 return modifiers; 361 } 362 363 // Windows emulates mouse messages for touch events. 364 bool IsMouseEventFromTouch(UINT message) { 365 return (message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST) && 366 (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == 367 MOUSEEVENTF_FROMTOUCH; 368 } 369 370 } // namespace ui 371