Commit 9cf5c866 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Fix setting custom tablet mapping

1) Fix support for negative offsets
2) The setting is applied right after pressing OK in the
   configuration dialog
3) Qt fetches this updated info after tablet proximity leave/enter
   cycle.
parent 71371bbc
From 8a1dc023446ee4c114646b7cb5f9d6265d29877a Mon Sep 17 00:00:00 2001
From 087561675d1c1922265c3c52faeac61ab1bc2ecf Mon Sep 17 00:00:00 2001
From: Dmitry Kazakov <dimula73@gmail.com>
Date: Mon, 15 Apr 2019 13:48:16 +0300
Subject: [PATCH] Fetch tablet mapping from Wintab instead virtual screen
geometry
Date: Sat, 13 Apr 2019 23:24:01 +0300
Subject: [PATCH] Fetch mapped screen size from the Wintab driver
Some devices, like Microsoft Surface Pro 5, don't map tablet's
input range to the entire virtual screen area, but map it to
......@@ -11,23 +10,37 @@ the primary display that has actual built-in tablet sensor.
In such cases we should fetch actualy mapped aread from Wintab's
lcSys{Org,Ext}{X,Y} fields and use it for cursor mapping.
The patch also introduces an environment variable switch that
falls back to the old method of mapping:
If one wants to fall back to the old screen size detection method,
then an environment variable can be set:
QT_IGNORE_WINTAB_MAPPING=1
When the variable is set, the scaling is done via virtual desktop
area only.
If the tablet driver is broken (e.g. Microsoft SP5, when primary
display is set to an external monitor) the user might want to override
mapping completely. Then the following variable can be used:
QT_WINTAB_DESKTOP_RECT=x;y;width;height
---
.../windows/qwindowstabletsupport.cpp | 55 ++++++++++++++++++-
.../platforms/windows/qwindowstabletsupport.h | 11 +++-
2 files changed, 64 insertions(+), 2 deletions(-)
.../windows/qwindowstabletsupport.cpp | 89 ++++++++++++++++++-
.../platforms/windows/qwindowstabletsupport.h | 13 ++-
2 files changed, 99 insertions(+), 3 deletions(-)
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
index 43c6130f..e5aab523 100644
index 18ec05e4..6a1bf02b 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
@@ -217,6 +217,10 @@ QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context)
@@ -53,6 +53,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qmath.h>
+#include <QtCore/qregularexpression.h>
#include <private/qguiapplication_p.h>
#include <QtCore/private/qsystemlibrary_p.h>
@@ -216,6 +217,10 @@ QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context)
// 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;
......@@ -38,7 +51,7 @@ index 43c6130f..e5aab523 100644
}
QWindowsTabletSupport::~QWindowsTabletSupport()
@@ -395,6 +399,43 @@ QWindowsTabletDeviceData QWindowsTabletSupport::tabletInit(qint64 uniqueId, UINT
@@ -394,6 +399,84 @@ QWindowsTabletDeviceData QWindowsTabletSupport::tabletInit(qint64 uniqueId, UINT
return result;
}
......@@ -71,52 +84,80 @@ index 43c6130f..e5aab523 100644
+
+ LOGCONTEXT lc;
+ QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEFSYSCTX, 0, &lc);
+ m_mappedScreenGeometry = QRect(lc.lcSysOrgX, lc.lcSysOrgY, lc.lcSysExtX, lc.lcSysExtY);
+ m_wintabScreenGeometry = QRect(lc.lcSysOrgX, lc.lcSysOrgY, lc.lcSysExtX, lc.lcSysExtY);
+
+ qCDebug(lcQpaTablet) << "Updated tablet mapping: " << m_mappedScreenGeometry;
+ qCDebug(lcQpaTablet) << "Updated tablet mapping: " << m_wintabScreenGeometry;
+ if (QGuiApplication::primaryScreen()) {
+ qCDebug(lcQpaTablet) << " real desktop geometry: " << QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle());
+ }
+}
+
+void QWindowsTabletSupport::updateEffectiveScreenGeometry()
+{
+ QRect customGeometry;
+ bool dontUseWintabDesktopRect = false;
+
+ const QString geometry = qEnvironmentVariable("QT_WINTAB_DESKTOP_RECT");
+ if (!geometry.isEmpty()) {
+ QString tmp = QString::fromLatin1("([+-]?\\d+);([+-]?\\d+);(\\d+);(\\d+)");
+
+ QRegularExpression rex(tmp);
+ QRegularExpressionMatch match = rex.match(geometry);
+
+ if (match.hasMatch()) {
+ customGeometry.setRect(match.captured(1).toInt(),
+ match.captured(2).toInt(),
+ match.captured(3).toInt(),
+ match.captured(4).toInt());
+
+ qCDebug(lcQpaTablet) << "apply QT_WINTAB_DESKTOP_RECT:" << customGeometry;
+ } else {
+ qCWarning(lcQpaTablet) << "failed to parse QT_WINTAB_DESKTOP_RECT:" << geometry;
+ }
+ }
+
+ if (qEnvironmentVariableIsSet("QT_IGNORE_WINTAB_MAPPING")) {
+ if (!customGeometry.isValid()) {
+ qCDebug(lcQpaTablet) << "fallback mapping is requested via QT_IGNORE_WINTAB_MAPPING";
+ } else {
+ qCWarning(lcQpaTablet) << "ignoring QT_IGNORE_WINTAB_MAPPING, because QT_WINTAB_DESKTOP_RECT is set";
+ }
+ dontUseWintabDesktopRect = true;
+ }
+
+ m_effectiveScreenGeometry =
+ !customGeometry.isValid() ?
+ (dontUseWintabDesktopRect ?
+ QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle()) :
+ m_wintabScreenGeometry) :
+ customGeometry;
+}
+
bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, LPARAM lParam)
{
PACKET proximityBuffer[1]; // we are only interested in the first packet in this case
@@ -538,6 +579,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
static bool customGeometryIsInitialized = false;
static QRect customGeometry;
+ static bool dontUseWintabDesktopRect = false;
if (!customGeometryIsInitialized) {
const QString geometry = qEnvironmentVariable("QT_WINTAB_DESKTOP_RECT");
@@ -559,12 +601,23 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
}
}
@@ -421,6 +504,8 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L
if (!totalPacks)
return false;
+ if (qEnvironmentVariableIsSet("QT_IGNORE_WINTAB_MAPPING")) {
+ if (!customGeometry.isValid()) {
+ qInfo() << "INFO: fallback mapping is requested via QT_IGNORE_WINTAB_MAPPING";
+ } else {
+ qInfo() << "INFO: ignoring QT_IGNORE_WINTAB_MAPPING, because QT_WINTAB_DESKTOP_RECT is set";
+ }
+ dontUseWintabDesktopRect = true;
+ }
+ updateEffectiveScreenGeometry();
+
customGeometryIsInitialized = true;
}
const QRect virtualDesktopArea =
!customGeometry.isValid() ?
- QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle()) :
+ (dontUseWintabDesktopRect ?
+ QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle()) :
+ m_mappedScreenGeometry) :
customGeometry;
const UINT currentCursor = proximityBuffer[0].pkCursor;
UINT physicalCursorId;
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId);
@@ -534,8 +619,8 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
// in which case we snap the position to the mouse position.
// It seems there is no way to find out the mode programmatically, the LOGCONTEXT orgX/Y/Ext
// area is always the virtual desktop.
- const QRect virtualDesktopArea =
- QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle());
+
+ const QRect virtualDesktopArea = m_effectiveScreenGeometry;
if (QWindowsContext::verbose > 1) {
qCDebug(lcQpaTablet) << __FUNCTION__ << "processing" << packetCount
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h
index 5b1ddb52..e570f56d 100644
index 5b1ddb52..e8b0c01b 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.h
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.h
@@ -45,7 +45,9 @@
......@@ -146,7 +187,7 @@ index 5b1ddb52..e570f56d 100644
{
Q_DISABLE_COPY(QWindowsTabletSupport)
@@ -141,6 +144,10 @@ public:
@@ -141,9 +144,14 @@ public:
int absoluteRange() const { return m_absoluteRange; }
void setAbsoluteRange(int a) { m_absoluteRange = a; }
......@@ -157,12 +198,17 @@ index 5b1ddb52..e570f56d 100644
private:
unsigned options() const;
QWindowsTabletDeviceData tabletInit(qint64 uniqueId, UINT cursorType) const;
@@ -154,6 +161,8 @@ private:
+ void updateEffectiveScreenGeometry();
static QWindowsWinTab32DLL m_winTab32DLL;
const HWND m_window;
@@ -154,6 +162,9 @@ private:
int m_currentDevice = -1;
Mode m_mode = PenMode;
State m_state = PenUp;
+ QScreen *m_connectedScreen = 0;
+ QRect m_mappedScreenGeometry;
+ QRect m_wintabScreenGeometry;
+ QRect m_effectiveScreenGeometry;
};
QT_END_NAMESPACE
......
From 73d1e5fac0d9f78a6ba23db2ac648ec52273a2dc Mon Sep 17 00:00:00 2001
From: Dmitry Kazakov <dimula73@gmail.com>
Date: Sat, 13 Apr 2019 23:24:01 +0300
Subject: [PATCH] Implement a custom variable for overriding Wintab's desktop
area
If you think that Qt recognizes desktop area incorrectly, you can try
to override this choice by setting environment variable
QT_WINTAB_DESKTOP_RECT and running the application in this environment.
The value of the variable is a semicolon-separated list of integers:
QT_WINTAB_DESKTOP_RECT=x;y;width;height
---
.../windows/qwindowstabletsupport.cpp | 32 ++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
index 18ec05e4..43c6130f 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
@@ -53,6 +53,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qmath.h>
+#include <QtCore/qregularexpression.h>
#include <private/qguiapplication_p.h>
#include <QtCore/private/qsystemlibrary_p.h>
@@ -534,8 +535,37 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
// in which case we snap the position to the mouse position.
// It seems there is no way to find out the mode programmatically, the LOGCONTEXT orgX/Y/Ext
// area is always the virtual desktop.
+
+ static bool customGeometryIsInitialized = false;
+ static QRect customGeometry;
+
+ if (!customGeometryIsInitialized) {
+ const QString geometry = qEnvironmentVariable("QT_WINTAB_DESKTOP_RECT");
+ if (!geometry.isEmpty()) {
+ QString tmp = QString::fromLatin1("(\\d+);(\\d+);(\\d+);(\\d+)");
+
+ QRegularExpression rex(tmp);
+ QRegularExpressionMatch match = rex.match(geometry);
+
+ if (match.hasMatch()) {
+ customGeometry.setRect(match.captured(1).toInt(),
+ match.captured(2).toInt(),
+ match.captured(3).toInt(),
+ match.captured(4).toInt());
+
+ qInfo() << "INFO: apply QT_WINTAB_DESKTOP_RECT:" << customGeometry;
+ } else {
+ qWarning() << "WARNING: failed to parse QT_WINTAB_DESKTOP_RECT:" << geometry;
+ }
+ }
+
+ customGeometryIsInitialized = true;
+ }
+
const QRect virtualDesktopArea =
- QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle());
+ !customGeometry.isValid() ?
+ QWindowsScreen::virtualGeometry(QGuiApplication::primaryScreen()->handle()) :
+ customGeometry;
if (QWindowsContext::verbose > 1) {
qCDebug(lcQpaTablet) << __FUNCTION__ << "processing" << packetCount
--
2.20.1.windows.1
......@@ -53,8 +53,7 @@ if (WIN32)
COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0023-Implement-a-switch-for-tablet-API-on-Windows.patch
COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0024-Fetch-stylus-button-remapping-from-WinTab-driver.patch
COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0025-Disable-tablet-relative-mode-in-Qt.patch
COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0026-Implement-a-custom-variable-for-overriding-Wintab-s-.patch
COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0027-Fetch-tablet-mapping-from-Wintab-instead-virtual-scr.patch
COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0026-Fetch-mapped-screen-size-from-the-Wintab-driver.patch
)
endif()
......
......@@ -317,19 +317,8 @@ extern "C" int main(int argc, char **argv)
QRect customTabletRect;
KisDlgCustomTabletResolution::Mode tabletMode =
KisDlgCustomTabletResolution::getTabletMode(&customTabletRect);
if (tabletMode == KisDlgCustomTabletResolution::USE_CUSTOM) {
qputenv("QT_WINTAB_DESKTOP_RECT",
QString("%1;%2;%3;%4")
.arg(customTabletRect.x())
.arg(customTabletRect.y())
.arg(customTabletRect.width())
.arg(customTabletRect.height()).toLatin1());
} else if (tabletMode == KisDlgCustomTabletResolution::USE_VIRTUAL_SCREEN) {
qputenv("QT_IGNORE_WINTAB_MAPPING", "1");
}
KisDlgCustomTabletResolution::applyConfiguration(tabletMode, customTabletRect);
}
#endif
// first create the application so we can create a pixmap
......
......@@ -27,6 +27,15 @@
#include <QStandardPaths>
#include <qpa/qplatformscreen.h>
namespace {
QString rectToString(const QRect &rc) {
return QString("%1, %2 %3 x %4")
.arg(rc.x())
.arg(rc.y())
.arg(rc.width())
.arg(rc.height());
}
}
KisDlgCustomTabletResolution::KisDlgCustomTabletResolution(QWidget *parent) :
QDialog(parent),
......@@ -48,14 +57,13 @@ KisDlgCustomTabletResolution::KisDlgCustomTabletResolution(QWidget *parent) :
const QRect virtualScreenRect = calcNativeScreenRect();
const QString rectToString =
QString("%1, %2 %3 x %4")
.arg(virtualScreenRect.x())
.arg(virtualScreenRect.y())
.arg(virtualScreenRect.width())
.arg(virtualScreenRect.height());
ui->radioMapToEntireScreen->setText(i18nc("@option:radio", "Map to entire virtual screen (%1)", rectToString(virtualScreenRect)));
ui->radioMapToEntireScreen->setText(i18nc("@option:radio", "Map to entire virtual screen (%1)", rectToString));
QRect nativeScreenRect;
QPlatformScreen *screen = qGuiApp->primaryScreen()->handle();
Q_FOREACH (QPlatformScreen *scr, screen->virtualSiblings()) {
nativeScreenRect |= scr->geometry();
}
QRect customScreenRect = virtualScreenRect;
Mode mode = getTabletMode(&customScreenRect);
......@@ -92,6 +100,13 @@ void KisDlgCustomTabletResolution::accept()
cfg.setValue("wintabCustomResolutionHeight", ui->intHeight->value());
}
// apply the mode right now
{
QRect customTabletRect;
const Mode tabletMode = getTabletMode(&customTabletRect);
applyConfiguration(tabletMode, customTabletRect);
}
QDialog::accept();
}
......@@ -135,3 +150,22 @@ KisDlgCustomTabletResolution::Mode KisDlgCustomTabletResolution::getTabletMode(Q
return modeValue;
}
void KisDlgCustomTabletResolution::applyConfiguration(KisDlgCustomTabletResolution::Mode tabletMode, const QRect &customTabletRect)
{
if (tabletMode == KisDlgCustomTabletResolution::USE_CUSTOM) {
qputenv("QT_WINTAB_DESKTOP_RECT",
QString("%1;%2;%3;%4")
.arg(customTabletRect.x())
.arg(customTabletRect.y())
.arg(customTabletRect.width())
.arg(customTabletRect.height()).toLatin1());
qunsetenv("QT_IGNORE_WINTAB_MAPPING");
} else if (tabletMode == KisDlgCustomTabletResolution::USE_VIRTUAL_SCREEN) {
qputenv("QT_IGNORE_WINTAB_MAPPING", "1");
qunsetenv("QT_WINTAB_DESKTOP_RECT");
} else {
qunsetenv("QT_WINTAB_DESKTOP_RECT");
qunsetenv("QT_IGNORE_WINTAB_MAPPING");
}
}
......@@ -46,6 +46,8 @@ public:
static QRect calcNativeScreenRect();
static Mode getTabletMode(QRect *customRect);
static void applyConfiguration(Mode mode, const QRect &customRect);
private:
Ui::KisDlgCustomTabletResolution *ui;
};
......
......@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>321</width>
<height>237</height>
<height>255</height>
</rect>
</property>
<property name="windowTitle">
......@@ -17,7 +17,7 @@
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Select area your tablet is mappet to (needs restart):</string>
<string>Select area your tablet is mappet to:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
......@@ -139,6 +139,29 @@
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="lblDisplayInformation">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
......@@ -150,7 +173,7 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>29</height>
<height>15</height>
</size>
</property>
</spacer>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment