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