Commit 13181cd8 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement a switch for Tablet API in Qt

The patch allows switching of the Tablet API when we use Qt's own
implementation.

The patch is added to our build system, so the fix should appear
in nightlies very soon.

The patch has also been proposed to Qt:
https://codereview.qt-project.org/#/c/258067/

BUG:405494
parent bdb98612
From 880c9387d5e889e52e0db22f629443c1006988f0 Mon Sep 17 00:00:00 2001
From: Dmitry Kazakov <dimula73@gmail.com>
Date: Wed, 3 Apr 2019 18:37:56 +0300
Subject: [PATCH] Implement a switch for tablet API on Windows
Qt has support for two tablet APIs: WinTab and Windows Pointer API.
The former one is used in professional graphical tablet devices,
like Wacom, Huion and etc. The latter is mostly used in two-in-one
convertible laptops, like Surface Pro. By default Qt prefers Windows
Pointer API, if it is available.
The problem is that some devices (e.g. Huion tablets) do not
support Windows Pointer API. More than that, even devices, which
support Pointer API, must limit their capabilities to fit it:
1) Winodws Pointer API doesn't support more than one stylus barrel
buttons, but all professional devices have at least two buttons.
2) Winodws Pointer API limits pressure resolution to 1024 levels,
but even entry-level Wacom devices have at least 2048 levels.
Professional-level devices have 4096 levels.
Therefore painting applications should be able to choose, which API
they prefer.
This patch implements a special application attribute
Qt::AA_MSWindowsUseWinTabAPI. Application should set it before creation
of QApplication to force selection of WinTab API.
When running, application can check currently running API by
testing this attribute.
---
src/corelib/global/qnamespace.h | 1 +
src/plugins/platforms/windows/qwindowsintegration.cpp | 8 +++++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index dec2c446..3ab99219 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -525,6 +525,7 @@ public:
AA_DontShowShortcutsInContextMenus = 28,
AA_CompressTabletEvents = 29,
AA_DisableWindowContextHelpButton = 30, // ### Qt 6: remove me
+ AA_MSWindowsUseWinTabAPI = 31, // Win only
// Add new attributes before this line
AA_AttributeCount
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 2c90b048..c415cf28 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -236,10 +236,16 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList &paramL
m_options = parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness);
QWindowsFontDatabase::setFontOptions(m_options);
+ if (QCoreApplication::testAttribute(Qt::AA_MSWindowsUseWinTabAPI)) {
+ m_options |= QWindowsIntegration::DontUseWMPointer;
+ }
+
if (m_context.initPointer(m_options)) {
QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
} else {
- m_context.initTablet(m_options);
+ if (m_context.initTablet(m_options))
+ QCoreApplication::setAttribute(Qt::AA_MSWindowsUseWinTabAPI);
+
if (tabletAbsoluteRange >= 0)
m_context.setTabletAbsoluteRange(tabletAbsoluteRange);
}
--
2.20.1.windows.1
......@@ -48,6 +48,7 @@ if (WIN32)
COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0020-Synthesize-Enter-LeaveEvent-for-accepted-QTabletEven.patch
COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0021-Fix-QTabletEvent-uniqueId-when-Qt-uses-WinInk.patch
COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0022-Fix-generation-of-Leave-events-when-using-tablet-dev.patch
COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0023-Implement-a-switch-for-tablet-API-on-Windows.patch
)
endif()
......
......@@ -307,6 +307,21 @@ find_package(Qt5 ${MIN_QT_VERSION}
)
if (WIN32)
set(CMAKE_REQUIRED_INCLUDES ${Qt5Core_INCLUDE_DIRS})
set(CMAKE_REQUIRED_LIBRARIES ${Qt5Core_LIBRARIES})
CHECK_CXX_SOURCE_COMPILES("
#include <QCoreApplication>
int main(int argc, char *argv[]) {
QCoreApplication::setAttribute(Qt::AA_MSWindowsUseWinTabAPI);
}
"
QT_HAS_WINTAB_SWITCH
)
unset(CMAKE_REQUIRED_INCLUDES)
unset(CMAKE_REQUIRED_LIBRARIES)
option(USE_QT_TABLET_WINDOWS "Do not use Krita's forked Wintab and Windows Ink support on Windows, but leave everything to Qt." ON)
add_feature_info("Use Qt's Windows Tablet Support" USE_QT_TABLET_WINDOWS "Do not use Krita's forked Wintab and Windows Ink support on Windows, but leave everything to Qt.")
configure_file(config_use_qt_tablet_windows.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_use_qt_tablet_windows.h)
......
#cmakedefine USE_QT_TABLET_WINDOWS !
#cmakedefine QT_HAS_WINTAB_SWITCH !
......@@ -305,6 +305,11 @@ extern "C" int main(int argc, char **argv)
}
}
#if defined Q_OS_WIN && defined USE_QT_TABLET_WINDOWS && defined QT_HAS_WINTAB_SWITCH
const bool forceWinTab = !KisConfig::useWin8PointerInputNoApp(&kritarc);
QCoreApplication::setAttribute(Qt::AA_MSWindowsUseWinTabAPI, forceWinTab);
#endif
// first create the application so we can create a pixmap
KisApplication app(key, argc, argv);
......@@ -453,6 +458,15 @@ extern "C" int main(int argc, char **argv)
}
}
}
#elif defined QT_HAS_WINTAB_SWITCH
// Check if WinTab/WinInk has actually activated
const bool useWinTabAPI = app.testAttribute(Qt::AA_MSWindowsUseWinTabAPI);
if (useWinTabAPI != !cfg.useWin8PointerInput()) {
cfg.setUseWin8PointerInput(useWinTabAPI);
}
#endif
#endif
......
......@@ -706,9 +706,15 @@ void TabletSettingsTab::setDefault()
curve.fromString(DEFAULT_CURVE_STRING);
m_page->pressureCurve->setCurve(curve);
#ifdef Q_OS_WIN
#ifndef USE_QT_TABLET_WINDOWS
if (KisTabletSupportWin8::isAvailable()) {
#if defined Q_OS_WIN && (!defined USE_QT_TABLET_WINDOWS || defined QT_HAS_WINTAB_SWITCH)
#ifdef USE_QT_TABLET_WINDOWS
// ask Qt if WinInk is actually available
const bool isWinInkAvailable = true;
#else
const bool isWinInkAvailable = KisTabletSupportWin8::isAvailable();
#endif
if (isWinInkAvailable) {
KisConfig cfg(true);
m_page->radioWintab->setChecked(!cfg.useWin8PointerInput(true));
m_page->radioWin8PointerInput->setChecked(cfg.useWin8PointerInput(true));
......@@ -719,7 +725,6 @@ void TabletSettingsTab::setDefault()
#else
m_page->grpTabletApi->setVisible(false);
#endif
#endif
}
TabletSettingsTab::TabletSettingsTab(QWidget* parent, const char* name): QWidget(parent)
......@@ -738,9 +743,14 @@ TabletSettingsTab::TabletSettingsTab(QWidget* parent, const char* name): QWidget
m_page->pressureCurve->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
m_page->pressureCurve->setCurve(curve);
#ifdef Q_OS_WIN
#ifndef USE_QT_TABLET_WINDOWS
if (KisTabletSupportWin8::isAvailable()) {
#if defined Q_OS_WIN && (!defined USE_QT_TABLET_WINDOWS || defined QT_HAS_WINTAB_SWITCH)
#ifdef USE_QT_TABLET_WINDOWS
// ask Qt if WinInk is actually available
const bool isWinInkAvailable = true;
#else
const bool isWinInkAvailable = KisTabletSupportWin8::isAvailable();
#endif
if (isWinInkAvailable) {
m_page->radioWintab->setChecked(!cfg.useWin8PointerInput());
m_page->radioWin8PointerInput->setChecked(cfg.useWin8PointerInput());
} else {
......@@ -748,9 +758,6 @@ TabletSettingsTab::TabletSettingsTab(QWidget* parent, const char* name): QWidget
m_page->radioWin8PointerInput->setChecked(false);
m_page->grpTabletApi->setVisible(false);
}
#else
m_page->grpTabletApi->setVisible(false);
#endif
#else
m_page->grpTabletApi->setVisible(false);
#endif
......@@ -1578,12 +1585,16 @@ bool KisDlgPreferences::editPreferences()
// Tablet settings
cfg.setPressureTabletCurve( dialog->m_tabletSettings->m_page->pressureCurve->curve().toString() );
#ifdef Q_OS_WIN
#ifndef USE_QT_TABLET_WINDOWS
if (KisTabletSupportWin8::isAvailable()) {
#if defined Q_OS_WIN && (!defined USE_QT_TABLET_WINDOWS || defined QT_HAS_WINTAB_SWITCH)
#ifdef USE_QT_TABLET_WINDOWS
// ask Qt if WinInk is actually available
const bool isWinInkAvailable = true;
#else
const bool isWinInkAvailable = KisTabletSupportWin8::isAvailable();
#endif
if (isWinInkAvailable) {
cfg.setUseWin8PointerInput(dialog->m_tabletSettings->m_page->radioWin8PointerInput->isChecked());
}
#endif
#endif
dialog->m_performanceSettings->save();
......
......@@ -51,6 +51,10 @@
#include <kis_color_manager.h>
#include <KisOcioConfiguration.h>
#ifdef Q_OS_WIN
#include "config_use_qt_tablet_windows.h"
#endif
KisConfig::KisConfig(bool readOnly)
: m_cfg( KSharedConfig::openConfig()->group(""))
, m_readOnly(readOnly)
......@@ -1118,26 +1122,53 @@ void KisConfig::setPressureTabletCurve(const QString& curveString) const
bool KisConfig::useWin8PointerInput(bool defaultValue) const
{
#ifdef Q_OS_WIN
#ifdef USE_QT_TABLET_WINDOWS
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
return useWin8PointerInputNoApp(&kritarc, defaultValue);
#else
return (defaultValue ? false : m_cfg.readEntry("useWin8PointerInput", false));
#endif
#else
Q_UNUSED(defaultValue);
return false;
#endif
}
void KisConfig::setUseWin8PointerInput(bool value) const
void KisConfig::setUseWin8PointerInput(bool value)
{
#ifdef Q_OS_WIN
// Special handling: Only set value if changed
// I don't want it to be set if the user hasn't touched it
if (useWin8PointerInput() != value) {
#ifdef USE_QT_TABLET_WINDOWS
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
setUseWin8PointerInputNoApp(&kritarc, value);
#else
m_cfg.writeEntry("useWin8PointerInput", value);
#endif
}
#else
Q_UNUSED(value)
#endif
}
bool KisConfig::useWin8PointerInputNoApp(QSettings *settings, bool defaultValue)
{
return defaultValue ? false : settings->value("useWin8PointerInput", false).toBool();
}
void KisConfig::setUseWin8PointerInputNoApp(QSettings *settings, bool value)
{
settings->setValue("useWin8PointerInput", value);
}
qreal KisConfig::vastScrolling(bool defaultValue) const
{
return (defaultValue ? 0.9 : m_cfg.readEntry("vastScrolling", 0.9));
......
......@@ -305,7 +305,10 @@ public:
void setPressureTabletCurve(const QString& curveString) const;
bool useWin8PointerInput(bool defaultValue = false) const;
void setUseWin8PointerInput(bool value) const;
void setUseWin8PointerInput(bool value);
static bool useWin8PointerInputNoApp(QSettings *settings, bool defaultValue = false);
static void setUseWin8PointerInputNoApp(QSettings *settings, bool value);
qreal vastScrolling(bool defaultValue = false) const;
void setVastScrolling(const qreal factor) const;
......
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