Add WACOM tablet support for Windows.

Task-number: QTBUG-30008

Change-Id: I3327baecae7c5d1411bcd125411097f36460cde5
Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
bb10
Friedemann Kleint 2013-06-14 17:04:41 +02:00 committed by The Qt Project
parent ac720981d2
commit 3168c94577
5 changed files with 653 additions and 5 deletions

View File

@ -47,6 +47,7 @@
#include "qtwindowsglobal.h"
#include "qwindowsmime.h"
#include "qwindowsinputcontext.h"
#include "qwindowstabletsupport.h"
#ifndef QT_NO_ACCESSIBILITY
#include "accessible/qwindowsaccessibility.h"
#endif
@ -83,6 +84,7 @@ int QWindowsContext::verboseOLE = 0;
int QWindowsContext::verboseInputMethods = 0;
int QWindowsContext::verboseDialogs = 0;
int QWindowsContext::verboseTheming = 0;
int QWindowsContext::verboseTablet = 0;
// Get verbosity of components from "foo:2,bar:3"
static inline int componentVerbose(const char *v, const char *keyWord)
@ -259,17 +261,20 @@ struct QWindowsContextPrivate {
QWindowsMimeConverter m_mimeConverter;
QWindowsScreenManager m_screenManager;
QSharedPointer<QWindowCreationContext> m_creationContext;
#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE)
QScopedPointer<QWindowsTabletSupport> m_tabletSupport;
#endif
const HRESULT m_oleInitializeResult;
const QByteArray m_eventType;
QWindow *m_lastActiveWindow;
bool m_asyncExpose;
};
QWindowsContextPrivate::QWindowsContextPrivate() :
m_systemInfo(0),
m_oleInitializeResult(OleInitialize(NULL)),
m_eventType(QByteArrayLiteral("windows_generic_MSG")),
m_lastActiveWindow(0), m_asyncExpose(0)
QWindowsContextPrivate::QWindowsContextPrivate()
: m_systemInfo(0)
, m_oleInitializeResult(OleInitialize(NULL))
, m_eventType(QByteArrayLiteral("windows_generic_MSG"))
, m_lastActiveWindow(0), m_asyncExpose(0)
{
const QSysInfo::WinVersion ver = QSysInfo::windowsVersion();
#ifndef Q_OS_WINCE
@ -310,7 +315,13 @@ QWindowsContext::QWindowsContext() :
QWindowsContext::verboseInputMethods = componentVerbose(v, "im");
QWindowsContext::verboseDialogs = componentVerbose(v, "dialogs");
QWindowsContext::verboseTheming = componentVerbose(v, "theming");
QWindowsContext::verboseTablet = componentVerbose(v, "tablet");
}
#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE)
d->m_tabletSupport.reset(QWindowsTabletSupport::create());
if (QWindowsContext::verboseTablet)
qDebug() << "Tablet support: " << (d->m_tabletSupport.isNull() ? QStringLiteral("None") : d->m_tabletSupport->description());
#endif
}
QWindowsContext::~QWindowsContext()
@ -626,6 +637,15 @@ QWindowsScreenManager &QWindowsContext::screenManager()
return d->m_screenManager;
}
QWindowsTabletSupport *QWindowsContext::tabletSupport() const
{
#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE)
return d->m_tabletSupport.data();
#else
return 0;
#endif
}
/*!
\brief Convenience to create a non-visible, message-only dummy
window for example used as clipboard watcher or for GL.
@ -854,6 +874,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return true;
#ifndef Q_OS_WINCE
case QtWindows::ActivateWindowEvent:
#ifndef QT_NO_TABLETEVENT
if (!d->m_tabletSupport.isNull())
d->m_tabletSupport->notifyActivate();
#endif // !QT_NO_TABLETEVENT
if (platformWindow->testFlag(QWindowsWindow::BlockedByModal))
if (const QWindow *modalWindow = QGuiApplication::modalWindow())
QWindowsWindow::baseWindowOf(modalWindow)->alertWindow();

View File

@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE
class QWindow;
class QPlatformScreen;
class QWindowsScreenManager;
class QWindowsTabletSupport;
class QWindowsWindow;
class QWindowsMimeConverter;
struct QWindowCreationContext;
@ -135,6 +136,7 @@ public:
static int verboseInputMethods;
static int verboseDialogs;
static int verboseTheming;
static int verboseTablet;
explicit QWindowsContext();
~QWindowsContext();
@ -184,6 +186,7 @@ public:
QWindowsMimeConverter &mimeConverter() const;
QWindowsScreenManager &screenManager();
QWindowsTabletSupport *tabletSupport() const;
#ifndef Q_OS_WINCE
static QWindowsUser32DLL user32dll;
static QWindowsShell32DLL shell32dll;

View File

@ -0,0 +1,473 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qwindowstabletsupport.h"
#ifndef QT_NO_TABLETEVENT
#include "qwindowscontext.h"
#include "qwindowskeymapper.h"
#include "qwindowswindow.h"
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/QTabletEvent>
#include <QtGui/QScreen>
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
#include <QtCore/QDebug>
#include <QtCore/QScopedArrayPointer>
#include <QtCore/QtMath>
#include <private/qguiapplication_p.h>
#include <QtCore/private/qsystemlibrary_p.h>
// Note: The definition of the PACKET structure in pktdef.h depends on this define.
#define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_Z)
#include <pktdef.h>
QT_BEGIN_NAMESPACE
enum {
PacketMode = 0,
TabletPacketQSize = 128,
DeviceIdMask = 0xFF6, // device type mask && device color mask
CursorTypeBitMask = 0x0F06 // bitmask to find the specific cursor type (see Wacom FAQ)
};
extern "C" LRESULT QT_WIN_CALLBACK qWindowsTabletSupportWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WT_PROXIMITY:
if (QWindowsContext::instance()->tabletSupport()->translateTabletProximityEvent(wParam, lParam))
return 0;
break;
case WT_PACKET:
if (QWindowsContext::instance()->tabletSupport()->translateTabletPacketEvent())
return 0;
break;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
// Scale tablet coordinates to screen coordinates.
static inline int sign(int x)
{
return x >= 0 ? 1 : -1;
}
inline QPointF QWindowsTabletDeviceData::scaleCoordinates(int coordX, int coordY, const QRect &targetArea) const
{
const int targetX = targetArea.x();
const int targetY = targetArea.y();
const int targetWidth = targetArea.width();
const int targetHeight = targetArea.height();
const qreal x = sign(targetWidth) == sign(maxX) ?
((coordX - minX) * qAbs(targetWidth) / qAbs(qreal(maxX - minX))) + targetX :
((qAbs(maxX) - (coordX - minX)) * qAbs(targetWidth) / qAbs(qreal(maxX - minX))) + targetX;
const qreal y = sign(targetHeight) == sign(maxY) ?
((coordY - minY) * qAbs(targetHeight) / qAbs(qreal(maxY - minY))) + targetY :
((qAbs(maxY) - (coordY - minY)) * qAbs(targetHeight) / qAbs(qreal(maxY - minY))) + targetY;
return QPointF(x, y);
}
QWindowsWinTab32DLL QWindowsTabletSupport::m_winTab32DLL;
/*!
\class QWindowsWinTab32DLL QWindowsTabletSupport
\brief Functions from wintabl32.dll shipped with WACOM tablets used by QWindowsTabletSupport.
\internal
\ingroup qt-lighthouse-win
*/
bool QWindowsWinTab32DLL::init()
{
if (wTInfo)
return true;
QSystemLibrary library(QStringLiteral("wintab32"));
if (!library.load())
return false;
wTOpen = (PtrWTOpen)library.resolve("WTOpenW");
wTClose = (PtrWTClose)library.resolve("WTClose");
wTInfo = (PtrWTInfo)library.resolve("WTInfoW");
wTEnable = (PtrWTEnable)library.resolve("WTEnable");
wTOverlap = (PtrWTEnable)library.resolve("WTOverlap");
wTPacketsGet = (PtrWTPacketsGet)library.resolve("WTPacketsGet");
wTGet = (PtrWTGet)library.resolve("WTGetW");
wTQueueSizeGet = (PtrWTQueueSizeGet)library.resolve("WTQueueSizeGet");
wTQueueSizeSet = (PtrWTQueueSizeSet)library.resolve("WTQueueSizeSet");
return wTOpen && wTClose && wTInfo && wTEnable && wTOverlap && wTPacketsGet && wTQueueSizeGet && wTQueueSizeSet;
}
/*!
\class QWindowsTabletSupport
\brief Tablet support for Windows.
Support for WACOM tablets.
\sa http://www.wacomeng.com/windows/docs/Wintab_v140.htm
\internal
\since 5.2
\ingroup qt-lighthouse-win
*/
QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context)
: m_window(window)
, m_context(context)
, m_tiltSupport(false)
, m_currentDevice(-1)
{
AXIS orientation[3];
// Some tablets don't support tilt, check if it is possible,
if (QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES, DVC_ORIENTATION, &orientation))
m_tiltSupport = orientation[0].axResolution && orientation[1].axResolution;
}
QWindowsTabletSupport::~QWindowsTabletSupport()
{
QWindowsTabletSupport::m_winTab32DLL.wTClose(m_context);
DestroyWindow(m_window);
}
QWindowsTabletSupport *QWindowsTabletSupport::create()
{
if (!m_winTab32DLL.init())
return 0;
const HWND window = QWindowsContext::instance()->createDummyWindow(QStringLiteral("TabletDummyWindow"),
L"TabletDummyWindow",
qWindowsTabletSupportWndProc);
if (!window) {
if (QWindowsContext::verboseTablet)
qWarning() << __FUNCTION__ << "Unable to create window for tablet.";
return 0;
}
LOGCONTEXT lcMine;
// build our context from the default context
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEFSYSCTX, 0, &lcMine);
// Go for the raw coordinates, the tablet event will return good stuff
lcMine.lcOptions |= CXO_MESSAGES | CXO_CSRMESSAGES;
lcMine.lcPktData = lcMine.lcMoveMask = PACKETDATA;
lcMine.lcPktMode = PacketMode;
lcMine.lcOutOrgX = 0;
lcMine.lcOutExtX = lcMine.lcInExtX;
lcMine.lcOutOrgY = 0;
lcMine.lcOutExtY = -lcMine.lcInExtY;
const HCTX context = QWindowsTabletSupport::m_winTab32DLL.wTOpen(window, &lcMine, true);
if (!context) {
if (QWindowsContext::verboseTablet)
qWarning() << __FUNCTION__ << "Unable to open tablet.";
DestroyWindow(window);
return 0;
}
// Set the size of the Packet Queue to the correct size
const int currentQueueSize = QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeGet(context);
if (currentQueueSize != TabletPacketQSize) {
if (!QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeSet(context, TabletPacketQSize)) {
if (!QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeSet(context, currentQueueSize)) {
qWarning() << "Unable to set queue size on tablet. The tablet will not work.";
QWindowsTabletSupport::m_winTab32DLL.wTClose(context);
DestroyWindow(window);
return 0;
} // cannot restore old size
} // cannot set
} // mismatch
if (QWindowsContext::verboseTablet)
qDebug("Opened tablet context %p on window %p, changed packet queue size %d -> %d",
context, window, currentQueueSize, TabletPacketQSize);
return new QWindowsTabletSupport(window, context);
}
unsigned QWindowsTabletSupport::options() const
{
UINT result = 0;
m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_CTXOPTIONS, &result);
return result;
}
QString QWindowsTabletSupport::description() const
{
const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, 0);
if (!size)
return QString();
QScopedPointer<TCHAR> winTabId(new TCHAR[size + 1]);
m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, winTabId.data());
WORD implementationVersion = 0;
m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_IMPLVERSION, &implementationVersion);
WORD specificationVersion = 0;
m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_SPECVERSION, &specificationVersion);
const unsigned opts = options();
QString result = QString::fromLatin1("%1 specification: v%2.%3 implementation: v%4.%5 options: 0x%6")
.arg(QString::fromWCharArray(winTabId.data()))
.arg(specificationVersion >> 8).arg(specificationVersion & 0xFF)
.arg(implementationVersion >> 8).arg(implementationVersion & 0xFF)
.arg(opts, 0, 16);
if (opts & CXO_MESSAGES)
result += QStringLiteral(" CXO_MESSAGES");
if (opts & CXO_CSRMESSAGES)
result += QStringLiteral(" CXO_CSRMESSAGES");
if (m_tiltSupport)
result += QStringLiteral(" tilt");
return result;
}
void QWindowsTabletSupport::notifyActivate()
{
// Cooperate with other tablet applications, but when we get focus, I want to use the tablet.
const bool result = QWindowsTabletSupport::m_winTab32DLL.wTEnable(m_context, true)
&& QWindowsTabletSupport::m_winTab32DLL.wTOverlap(m_context, true);
if (QWindowsContext::verboseTablet)
qDebug() << __FUNCTION__ << result;
}
static inline int indexOfDevice(const QVector<QWindowsTabletDeviceData> &devices, qint64 uniqueId)
{
for (int i = 0; i < devices.size(); ++i)
if (devices.at(i).uniqueId == uniqueId)
return i;
return -1;
}
static inline QTabletEvent::TabletDevice deviceType(const UINT cursorType)
{
if (((cursorType & 0x0006) == 0x0002) && ((cursorType & CursorTypeBitMask) != 0x0902))
return QTabletEvent::Stylus;
switch (cursorType & CursorTypeBitMask) {
case 0x0802:
return QTabletEvent::Stylus;
case 0x0902:
return QTabletEvent::Airbrush;
case 0x0004:
return QTabletEvent::FourDMouse;
case 0x0006:
return QTabletEvent::Puck;
case 0x0804:
return QTabletEvent::RotationStylus;
default:
break;
}
return QTabletEvent::NoDevice;
}
static inline QTabletEvent::PointerType pointerType(unsigned currentCursor)
{
switch (currentCursor % 3) { // %3 for dual track
case 0:
return QTabletEvent::Cursor;
case 1:
return QTabletEvent::Pen;
case 2:
return QTabletEvent::Eraser;
default:
break;
}
return QTabletEvent::UnknownPointer;
}
QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t)
{
d << "TabletDevice id:" << t.uniqueId << " pressure: " << t.minPressure
<< ".." << t.maxPressure << " tan pressure: " << t.minTanPressure << ".."
<< t.maxTanPressure << " area:" << t.minX << t.minY <<t.minZ
<< ".." << t.maxX << t.maxY << t.maxZ << " device " << t.currentDevice
<< " pointer " << t.currentPointerType;
return d;
}
QWindowsTabletDeviceData QWindowsTabletSupport::tabletInit(const quint64 uniqueId, const UINT cursorType) const
{
QWindowsTabletDeviceData result;
result.uniqueId = uniqueId;
/* browse WinTab's many info items to discover pressure handling. */
AXIS axis;
LOGCONTEXT lc;
/* get the current context for its device variable. */
QWindowsTabletSupport::m_winTab32DLL.wTGet(m_context, &lc);
/* get the size of the pressure axis. */
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES + lc.lcDevice, DVC_NPRESSURE, &axis);
result.minPressure = int(axis.axMin);
result.maxPressure = int(axis.axMax);
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES + lc.lcDevice, DVC_TPRESSURE, &axis);
result.minTanPressure = int(axis.axMin);
result.maxTanPressure = int(axis.axMax);
LOGCONTEXT defaultLc;
/* get default region */
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEFCONTEXT, 0, &defaultLc);
result.maxX = int(defaultLc.lcInExtX) - int(defaultLc.lcInOrgX);
result.maxY = int(defaultLc.lcInExtY) - int(defaultLc.lcInOrgY);
result.maxZ = int(defaultLc.lcInExtZ) - int(defaultLc.lcInOrgZ);
result.currentDevice = deviceType(cursorType);
return result;
}
bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, LPARAM lParam)
{
const bool enteredProximity = LOWORD(lParam) != 0;
PACKET proximityBuffer[1]; // we are only interested in the first packet in this case
const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, 1, proximityBuffer);
if (!totalPacks)
return false;
const UINT currentCursor = proximityBuffer[0].pkCursor;
UINT physicalCursorId;
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId);
UINT cursorType;
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_TYPE, &cursorType);
const qint64 uniqueId = (qint64(cursorType & DeviceIdMask) << 32L) | qint64(physicalCursorId);
// initializing and updating the cursor should be done in response to
// WT_CSRCHANGE. We do it in WT_PROXIMITY because some wintab never send
// the event WT_CSRCHANGE even if asked with CXO_CSRMESSAGES
m_currentDevice = indexOfDevice(m_devices, uniqueId);
if (m_currentDevice < 0) {
m_currentDevice = m_devices.size();
m_devices.push_back(tabletInit(uniqueId, cursorType));
}
m_devices[m_currentDevice].currentPointerType = pointerType(currentCursor);
if (QWindowsContext::verboseTablet)
qDebug() << __FUNCTION__ << (enteredProximity ? "enter" : "leave")
<< " proximity for device #"
<< m_currentDevice << m_devices.at(m_currentDevice);
if (enteredProximity) {
QWindowSystemInterface::handleTabletEnterProximityEvent(m_devices.at(m_currentDevice).currentDevice,
m_devices.at(m_currentDevice).currentPointerType,
m_devices.at(m_currentDevice).uniqueId);
} else {
QWindowSystemInterface::handleTabletLeaveProximityEvent(m_devices.at(m_currentDevice).currentDevice,
m_devices.at(m_currentDevice).currentPointerType,
m_devices.at(m_currentDevice).uniqueId);
}
return true;
}
bool QWindowsTabletSupport::translateTabletPacketEvent()
{
static PACKET localPacketBuf[TabletPacketQSize]; // our own tablet packet queue.
const int packetCount = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, TabletPacketQSize, &localPacketBuf);
if (!packetCount || m_currentDevice < 0)
return false;
const int currentDevice = m_devices.at(m_currentDevice).currentDevice;
const int currentPointer = m_devices.at(m_currentDevice).currentPointerType;
// When entering proximity, the tablet driver snaps the mouse pointer to the
// tablet position scaled to the virtual desktop and keeps it in sync.
const QRect virtualDesktopArea = QGuiApplication::primaryScreen()->virtualGeometry();
if (QWindowsContext::verboseTablet)
qDebug() << __FUNCTION__ << "processing " << packetCount
<< "target:" << QGuiApplicationPrivate::tabletPressTarget;
const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
for (int i = 0; i < packetCount ; ++i) {
const PACKET &packet = localPacketBuf[i];
const int z = currentDevice == QTabletEvent::FourDMouse ? int(packet.pkZ) : 0;
const QPointF globalPosF = m_devices.at(m_currentDevice).scaleCoordinates(packet.pkX, packet.pkY, virtualDesktopArea);
QWindow *target = QGuiApplicationPrivate::tabletPressTarget; // Pass to window that grabbed it.
const QPoint globalPos = globalPosF.toPoint();
if (!target)
if (QPlatformWindow *pw = QWindowsContext::instance()->findPlatformWindowAt(GetDesktopWindow(), globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT))
target = pw->window();
if (!target)
continue;
const QPoint localPos = target->mapFromGlobal(globalPos);
const qreal pressureNew = packet.pkButtons && (currentPointer == QTabletEvent::Pen || currentPointer == QTabletEvent::Eraser) ?
m_devices.at(m_currentDevice).scalePressure(packet.pkNormalPressure) :
qreal(0);
const qreal tangentialPressure = currentDevice == QTabletEvent::Airbrush ?
m_devices.at(m_currentDevice).scaleTangentialPressure(packet.pkTangentPressure) :
qreal(0);
int tiltX = 0;
int tiltY = 0;
qreal rotation = 0;
if (m_tiltSupport) {
// Convert from azimuth and altitude to x tilt and y tilt. What
// follows is the optimized version. Here are the equations used:
// X = sin(azimuth) * cos(altitude)
// Y = cos(azimuth) * cos(altitude)
// Z = sin(altitude)
// X Tilt = arctan(X / Z)
// Y Tilt = arctan(Y / Z)
const double radAzim = (packet.pkOrientation.orAzimuth / 10) * (M_PI / 180);
const double tanAlt = tan((abs(packet.pkOrientation.orAltitude / 10)) * (M_PI / 180));
const double degX = atan(sin(radAzim) / tanAlt);
const double degY = atan(cos(radAzim) / tanAlt);
tiltX = int(degX * (180 / M_PI));
tiltY = int(-degY * (180 / M_PI));
rotation = packet.pkOrientation.orTwist;
}
if (QWindowsContext::verboseTablet > 1) {
qDebug()
<< "Packet #" << i << '/' << packetCount << "button:" << packet.pkButtons
<< globalPosF << z << "to:" << target << localPos << "(packet" << packet.pkX
<< packet.pkY << ") dev:" << currentDevice << "pointer:"
<< currentPointer << "P:" << pressureNew << "tilt:" << tiltX << ','
<< tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation;
}
QWindowSystemInterface::handleTabletEvent(target, packet.pkButtons, localPos, globalPosF,
currentDevice, currentPointer,
pressureNew, tiltX, tiltY,
tangentialPressure, rotation, z,
m_devices.at(m_currentDevice).uniqueId,
keyboardModifiers);
}
return true;
}
QT_END_NAMESPACE
#endif // QT_NO_TABLETEVENT

View File

@ -0,0 +1,142 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QWINDOWSTABLETSUPPORT_H
#define QWINDOWSTABLETSUPPORT_H
#include "qtwindowsglobal.h"
#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE)
#include <QtCore/QVector>
#include <QtCore/QPointF>
#include <wintab.h>
QT_BEGIN_NAMESPACE
class QDebug;
class QWindow;
class QRect;
struct QWindowsWinTab32DLL
{
QWindowsWinTab32DLL() : wTOpen(0), wTClose(0), wTInfo(0), wTEnable(0), wTOverlap(0), wTPacketsGet(0), wTGet(0),
wTQueueSizeGet(0), wTQueueSizeSet(0) {}
bool init();
typedef HCTX (API *PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL);
typedef BOOL (API *PtrWTClose)(HCTX);
typedef UINT (API *PtrWTInfo)(UINT, UINT, LPVOID);
typedef BOOL (API *PtrWTEnable)(HCTX, BOOL);
typedef BOOL (API *PtrWTOverlap)(HCTX, BOOL);
typedef int (API *PtrWTPacketsGet)(HCTX, int, LPVOID);
typedef BOOL (API *PtrWTGet)(HCTX, LPLOGCONTEXT);
typedef int (API *PtrWTQueueSizeGet)(HCTX);
typedef BOOL (API *PtrWTQueueSizeSet)(HCTX, int);
PtrWTOpen wTOpen;
PtrWTClose wTClose;
PtrWTInfo wTInfo;
PtrWTEnable wTEnable;
PtrWTOverlap wTOverlap;
PtrWTPacketsGet wTPacketsGet;
PtrWTGet wTGet;
PtrWTQueueSizeGet wTQueueSizeGet;
PtrWTQueueSizeSet wTQueueSizeSet;
};
struct QWindowsTabletDeviceData
{
QWindowsTabletDeviceData() : minPressure(0), maxPressure(0), minTanPressure(0),
maxTanPressure(0), minX(0), maxX(0), minY(0), maxY(0), minZ(0), maxZ(0),
uniqueId(0), currentDevice(0), currentPointerType(0) {}
QPointF scaleCoordinates(int coordX, int coordY,const QRect &targetArea) const;
qreal scalePressure(qreal p) const { return p / qreal(maxPressure - minPressure); }
qreal scaleTangentialPressure(qreal p) const { return p / qreal(maxTanPressure - minTanPressure); }
int minPressure;
int maxPressure;
int minTanPressure;
int maxTanPressure;
int minX, maxX, minY, maxY, minZ, maxZ;
qint64 uniqueId;
int currentDevice;
int currentPointerType;
};
QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t);
class QWindowsTabletSupport
{
Q_DISABLE_COPY(QWindowsTabletSupport)
explicit QWindowsTabletSupport(HWND window, HCTX context);
public:
~QWindowsTabletSupport();
static QWindowsTabletSupport *create();
void notifyActivate();
QString description() const;
bool translateTabletProximityEvent(WPARAM wParam, LPARAM lParam);
bool translateTabletPacketEvent();
private:
unsigned options() const;
QWindowsTabletDeviceData tabletInit(const quint64 uniqueId, const UINT cursorType) const;
static QWindowsWinTab32DLL m_winTab32DLL;
const HWND m_window;
const HCTX m_context;
bool m_tiltSupport;
QVector<QWindowsTabletDeviceData> m_devices;
int m_currentDevice;
};
QT_END_NAMESPACE
#endif // !QT_NO_TABLETEVENT && !Q_OS_WINCE
#endif // QWINDOWSTABLETSUPPORT_H

View File

@ -102,6 +102,12 @@ contains(QT_CONFIG, opengles2) {
}
}
!wince*:!contains( DEFINES, QT_NO_TABLETEVENT ) {
INCLUDEPATH += ../../../3rdparty/wintab
HEADERS += qwindowstabletsupport.h
SOURCES += qwindowstabletsupport.cpp
}
contains(QT_CONFIG, freetype) {
DEFINES *= QT_NO_FONTCONFIG
QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype