11#include <qpa/qwindowsysteminterface.h>
13#include <QtGui/qevent.h>
14#include <QtGui/qscreen.h>
15#include <QtGui/qguiapplication.h>
16#include <QtGui/qwindow.h>
17#include <QtCore/qdebug.h>
18#include <QtCore/qvarlengtharray.h>
19#include <QtCore/qmath.h>
21#include <private/qguiapplication_p.h>
22#include <QtCore/private/qsystemlibrary_p.h>
25#define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_Z | PK_TIME)
49 return DefWindowProc(hwnd,
message, wParam, lParam);
57 return x >= 0 ? 1 : -1;
62 const int targetX = targetArea.
x();
63 const int targetY = targetArea.
y();
64 const int targetWidth = targetArea.
width();
65 const int targetHeight = targetArea.
height();
78template <
class Stream>
81 if (options & CXO_SYSTEM)
83 if (options & CXO_PEN)
85 if (options & CXO_MESSAGES)
86 str <<
" CXO_MESSAGES";
87 if (options & CXO_MARGIN)
89 if (options & CXO_MGNINSIDE)
90 str <<
" CXO_MGNINSIDE";
91 if (options & CXO_CSRMESSAGES)
92 str <<
" CXO_CSRMESSAGES";
95#ifndef QT_NO_DEBUG_STREAM
100 d <<
"TabletDevice id:" <<
t.systemId <<
" pressure: " <<
t.minPressure
101 <<
".." <<
t.maxPressure <<
" tan pressure: " <<
t.minTanPressure <<
".."
102 <<
t.maxTanPressure <<
" area: (" <<
t.minX <<
',' <<
t.minY <<
',' <<
t.minZ
103 <<
")..(" <<
t.maxX <<
',' <<
t.maxY <<
',' <<
t.maxZ <<
')';
114 d <<
", status=0x" <<
Qt::hex << lc.lcStatus <<
", device=0x" << lc.lcDevice
115 <<
Qt::dec <<
", PktRate=" << lc.lcPktRate
116 <<
", PktData=" << lc.lcPktData <<
", PktMode=" << lc.lcPktMode
117 <<
", MoveMask=0x" <<
Qt::hex << lc.lcMoveMask <<
", BtnDnMask=0x" << lc.lcBtnDnMask
118 <<
", BtnUpMask=0x" << lc.lcBtnUpMask <<
Qt::dec <<
", SysMode=" << lc.lcSysMode
119 <<
", InOrg=(" << lc.lcInOrgX <<
", " << lc.lcInOrgY <<
", " << lc.lcInOrgZ
120 <<
"), InExt=(" << lc.lcInExtX <<
", " << lc.lcInExtY <<
", " << lc.lcInExtZ
121 <<
") OutOrg=(" << lc.lcOutOrgX <<
", " << lc.lcOutOrgY <<
", "
122 << lc.lcOutOrgZ <<
"), OutExt=(" << lc.lcOutExtX <<
", " << lc.lcOutExtY
123 <<
", " << lc.lcOutExtZ
124 <<
"), Sens=(" << lc.lcSensX <<
", " << lc.lcSensX <<
", " << lc.lcSensZ
125 <<
") SysOrg=(" << lc.lcSysOrgX <<
", " << lc.lcSysOrgY
126 <<
"), SysExt=(" << lc.lcSysExtX <<
", " << lc.lcSysExtY
127 <<
"), SysSens=(" << lc.lcSysSensX <<
", " << lc.lcSysSensY <<
"))";
136 const qint64 uniqueId =
d->systemId | (
qint64(devType) << 32)
144 if (
d->tiltCapability) {
163 QInputDevice::Capabilities caps,
164 int maxPoints,
int buttonCount,
169 seatName, uniqueId,
parent),
214int QWindowsTabletSupport::m_absoluteRange = 20;
216QWindowsTabletSupport::QWindowsTabletSupport(HWND
window, HCTX
context)
222 if (QWindowsTabletSupport::m_winTab32DLL.
wTInfo(WTI_DEVICES, DVC_ORIENTATION, &orientation))
223 m_tiltSupport = orientation[0].axResolution && orientation[1].axResolution;
228 QWindowsTabletSupport::m_winTab32DLL.
wTClose(m_context);
229 DestroyWindow(m_window);
234 if (!m_winTab32DLL.
init())
237 L
"TabletDummyWindow",
240 qCWarning(lcQpaTablet) << __FUNCTION__ <<
"Unable to create window for tablet.";
245 QWindowsTabletSupport::m_winTab32DLL.
wTInfo(WTI_DEFSYSCTX, 0, &lcMine);
246 qCDebug(lcQpaTablet) <<
"Default: " << lcMine;
248 lcMine.lcOptions |= CXO_MESSAGES | CXO_CSRMESSAGES;
249 lcMine.lcPktData = lcMine.lcMoveMask =
PACKETDATA;
251 lcMine.lcOutOrgX = 0;
252 lcMine.lcOutExtX = lcMine.lcInExtX;
253 lcMine.lcOutOrgY = 0;
254 lcMine.lcOutExtY = -lcMine.lcInExtY;
255 qCDebug(lcQpaTablet) <<
"Requesting: " << lcMine;
258 qCDebug(lcQpaTablet) << __FUNCTION__ <<
"Unable to open tablet.";
267 if (!QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeSet(
context, currentQueueSize)) {
268 qWarning(
"Unable to set queue size on tablet. The tablet will not work.");
275 qCDebug(lcQpaTablet) <<
"Opened tablet context " <<
context <<
" on window "
276 <<
window <<
"changed packet queue size " << currentQueueSize
281unsigned QWindowsTabletSupport::options()
const
284 m_winTab32DLL.
wTInfo(WTI_INTERFACE, IFC_CTXOPTIONS, &
result);
290 const unsigned size = m_winTab32DLL.
wTInfo(WTI_INTERFACE, IFC_WINTABID,
nullptr);
294 m_winTab32DLL.
wTInfo(WTI_INTERFACE, IFC_WINTABID, winTabId.
data());
295 WORD implementationVersion = 0;
296 m_winTab32DLL.
wTInfo(WTI_INTERFACE, IFC_IMPLVERSION, &implementationVersion);
297 WORD specificationVersion = 0;
298 m_winTab32DLL.
wTInfo(WTI_INTERFACE, IFC_SPECVERSION, &specificationVersion);
299 const unsigned opts = options();
303 m_winTab32DLL.
wTInfo(WTI_INTERFACE, IFC_NCURSORS, &cursors);
305 m_winTab32DLL.
wTInfo(WTI_INTERFACE, IFC_NEXTENSIONS, &extensions);
309 <<
"\" specification: v" << (specificationVersion >> 8)
310 <<
'.' << (specificationVersion & 0xFF) <<
" implementation: v"
311 << (implementationVersion >> 8) <<
'.' << (implementationVersion & 0xFF)
312 <<
' ' <<
devices <<
" device(s), " << cursors <<
" cursor(s), "
313 << extensions <<
" extensions" <<
", options: 0x" <<
Qt::hex << opts <<
Qt::dec;
323 const bool result = QWindowsTabletSupport::m_winTab32DLL.
wTEnable(m_context,
true)
324 && QWindowsTabletSupport::m_winTab32DLL.
wTOverlap(m_context,
true);
330 if (((cursorType & 0x0006) == 0x0002) && ((cursorType &
CursorTypeBitMask) != 0x0902))
332 if (cursorType == 0x4020)
353 switch (currentCursor % 3) {
384 m_currentDevice.
data(),
390 for (
const auto &
d : m_devices) {
391 if (
d->deviceData()->systemId == systemId)
401 for (
const auto &
d : m_devices) {
402 if (
d->deviceData()->systemId == systemId &&
d->type() ==
deviceType
415 auto similar = findDevice(systemId);
416 if (similar.isNull())
429 QWindowsTabletSupport::m_winTab32DLL.
wTGet(m_context, &lc);
431 QWindowsTabletSupport::m_winTab32DLL.
wTInfo(WTI_DEVICES + lc.lcDevice, DVC_NPRESSURE, &axis);
432 data->minPressure = int(axis.axMin);
433 data->maxPressure = int(axis.axMax);
435 QWindowsTabletSupport::m_winTab32DLL.
wTInfo(WTI_DEVICES + lc.lcDevice, DVC_TPRESSURE, &axis);
436 data->minTanPressure = int(axis.axMin);
437 data->maxTanPressure = int(axis.axMax);
439 LOGCONTEXT defaultLc;
441 QWindowsTabletSupport::m_winTab32DLL.
wTInfo(WTI_DEFCONTEXT, 0, &defaultLc);
442 data->maxX = int(defaultLc.lcInExtX) - int(defaultLc.lcInOrgX);
443 data->maxY = int(defaultLc.lcInExtY) - int(defaultLc.lcInOrgY);
444 data->maxZ = int(defaultLc.lcInExtZ) - int(defaultLc.lcInOrgZ);
459 BYTE logicalButtons[32];
460 memset(logicalButtons, 0, 32);
461 m_winTab32DLL.
wTInfo(WTI_CURSORS + currentCursor, CSR_SYSBTNMAP, &logicalButtons);
462 data->buttonsMap.clear();
463 data->buttonsMap[0x1] = logicalButtons[0];
464 data->buttonsMap[0x2] = logicalButtons[1];
465 data->buttonsMap[0x4] = logicalButtons[2];
470 PACKET proximityBuffer[1];
471 const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.
wTPacketsGet(m_context, 1, proximityBuffer);
473 if (!LOWORD(lParam)) {
474 if (m_currentDevice.
isNull())
476 qCDebug(lcQpaTablet) <<
"leave proximity for device #" << m_currentDevice.
data();
478 leaveProximity(totalPacks > 0 ? proximityBuffer[0].pkTime : 0u);
485 const UINT currentCursor = proximityBuffer[0].pkCursor;
486 UINT physicalCursorId;
487 QWindowsTabletSupport::m_winTab32DLL.
wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId);
488 const qint64 systemId = physicalCursorId;
490 QWindowsTabletSupport::m_winTab32DLL.
wTInfo(WTI_CURSORS + currentCursor, CSR_TYPE, &cursorType);
497 m_currentDevice = findDevice(systemId, currentType, currentPointerType);
498 if (m_currentDevice.
isNull())
499 m_currentDevice = clonePhysicalDevice(systemId, currentType, currentPointerType);
500 if (m_currentDevice.
isNull()) {
502 data->systemId = systemId;
503 data->tiltCapability = m_tiltSupport;
504 data->zCapability = (cursorType == 0x0004);
505 updateButtons(currentCursor,
data.data());
507 m_devices.
append(m_currentDevice);
516 qCDebug(lcQpaTablet) <<
"enter proximity for device #"
517 << m_currentDevice.
data();
518 enterProximity(proximityBuffer[0].pkTime);
526 leftButtonValue = 0x1,
527 middleButtonValue = 0x2,
528 rightButtonValue = 0x4,
529 doubleClickButtonValue = 0x7
546 for (
unsigned int i = 0;
i < 3;
i++) {
547 unsigned int btn = 0x1 <<
i;
553 buttons |= convertedButton;
572 if (!packetCount || m_currentDevice.
isNull())
590 const QRect virtualDesktopArea =
594 qCDebug(lcQpaTablet) << __FUNCTION__ <<
"processing" << packetCount
595 <<
"mode=" << m_mode;
600 for (
int i = 0;
i < packetCount ; ++
i) {
601 const PACKET &packet = localPacketBuf[
i];
603 const int z = current.
zCapability ? int(packet.pkZ) : 0;
605 const auto packetPointerType =
pointerType(packet.pkCursor);
607 const Qt::MouseButtons buttons =
611 leaveProximity(packet.pkTime);
616 m_currentDevice = findDevice(systemId,
type, packetPointerType);
617 if (m_currentDevice.
isNull())
618 m_currentDevice = clonePhysicalDevice(systemId,
type, packetPointerType);
620 enterProximity(packet.pkTime);
633 m_mode = (mouseLocation - globalPosF).manhattanLength() > m_absoluteRange
635 qCDebug(lcQpaTablet) << __FUNCTION__ <<
"mode=" << m_mode <<
"pen:"
636 << globalPosF <<
"mouse:" << mouseLocation;
639 globalPosF = mouseLocation;
651 const qreal pressureNew = packet.pkButtons
670 const double tanAlt = std::tan(
qDegreesToRadians(std::abs(packet.pkOrientation.orAltitude / 10.0)));
672 const double radX = std::atan(std::sin(radAzim) / tanAlt);
673 const double radY = std::atan(std::cos(radAzim) / tanAlt);
676 rotation = 360.0 - (packet.pkOrientation.orTwist / 10.0);
677 if (rotation > 180.0)
683 <<
"Packet #" <<
i <<
'/' << packetCount <<
"button:" << packet.pkButtons
684 << globalPosF <<
z <<
"to:" <<
target << localPos <<
"(packet" << packet.pkX
685 << packet.pkY <<
") dev:" << m_currentDevice->
type() <<
"pointer:"
686 << m_currentDevice->
pointerType() <<
"P:" << pressureNew <<
"tilt:" << tiltX <<
','
687 << tiltY <<
"tanP:" << tangentialPressure <<
"rotation:" << rotation
691 m_eventTime = packet.pkTime;
693 m_currentDevice.
data(),
695 buttons, pressureNew, tiltX, tiltY,
696 tangentialPressure, rotation,
z,
static TabletPointData & tabletDevicePoint(qint64 deviceId)
QScreen * primaryScreen
the primary (or default) screen of the application.
T value(const Key &key) const noexcept
void append(parameter_type t)
\inmodule QtCore\reentrant
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
\inmodule QtCore\reentrant
QPointingDeviceUniqueId identifies a unique object, such as a tagged token or stylus,...
qint64 numericId
the numeric unique ID of the token represented by a touchpoint
static QPointingDeviceUniqueId fromNumericId(qint64 id)
Constructs a unique pointer ID from numeric ID id.
The QPointingDevice class describes a device from which mouse, touch or tablet events originate.
PointerType
This enum represents what is interacting with the pointing device.
QPointingDeviceUniqueId uniqueId
\inmodule QtCore\reentrant
constexpr int height() const noexcept
Returns the height of the rectangle.
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr int width() const noexcept
Returns the width of the rectangle.
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
bool isNull() const noexcept
Returns true if this object refers to \nullptr.
T * data() const noexcept
Returns the value of the pointer referenced by this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
QWinTabPointingDevice(const DeviceDataPtr &data, const QString &name, qint64 systemId, QInputDevice::DeviceType devType, PointerType pType, Capabilities caps, int maxPoints, int buttonCount, const QString &seatName=QString(), QPointingDeviceUniqueId uniqueId=QPointingDeviceUniqueId(), QObject *parent=nullptr)
const DeviceDataPtr & deviceData() const
static bool handleTabletEvent(QWindow *window, ulong timestamp, const QPointingDevice *device, const QPointF &local, const QPointF &global, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, int z, Qt::KeyboardModifiers modifiers=Qt::NoModifier)
static void registerInputDevice(const QInputDevice *device)
static bool handleTabletEnterLeaveProximityEvent(QWindow *window, ulong timestamp, const QPointingDevice *device, bool inProximity, const QPointF &local=QPointF(), const QPointF &global=QPointF(), Qt::MouseButtons buttons={}, int xTilt=0, int yTilt=0, qreal tangentialPressure=0, qreal rotation=0, int z=0, Qt::KeyboardModifiers modifiers=Qt::NoModifier)
HWND createDummyWindow(const QString &classNameIn, const wchar_t *windowName, WNDPROC wndProc=nullptr, DWORD style=WS_OVERLAPPED)
Convenience to create a non-visible, message-only dummy window for example used as clipboard watcher ...
static QWindowsContext * instance()
static QPoint mousePosition()
static Qt::KeyboardModifiers queryKeyboardModifiers()
static QWindow * windowAt(const QPoint &point, unsigned flags)
static QRect virtualGeometry(const QPlatformScreen *screen)
Tablet support for Windows.
QString description() const
bool translateTabletPacketEvent()
bool translateTabletProximityEvent(WPARAM wParam, LPARAM lParam)
QSharedPointer< QWinTabPointingDevice > DevicePtr
static QWindowsTabletSupport * create()
const QStyleOptionButton * btn
[3]
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
#define qCWarning(category,...)
#define qCDebug(category,...)
constexpr float qRadiansToDegrees(float radians)
constexpr float qDegreesToRadians(float degrees)
constexpr T qAbs(const T &t)
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLuint64 GLenum void * handle
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat GLfloat GLfloat maxY
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat GLfloat GLfloat maxX
#define QStringLiteral(str)
Qt::MouseButtons convertTabletButtons(DWORD btnNew, const QWindowsTabletDeviceData &tdd)
static QPointingDevice::PointerType pointerType(unsigned currentCursor)
QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t)
LRESULT QT_WIN_CALLBACK qWindowsTabletSupportWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
QWinTabPointingDevice * createInputDevice(const QSharedPointer< QWindowsTabletDeviceData > &d, QInputDevice::DeviceType devType, QPointingDevice::PointerType pointerType)
Qt::MouseButton buttonValueToEnum(DWORD button, const QWindowsTabletDeviceData &tdd)
static QInputDevice::DeviceType deviceType(const UINT cursorType)
static void formatOptions(Stream &str, unsigned options)
QPointF scaleCoordinates(int coordX, int coordY, const QRect &targetArea) const
qreal scalePressure(qreal p) const
qreal scaleTangentialPressure(qreal p) const
QHash< quint8, quint8 > buttonsMap
Functions from wintabl32.dll shipped with WACOM tablets used by QWindowsTabletSupport.
PtrWTQueueSizeSet wTQueueSizeSet
int(API * PtrWTQueueSizeGet)(HCTX)
BOOL(API * PtrWTGet)(HCTX, LPLOGCONTEXT)
UINT(API * PtrWTInfo)(UINT, UINT, LPVOID)
BOOL(API * PtrWTEnable)(HCTX, BOOL)
BOOL(API * PtrWTClose)(HCTX)
BOOL(API * PtrWTQueueSizeSet)(HCTX, int)
PtrWTPacketsGet wTPacketsGet
int(API * PtrWTPacketsGet)(HCTX, int, LPVOID)
PtrWTQueueSizeGet wTQueueSizeGet
HCTX(API * PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL)
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent