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 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 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. 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. 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 139 void UpdateDeviceList() { 140 NOTIMPLEMENTED(); 141 } 142 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 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 207 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) { 208 return base::TimeDelta::FromMilliseconds(native_event.time); 209 } 210 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 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 244 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) { 245 return KeyboardCodeForWindowsKeyCode(native_event.wParam); 246 } 247 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 253 bool IsMouseEvent(const base::NativeEvent& native_event) { 254 return IsClientMouseEvent(native_event) || 255 IsNonClientMouseEvent(native_event); 256 } 257 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 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 282 void ClearTouchIdIfReleased(const base::NativeEvent& xev) { 283 NOTIMPLEMENTED(); 284 } 285 286 int GetTouchId(const base::NativeEvent& xev) { 287 NOTIMPLEMENTED(); 288 return 0; 289 } 290 291 float GetTouchRadiusX(const base::NativeEvent& native_event) { 292 NOTIMPLEMENTED(); 293 return 1.0; 294 } 295 296 float GetTouchRadiusY(const base::NativeEvent& native_event) { 297 NOTIMPLEMENTED(); 298 return 1.0; 299 } 300 301 float GetTouchAngle(const base::NativeEvent& native_event) { 302 NOTIMPLEMENTED(); 303 return 0.0; 304 } 305 306 float GetTouchForce(const base::NativeEvent& native_event) { 307 NOTIMPLEMENTED(); 308 return 0.0; 309 } 310 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 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 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 344 void SetNaturalScroll(bool enabled) { 345 NOTIMPLEMENTED(); 346 } 347 348 bool IsNaturalScrollEnabled() { 349 NOTIMPLEMENTED(); 350 return false; 351 } 352 353 bool IsTouchpadEvent(const base::NativeEvent& event) { 354 NOTIMPLEMENTED(); 355 return false; 356 } 357 358 bool IsNoopEvent(const base::NativeEvent& event) { 359 return event.message == WM_USER + 310; 360 } 361 362 base::NativeEvent CreateNoopEvent() { 363 MSG event = { NULL }; 364 event.message = WM_USER + 310; 365 return event; 366 } 367 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 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. 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. 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 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