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 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