Home | History | Annotate | Download | only in win
      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