root/ui/events/win/events_win.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetNativeMouseKey
  2. IsButtonDown
  3. IsClientMouseEvent
  4. IsNonClientMouseEvent
  5. IsMouseEvent
  6. IsMouseWheelEvent
  7. IsKeyEvent
  8. IsScrollEvent
  9. KeyStateFlagsFromNative
  10. MouseStateFlagsFromNative
  11. UpdateDeviceList
  12. EventTypeFromNative
  13. EventFlagsFromNative
  14. EventTimeFromNative
  15. EventLocationFromNative
  16. EventSystemLocationFromNative
  17. KeyboardCodeFromNative
  18. CodeFromNative
  19. GetChangedMouseButtonFlagsFromNative
  20. GetMouseWheelOffset
  21. ClearTouchIdIfReleased
  22. GetTouchId
  23. GetTouchRadiusX
  24. GetTouchRadiusY
  25. GetTouchAngle
  26. GetTouchForce
  27. GetScrollOffsets
  28. GetFlingData
  29. GetGestureTimes
  30. SetNaturalScroll
  31. IsNaturalScrollEnabled
  32. IsTouchpadEvent
  33. GetModifiersFromACCEL
  34. GetModifiersFromKeyState
  35. IsMouseEventFromTouch
  36. GetScanCodeFromLParam
  37. GetLParamFromScanCode

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <windowsx.h>

#include "ui/events/event_constants.h"

#include "base/logging.h"
#include "base/time/time.h"
#include "base/win/win_util.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/keyboard_code_conversion_win.h"
#include "ui/gfx/point.h"
#include "ui/gfx/win/dpi.h"

