From 01e388118847a20f2cdf89d189cc121077d56c74 Mon Sep 17 00:00:00 2001 From: reionwong Date: Wed, 11 Aug 2021 23:45:40 +0800 Subject: [PATCH] SettingsDaemon: Add mouse module --- debian/control | 1 + settings-daemon/CMakeLists.txt | 13 +- settings-daemon/application.cpp | 1 + settings-daemon/application.h | 2 + settings-daemon/mouse/libinputsettings.cpp | 39 +++ settings-daemon/mouse/libinputsettings.h | 20 ++ settings-daemon/mouse/mousemanager.cpp | 84 +++++ settings-daemon/mouse/mousemanager.h | 60 ++++ settings-daemon/mouse/org.cutefish.Mouse.xml | 16 + .../mouse/x11libinputdummydevice.cpp | 242 ++++++++++++++ .../mouse/x11libinputdummydevice.h | 297 ++++++++++++++++++ 11 files changed, 774 insertions(+), 1 deletion(-) create mode 100644 settings-daemon/mouse/libinputsettings.cpp create mode 100644 settings-daemon/mouse/libinputsettings.h create mode 100644 settings-daemon/mouse/mousemanager.cpp create mode 100644 settings-daemon/mouse/mousemanager.h create mode 100644 settings-daemon/mouse/org.cutefish.Mouse.xml create mode 100644 settings-daemon/mouse/x11libinputdummydevice.cpp create mode 100644 settings-daemon/mouse/x11libinputdummydevice.h diff --git a/debian/control b/debian/control index 51f1db1..100365e 100644 --- a/debian/control +++ b/debian/control @@ -6,6 +6,7 @@ Build-Depends: cmake, debhelper (>= 9), extra-cmake-modules, pkg-config, + xserver-xorg-input-libinput-dev, libxcb1-dev, libxcb-randr0-dev, libsm-dev, diff --git a/settings-daemon/CMakeLists.txt b/settings-daemon/CMakeLists.txt index 3a96f01..0f2e57e 100644 --- a/settings-daemon/CMakeLists.txt +++ b/settings-daemon/CMakeLists.txt @@ -2,6 +2,8 @@ project(cutefish-settings-daemon) set(TARGET cutefish-settings-daemon) find_package(PulseAudio) +find_package(X11 REQUIRED) +pkg_check_modules(XORGLIBINPUT xorg-libinput IMPORTED_TARGET) file (GLOB_RECURSE SRCS "*.cpp" @@ -19,6 +21,8 @@ file (GLOB_RECURSE SRCS "language/*.h" "dock/*.cpp" "dock/*.h" + "mouse/*.h" + "mouse/*.cpp" ) set(SOURCES ${SRCS}) @@ -44,6 +48,9 @@ qt5_add_dbus_adaptor(DBUS_SOURCES qt5_add_dbus_adaptor(DBUS_SOURCES dock/org.cutefish.Dock.xml dock/dock.h Dock) +qt5_add_dbus_adaptor(DBUS_SOURCES + mouse/org.cutefish.Mouse.xml + mouse/mousemanager.h Mouse) set_source_files_properties(${DBUS_SOURCES} PROPERTIES SKIP_AUTOGEN ON) add_executable(${TARGET} ${SOURCES} ${DBUS_SOURCES} ${HEADERS} ${FORMS} ${RESOURCES}) @@ -54,6 +61,10 @@ target_link_libraries(${TARGET} Qt5::DBus Qt5::X11Extras ${PULSEAUDIO_LIBRARY} + ${X11_LIBRARIES} + X11::X11 + X11::Xi + PkgConfig::XORGLIBINPUT ) file(GLOB TS_FILES translations/*.ts) @@ -62,4 +73,4 @@ add_custom_target(translations DEPENDS ${QM_FILES} SOURCES ${TS_FILES}) add_dependencies(${TARGET} translations) install(TARGETS ${TARGET} DESTINATION /usr/bin) -install(FILES ${QM_FILES} DESTINATION /usr/share/${TARGET}/translations) \ No newline at end of file +install(FILES ${QM_FILES} DESTINATION /usr/share/${TARGET}/translations) diff --git a/settings-daemon/application.cpp b/settings-daemon/application.cpp index d2c71c0..0faec99 100644 --- a/settings-daemon/application.cpp +++ b/settings-daemon/application.cpp @@ -36,6 +36,7 @@ Application::Application(int &argc, char **argv) , m_brightnessManager(new BrightnessManager(this)) , m_upowerManager(new UPowerManager(this)) , m_language(new Language(this)) + , m_mouse(new Mouse) { new DBusAdaptor(this); // connect to D-Bus and register as an object: diff --git a/settings-daemon/application.h b/settings-daemon/application.h index eea1f59..0776127 100644 --- a/settings-daemon/application.h +++ b/settings-daemon/application.h @@ -26,6 +26,7 @@ #include "brightness/brightnessmanager.h" #include "battery/upowermanager.h" #include "language/language.h" +#include "mouse/mousemanager.h" class Application : public QApplication { @@ -44,6 +45,7 @@ private: BrightnessManager *m_brightnessManager; UPowerManager *m_upowerManager; Language *m_language; + Mouse *m_mouse; }; #endif // APPLICATION_H diff --git a/settings-daemon/mouse/libinputsettings.cpp b/settings-daemon/mouse/libinputsettings.cpp new file mode 100644 index 0000000..7bfd61e --- /dev/null +++ b/settings-daemon/mouse/libinputsettings.cpp @@ -0,0 +1,39 @@ +/* + SPDX-FileCopyrightText: 2018 Roman Gilg + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#include "libinputsettings.h" + +#include +#include + +template<> +bool LibinputSettings::load(QString key, bool defVal) +{ + QSettings settings("cutefishos", "mouse"); + return settings.value(key, defVal).toBool(); +} + +template<> +qreal LibinputSettings::load(QString key, qreal defVal) +{ + QSettings settings("cutefishos", "mouse"); + return settings.value(key, defVal).toReal(); +} + +template<> +void LibinputSettings::save(QString key, bool val) +{ + QSettings settings("cutefishos", "mouse"); + settings.setValue(key, val); + settings.sync(); +} + +template<> +void LibinputSettings::save(QString key, qreal val) +{ + QSettings settings("cutefishos", "mouse"); + settings.setValue(key, val); + settings.sync(); +} diff --git a/settings-daemon/mouse/libinputsettings.h b/settings-daemon/mouse/libinputsettings.h new file mode 100644 index 0000000..5941690 --- /dev/null +++ b/settings-daemon/mouse/libinputsettings.h @@ -0,0 +1,20 @@ +/* + SPDX-FileCopyrightText: 2018 Roman Gilg + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#ifndef LIBINPUTSETTINGS_H +#define LIBINPUTSETTINGS_H + +#include + +struct LibinputSettings { + template + T load(QString key, T defVal); + + template + void save(QString key, T val); +}; + +#endif // LIBINPUTSETTINGS_H diff --git a/settings-daemon/mouse/mousemanager.cpp b/settings-daemon/mouse/mousemanager.cpp new file mode 100644 index 0000000..074a038 --- /dev/null +++ b/settings-daemon/mouse/mousemanager.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "mousemanager.h" +#include "mouseadaptor.h" + +Mouse::Mouse(QObject *parent) + : QObject(parent) + , m_inputDummydevice(new X11LibinputDummyDevice(this, QX11Info::display())) +{ + // init dbus + new MouseAdaptor(this); + QDBusConnection::sessionBus().registerObject(QStringLiteral("/Mouse"), this); + + connect(m_inputDummydevice, &X11LibinputDummyDevice::leftHandedChanged, this, &Mouse::leftHandedChanged); + connect(m_inputDummydevice, &X11LibinputDummyDevice::pointerAccelerationProfileChanged, this, &Mouse::accelerationChanged); + connect(m_inputDummydevice, &X11LibinputDummyDevice::naturalScrollChanged, this, &Mouse::naturalScrollChanged); + connect(m_inputDummydevice, &X11LibinputDummyDevice::pointerAccelerationChanged, this, &Mouse::pointerAccelerationChanged); +} + +Mouse::~Mouse() +{ + delete m_inputDummydevice; +} + +bool Mouse::leftHanded() const +{ + return m_inputDummydevice->isLeftHanded(); +} + +void Mouse::setLeftHanded(bool enabled) +{ + m_inputDummydevice->setLeftHanded(enabled); + m_inputDummydevice->applyConfig(); +} + +bool Mouse::acceleration() const +{ + return m_inputDummydevice->pointerAccelerationProfileFlat(); +} + +void Mouse::setAcceleration(bool enabled) +{ + m_inputDummydevice->setPointerAccelerationProfileFlat(enabled); + m_inputDummydevice->applyConfig(); +} + +bool Mouse::naturalScroll() const +{ + return m_inputDummydevice->isNaturalScroll(); +} + +void Mouse::setNaturalScroll(bool enabled) +{ + m_inputDummydevice->setNaturalScroll(enabled); + m_inputDummydevice->applyConfig(); +} + +qreal Mouse::pointerAcceleration() const +{ + return m_inputDummydevice->pointerAcceleration(); +} + +void Mouse::setPointerAcceleration(qreal value) +{ + m_inputDummydevice->setPointerAcceleration(value); + m_inputDummydevice->applyConfig(); +} diff --git a/settings-daemon/mouse/mousemanager.h b/settings-daemon/mouse/mousemanager.h new file mode 100644 index 0000000..1a14a60 --- /dev/null +++ b/settings-daemon/mouse/mousemanager.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MOUSE_H +#define MOUSE_H + +#include +#include "x11libinputdummydevice.h" + +class Mouse : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool leftHanded READ leftHanded WRITE setLeftHanded NOTIFY leftHandedChanged) + Q_PROPERTY(bool acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged) + Q_PROPERTY(bool naturalScroll READ naturalScroll WRITE setNaturalScroll NOTIFY naturalScrollChanged) + Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration NOTIFY pointerAccelerationChanged) + +public: + explicit Mouse(QObject *parent = nullptr); + ~Mouse(); + + bool leftHanded() const; + void setLeftHanded(bool enabled); + + bool acceleration() const; + void setAcceleration(bool enabled); + + bool naturalScroll() const; + void setNaturalScroll(bool enabled); + + qreal pointerAcceleration() const; + void setPointerAcceleration(qreal value); + +signals: + void leftHandedChanged(); + void accelerationChanged(); + void naturalScrollChanged(); + void pointerAccelerationChanged(); + +private: + X11LibinputDummyDevice *m_inputDummydevice; +}; + +#endif // MOUSE_H diff --git a/settings-daemon/mouse/org.cutefish.Mouse.xml b/settings-daemon/mouse/org.cutefish.Mouse.xml new file mode 100644 index 0000000..88d6d13 --- /dev/null +++ b/settings-daemon/mouse/org.cutefish.Mouse.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/settings-daemon/mouse/x11libinputdummydevice.cpp b/settings-daemon/mouse/x11libinputdummydevice.cpp new file mode 100644 index 0000000..6c9b44d --- /dev/null +++ b/settings-daemon/mouse/x11libinputdummydevice.cpp @@ -0,0 +1,242 @@ +/* + SPDX-FileCopyrightText: 2018 Roman Gilg + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#include "x11libinputdummydevice.h" +#include "libinputsettings.h" +#include +#include + +#include +#include +#include + +static Atom s_touchpadAtom; + +template +static void XIForallPointerDevices(Display *dpy, const Callback &callback) +{ + int ndevices_return; + XDeviceInfo *info = XListInputDevices(dpy, &ndevices_return); + if (!info) { + return; + } + for (int i = 0; i < ndevices_return; ++i) { + XDeviceInfo *dev = info + i; + if ((dev->use == IsXPointer || dev->use == IsXExtensionPointer) && dev->type != s_touchpadAtom) { + callback(dev); + } + } + XFreeDeviceList(info); +} + +struct ScopedXDeleter { + static inline void cleanup(void *pointer) + { + if (pointer) { + XFree(pointer); + } + } +}; + +namespace +{ +template +void valueWriterPart(T val, Atom valAtom, Display *dpy) +{ + Q_UNUSED(val); + Q_UNUSED(valAtom); + Q_UNUSED(dpy); +} + +template<> +void valueWriterPart(bool val, Atom valAtom, Display *dpy) +{ + XIForallPointerDevices(dpy, [&](XDeviceInfo *info) { + int deviceid = info->id; + Status status; + Atom type_return; + int format_return; + unsigned long num_items_return; + unsigned long bytes_after_return; + + unsigned char *_data = nullptr; + // data returned is an 1 byte boolean + status = XIGetProperty(dpy, deviceid, valAtom, 0, 1, False, XA_INTEGER, &type_return, &format_return, &num_items_return, &bytes_after_return, &_data); + if (status != Success) { + return; + } + + QScopedArrayPointer data(_data); + _data = nullptr; + + if (type_return != XA_INTEGER || !data || format_return != 8) { + return; + } + + unsigned char sendVal[2] = {0}; + if (num_items_return == 1) { + sendVal[0] = val; + } else { + // Special case for acceleration profile. + const Atom accel = XInternAtom(dpy, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, True); + if (num_items_return != 2 || valAtom != accel) { + return; + } + sendVal[val] = 1; + } + + XIChangeProperty(dpy, deviceid, valAtom, XA_INTEGER, 8, XIPropModeReplace, sendVal, num_items_return); + }); +} + +template<> +void valueWriterPart(qreal val, Atom valAtom, Display *dpy) +{ + XIForallPointerDevices(dpy, [&](XDeviceInfo *info) { + int deviceid = info->id; + Status status; + Atom float_type = XInternAtom(dpy, "FLOAT", False); + Atom type_return; + int format_return; + unsigned long num_items_return; + unsigned long bytes_after_return; + + unsigned char *_data = nullptr; + // data returned is an 1 byte boolean + status = XIGetProperty(dpy, deviceid, valAtom, 0, 1, False, float_type, &type_return, &format_return, &num_items_return, &bytes_after_return, &_data); + if (status != Success) { + return; + } + + QScopedArrayPointer data(_data); + _data = nullptr; + + if (type_return != float_type || !data || format_return != 32 || num_items_return != 1) { + return; + } + + unsigned char buffer[4096]; + float *sendPtr = (float *)buffer; + *sendPtr = val; + + XIChangeProperty(dpy, deviceid, valAtom, float_type, format_return, XIPropModeReplace, buffer, 1); + }); +} +} + +X11LibinputDummyDevice::X11LibinputDummyDevice(QObject *parent, Display *dpy) + : QObject(parent) + , m_settings(new LibinputSettings()) + , m_dpy(dpy) +{ + m_leftHanded.atom = XInternAtom(dpy, LIBINPUT_PROP_LEFT_HANDED, True); + m_middleEmulation.atom = XInternAtom(dpy, LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED, True); + m_naturalScroll.atom = XInternAtom(dpy, LIBINPUT_PROP_NATURAL_SCROLL, True); + m_pointerAcceleration.atom = XInternAtom(dpy, LIBINPUT_PROP_ACCEL, True); + m_pointerAccelerationProfileFlat.atom = XInternAtom(dpy, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, True); + + m_supportsDisableEvents.val = false; + m_enabled.val = true; + m_supportedButtons.val = Qt::LeftButton | Qt::MiddleButton | Qt::RightButton; + m_supportsLeftHanded.val = true; + m_supportsMiddleEmulation.val = true; + m_middleEmulationEnabledByDefault.val = false; + + m_supportsPointerAcceleration.val = true; + m_defaultPointerAcceleration.val = 0; + + m_supportsPointerAccelerationProfileAdaptive.val = true; + m_supportsPointerAccelerationProfileFlat.val = true; + + m_defaultPointerAccelerationProfileAdaptive.val = true; + m_defaultPointerAccelerationProfileFlat.val = false; + + m_supportsNaturalScroll.val = true; + m_naturalScrollEnabledByDefault.val = false; + + s_touchpadAtom = XInternAtom(m_dpy, XI_TOUCHPAD, True); + + // Init + getConfig(); + applyConfig(); +} + +X11LibinputDummyDevice::~X11LibinputDummyDevice() +{ + delete m_settings; +} + +bool X11LibinputDummyDevice::getConfig() +{ + auto reset = [this](Prop &prop, bool defVal) { + prop.reset(m_settings->load(prop.cfgName, defVal)); + }; + + reset(m_leftHanded, false); + + reset(m_middleEmulation, false); + reset(m_naturalScroll, false); + reset(m_pointerAccelerationProfileFlat, false); + + m_pointerAccelerationProfileAdaptive.reset(!m_settings->load(m_pointerAccelerationProfileFlat.cfgName, false)); + m_pointerAcceleration.reset(m_settings->load(m_pointerAcceleration.cfgName, 0.)); + + emit leftHandedChanged(); + emit naturalScrollChanged(); + emit pointerAccelerationProfileChanged(); + emit pointerAccelerationChanged(); + + return true; +} + +bool X11LibinputDummyDevice::getDefaultConfig() +{ + m_leftHanded.set(false); + + m_pointerAcceleration.set(m_defaultPointerAcceleration); + m_pointerAccelerationProfileFlat.set(m_defaultPointerAccelerationProfileFlat); + m_pointerAccelerationProfileAdaptive.set(m_defaultPointerAccelerationProfileAdaptive); + + m_middleEmulation.set(m_middleEmulationEnabledByDefault); + m_naturalScroll.set(m_naturalScrollEnabledByDefault); + + return true; +} + +bool X11LibinputDummyDevice::applyConfig() +{ + valueWriter(m_leftHanded); + valueWriter(m_middleEmulation); + valueWriter(m_naturalScroll); + valueWriter(m_pointerAcceleration); + valueWriter(m_pointerAccelerationProfileFlat); + + return true; +} + +template +bool X11LibinputDummyDevice::valueWriter(Prop &prop) +{ + // Check atom availability first. + if (prop.atom == None) { + return false; + } + + if (prop.val != prop.old) { + m_settings->save(prop.cfgName, prop.val); + } + + valueWriterPart(prop.val, prop.atom, m_dpy); + + prop.old = prop.val; + + return true; +} + +bool X11LibinputDummyDevice::isChangedConfig() const +{ + return m_leftHanded.changed() || m_pointerAcceleration.changed() || m_pointerAccelerationProfileFlat.changed() + || m_pointerAccelerationProfileAdaptive.changed() || m_middleEmulation.changed() || m_naturalScroll.changed(); +} diff --git a/settings-daemon/mouse/x11libinputdummydevice.h b/settings-daemon/mouse/x11libinputdummydevice.h new file mode 100644 index 0000000..2298626 --- /dev/null +++ b/settings-daemon/mouse/x11libinputdummydevice.h @@ -0,0 +1,297 @@ +/* + SPDX-FileCopyrightText: 2018 Roman Gilg + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#ifndef X11LIBINPUTDUMMYDEVICE_H +#define X11LIBINPUTDUMMYDEVICE_H + +#include +#include +#include + +#include + +struct LibinputSettings; + +class X11LibinputDummyDevice : public QObject +{ + Q_OBJECT + + // + // general + Q_PROPERTY(QString name READ name CONSTANT) + Q_PROPERTY(bool supportsDisableEvents READ supportsDisableEvents CONSTANT) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) + + // + // advanced + Q_PROPERTY(Qt::MouseButtons supportedButtons READ supportedButtons CONSTANT) + + Q_PROPERTY(bool supportsLeftHanded READ supportsLeftHanded CONSTANT) + Q_PROPERTY(bool leftHandedEnabledByDefault READ leftHandedEnabledByDefault CONSTANT) + Q_PROPERTY(bool leftHanded READ isLeftHanded WRITE setLeftHanded NOTIFY leftHandedChanged) + + Q_PROPERTY(bool supportsMiddleEmulation READ supportsMiddleEmulation CONSTANT) + Q_PROPERTY(bool middleEmulationEnabledByDefault READ middleEmulationEnabledByDefault CONSTANT) + Q_PROPERTY(bool middleEmulation READ isMiddleEmulation WRITE setMiddleEmulation NOTIFY middleEmulationChanged) + + // + // acceleration speed and profile + Q_PROPERTY(bool supportsPointerAcceleration READ supportsPointerAcceleration CONSTANT) + Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration NOTIFY pointerAccelerationChanged) + + Q_PROPERTY(bool supportsPointerAccelerationProfileFlat READ supportsPointerAccelerationProfileFlat CONSTANT) + Q_PROPERTY(bool defaultPointerAccelerationProfileFlat READ defaultPointerAccelerationProfileFlat CONSTANT) + Q_PROPERTY(bool pointerAccelerationProfileFlat READ pointerAccelerationProfileFlat WRITE setPointerAccelerationProfileFlat NOTIFY + pointerAccelerationProfileChanged) + + Q_PROPERTY(bool supportsPointerAccelerationProfileAdaptive READ supportsPointerAccelerationProfileAdaptive CONSTANT) + Q_PROPERTY(bool defaultPointerAccelerationProfileAdaptive READ defaultPointerAccelerationProfileAdaptive CONSTANT) + Q_PROPERTY(bool pointerAccelerationProfileAdaptive READ pointerAccelerationProfileAdaptive WRITE setPointerAccelerationProfileAdaptive NOTIFY + pointerAccelerationProfileChanged) + + // + // scrolling + Q_PROPERTY(bool supportsNaturalScroll READ supportsNaturalScroll CONSTANT) + Q_PROPERTY(bool naturalScrollEnabledByDefault READ naturalScrollEnabledByDefault CONSTANT) + Q_PROPERTY(bool naturalScroll READ isNaturalScroll WRITE setNaturalScroll NOTIFY naturalScrollChanged) + +public: + X11LibinputDummyDevice(QObject *parent, Display *dpy); + ~X11LibinputDummyDevice() override; + + bool getConfig(); + bool getDefaultConfig(); + bool applyConfig(); + bool isChangedConfig() const; + + // + // general + QString name() const + { + return m_name.val; + } + QString sysName() const + { + return m_sysName.val; + } + bool supportsDisableEvents() const + { + return m_supportsDisableEvents.val; + } + void setEnabled(bool enabled) + { + m_enabled.set(enabled); + } + bool isEnabled() const + { + return m_enabled.val; + } + Qt::MouseButtons supportedButtons() const + { + return m_supportedButtons.val; + } + + // + // advanced + bool supportsLeftHanded() const + { + return m_supportsLeftHanded.val; + } + bool leftHandedEnabledByDefault() const + { + return m_leftHandedEnabledByDefault.val; + } + bool isLeftHanded() const + { + return m_leftHanded.val; + } + void setLeftHanded(bool set) + { + m_leftHanded.set(set); + } + + bool supportsMiddleEmulation() const + { + return m_supportsMiddleEmulation.val; + } + bool middleEmulationEnabledByDefault() const + { + return m_middleEmulationEnabledByDefault.val; + } + bool isMiddleEmulation() const + { + return m_middleEmulation.val; + } + void setMiddleEmulation(bool set) + { + m_middleEmulation.set(set); + } + + // + // acceleration speed and profile + bool supportsPointerAcceleration() const + { + return m_supportsPointerAcceleration.val; + } + qreal pointerAcceleration() const + { + return m_pointerAcceleration.val; + } + void setPointerAcceleration(qreal acceleration) + { + m_pointerAcceleration.set(acceleration); + } + + bool supportsPointerAccelerationProfileFlat() const + { + return m_supportsPointerAccelerationProfileFlat.val; + } + bool defaultPointerAccelerationProfileFlat() const + { + return m_defaultPointerAccelerationProfileFlat.val; + } + bool pointerAccelerationProfileFlat() const + { + return m_pointerAccelerationProfileFlat.val; + } + void setPointerAccelerationProfileFlat(bool set) + { + m_pointerAccelerationProfileFlat.set(set); + } + + bool supportsPointerAccelerationProfileAdaptive() const + { + return m_supportsPointerAccelerationProfileAdaptive.val; + } + bool defaultPointerAccelerationProfileAdaptive() const + { + return m_defaultPointerAccelerationProfileAdaptive.val; + } + bool pointerAccelerationProfileAdaptive() const + { + return m_pointerAccelerationProfileAdaptive.val; + } + void setPointerAccelerationProfileAdaptive(bool set) + { + m_pointerAccelerationProfileAdaptive.set(set); + } + + // + // scrolling + bool supportsNaturalScroll() const + { + return m_supportsNaturalScroll.val; + } + bool naturalScrollEnabledByDefault() const + { + return m_naturalScrollEnabledByDefault.val; + } + bool isNaturalScroll() const + { + return m_naturalScroll.val; + } + void setNaturalScroll(bool set) + { + m_naturalScroll.set(set); + } + +Q_SIGNALS: + void leftHandedChanged(); + void pointerAccelerationChanged(); + void pointerAccelerationProfileChanged(); + void enabledChanged(); + void middleEmulationChanged(); + void naturalScrollChanged(); + +private: + template + struct Prop { + explicit Prop(const QString &_name, const QString &_cfgName = "") + : name(_name) + , cfgName(_cfgName) + { + } + + void set(T newVal) + { + if (avail && val != newVal) { + val = newVal; + } + } + void set(const Prop &p) + { + if (avail && val != p.val) { + val = p.val; + } + } + bool changed() const + { + return avail && (old != val); + } + + void reset(T newVal) + { + val = newVal; + old = newVal; + } + + QString name; + QString cfgName; + + bool avail = true; + T old; + T val; + + Atom atom; + }; + + template + bool valueWriter(Prop &prop); + + // + // general + Prop m_name = Prop("name"); + Prop m_sysName = Prop("sysName"); + Prop m_supportsDisableEvents = Prop("supportsDisableEvents"); + Prop m_enabled = Prop("enabled"); + + // + // advanced + Prop m_supportedButtons = Prop("supportedButtons"); + + Prop m_supportsLeftHanded = Prop("supportsLeftHanded"); + Prop m_leftHandedEnabledByDefault = Prop("leftHandedEnabledByDefault"); + Prop m_leftHanded = Prop("leftHanded", "XLbInptLeftHanded"); + + Prop m_supportsMiddleEmulation = Prop("supportsMiddleEmulation"); + Prop m_middleEmulationEnabledByDefault = Prop("middleEmulationEnabledByDefault"); + Prop m_middleEmulation = Prop("middleEmulation", "XLbInptMiddleEmulation"); + + // + // acceleration speed and profile + Prop m_supportsPointerAcceleration = Prop("supportsPointerAcceleration"); + Prop m_defaultPointerAcceleration = Prop("defaultPointerAcceleration"); + Prop m_pointerAcceleration = Prop("pointerAcceleration", "XLbInptPointerAcceleration"); + + Prop m_supportsPointerAccelerationProfileFlat = Prop("supportsPointerAccelerationProfileFlat"); + Prop m_defaultPointerAccelerationProfileFlat = Prop("defaultPointerAccelerationProfileFlat"); + Prop m_pointerAccelerationProfileFlat = Prop("pointerAccelerationProfileFlat", "XLbInptAccelProfileFlat"); + + Prop m_supportsPointerAccelerationProfileAdaptive = Prop("supportsPointerAccelerationProfileAdaptive"); + Prop m_defaultPointerAccelerationProfileAdaptive = Prop("defaultPointerAccelerationProfileAdaptive"); + Prop m_pointerAccelerationProfileAdaptive = Prop("pointerAccelerationProfileAdaptive"); + + // + // scrolling + Prop m_supportsNaturalScroll = Prop("supportsNaturalScroll"); + Prop m_naturalScrollEnabledByDefault = Prop("naturalScrollEnabledByDefault"); + Prop m_naturalScroll = Prop("naturalScroll", "XLbInptNaturalScroll"); + + LibinputSettings *m_settings; + Display *m_dpy = nullptr; +}; + +#endif // X11LIBINPUTDUMMYDEVICE_H