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. 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 IsMouseEvent(const base::NativeEvent& native_event) { 81 return IsClientMouseEvent(native_event) || 82 IsNonClientMouseEvent(native_event); 83 } 84 85 bool IsMouseWheelEvent(const base::NativeEvent& native_event) { 86 return native_event.message == WM_MOUSEWHEEL || 87 native_event.message == WM_MOUSEHWHEEL; 88 } 89 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 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. 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. 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 144 void UpdateDeviceList() { 145 NOTIMPLEMENTED(); 146 } 147 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 case WM_KEYUP: 155 case WM_SYSKEYUP: 156 return ET_KEY_RELEASED; 157 case WM_LBUTTONDBLCLK: 158 case WM_LBUTTONDOWN: 159 case WM_MBUTTONDBLCLK: 160 case WM_MBUTTONDOWN: 161 case WM_NCLBUTTONDBLCLK: 162 case WM_NCLBUTTONDOWN: 163 case WM_NCMBUTTONDBLCLK: 164 case WM_NCMBUTTONDOWN: 165 case WM_NCRBUTTONDBLCLK: 166 case WM_NCRBUTTONDOWN: 167 case WM_NCXBUTTONDBLCLK: 168 case WM_NCXBUTTONDOWN: 169 case WM_RBUTTONDBLCLK: 170 case WM_RBUTTONDOWN: 171 case WM_XBUTTONDBLCLK: 172 case WM_XBUTTONDOWN: 173 return ET_MOUSE_PRESSED; 174 case WM_LBUTTONUP: 175 case WM_MBUTTONUP: 176 case WM_NCLBUTTONUP: 177 case WM_NCMBUTTONUP: 178 case WM_NCRBUTTONUP: 179 case WM_NCXBUTTONUP: 180 case WM_RBUTTONUP: 181 case WM_XBUTTONUP: 182 return ET_MOUSE_RELEASED; 183 case WM_MOUSEMOVE: 184 return IsButtonDown(native_event) ? ET_MOUSE_DRAGGED : ET_MOUSE_MOVED; 185 case WM_NCMOUSEMOVE: 186 return ET_MOUSE_MOVED; 187 case WM_MOUSEWHEEL: 188 case WM_MOUSEHWHEEL: 189 return ET_MOUSEWHEEL; 190 case WM_MOUSELEAVE: 191 case WM_NCMOUSELEAVE: 192 return ET_MOUSE_EXITED; 193 case WM_VSCROLL: 194 case WM_HSCROLL: 195 return ET_SCROLL; 196 default: 197 // We can't NOTREACHED() here, since this function can be called for any 198 // message. 199 break; 200 } 201 return ET_UNKNOWN; 202 } 203 204 int EventFlagsFromNative(const base::NativeEvent& native_event) { 205 int flags = KeyStateFlagsFromNative(native_event); 206 if (IsMouseEvent(native_event)) 207 flags |= MouseStateFlagsFromNative(native_event); 208 209 return flags; 210 } 211 212 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) { 213 return base::TimeDelta::FromMilliseconds(native_event.time); 214 } 215 216 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) { 217 POINT native_point; 218 if ((native_event.message == WM_MOUSELEAVE || 219 native_event.message == WM_NCMOUSELEAVE) || 220 IsScrollEvent(native_event)) { 221 // These events have no coordinates. For sanity with rest of events grab 222 // coordinates from the OS. 223 ::GetCursorPos(&native_point); 224 } else if (IsClientMouseEvent(native_event) && 225 !IsMouseWheelEvent(native_event)) { 226 // Note: Wheel events are considered client, but their position is in screen 227 // coordinates. 228 // Client message. The position is contained in the LPARAM. 229 return gfx::Point(native_event.lParam); 230 } else { 231 DCHECK(IsNonClientMouseEvent(native_event) || 232 IsMouseWheelEvent(native_event) || IsScrollEvent(native_event)); 233 // Non-client message. The position is contained in a POINTS structure in 234 // LPARAM, and is in screen coordinates so we have to convert to client. 235 native_point.x = GET_X_LPARAM(native_event.lParam); 236 native_point.y = GET_Y_LPARAM(native_event.lParam); 237 } 238 ScreenToClient(native_event.hwnd, &native_point); 239 return gfx::Point(native_point); 240 } 241 242 gfx::Point EventSystemLocationFromNative( 243 const base::NativeEvent& native_event) { 244 // TODO(ben): Needs to always return screen position here. Returning normal 245 // origin for now since that's obviously wrong. 246 return gfx::Point(0, 0); 247 } 248 249 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) { 250 return KeyboardCodeForWindowsKeyCode(native_event.wParam); 251 } 252 253 const char* CodeFromNative(const base::NativeEvent& native_event) { 254 const uint16 scan_code = GetScanCodeFromLParam(native_event.lParam); 255 return CodeForWindowsScanCode(scan_code); 256 } 257 258 uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) { 259 return static_cast<uint32>(native_event.wParam); 260 } 261 262 int GetChangedMouseButtonFlagsFromNative( 263 const base::NativeEvent& native_event) { 264 switch (GetNativeMouseKey(native_event)) { 265 case MK_LBUTTON: 266 return EF_LEFT_MOUSE_BUTTON; 267 case MK_MBUTTON: 268 return EF_MIDDLE_MOUSE_BUTTON; 269 case MK_RBUTTON: 270 return EF_RIGHT_MOUSE_BUTTON; 271 // TODO: add support for MK_XBUTTON1. 272 default: 273 break; 274 } 275 return 0; 276 } 277 278 gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) { 279 DCHECK(native_event.message == WM_MOUSEWHEEL || 280 native_event.message == WM_MOUSEHWHEEL); 281 if (native_event.message == WM_MOUSEWHEEL) 282 return gfx::Vector2d(0, GET_WHEEL_DELTA_WPARAM(native_event.wParam)); 283 return gfx::Vector2d(GET_WHEEL_DELTA_WPARAM(native_event.wParam), 0); 284 } 285 286 base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) { 287 return event; 288 } 289 290 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) { 291 } 292 293 void ClearTouchIdIfReleased(const base::NativeEvent& xev) { 294 NOTIMPLEMENTED(); 295 } 296 297 int GetTouchId(const base::NativeEvent& xev) { 298 NOTIMPLEMENTED(); 299 return 0; 300 } 301 302 float GetTouchRadiusX(const base::NativeEvent& native_event) { 303 NOTIMPLEMENTED(); 304 return 1.0; 305 } 306 307 float GetTouchRadiusY(const base::NativeEvent& native_event) { 308 NOTIMPLEMENTED(); 309 return 1.0; 310 } 311 312 float GetTouchAngle(const base::NativeEvent& native_event) { 313 NOTIMPLEMENTED(); 314 return 0.0; 315 } 316 317 float GetTouchForce(const base::NativeEvent& native_event) { 318 NOTIMPLEMENTED(); 319 return 0.0; 320 } 321 322 bool GetScrollOffsets(const base::NativeEvent& native_event, 323 float* x_offset, 324 float* y_offset, 325 float* x_offset_ordinal, 326 float* y_offset_ordinal, 327 int* finger_count) { 328 // TODO(ananta) 329 // Support retrieving the scroll offsets from the scroll event. 330 if (native_event.message == WM_VSCROLL || native_event.message == WM_HSCROLL) 331 return true; 332 return false; 333 } 334 335 bool GetFlingData(const base::NativeEvent& native_event, 336 float* vx, 337 float* vy, 338 float* vx_ordinal, 339 float* vy_ordinal, 340 bool* is_cancel) { 341 // Not supported in Windows. 342 NOTIMPLEMENTED(); 343 return false; 344 } 345 346 bool GetGestureTimes(const base::NativeEvent& native_event, 347 double* start_time, 348 double* end_time) { 349 // Not supported in Windows. 350 *start_time = 0; 351 *end_time = 0; 352 return false; 353 } 354 355 void SetNaturalScroll(bool enabled) { 356 NOTIMPLEMENTED(); 357 } 358 359 bool IsNaturalScrollEnabled() { 360 NOTIMPLEMENTED(); 361 return false; 362 } 363 364 bool IsTouchpadEvent(const base::NativeEvent& event) { 365 NOTIMPLEMENTED(); 366 return false; 367 } 368 369 int GetModifiersFromACCEL(const ACCEL& accel) { 370 int modifiers = EF_NONE; 371 if (accel.fVirt & FSHIFT) 372 modifiers |= EF_SHIFT_DOWN; 373 if (accel.fVirt & FCONTROL) 374 modifiers |= EF_CONTROL_DOWN; 375 if (accel.fVirt & FALT) 376 modifiers |= EF_ALT_DOWN; 377 return modifiers; 378 } 379 380 int GetModifiersFromKeyState() { 381 int modifiers = EF_NONE; 382 if (base::win::IsShiftPressed()) 383 modifiers |= EF_SHIFT_DOWN; 384 if (base::win::IsCtrlPressed()) 385 modifiers |= EF_CONTROL_DOWN; 386 if (base::win::IsAltPressed()) 387 modifiers |= EF_ALT_DOWN; 388 if (base::win::IsAltGrPressed()) 389 modifiers |= EF_ALTGR_DOWN; 390 return modifiers; 391 } 392 393 // Windows emulates mouse messages for touch events. 394 bool IsMouseEventFromTouch(UINT message) { 395 return (message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST) && 396 (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == 397 MOUSEEVENTF_FROMTOUCH; 398 } 399 400 // Conversion scan_code and LParam each other. 401 // uint16 scan_code: 402 // ui/events/keycodes/dom4/keycode_converter_data.h 403 // 0 - 15bits: represetns the scan code. 404 // 28 - 30 bits (0xE000): represents whether this is an extended key or not. 405 // 406 // LPARAM lParam: 407 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms644984.aspx 408 // 16 - 23bits: represetns the scan code. 409 // 24bit (0x0100): represents whether this is an extended key or not. 410 uint16 GetScanCodeFromLParam(LPARAM l_param) { 411 uint16 scan_code = ((l_param >> 16) & 0x00FF); 412 if (l_param & (1 << 24)) 413 scan_code |= 0xE000; 414 return scan_code; 415 } 416 417 LPARAM GetLParamFromScanCode(uint16 scan_code) { 418 LPARAM l_param = static_cast<LPARAM>(scan_code & 0x00FF) << 16; 419 if ((scan_code & 0xE000) == 0xE000) 420 l_param |= (1 << 24); 421 return l_param; 422 } 423 424 } // namespace ui 425