From 955f86fc9eef40c59262ef2cf1cea0345f87d144 Mon Sep 17 00:00:00 2001 From: David Capello Date: Wed, 20 Apr 2016 15:44:15 -0300 Subject: [PATCH] Add pressure and input device (mouse/stylus/eraser) info to mouse events This is a first step to implement #610 and #710 --- src/she/event.h | 24 +++++++++++++- src/she/win/pen.cpp | 25 ++++++++++++--- src/she/win/pen.h | 11 +++++-- src/she/win/window.h | 75 +++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 122 insertions(+), 13 deletions(-) diff --git a/src/she/event.h b/src/she/event.h index a41ee6dc8..8d280cc4c 100644 --- a/src/she/event.h +++ b/src/she/event.h @@ -41,6 +41,14 @@ namespace she { TouchMagnify, }; + enum InputDevice { + UnknownDevice, + MouseDevice, + MultitouchDevice, // Multitouch device with finger gestures + StylusDevice, // Pen/stylus device + EraserDevice, // Inverted-stylus device + }; + enum MouseButton { NoneButton, LeftButton, @@ -57,7 +65,10 @@ namespace she { m_unicodeChar(0), m_repeat(0), m_preciseWheel(false), - m_button(NoneButton) { + m_device(UnknownDevice), + m_button(NoneButton), + m_magnification(0.0), + m_pressure(0.0) { } Type type() const { return m_type; } @@ -73,10 +84,13 @@ namespace she { // We suppose that if we are receiving precise scrolling deltas, // it means that the user is using a touch-like surface (trackpad, // magic mouse scrolling, touch wacom tablet, etc.) + // TODO change this with the new InputDevice::MultitouchDevice bool preciseWheel() const { return m_preciseWheel; } + InputDevice device() const { return m_device; } MouseButton button() const { return m_button; } double magnification() const { return m_magnification; } + double pressure() const { return m_pressure; } void setType(Type type) { m_type = type; } void setDisplay(Display* display) { m_display = display; } @@ -89,8 +103,10 @@ namespace she { void setPosition(const gfx::Point& pos) { m_position = pos; } void setWheelDelta(const gfx::Point& delta) { m_wheelDelta = delta; } void setPreciseWheel(bool precise) { m_preciseWheel = precise; } + void setDevice(InputDevice device) { m_device = device; } void setButton(MouseButton button) { m_button = button; } void setMagnification(double magnification) { m_magnification = magnification; } + void setPressure(double pressure) { m_pressure = pressure; } private: Type m_type; @@ -103,8 +119,14 @@ namespace she { gfx::Point m_position; gfx::Point m_wheelDelta; bool m_preciseWheel; + InputDevice m_device; MouseButton m_button; + + // For TouchMagnify event double m_magnification; + + // Pressure of stylus used in mouse-like events + double m_pressure; }; } // namespace she diff --git a/src/she/win/pen.cpp b/src/she/win/pen.cpp index 343d08c4d..9baca486f 100644 --- a/src/she/win/pen.cpp +++ b/src/she/win/pen.cpp @@ -19,12 +19,14 @@ typedef UINT (API* WTInfoW_Func)(UINT, UINT, LPVOID); typedef HCTX (API* WTOpenW_Func)(HWND, LPLOGCONTEXTW, BOOL); typedef BOOL (API* WTClose_Func)(HCTX); +typedef BOOL (API* WTPacket_Func)(HCTX, UINT, LPVOID); namespace she { static WTInfoW_Func WTInfo; static WTOpenW_Func WTOpen; static WTClose_Func WTClose; +static WTPacket_Func WTPacket; PenAPI::PenAPI() : m_wintabLib(nullptr) @@ -40,18 +42,25 @@ PenAPI::~PenAPI() m_wintabLib = nullptr; } -HCTX PenAPI::attachDisplay(HWND hwnd) +HCTX PenAPI::open(HWND hwnd) { if (!m_wintabLib && !loadWintab()) return nullptr; LOGCONTEXTW logctx; memset(&logctx, 0, sizeof(LOGCONTEXTW)); - logctx.lcOptions |= CXO_SYSTEM; UINT infoRes = WTInfo(WTI_DEFSYSCTX, 0, &logctx); ASSERT(infoRes == sizeof(LOGCONTEXTW)); ASSERT(logctx.lcOptions & CXO_SYSTEM); - logctx.lcOptions |= CXO_SYSTEM; + + logctx.lcOptions = + CXO_SYSTEM | + CXO_MESSAGES | + CXO_CSRMESSAGES; + logctx.lcPktData = PACKETDATA; + logctx.lcPktMode = PACKETMODE; + logctx.lcMoveMask = PACKETDATA; + HCTX ctx = WTOpen(hwnd, &logctx, TRUE); if (!ctx) { LOG("Error attaching pen to display\n"); @@ -62,7 +71,7 @@ HCTX PenAPI::attachDisplay(HWND hwnd) return ctx; } -void PenAPI::detachDisplay(HCTX ctx) +void PenAPI::close(HCTX ctx) { if (ctx) { ASSERT(m_wintabLib); @@ -71,6 +80,11 @@ void PenAPI::detachDisplay(HCTX ctx) } } +bool PenAPI::packet(HCTX ctx, UINT serial, LPVOID packet) +{ + return (WTPacket(ctx, serial, packet) ? true: false); +} + bool PenAPI::loadWintab() { ASSERT(!m_wintabLib); @@ -84,7 +98,8 @@ bool PenAPI::loadWintab() WTInfo = base::get_dll_proc(m_wintabLib, "WTInfoW"); WTOpen = base::get_dll_proc(m_wintabLib, "WTOpenW"); WTClose = base::get_dll_proc(m_wintabLib, "WTClose"); - if (!WTInfo || !WTOpen || !WTClose) { + WTPacket = base::get_dll_proc(m_wintabLib, "WTPacket"); + if (!WTInfo || !WTOpen || !WTClose || !WTPacket) { LOG("wintab32.dll does not contain all required functions\n"); return false; } diff --git a/src/she/win/pen.h b/src/she/win/pen.h index d9ac9f6fb..20b97d8a7 100644 --- a/src/she/win/pen.h +++ b/src/she/win/pen.h @@ -13,15 +13,22 @@ #include #include "wacom/wintab.h" +#define PACKETDATA (PK_CURSOR | PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE) +#define PACKETMODE (PK_BUTTONS) +#include "wacom/pktdef.h" + namespace she { + // Wintab API wrapper + // Read http://www.wacomeng.com/windows/docs/Wintab_v140.htm for more information. class PenAPI { public: PenAPI(); ~PenAPI(); - HCTX attachDisplay(HWND hwnd); - void detachDisplay(HCTX ctx); + HCTX open(HWND hwnd); + void close(HCTX ctx); + bool packet(HCTX ctx, UINT serial, LPVOID packet); private: bool loadWintab(); diff --git a/src/she/win/window.h b/src/she/win/window.h index 216ccd537..060345359 100644 --- a/src/she/win/window.h +++ b/src/she/win/window.h @@ -41,11 +41,13 @@ namespace she { , m_restoredSize(0, 0) , m_isCreated(false) , m_hasMouse(false) - , m_captureMouse(false) { + , m_captureMouse(false) + , m_hpenctx(nullptr) + , m_device(Event::UnknownDevice) + , m_pressure(0.0) { registerClass(); m_hwnd = createHwnd(this, width, height); m_hcursor = nullptr; - m_hpenctx = nullptr; m_scale = scale; // This flag is used to avoid calling T::resizeImpl() when we @@ -55,13 +57,13 @@ namespace she { // Attach Wacom context m_hpenctx = static_cast(she::instance()) - ->penApi().attachDisplay(m_hwnd); + ->penApi().open(m_hwnd); } ~WinWindow() { if (m_hpenctx) static_cast(she::instance()) - ->penApi().detachDisplay(m_hpenctx); + ->penApi().close(m_hpenctx); } void queueEvent(Event& ev) { @@ -323,6 +325,11 @@ namespace she { _TrackMouseEvent(&tme); } + if (m_device != Event::UnknownDevice) { + ev.setDevice(m_device); + ev.setPressure(m_pressure); + } + ev.setType(Event::MouseMove); queueEvent(ev); break; @@ -353,6 +360,12 @@ namespace she { msg == WM_LBUTTONDOWN ? Event::LeftButton: msg == WM_RBUTTONDOWN ? Event::RightButton: msg == WM_MBUTTONDOWN ? Event::MiddleButton: Event::NoneButton); + + if (m_device != Event::UnknownDevice) { + ev.setDevice(m_device); + ev.setPressure(m_pressure); + } + queueEvent(ev); break; } @@ -370,6 +383,12 @@ namespace she { msg == WM_LBUTTONUP ? Event::LeftButton: msg == WM_RBUTTONUP ? Event::RightButton: msg == WM_MBUTTONUP ? Event::MiddleButton: Event::NoneButton); + + if (m_device != Event::UnknownDevice) { + ev.setDevice(m_device); + ev.setPressure(m_pressure); + } + queueEvent(ev); // Avoid popup menu for scrollbars @@ -585,6 +604,48 @@ namespace she { return result; } + case WT_PROXIMITY: { + bool entering_ctx = (LOWORD(lparam) ? true: false); + if (!entering_ctx) + m_device = Event::UnknownDevice; + break; + } + + case WT_CSRCHANGE: { // From Wintab 1.1 + auto& api = static_cast(she::instance())->penApi(); + UINT serial = wparam; + HCTX ctx = (HCTX)lparam; + PACKET packet; + + if (api.packet(ctx, serial, &packet)) { + if (packet.pkCursor == 2 || packet.pkCursor == 5) + m_device = Event::EraserDevice; + else + m_device = Event::StylusDevice; + } + else + m_device = Event::UnknownDevice; + } + + case WT_PACKET: { + auto& api = static_cast(she::instance())->penApi(); + UINT serial = wparam; + HCTX ctx = (HCTX)lparam; + PACKET packet; + + if (api.packet(ctx, serial, &packet)) { + m_pressure = packet.pkNormalPressure / 1000.0; // TODO get the maximum value + + if (packet.pkCursor == 2 || packet.pkCursor == 5) + m_device = Event::EraserDevice; + else + m_device = Event::StylusDevice; + } + else + m_device = Event::UnknownDevice; + break; + } + } LRESULT result = FALSE; @@ -679,13 +740,17 @@ namespace she { mutable HWND m_hwnd; HCURSOR m_hcursor; - HCTX m_hpenctx; // Wacom Pen context gfx::Size m_clientSize; gfx::Size m_restoredSize; int m_scale; bool m_isCreated; bool m_hasMouse; bool m_captureMouse; + + // Wintab API data + HCTX m_hpenctx; + Event::InputDevice m_device; + double m_pressure; }; } // namespace she