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 // 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 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 216 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) { 217 return base::TimeDelta::FromMilliseconds(native_event.time); 218 } 219 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 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 254 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) { 255 return KeyboardCodeForWindowsKeyCode(native_event.wParam); 256 } 257 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 263 uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) { 264 return static_cast<uint32>(native_event.wParam); 265 } 266 267 bool IsCharFromNative(const base::NativeEvent& native_event) { 268 return native_event.message == WM_CHAR; 269 } 270 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 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 295 base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) { 296 return event; 297 } 298 299 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) { 300 } 301 302 void IncrementTouchIdRefCount(const base::NativeEvent& event) { 303 NOTIMPLEMENTED(); 304 } 305 306 void ClearTouchIdIfReleased(const base::NativeEvent& xev) { 307 NOTIMPLEMENTED(); 308 } 309 310 int GetTouchId(const base::NativeEvent& xev) { 311 NOTIMPLEMENTED(); 312 return 0; 313 } 314 315 float GetTouchRadiusX(const base::NativeEvent& native_event) { 316 NOTIMPLEMENTED(); 317 return 1.0; 318 } 319 320 float GetTouchRadiusY(const base::NativeEvent& native_event) { 321 NOTIMPLEMENTED(); 322 return 1.0; 323 } 324 325 float GetTouchAngle(const base::NativeEvent& native_event) { 326 NOTIMPLEMENTED(); 327 return 0.0; 328 } 329 330 float GetTouchForce(const base::NativeEvent& native_event) { 331 NOTIMPLEMENTED(); 332 return 0.0; 333 } 334 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 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 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 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. 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. 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 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