namespace ui {

namespace {

// From MSDN: "Mouse" events are flagged with 0xFF515700 if they come
// from a touch or stylus device.  In Vista or later, they are also flagged
// with 0x80 if they come from touch.
#define MOUSEEVENTF_FROMTOUCH (0xFF515700 | 0x80)

// Get the native mouse key state from the native event message type.
int GetNativeMouseKey(const base::NativeEvent& native_event) {
  switch (native_event.message) {
    case WM_LBUTTONDBLCLK:
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_NCLBUTTONDBLCLK:
    case WM_NCLBUTTONDOWN:
    case WM_NCLBUTTONUP:
      return MK_LBUTTON;
    case WM_MBUTTONDBLCLK:
    case WM_MBUTTONDOWN:
    case WM_MBUTTONUP:
    case WM_NCMBUTTONDBLCLK:
    case WM_NCMBUTTONDOWN:
    case WM_NCMBUTTONUP:
      return MK_MBUTTON;
    case WM_RBUTTONDBLCLK:
    case WM_RBUTTONDOWN:
    case WM_RBUTTONUP:
    case WM_NCRBUTTONDBLCLK:
    case WM_NCRBUTTONDOWN:
    case WM_NCRBUTTONUP:
      return MK_RBUTTON;
    case WM_NCXBUTTONDBLCLK:
    case WM_NCXBUTTONDOWN:
    case WM_NCXBUTTONUP:
    case WM_XBUTTONDBLCLK:
    case WM_XBUTTONDOWN:
    case WM_XBUTTONUP:
      return MK_XBUTTON1;
  }
  return 0;
}

bool IsButtonDown(const base::NativeEvent& native_event) {
  return ((MK_LBUTTON | MK_MBUTTON | MK_RBUTTON | MK_XBUTTON1 | MK_XBUTTON2) &
          native_event.wParam) != 0;
}

bool IsClientMouseEvent(const base::NativeEvent& native_event) {
  return native_event.message == WM_MOUSELEAVE ||
         native_event.message == WM_MOUSEHOVER ||
        (native_event.message >= WM_MOUSEFIRST &&
         native_event.message <= WM_MOUSELAST);
}

bool IsNonClientMouseEvent(const base::NativeEvent& native_event) {
  return native_event.message == WM_NCMOUSELEAVE ||
         native_event.message == WM_NCMOUSEHOVER ||
        (native_event.message >= WM_NCMOUSEMOVE &&
         native_event.message <= WM_NCXBUTTONDBLCLK);
}

bool IsMouseEvent(const base::NativeEvent& native_event) {
  return IsClientMouseEvent(native_event) ||
         IsNonClientMouseEvent(native_event);
}

bool IsMouseWheelEvent(const base::NativeEvent& native_event) {
  return native_event.message == WM_MOUSEWHEEL ||
         native_event.message == WM_MOUSEHWHEEL;
}

bool IsKeyEvent(const base::NativeEvent& native_event) {
  return native_event.message == WM_KEYDOWN ||
         native_event.message == WM_SYSKEYDOWN ||
         native_event.message == WM_CHAR ||
         native_event.message == WM_KEYUP ||
         native_event.message == WM_SYSKEYUP;
}

bool IsScrollEvent(const base::NativeEvent& native_event) {
  return native_event.message == WM_VSCROLL ||
         native_event.message == WM_HSCROLL;
}

// Returns a mask corresponding to the set of pressed modifier keys.
// Checks the current global state and the state sent by client mouse messages.
int KeyStateFlagsFromNative(const base::NativeEvent& native_event) {
  int flags = 0;
  flags |= base::win::IsAltPressed() ? EF_ALT_DOWN : EF_NONE;
  flags |= base::win::IsShiftPressed() ? EF_SHIFT_DOWN : EF_NONE;
  flags |= base::win::IsCtrlPressed() ? EF_CONTROL_DOWN : EF_NONE;

  // Check key messages for the extended key flag.
  if (IsKeyEvent(native_event))
    flags |= (HIWORD(native_event.lParam) & KF_EXTENDED) ? EF_EXTENDED : 0;

  // Most client mouse messages include key state information.
  if (IsClientMouseEvent(native_event)) {
    int win_flags = GET_KEYSTATE_WPARAM(native_event.wParam);
    flags |= (win_flags & MK_SHIFT) ? EF_SHIFT_DOWN : 0;
    flags |= (win_flags & MK_CONTROL) ? EF_CONTROL_DOWN : 0;
  }

  return flags;
}

// Returns a mask corresponding to the set of pressed mouse buttons.
// This includes the button of the given message, even if it is being released.
int MouseStateFlagsFromNative(const base::NativeEvent& native_event) {
  int win_flags = GetNativeMouseKey(native_event);

  // Client mouse messages provide key states in their WPARAMs.
  if (IsClientMouseEvent(native_event))
    win_flags |= GET_KEYSTATE_WPARAM(native_event.wParam);

  int flags = 0;
  flags |= (win_flags & MK_LBUTTON) ? EF_LEFT_MOUSE_BUTTON : 0;
  flags |= (win_flags & MK_MBUTTON) ? EF_MIDDLE_MOUSE_BUTTON : 0;
  flags |= (win_flags & MK_RBUTTON) ? EF_RIGHT_MOUSE_BUTTON : 0;
  flags |= IsNonClientMouseEvent(native_event) ? EF_IS_NON_CLIENT : 0;
  return flags;
}

}  // namespace

void UpdateDeviceList() {
  NOTIMPLEMENTED();
}

EventType EventTypeFromNative(const base::NativeEvent& native_event) {
  switch (native_event.message) {
    case WM_KEYDOWN:
    case WM_SYSKEYDOWN:
    case WM_CHAR:
      return ET_KEY_PRESSED;
    case WM_KEYUP:
    case WM_SYSKEYUP:
      return ET_KEY_RELEASED;
    case WM_LBUTTONDBLCLK:
    case WM_LBUTTONDOWN:
    case WM_MBUTTONDBLCLK:
    case WM_MBUTTONDOWN:
    case WM_NCLBUTTONDBLCLK:
    case WM_NCLBUTTONDOWN:
    case WM_NCMBUTTONDBLCLK:
    case WM_NCMBUTTONDOWN:
    case WM_NCRBUTTONDBLCLK:
    case WM_NCRBUTTONDOWN:
    case WM_NCXBUTTONDBLCLK:
    case WM_NCXBUTTONDOWN:
    case WM_RBUTTONDBLCLK:
    case WM_RBUTTONDOWN:
    case WM_XBUTTONDBLCLK:
    case WM_XBUTTONDOWN:
      return ET_MOUSE_PRESSED;
    case WM_LBUTTONUP:
    case WM_MBUTTONUP:
    case WM_NCLBUTTONUP:
    case WM_NCMBUTTONUP:
    case WM_NCRBUTTONUP:
    case WM_NCXBUTTONUP:
    case WM_RBUTTONUP:
    case WM_XBUTTONUP:
      return ET_MOUSE_RELEASED;
    case WM_MOUSEMOVE:
      return IsButtonDown(native_event) ? ET_MOUSE_DRAGGED : ET_MOUSE_MOVED;
    case WM_NCMOUSEMOVE:
      return ET_MOUSE_MOVED;
    case WM_MOUSEWHEEL:
    case WM_MOUSEHWHEEL:
      return ET_MOUSEWHEEL;
    case WM_MOUSELEAVE:
    case WM_NCMOUSELEAVE:
      return ET_MOUSE_EXITED;
    case WM_VSCROLL:
    case WM_HSCROLL:
      return ET_SCROLL;
    default:
      // We can't NOTREACHED() here, since this function can be called for any
      // message.
      break;
  }
  return ET_UNKNOWN;
}

int EventFlagsFromNative(const base::NativeEvent& native_event) {
  int flags = KeyStateFlagsFromNative(native_event);
  if (IsMouseEvent(native_event))
    flags |= MouseStateFlagsFromNative(native_event);

  return flags;
}

base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
  return base::TimeDelta::FromMilliseconds(native_event.time);
}

gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
  POINT native_point;
  if ((native_event.message == WM_MOUSELEAVE ||
       native_event.message == WM_NCMOUSELEAVE) ||
      IsScrollEvent(native_event)) {
    // These events have no coordinates. For sanity with rest of events grab
    // coordinates from the OS.
    ::GetCursorPos(&native_point);
  } else if (IsClientMouseEvent(native_event) &&
             !IsMouseWheelEvent(native_event)) {
    // Note: Wheel events are considered client, but their position is in screen
    //       coordinates.
    // Client message. The position is contained in the LPARAM.
    return gfx::Point(native_event.lParam);
  } else {
    DCHECK(IsNonClientMouseEvent(native_event) ||
           IsMouseWheelEvent(native_event) || IsScrollEvent(native_event));
    // Non-client message. The position is contained in a POINTS structure in
    // LPARAM, and is in screen coordinates so we have to convert to client.
    native_point.x = GET_X_LPARAM(native_event.lParam);
    native_point.y = GET_Y_LPARAM(native_event.lParam);
  }
  ScreenToClient(native_event.hwnd, &native_point);
  return gfx::win::ScreenToDIPPoint(gfx::Point(native_point));
}

gfx::Point EventSystemLocationFromNative(
    const base::NativeEvent& native_event) {
  // TODO(ben): Needs to always return screen position here. Returning normal
  // origin for now since that's obviously wrong.
  return gfx::Point(0, 0);
}

KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
  return KeyboardCodeForWindowsKeyCode(native_event.wParam);
}

const char* CodeFromNative(const base::NativeEvent& native_event) {
  const uint16 scan_code = GetScanCodeFromLParam(native_event.lParam);
  return CodeForWindowsScanCode(scan_code);
}

int GetChangedMouseButtonFlagsFromNative(
    const base::NativeEvent& native_event) {
  switch (GetNativeMouseKey(native_event)) {
    case MK_LBUTTON:
      return EF_LEFT_MOUSE_BUTTON;
    case MK_MBUTTON:
      return EF_MIDDLE_MOUSE_BUTTON;
    case MK_RBUTTON:
      return EF_RIGHT_MOUSE_BUTTON;
    // TODO: add support for MK_XBUTTON1.
    default:
      break;
  }
  return 0;
}

gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
  DCHECK(native_event.message == WM_MOUSEWHEEL ||
         native_event.message == WM_MOUSEHWHEEL);
  if (native_event.message == WM_MOUSEWHEEL)
    return gfx::Vector2d(0, GET_WHEEL_DELTA_WPARAM(native_event.wParam));
  return gfx::Vector2d(GET_WHEEL_DELTA_WPARAM(native_event.wParam), 0);
}

void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
  NOTIMPLEMENTED();
}

int GetTouchId(const base::NativeEvent& xev) {
  NOTIMPLEMENTED();
  return 0;
}

float GetTouchRadiusX(const base::NativeEvent& native_event) {
  NOTIMPLEMENTED();
  return 1.0;
}

float GetTouchRadiusY(const base::NativeEvent& native_event) {
  NOTIMPLEMENTED();
  return 1.0;
}

float GetTouchAngle(const base::NativeEvent& native_event) {
  NOTIMPLEMENTED();
  return 0.0;
}

float GetTouchForce(const base::NativeEvent& native_event) {
  NOTIMPLEMENTED();
  return 0.0;
}

bool GetScrollOffsets(const base::NativeEvent& native_event,
                      float* x_offset,
                      float* y_offset,
                      float* x_offset_ordinal,
                      float* y_offset_ordinal,
                      int* finger_count) {
  // TODO(ananta)
  // Support retrieving the scroll offsets from the scroll event.
  if (native_event.message == WM_VSCROLL || native_event.message == WM_HSCROLL)
    return true;
  return false;
}

bool GetFlingData(const base::NativeEvent& native_event,
                  float* vx,
                  float* vy,
                  float* vx_ordinal,
                  float* vy_ordinal,
                  bool* is_cancel) {
  // Not supported in Windows.
  NOTIMPLEMENTED();
  return false;
}

bool GetGestureTimes(const base::NativeEvent& native_event,
                     double* start_time,
                     double* end_time) {
  // Not supported in Windows.
  *start_time = 0;
  *end_time = 0;
  return false;
}

void SetNaturalScroll(bool enabled) {
  NOTIMPLEMENTED();
}

bool IsNaturalScrollEnabled() {
  NOTIMPLEMENTED();
  return false;
}

bool IsTouchpadEvent(const base::NativeEvent& event) {
  NOTIMPLEMENTED();
  return false;
}

int GetModifiersFromACCEL(const ACCEL& accel) {
  int modifiers = EF_NONE;
  if (accel.fVirt & FSHIFT)
    modifiers |= EF_SHIFT_DOWN;
  if (accel.fVirt & FCONTROL)
    modifiers |= EF_CONTROL_DOWN;
  if (accel.fVirt & FALT)
    modifiers |= EF_ALT_DOWN;
  return modifiers;
}

int GetModifiersFromKeyState() {
  int modifiers = EF_NONE;
  if (base::win::IsShiftPressed())
    modifiers |= EF_SHIFT_DOWN;
  if (base::win::IsCtrlPressed())
    modifiers |= EF_CONTROL_DOWN;
  if (base::win::IsAltPressed())
    modifiers |= EF_ALT_DOWN;
  if (base::win::IsAltGrPressed())
    modifiers |= EF_ALTGR_DOWN;
  return modifiers;
}

// Windows emulates mouse messages for touch events.
bool IsMouseEventFromTouch(UINT message) {
  return (message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST) &&
      (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) ==
      MOUSEEVENTF_FROMTOUCH;
}

// Conversion scan_code and LParam each other.
// uint16 scan_code:
//     ui/events/keycodes/dom4/keycode_converter_data.h
// 0 - 15bits: represetns the scan code.
// 28 - 30 bits (0xE000): represents whether this is an extended key or not.
//
// LPARAM lParam:
//     http://msdn.microsoft.com/en-us/library/windows/desktop/ms644984.aspx
// 16 - 23bits: represetns the scan code.
// 24bit (0x0100): represents whether this is an extended key or not.
uint16 GetScanCodeFromLParam(LPARAM l_param) {
  uint16 scan_code = ((l_param >> 16) & 0x00FF);
  if (l_param & (1 << 24))
    scan_code |= 0xE000;
  return scan_code;
}

LPARAM GetLParamFromScanCode(uint16 scan_code) {
  LPARAM l_param = static_cast<LPARAM>(scan_code & 0x00FF) << 16;
  if ((scan_code & 0xE000) == 0xE000)
    l_param |= (1 << 24);
  return l_param;
}

}  // namespace ui

/* [<][>][^][v][top][bottom][index][help] */