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/base/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/base/events/event_utils.h"
     13 #include "ui/base/keycodes/keyboard_code_conversion_win.h"
     14 #include "ui/base/win/dpi.h"
     15 #include "ui/gfx/point.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 // Returns a mask corresponding to the set of pressed modifier keys.
     94 // Checks the current global state and the state sent by client mouse messages.
     95 int KeyStateFlagsFromNative(const base::NativeEvent& native_event) {
     96   int flags = 0;
     97   flags |= base::win::IsAltPressed() ? EF_ALT_DOWN : EF_NONE;
     98   flags |= base::win::IsShiftPressed() ? EF_SHIFT_DOWN : EF_NONE;
     99   flags |= base::win::IsCtrlPressed() ? EF_CONTROL_DOWN : EF_NONE;
    100 
    101   // Check key messages for the extended key flag.
    102   if (IsKeyEvent(native_event))
    103     flags |= (HIWORD(native_event.lParam) & KF_EXTENDED) ? EF_EXTENDED : 0;
    104 
    105   // Most client mouse messages include key state information.
    106   if (IsClientMouseEvent(native_event)) {
    107     int win_flags = GET_KEYSTATE_WPARAM(native_event.wParam);
    108     flags |= (win_flags & MK_SHIFT) ? EF_SHIFT_DOWN : 0;
    109     flags |= (win_flags & MK_CONTROL) ? EF_CONTROL_DOWN : 0;
    110   }
    111 
    112   return flags;
    113 }
    114 
    115 // Returns a mask corresponding to the set of pressed mouse buttons.
    116 // This includes the button of the given message, even if it is being released.
    117 int MouseStateFlagsFromNative(const base::NativeEvent& native_event) {
    118   int win_flags = GetNativeMouseKey(native_event);
    119 
    120   // Client mouse messages provide key states in their WPARAMs.
    121   if (IsClientMouseEvent(native_event))
    122     win_flags |= GET_KEYSTATE_WPARAM(native_event.wParam);
    123 
    124   int flags = 0;
    125   flags |= (win_flags & MK_LBUTTON) ? EF_LEFT_MOUSE_BUTTON : 0;
    126   flags |= (win_flags & MK_MBUTTON) ? EF_MIDDLE_MOUSE_BUTTON : 0;
    127   flags |= (win_flags & MK_RBUTTON) ? EF_RIGHT_MOUSE_BUTTON : 0;
    128   flags |= IsNonClientMouseEvent(native_event) ? EF_IS_NON_CLIENT : 0;
    129   return flags;
    130 }
    131 
    132 }  // namespace
    133 
    134 void UpdateDeviceList() {
    135   NOTIMPLEMENTED();
    136 }
    137 
    138 EventType EventTypeFromNative(const base::NativeEvent& native_event) {
    139   switch (native_event.message) {
    140     case WM_KEYDOWN:
    141     case WM_SYSKEYDOWN:
    142     case WM_CHAR:
    143       return ET_KEY_PRESSED;
    144     case WM_KEYUP:
    145     case WM_SYSKEYUP:
    146       return ET_KEY_RELEASED;
    147     case WM_LBUTTONDBLCLK:
    148     case WM_LBUTTONDOWN:
    149     case WM_MBUTTONDBLCLK:
    150     case WM_MBUTTONDOWN:
    151     case WM_NCLBUTTONDBLCLK:
    152     case WM_NCLBUTTONDOWN:
    153     case WM_NCMBUTTONDBLCLK:
    154     case WM_NCMBUTTONDOWN:
    155     case WM_NCRBUTTONDBLCLK:
    156     case WM_NCRBUTTONDOWN:
    157     case WM_NCXBUTTONDBLCLK:
    158     case WM_NCXBUTTONDOWN:
    159     case WM_RBUTTONDBLCLK:
    160     case WM_RBUTTONDOWN:
    161     case WM_XBUTTONDBLCLK:
    162     case WM_XBUTTONDOWN:
    163       return ET_MOUSE_PRESSED;
    164     case WM_LBUTTONUP:
    165     case WM_MBUTTONUP:
    166     case WM_NCLBUTTONUP:
    167     case WM_NCMBUTTONUP:
    168     case WM_NCRBUTTONUP:
    169     case WM_NCXBUTTONUP:
    170     case WM_RBUTTONUP:
    171     case WM_XBUTTONUP:
    172       return ET_MOUSE_RELEASED;
    173     case WM_MOUSEMOVE:
    174       return IsButtonDown(native_event) ? ET_MOUSE_DRAGGED : ET_MOUSE_MOVED;
    175     case WM_NCMOUSEMOVE:
    176       return ET_MOUSE_MOVED;
    177     case WM_MOUSEWHEEL:
    178       return ET_MOUSEWHEEL;
    179     case WM_MOUSELEAVE:
    180     case WM_NCMOUSELEAVE:
    181       return ET_MOUSE_EXITED;
    182     default:
    183       // We can't NOTREACHED() here, since this function can be called for any
    184       // message.
    185       break;
    186   }
    187   return ET_UNKNOWN;
    188 }
    189 
    190 int EventFlagsFromNative(const base::NativeEvent& native_event) {
    191   int flags = KeyStateFlagsFromNative(native_event);
    192   if (IsMouseEvent(native_event))
    193     flags |= MouseStateFlagsFromNative(native_event);
    194 
    195   return flags;
    196 }
    197 
    198 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
    199   return base::TimeDelta::FromMilliseconds(native_event.time);
    200 }
    201 
    202 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
    203   // Note: Wheel events are considered client, but their position is in screen
    204   //       coordinates.
    205   // Client message. The position is contained in the LPARAM.
    206   if (IsClientMouseEvent(native_event) && !IsMouseWheelEvent(native_event))
    207     return gfx::Point(native_event.lParam);
    208   DCHECK(IsNonClientMouseEvent(native_event) ||
    209          IsMouseWheelEvent(native_event));
    210   // Non-client message. The position is contained in a POINTS structure in
    211   // LPARAM, and is in screen coordinates so we have to convert to client.
    212   POINT native_point = { GET_X_LPARAM(native_event.lParam),
    213                          GET_Y_LPARAM(native_event.lParam) };
    214   ScreenToClient(native_event.hwnd, &native_point);
    215   gfx::Point location(native_point);
    216   location = ui::win::ScreenToDIPPoint(location);
    217   return location;
    218 }
    219 
    220 gfx::Point EventSystemLocationFromNative(
    221     const base::NativeEvent& native_event) {
    222   // TODO(ben): Needs to always return screen position here. Returning normal
    223   // origin for now since that's obviously wrong.
    224   return gfx::Point(0, 0);
    225 }
    226 
    227 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
    228   return KeyboardCodeForWindowsKeyCode(native_event.wParam);
    229 }
    230 
    231 bool IsMouseEvent(const base::NativeEvent& native_event) {
    232   return IsClientMouseEvent(native_event) ||
    233          IsNonClientMouseEvent(native_event);
    234 }
    235 
    236 int GetChangedMouseButtonFlagsFromNative(
    237     const base::NativeEvent& native_event) {
    238   switch (GetNativeMouseKey(native_event)) {
    239     case MK_LBUTTON:
    240       return EF_LEFT_MOUSE_BUTTON;
    241     case MK_MBUTTON:
    242       return EF_MIDDLE_MOUSE_BUTTON;
    243     case MK_RBUTTON:
    244       return EF_RIGHT_MOUSE_BUTTON;
    245     // TODO: add support for MK_XBUTTON1.
    246     default:
    247       break;
    248   }
    249   return 0;
    250 }
    251 
    252 gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
    253   DCHECK(native_event.message == WM_MOUSEWHEEL);
    254   return gfx::Vector2d(0, GET_WHEEL_DELTA_WPARAM(native_event.wParam));
    255 }
    256 
    257 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
    258   NOTIMPLEMENTED();
    259 }
    260 
    261 int GetTouchId(const base::NativeEvent& xev) {
    262   NOTIMPLEMENTED();
    263   return 0;
    264 }
    265 
    266 float GetTouchRadiusX(const base::NativeEvent& native_event) {
    267   NOTIMPLEMENTED();
    268   return 1.0;
    269 }
    270 
    271 float GetTouchRadiusY(const base::NativeEvent& native_event) {
    272   NOTIMPLEMENTED();
    273   return 1.0;
    274 }
    275 
    276 float GetTouchAngle(const base::NativeEvent& native_event) {
    277   NOTIMPLEMENTED();
    278   return 0.0;
    279 }
    280 
    281 float GetTouchForce(const base::NativeEvent& native_event) {
    282   NOTIMPLEMENTED();
    283   return 0.0;
    284 }
    285 
    286 bool GetScrollOffsets(const base::NativeEvent& native_event,
    287                       float* x_offset,
    288                       float* y_offset,
    289                       float* x_offset_ordinal,
    290                       float* y_offset_ordinal,
    291                       int* finger_count) {
    292   // Not supported in Windows.
    293   NOTIMPLEMENTED();
    294   return false;
    295 }
    296 
    297 bool GetFlingData(const base::NativeEvent& native_event,
    298                   float* vx,
    299                   float* vy,
    300                   float* vx_ordinal,
    301                   float* vy_ordinal,
    302                   bool* is_cancel) {
    303   // Not supported in Windows.
    304   NOTIMPLEMENTED();
    305   return false;
    306 }
    307 
    308 bool GetGestureTimes(const base::NativeEvent& native_event,
    309                      double* start_time,
    310                      double* end_time) {
    311   // Not supported in Windows.
    312   *start_time = 0;
    313   *end_time = 0;
    314   return false;
    315 }
    316 
    317 void SetNaturalScroll(bool enabled) {
    318   NOTIMPLEMENTED();
    319 }
    320 
    321 bool IsNaturalScrollEnabled() {
    322   NOTIMPLEMENTED();
    323   return false;
    324 }
    325 
    326 bool IsTouchpadEvent(const base::NativeEvent& event) {
    327   NOTIMPLEMENTED();
    328   return false;
    329 }
    330 
    331 bool IsNoopEvent(const base::NativeEvent& event) {
    332   return event.message == WM_USER + 310;
    333 }
    334 
    335 base::NativeEvent CreateNoopEvent() {
    336   MSG event = { NULL };
    337   event.message = WM_USER + 310;
    338   return event;
    339 }
    340 
    341 int GetModifiersFromACCEL(const ACCEL& accel) {
    342   int modifiers = EF_NONE;
    343   if (accel.fVirt & FSHIFT)
    344     modifiers |= EF_SHIFT_DOWN;
    345   if (accel.fVirt & FCONTROL)
    346     modifiers |= EF_CONTROL_DOWN;
    347   if (accel.fVirt & FALT)
    348     modifiers |= EF_ALT_DOWN;
    349   return modifiers;
    350 }
    351 
    352 int GetModifiersFromKeyState() {
    353   int modifiers = EF_NONE;
    354   if (base::win::IsShiftPressed())
    355     modifiers |= EF_SHIFT_DOWN;
    356   if (base::win::IsCtrlPressed())
    357     modifiers |= EF_CONTROL_DOWN;
    358   if (base::win::IsAltPressed())
    359     modifiers |= EF_ALT_DOWN;
    360   return modifiers;
    361 }
    362 
    363 // Windows emulates mouse messages for touch events.
    364 bool IsMouseEventFromTouch(UINT message) {
    365   return (message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST) &&
    366       (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) ==
    367       MOUSEEVENTF_FROMTOUCH;
    368 }
    369 
    370 }  // namespace ui
    371