SettingsDaemon: add touchpad

pull/15/head
reionwong 4 years ago
parent 9337102924
commit deb2af4984

2
debian/control vendored

@ -17,6 +17,8 @@ Build-Depends: cmake,
libxcb-shm0-dev,
libxcb-util-dev,
libxcb-image0-dev,
xserver-xorg-dev,
xserver-xorg-input-synaptics-dev,
libxtst-dev,
libsm-dev,
libpulse-dev,

@ -3,7 +3,12 @@ set(TARGET cutefish-settings-daemon)
find_package(PulseAudio)
find_package(X11 REQUIRED)
find_package(X11_XCB REQUIRED)
find_package(XCB REQUIRED)
pkg_check_modules(XORGLIBINPUT xorg-libinput IMPORTED_TARGET)
pkg_check_modules(XORGSERVER xorg-server IMPORTED_TARGET)
pkg_check_modules(SYNAPTICS xorg-synaptics IMPORTED_TARGET GLOBAL)
file (GLOB_RECURSE SRCS
"*.cpp"
@ -23,6 +28,10 @@ file (GLOB_RECURSE SRCS
"dock/*.h"
"mouse/*.h"
"mouse/*.cpp"
"touchpad/*.h"
"touchpad/*.cpp"
"touchpad/x11/*.h"
"touchpad/x11/*.cpp"
)
set(SOURCES ${SRCS})
@ -51,6 +60,9 @@ qt5_add_dbus_adaptor(DBUS_SOURCES
qt5_add_dbus_adaptor(DBUS_SOURCES
mouse/com.cutefish.Mouse.xml
mouse/mousemanager.h Mouse)
qt5_add_dbus_adaptor(DBUS_SOURCES
touchpad/com.cutefish.Touchpad.xml
touchpad/touchpadmanager.h TouchpadManager)
set_source_files_properties(${DBUS_SOURCES} PROPERTIES SKIP_AUTOGEN ON)
add_executable(${TARGET} ${SOURCES} ${DBUS_SOURCES} ${HEADERS} ${FORMS} ${RESOURCES})
@ -64,7 +76,11 @@ target_link_libraries(${TARGET}
${X11_LIBRARIES}
X11::X11
X11::Xi
X11::XCB
${XCB_LIBRARIES}
PkgConfig::XORGLIBINPUT
PkgConfig::XORGSERVER
PkgConfig::SYNAPTICS
)
file(GLOB TS_FILES translations/*.ts)

@ -37,6 +37,7 @@ Application::Application(int &argc, char **argv)
, m_upowerManager(new UPowerManager(this))
, m_language(new Language(this))
, m_mouse(new Mouse)
, m_touchpad(new TouchpadManager)
// , m_kwinTimer(new QTimer(this))
{
new DBusAdaptor(this);

@ -27,6 +27,7 @@
#include "battery/upowermanager.h"
#include "language/language.h"
#include "mouse/mousemanager.h"
#include "touchpad/touchpadmanager.h"
#include <QTimer>
@ -49,6 +50,7 @@ private:
UPowerManager *m_upowerManager;
Language *m_language;
Mouse *m_mouse;
TouchpadManager *m_touchpad;
// QTimer *m_kwinTimer;
};

@ -0,0 +1,21 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="com.cutefish.Touchpad">
<property name="available" type="b" access="read"/>
<property name="enabled" type="b" access="read"/>
<property name="tapToClick" type="b" access="read"/>
<property name="pointerAcceleration" type="d" access="read"/>
<method name="setEnabled">
<arg name="enabled" type="b" direction="in"/>
</method>
<method name="setTapToClick">
<arg name="enabled" type="b" direction="in"/>
</method>
<method name="setPointerAcceleration">
<arg name="value" type="d" direction="in"/>
</method>
</interface>
</node>

@ -0,0 +1,9 @@
/*
SPDX-FileCopyrightText: 2019 Atul Bisht <atulbisht26@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "libinputcommon.h"
#include "moc_libinputcommon.cpp"

@ -0,0 +1,566 @@
/*
SPDX-FileCopyrightText: 2017 Roman Gilg <subdiff@gmail.com>
SPDX-FileCopyrightText: 2019 Atul Bisht <atulbisht26@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef LIBINPUTCOMMON_H
#define LIBINPUTCOMMON_H
#include <QObject>
#include <QVariant>
namespace
{
template<typename T>
inline T valueLoaderPart(QVariant const &reply)
{
Q_UNUSED(reply);
return T();
}
template<>
inline bool valueLoaderPart(QVariant const &reply)
{
return reply.toBool();
}
template<>
inline int valueLoaderPart(QVariant const &reply)
{
return reply.toInt();
}
template<>
inline quint32 valueLoaderPart(QVariant const &reply)
{
return reply.toInt();
}
template<>
inline qreal valueLoaderPart(QVariant const &reply)
{
return reply.toReal();
}
template<>
inline QString valueLoaderPart(QVariant const &reply)
{
return reply.toString();
}
template<>
inline Qt::MouseButtons valueLoaderPart(QVariant const &reply)
{
return static_cast<Qt::MouseButtons>(reply.toInt());
}
}
class LibinputCommon : 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 supportsDisableEventsOnExternalMouse READ supportsDisableEventsOnExternalMouse CONSTANT)
Q_PROPERTY(bool supportsDisableWhileTyping READ supportsDisableWhileTyping CONSTANT)
Q_PROPERTY(bool disableWhileTypingEnabledByDefault READ disableWhileTypingEnabledByDefault CONSTANT)
Q_PROPERTY(bool disableWhileTyping READ isDisableWhileTyping WRITE setDisableWhileTyping NOTIFY disableWhileTypingChanged)
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)
//
// tapping
Q_PROPERTY(int tapFingerCount READ tapFingerCount CONSTANT)
Q_PROPERTY(bool tapToClickEnabledByDefault READ tapToClickEnabledByDefault CONSTANT)
Q_PROPERTY(bool tapToClick READ isTapToClick WRITE setTapToClick NOTIFY tapToClickChanged)
Q_PROPERTY(bool supportsLmrTapButtonMap READ supportsLmrTapButtonMap CONSTANT)
Q_PROPERTY(bool lmrTapButtonMapEnabledByDefault READ lmrTapButtonMapEnabledByDefault CONSTANT)
Q_PROPERTY(bool lmrTapButtonMap READ lmrTapButtonMap WRITE setLmrTapButtonMap NOTIFY lmrTapButtonMapChanged)
Q_PROPERTY(bool tapAndDragEnabledByDefault READ tapAndDragEnabledByDefault CONSTANT)
Q_PROPERTY(bool tapAndDrag READ isTapAndDrag WRITE setTapAndDrag NOTIFY tapAndDragChanged)
Q_PROPERTY(bool tapDragLockEnabledByDefault READ tapDragLockEnabledByDefault CONSTANT)
Q_PROPERTY(bool tapDragLock READ isTapDragLock WRITE setTapDragLock NOTIFY tapDragLockChanged)
//
// 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)
Q_PROPERTY(bool supportsHorizontalScrolling READ supportsHorizontalScrolling CONSTANT)
Q_PROPERTY(bool horizontalScrollingByDefault READ horizontalScrollingByDefault CONSTANT)
Q_PROPERTY(bool horizontalScrolling READ horizontalScrolling WRITE setHorizontalScrolling NOTIFY horizontalScrollingChanged)
Q_PROPERTY(bool supportsScrollTwoFinger READ supportsScrollTwoFinger CONSTANT)
Q_PROPERTY(bool scrollTwoFingerEnabledByDefault READ scrollTwoFingerEnabledByDefault CONSTANT)
Q_PROPERTY(bool scrollTwoFinger READ isScrollTwoFinger WRITE setScrollTwoFinger NOTIFY scrollMethodChanged)
Q_PROPERTY(bool supportsScrollEdge READ supportsScrollEdge CONSTANT)
Q_PROPERTY(bool scrollEdgeEnabledByDefault READ scrollEdgeEnabledByDefault CONSTANT)
Q_PROPERTY(bool scrollEdge READ isScrollEdge WRITE setScrollEdge NOTIFY scrollMethodChanged)
Q_PROPERTY(bool supportsScrollOnButtonDown READ supportsScrollOnButtonDown CONSTANT)
Q_PROPERTY(bool scrollOnButtonDownEnabledByDefault READ scrollOnButtonDownEnabledByDefault CONSTANT)
Q_PROPERTY(bool scrollOnButtonDown READ isScrollOnButtonDown WRITE setScrollOnButtonDown NOTIFY scrollMethodChanged)
Q_PROPERTY(quint32 defaultScrollButton READ defaultScrollButton CONSTANT)
Q_PROPERTY(quint32 scrollButton READ scrollButton WRITE setScrollButton NOTIFY scrollButtonChanged)
// Click Methods
Q_PROPERTY(bool supportsClickMethodAreas READ supportsClickMethodAreas CONSTANT)
Q_PROPERTY(bool defaultClickMethodAreas READ defaultClickMethodAreas CONSTANT)
Q_PROPERTY(bool clickMethodAreas READ isClickMethodAreas WRITE setClickMethodAreas NOTIFY clickMethodChanged)
Q_PROPERTY(bool supportsClickMethodClickfinger READ supportsClickMethodClickfinger CONSTANT)
Q_PROPERTY(bool defaultClickMethodClickfinger READ defaultClickMethodClickfinger CONSTANT)
Q_PROPERTY(bool clickMethodClickfinger READ isClickMethodClickfinger WRITE setClickMethodClickfinger NOTIFY clickMethodChanged)
Q_PROPERTY(bool supportsScrollFactor READ supportsScrollFactor CONSTANT)
public:
LibinputCommon()
{
}
virtual ~LibinputCommon()
{
}
virtual QString name() const = 0;
virtual bool supportsDisableEvents() const = 0;
virtual bool isEnabled() const = 0;
virtual void setEnabled(bool set) = 0;
//
// advanced
Qt::MouseButtons supportedButtons() const
{
return m_supportedButtons.val;
}
virtual bool supportsLeftHanded() const = 0;
bool leftHandedEnabledByDefault() const
{
return m_leftHandedEnabledByDefault.val;
}
bool isLeftHanded() const
{
return m_leftHanded.val;
}
void setLeftHanded(bool set)
{
m_leftHanded.set(set);
}
virtual bool supportsDisableEventsOnExternalMouse() const = 0;
virtual bool supportsDisableWhileTyping() const = 0;
bool disableWhileTypingEnabledByDefault() const
{
return m_disableWhileTypingEnabledByDefault.val;
}
bool isDisableWhileTyping() const
{
return m_disableWhileTyping.val;
}
void setDisableWhileTyping(bool set)
{
m_disableWhileTyping.set(set);
}
virtual bool supportsMiddleEmulation() const = 0;
bool middleEmulationEnabledByDefault() const
{
return m_middleEmulationEnabledByDefault.val;
}
bool isMiddleEmulation() const
{
return m_middleEmulation.val;
}
void setMiddleEmulation(bool set)
{
m_middleEmulation.set(set);
}
virtual bool supportsPointerAcceleration() const = 0;
qreal pointerAcceleration() const
{
return m_pointerAcceleration.val;
}
void setPointerAcceleration(qreal acceleration)
{
m_pointerAcceleration.set(acceleration);
}
virtual bool supportsPointerAccelerationProfileFlat() const = 0;
bool defaultPointerAccelerationProfileFlat() const
{
return m_defaultPointerAccelerationProfileFlat.val;
}
bool pointerAccelerationProfileFlat() const
{
return m_pointerAccelerationProfileFlat.val;
}
void setPointerAccelerationProfileFlat(bool set)
{
m_pointerAccelerationProfileFlat.set(set);
}
virtual bool supportsPointerAccelerationProfileAdaptive() const = 0;
bool defaultPointerAccelerationProfileAdaptive() const
{
return m_defaultPointerAccelerationProfileAdaptive.val;
}
bool pointerAccelerationProfileAdaptive() const
{
return m_pointerAccelerationProfileAdaptive.val;
}
void setPointerAccelerationProfileAdaptive(bool set)
{
m_pointerAccelerationProfileAdaptive.set(set);
}
//
// scrolling
virtual bool supportsNaturalScroll() const = 0;
bool naturalScrollEnabledByDefault() const
{
return m_naturalScrollEnabledByDefault.val;
}
bool isNaturalScroll() const
{
return m_naturalScroll.val;
}
void setNaturalScroll(bool set)
{
m_naturalScroll.set(set);
}
virtual bool supportsHorizontalScrolling() const = 0;
bool horizontalScrollingByDefault() const
{
return true;
}
bool horizontalScrolling() const
{
return m_horizontalScrolling.val;
}
void setHorizontalScrolling(bool set)
{
m_horizontalScrolling.set(set);
}
virtual bool supportsScrollTwoFinger() const = 0;
bool scrollTwoFingerEnabledByDefault() const
{
return m_scrollTwoFingerEnabledByDefault.val;
}
bool isScrollTwoFinger() const
{
return m_isScrollTwoFinger.val;
}
void setScrollTwoFinger(bool set)
{
m_isScrollTwoFinger.set(set);
}
virtual bool supportsScrollEdge() const = 0;
bool scrollEdgeEnabledByDefault() const
{
return m_scrollEdgeEnabledByDefault.val;
}
bool isScrollEdge() const
{
return m_isScrollEdge.val;
}
void setScrollEdge(bool set)
{
m_isScrollEdge.set(set);
}
virtual bool supportsScrollOnButtonDown() const = 0;
bool scrollOnButtonDownEnabledByDefault() const
{
return m_scrollOnButtonDownEnabledByDefault.val;
}
bool isScrollOnButtonDown() const
{
return m_isScrollOnButtonDown.val;
}
void setScrollOnButtonDown(bool set)
{
m_isScrollOnButtonDown.set(set);
}
quint32 defaultScrollButton() const
{
return m_defaultScrollButton.val;
}
quint32 scrollButton() const
{
return m_scrollButton.val;
}
void setScrollButton(quint32 button)
{
m_scrollButton.set(button);
}
//
// tapping
int tapFingerCount() const
{
return m_tapFingerCount.val;
}
bool tapToClickEnabledByDefault() const
{
return m_tapToClickEnabledByDefault.val;
}
bool isTapToClick() const
{
return m_tapToClick.val;
}
void setTapToClick(bool set)
{
m_tapToClick.set(set);
}
bool supportsLmrTapButtonMap() const
{
return m_tapFingerCount.val > 1;
}
bool lmrTapButtonMapEnabledByDefault() const
{
return m_lmrTapButtonMapEnabledByDefault.val;
}
bool lmrTapButtonMap() const
{
return m_lmrTapButtonMap.val;
}
virtual void setLmrTapButtonMap(bool set) = 0;
bool tapAndDragEnabledByDefault() const
{
return m_tapAndDragEnabledByDefault.val;
}
bool isTapAndDrag() const
{
return m_tapAndDrag.val;
}
void setTapAndDrag(bool set)
{
m_tapAndDrag.set(set);
}
bool tapDragLockEnabledByDefault() const
{
return m_tapDragLockEnabledByDefault.val;
}
bool isTapDragLock() const
{
return m_tapDragLock.val;
}
void setTapDragLock(bool set)
{
m_tapDragLock.set(set);
}
//
// click method
virtual bool supportsClickMethodAreas() const = 0;
bool defaultClickMethodAreas() const
{
return m_defaultClickMethodAreas.val;
}
bool isClickMethodAreas() const
{
return m_clickMethodAreas.val;
}
void setClickMethodAreas(bool set)
{
m_clickMethodAreas.set(set);
}
virtual bool supportsClickMethodClickfinger() const = 0;
bool defaultClickMethodClickfinger() const
{
return m_defaultClickMethodClickfinger.val;
}
bool isClickMethodClickfinger() const
{
return m_clickMethodClickfinger.val;
}
void setClickMethodClickfinger(bool set)
{
m_clickMethodClickfinger.set(set);
}
virtual bool supportsScrollFactor() const = 0;
Q_SIGNALS:
void enabledChanged();
// Tapping
void tapToClickChanged();
void lmrTapButtonMapChanged();
void tapAndDragChanged();
void tapDragLockChanged();
// Advanced
void leftHandedChanged();
void disableWhileTypingChanged();
void middleEmulationChanged();
// acceleration speed and profile
void pointerAccelerationChanged();
void pointerAccelerationProfileChanged();
// scrolling
void naturalScrollChanged();
void horizontalScrollingChanged();
void scrollMethodChanged();
void scrollButtonChanged();
// click methods
void clickMethodChanged();
protected:
template<typename T>
struct Prop {
explicit Prop(const QByteArray &name)
: name(name)
{
}
void set(T newVal)
{
if (avail && val != newVal) {
val = newVal;
}
}
void set(const Prop<T> &p)
{
if (avail && val != p.val) {
val = p.val;
}
}
bool changed() const
{
return avail && (old != val);
}
// In wayland, name will be dbus name
QByteArray name;
bool avail;
T old;
T val;
};
//
// general
Prop<bool> m_supportsDisableEvents = Prop<bool>("supportsDisableEvents");
Prop<bool> m_enabledDefault = Prop<bool>("enabledDefault");
Prop<bool> m_enabled = Prop<bool>("enabled");
//
// advanced
Prop<Qt::MouseButtons> m_supportedButtons = Prop<Qt::MouseButtons>("supportedButtons");
Prop<bool> m_leftHandedEnabledByDefault = Prop<bool>("leftHandedEnabledByDefault");
Prop<bool> m_leftHanded = Prop<bool>("leftHanded");
Prop<bool> m_supportsDisableEventsOnExternalMouse = Prop<bool>("supportsDisableEventsOnExternalMouse");
Prop<bool> m_disableWhileTypingEnabledByDefault = Prop<bool>("disableWhileTypingEnabledByDefault");
Prop<bool> m_disableWhileTyping = Prop<bool>("disableWhileTyping");
Prop<bool> m_middleEmulationEnabledByDefault = Prop<bool>("middleEmulationEnabledByDefault");
Prop<bool> m_middleEmulation = Prop<bool>("middleEmulation");
//
// acceleration speed and profile
Prop<qreal> m_defaultPointerAcceleration = Prop<qreal>("defaultPointerAcceleration");
Prop<qreal> m_pointerAcceleration = Prop<qreal>("pointerAcceleration");
Prop<bool> m_supportsPointerAccelerationProfileFlat = Prop<bool>("supportsPointerAccelerationProfileFlat");
Prop<bool> m_defaultPointerAccelerationProfileFlat = Prop<bool>("defaultPointerAccelerationProfileFlat");
Prop<bool> m_pointerAccelerationProfileFlat = Prop<bool>("pointerAccelerationProfileFlat");
Prop<bool> m_supportsPointerAccelerationProfileAdaptive = Prop<bool>("supportsPointerAccelerationProfileAdaptive");
Prop<bool> m_defaultPointerAccelerationProfileAdaptive = Prop<bool>("defaultPointerAccelerationProfileAdaptive");
Prop<bool> m_pointerAccelerationProfileAdaptive = Prop<bool>("pointerAccelerationProfileAdaptive");
//
// tapping
Prop<int> m_tapFingerCount = Prop<int>("tapFingerCount");
Prop<bool> m_tapToClickEnabledByDefault = Prop<bool>("tapToClickEnabledByDefault");
Prop<bool> m_tapToClick = Prop<bool>("tapToClick");
Prop<bool> m_lmrTapButtonMapEnabledByDefault = Prop<bool>("lmrTapButtonMapEnabledByDefault");
Prop<bool> m_lmrTapButtonMap = Prop<bool>("lmrTapButtonMap");
Prop<bool> m_tapAndDragEnabledByDefault = Prop<bool>("tapAndDragEnabledByDefault");
Prop<bool> m_tapAndDrag = Prop<bool>("tapAndDrag");
Prop<bool> m_tapDragLockEnabledByDefault = Prop<bool>("tapDragLockEnabledByDefault");
Prop<bool> m_tapDragLock = Prop<bool>("tapDragLock");
//
// scrolling
Prop<bool> m_naturalScrollEnabledByDefault = Prop<bool>("naturalScrollEnabledByDefault");
Prop<bool> m_naturalScroll = Prop<bool>("naturalScroll");
Prop<bool> m_horizontalScrolling = Prop<bool>("horizontalScrolling");
Prop<bool> m_supportsScrollTwoFinger = Prop<bool>("supportsScrollTwoFinger");
Prop<bool> m_scrollTwoFingerEnabledByDefault = Prop<bool>("scrollTwoFingerEnabledByDefault");
Prop<bool> m_isScrollTwoFinger = Prop<bool>("scrollTwoFinger");
Prop<bool> m_supportsScrollEdge = Prop<bool>("supportsScrollEdge");
Prop<bool> m_scrollEdgeEnabledByDefault = Prop<bool>("scrollEdgeEnabledByDefault");
Prop<bool> m_isScrollEdge = Prop<bool>("scrollEdge");
Prop<bool> m_supportsScrollOnButtonDown = Prop<bool>("supportsScrollOnButtonDown");
Prop<bool> m_scrollOnButtonDownEnabledByDefault = Prop<bool>("scrollOnButtonDownEnabledByDefault");
Prop<bool> m_isScrollOnButtonDown = Prop<bool>("scrollOnButtonDown");
Prop<quint32> m_defaultScrollButton = Prop<quint32>("defaultScrollButton");
Prop<quint32> m_scrollButton = Prop<quint32>("scrollButton");
// Click Method
Prop<bool> m_supportsClickMethodAreas = Prop<bool>("supportsClickMethodAreas");
Prop<bool> m_defaultClickMethodAreas = Prop<bool>("defaultClickMethodAreas");
Prop<bool> m_clickMethodAreas = Prop<bool>("clickMethodAreas");
Prop<bool> m_supportsClickMethodClickfinger = Prop<bool>("supportsClickMethodClickfinger");
Prop<bool> m_defaultClickMethodClickfinger = Prop<bool>("defaultClickMethodClickfinger");
Prop<bool> m_clickMethodClickfinger = Prop<bool>("clickMethodClickfinger");
};
#endif // LIBINPUTCOMMON_H

@ -0,0 +1,55 @@
#include "touchpadmanager.h"
#include "touchpadadaptor.h"
#include <QDebug>
TouchpadManager::TouchpadManager(QObject *parent)
: QObject(parent)
, m_backend(XlibBackend::initialize())
{
// init dbus
new TouchpadAdaptor(this);
QDBusConnection::sessionBus().registerObject(QStringLiteral("/Touchpad"), this);
m_backend->getConfig();
m_backend->applyConfig();
}
bool TouchpadManager::available() const
{
return m_backend->isTouchpadAvailable();
}
bool TouchpadManager::enabled() const
{
return m_backend->isTouchpadEnabled();
}
void TouchpadManager::setEnabled(bool enabled)
{
m_backend->setTouchpadEnabled(enabled);
m_backend->applyConfig();
}
bool TouchpadManager::tapToClick() const
{
return m_backend->tapToClick();
}
void TouchpadManager::setTapToClick(bool value)
{
m_backend->setTapToClick(value);
m_backend->applyConfig();
}
qreal TouchpadManager::pointerAcceleration() const
{
return m_backend->pointerAcceleration();
}
void TouchpadManager::setPointerAcceleration(qreal value)
{
qDebug() << value;
m_backend->setPointerAcceleration(value);
m_backend->applyConfig();
}

@ -0,0 +1,33 @@
#ifndef TOUCHPADMANAGER_H
#define TOUCHPADMANAGER_H
#include <QObject>
#include "x11/xlibbackend.h"
class TouchpadManager : public QObject
{
Q_OBJECT
Q_PROPERTY(bool available READ available CONSTANT)
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled CONSTANT)
Q_PROPERTY(bool tapToClick READ tapToClick WRITE setTapToClick CONSTANT)
Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration CONSTANT)
public:
explicit TouchpadManager(QObject *parent = nullptr);
bool available() const;
bool enabled() const;
void setEnabled(bool enabled);
bool tapToClick() const;
void setTapToClick(bool value);
qreal pointerAcceleration() const;
void setPointerAcceleration(qreal value);
private:
XlibBackend *m_backend;
};
#endif // TOUCHPADMANAGER_H

@ -0,0 +1,401 @@
/*
SPDX-FileCopyrightText: 2019 Atul Bisht <atulbisht26@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "libinputtouchpad.h"
#include <QSet>
#include <QDebug>
#include <limits.h>
#include <stddef.h>
#include <libinput-properties.h>
#include <xserver-properties.h>
#include <X11/extensions/XInput2.h>
const Parameter libinputProperties[] = {
/* libinput disable supports property */
{"supportsDisableEvents", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_AVAILABLE, 8, 0},
{"enabled", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_ENABLED, 8, 0},
{"enabledDefault", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_ENABLED_DEFAULT, 8, 0},
/* LeftHandSupport */
{"leftHandedEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_LEFT_HANDED_DEFAULT, 8, 0},
{"leftHanded", PT_INT, 0, 1, LIBINPUT_PROP_LEFT_HANDED, 8, 0},
/* Disable on external mouse */
{"supportsDisableEventsOnExternalMouse", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_AVAILABLE, 8, 1},
{"disableEventsOnExternalMouse", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_ENABLED, 8, 1},
{"disableEventsOnExternalMouseDefault", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_ENABLED_DEFAULT, 8, 1},
/* Disable while typing */
{"disableWhileTypingEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_DISABLE_WHILE_TYPING_DEFAULT, 8, 0},
{"disableWhileTyping", PT_INT, 0, 1, LIBINPUT_PROP_DISABLE_WHILE_TYPING, 8, 0},
/* Middle Emulation */
{"middleEmulationEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED_DEFAULT, 8, 0},
{"middleEmulation", PT_INT, 0, 1, LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED, 8, 0},
/* This is a boolean for all three fingers, no per-finger config */
{"tapToClick", PT_INT, 0, 1, LIBINPUT_PROP_TAP, 8, 0},
{"tapToClickEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DEFAULT, 8, 0},
/* LMR */
{"lrmTapButtonMapEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_BUTTONMAP_DEFAULT, 8, 0},
{"lrmTapButtonMap", PT_INT, 0, 1, LIBINPUT_PROP_TAP_BUTTONMAP, 8, 0},
{"lmrTapButtonMapEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_BUTTONMAP_DEFAULT, 8, 1},
{"lmrTapButtonMap", PT_INT, 0, 1, LIBINPUT_PROP_TAP_BUTTONMAP, 8, 1},
/* Tap and Drag Enabled */
{"tapAndDragEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DRAG_DEFAULT, 8, 0},
{"tapAndDrag", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DRAG, 8, 0},
/* Tap and Drag Lock Enabled */
{"tapDragLockEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DRAG_LOCK_DEFAULT, 8, 0},
{"tapDragLock", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DRAG_LOCK, 8, 0},
/* libinput normalizes the accel to -1/1 */
{"defaultPointerAcceleration", PT_DOUBLE, -1.0, 1.0, LIBINPUT_PROP_ACCEL_DEFAULT, 0 /*float */, 0},
{"pointerAcceleration", PT_DOUBLE, -1.0, 1.0, LIBINPUT_PROP_ACCEL, 0 /*float */, 0},
/* Libinput Accel Profile */
{"supportsPointerAccelerationProfileAdaptive", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILES_AVAILABLE, 8, 0},
{"defaultPointerAccelerationProfileAdaptive", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED_DEFAULT, 8, 0},
{"pointerAccelerationProfileAdaptive", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, 8, 0},
{"supportsPointerAccelerationProfileFlat", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILES_AVAILABLE, 8, 1},
{"defaultPointerAccelerationProfileFlat", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED_DEFAULT, 8, 1},
{"pointerAccelerationProfileFlat", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, 8, 1},
/* Natural Scrolling */
{"naturalScrollEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_NATURAL_SCROLL_DEFAULT, 8, 0},
{"naturalScroll", PT_INT, 0, 1, LIBINPUT_PROP_NATURAL_SCROLL, 8, 0},
/* Horizontal scrolling */
{"horizontalScrolling", PT_INT, 0, 1, LIBINPUT_PROP_HORIZ_SCROLL_ENABLED, 8, 0},
/* Two-Finger Scrolling */
{"supportsScrollTwoFinger", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE, 8, 0},
{"scrollTwoFingerEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED_DEFAULT, 8, 0},
{"scrollTwoFinger", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED, 8, 0},
/* Edge Scrolling */
{"supportsScrollEdge", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE, 8, 1},
{"scrollEdgeEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED_DEFAULT, 8, 1},
{"scrollEdge", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED, 8, 1},
/* scroll on button */
{"supportsScrollOnButtonDown", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE, 8, 2},
{"scrollOnButtonDownEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED_DEFAULT, 8, 2},
{"scrollOnButtonDown", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED, 8, 2},
/* Scroll Button for scroll on button Down */
{"defaultScrollButton", PT_INT, 0, INT_MAX, LIBINPUT_PROP_SCROLL_BUTTON_DEFAULT, 32, 0},
{"scrollButton", PT_INT, 0, INT_MAX, LIBINPUT_PROP_SCROLL_BUTTON, 32, 0},
/* Click Methods */
{"supportsClickMethodAreas", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHODS_AVAILABLE, 8, 0},
{"defaultClickMethodAreas", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHOD_ENABLED_DEFAULT, 8, 0},
{"clickMethodAreas", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHOD_ENABLED, 8, 0},
{"supportsClickMethodClickfinger", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHODS_AVAILABLE, 8, 1},
{"defaultClickMethodClickfinger", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHOD_ENABLED_DEFAULT, 8, 1},
{"clickMethodClickfinger", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHOD_ENABLED, 8, 1},
/* libinput doesn't have a separate toggle for horiz scrolling */
{nullptr, PT_INT, 0, 0, nullptr, 0, 0}};
Qt::MouseButtons maskBtns(Display *display, XIButtonClassInfo *buttonInfo)
{
Qt::MouseButtons buttons = Qt::NoButton;
for (int i = 0; i < buttonInfo->num_buttons; ++i) {
QByteArray reply = XGetAtomName(display, buttonInfo->labels[i]);
if (reply == BTN_LABEL_PROP_BTN_LEFT) {
buttons |= Qt::LeftButton;
}
if (reply == BTN_LABEL_PROP_BTN_RIGHT) {
buttons |= Qt::RightButton;
}
if (reply == BTN_LABEL_PROP_BTN_MIDDLE) {
buttons |= Qt::MiddleButton;
}
if (reply == BTN_LABEL_PROP_BTN_SIDE) {
buttons |= Qt::ExtraButton1;
}
if (reply == BTN_LABEL_PROP_BTN_EXTRA) {
buttons |= Qt::ExtraButton2;
}
if (reply == BTN_LABEL_PROP_BTN_FORWARD) {
buttons |= Qt::ForwardButton;
}
if (reply == BTN_LABEL_PROP_BTN_BACK) {
buttons |= Qt::BackButton;
}
if (reply == BTN_LABEL_PROP_BTN_TASK) {
buttons |= Qt::TaskButton;
}
}
return buttons;
}
LibinputTouchpad::LibinputTouchpad(Display *display, int deviceId)
: LibinputCommon()
, XlibTouchpad(display, deviceId)
, m_config("cutefishos", "touchpadxlibinputrc")
{
loadSupportedProperties(libinputProperties);
int nDevices = 0;
XIDeviceInfo *deviceInfo = XIQueryDevice(m_display, m_deviceId, &nDevices);
m_name = deviceInfo->name;
for (int i = 0; i < deviceInfo->num_classes; ++i) {
XIAnyClassInfo *classInfo = deviceInfo->classes[i];
if (classInfo->type == XIButtonClass) {
XIButtonClassInfo *btnInfo = (XIButtonClassInfo *)classInfo;
m_supportedButtons.avail = true;
m_supportedButtons.set(maskBtns(m_display, btnInfo));
}
if (classInfo->type == XITouchClass) {
XITouchClassInfo *touchInfo = (XITouchClassInfo *)classInfo;
m_tapFingerCount.avail = true;
m_tapFingerCount.set(touchInfo->num_touches);
}
}
XIFreeDeviceInfo(deviceInfo);
/* FingerCount cannot be zero */
if (!m_tapFingerCount.val) {
m_tapFingerCount.avail = true;
m_tapFingerCount.set(1);
}
}
bool LibinputTouchpad::getConfig()
{
bool success = true;
success &= valueLoader(m_supportsDisableEvents);
success &= valueLoader(m_enabled);
success &= valueLoader(m_enabledDefault);
success &= valueLoader(m_tapToClickEnabledByDefault);
success &= valueLoader(m_tapToClick);
success &= valueLoader(m_lrmTapButtonMapEnabledByDefault);
success &= valueLoader(m_lrmTapButtonMap);
success &= valueLoader(m_lmrTapButtonMapEnabledByDefault);
success &= valueLoader(m_lmrTapButtonMap);
success &= valueLoader(m_tapAndDragEnabledByDefault);
success &= valueLoader(m_tapAndDrag);
success &= valueLoader(m_tapDragLockEnabledByDefault);
success &= valueLoader(m_tapDragLock);
success &= valueLoader(m_leftHandedEnabledByDefault);
success &= valueLoader(m_leftHanded);
success &= valueLoader(m_supportsDisableEventsOnExternalMouse);
success &= valueLoader(m_disableEventsOnExternalMouse);
success &= valueLoader(m_disableEventsOnExternalMouseDefault);
success &= valueLoader(m_disableWhileTypingEnabledByDefault);
success &= valueLoader(m_disableWhileTyping);
success &= valueLoader(m_middleEmulationEnabledByDefault);
success &= valueLoader(m_middleEmulation);
success &= valueLoader(m_defaultPointerAcceleration);
success &= valueLoader(m_pointerAcceleration);
success &= valueLoader(m_supportsPointerAccelerationProfileFlat);
success &= valueLoader(m_defaultPointerAccelerationProfileFlat);
success &= valueLoader(m_pointerAccelerationProfileFlat);
success &= valueLoader(m_supportsPointerAccelerationProfileAdaptive);
success &= valueLoader(m_defaultPointerAccelerationProfileAdaptive);
success &= valueLoader(m_pointerAccelerationProfileAdaptive);
success &= valueLoader(m_naturalScrollEnabledByDefault);
success &= valueLoader(m_naturalScroll);
success &= valueLoader(m_horizontalScrolling);
success &= valueLoader(m_supportsScrollTwoFinger);
success &= valueLoader(m_scrollTwoFingerEnabledByDefault);
success &= valueLoader(m_isScrollTwoFinger);
success &= valueLoader(m_supportsScrollEdge);
success &= valueLoader(m_scrollEdgeEnabledByDefault);
success &= valueLoader(m_isScrollEdge);
success &= valueLoader(m_supportsScrollOnButtonDown);
success &= valueLoader(m_scrollOnButtonDownEnabledByDefault);
success &= valueLoader(m_isScrollOnButtonDown);
success &= valueLoader(m_defaultScrollButton);
success &= valueLoader(m_scrollButton);
// click methods
success &= valueLoader(m_supportsClickMethodAreas);
success &= valueLoader(m_supportsClickMethodClickfinger);
success &= valueLoader(m_defaultClickMethodAreas);
success &= valueLoader(m_defaultClickMethodClickfinger);
success &= valueLoader(m_clickMethodAreas);
success &= valueLoader(m_clickMethodClickfinger);
return success;
}
bool LibinputTouchpad::applyConfig()
{
QVector<QString> msgs;
msgs << valueWriter(m_enabled) << valueWriter(m_tapToClick) << valueWriter(m_lrmTapButtonMap) << valueWriter(m_lmrTapButtonMap) << valueWriter(m_tapAndDrag)
<< valueWriter(m_tapDragLock) << valueWriter(m_leftHanded) << valueWriter(m_disableWhileTyping) << valueWriter(m_middleEmulation)
<< valueWriter(m_pointerAcceleration) << valueWriter(m_pointerAccelerationProfileFlat) << valueWriter(m_pointerAccelerationProfileAdaptive)
<< valueWriter(m_naturalScroll) << valueWriter(m_horizontalScrolling) << valueWriter(m_isScrollTwoFinger) << valueWriter(m_isScrollEdge)
<< valueWriter(m_isScrollOnButtonDown) << valueWriter(m_scrollButton) << valueWriter(m_clickMethodAreas) << valueWriter(m_clickMethodClickfinger);
bool success = true;
QString error_msg;
for (QString m : msgs) {
if (!m.isNull()) {
// qCCritical(KCM_TOUCHPAD) << "in error:" << m;
if (!success) {
error_msg.append("\n");
}
error_msg.append(m);
success = false;
}
}
if (!success) {
// qCCritical(KCM_TOUCHPAD) << error_msg;
}
flush();
return success;
}
bool LibinputTouchpad::getDefaultConfig()
{
m_enabled.set(m_enabledDefault);
m_tapToClick.set(m_tapToClickEnabledByDefault);
m_lrmTapButtonMap.set(m_lrmTapButtonMap);
m_lmrTapButtonMap.set(m_lmrTapButtonMapEnabledByDefault);
m_tapAndDrag.set(m_tapAndDragEnabledByDefault);
m_tapDragLock.set(m_tapDragLockEnabledByDefault);
m_leftHanded.set(m_leftHandedEnabledByDefault);
m_disableEventsOnExternalMouse.set(m_disableEventsOnExternalMouseDefault);
m_disableWhileTyping.set(m_disableWhileTypingEnabledByDefault);
m_middleEmulation.set(m_middleEmulationEnabledByDefault);
m_pointerAcceleration.set(m_defaultPointerAcceleration);
m_pointerAccelerationProfileFlat.set(m_defaultPointerAccelerationProfileFlat);
m_pointerAccelerationProfileAdaptive.set(m_defaultPointerAccelerationProfileAdaptive);
m_naturalScroll.set(m_naturalScrollEnabledByDefault);
m_horizontalScrolling.set(true);
m_isScrollTwoFinger.set(m_scrollTwoFingerEnabledByDefault);
m_isScrollEdge.set(m_scrollEdgeEnabledByDefault);
m_isScrollOnButtonDown.set(m_scrollOnButtonDownEnabledByDefault);
m_scrollButton.set(m_defaultScrollButton);
m_clickMethodAreas.set(m_defaultClickMethodAreas);
m_clickMethodClickfinger.set(m_defaultClickMethodClickfinger);
return true;
}
bool LibinputTouchpad::isChangedConfig()
{
// clang-format off
bool changed = m_enabled.changed() ||
m_tapToClick.changed() ||
m_lrmTapButtonMap.changed() ||
m_lmrTapButtonMap.changed() ||
m_tapAndDrag.changed() ||
m_tapDragLock.changed() ||
m_leftHanded.changed() ||
m_disableEventsOnExternalMouse.changed() ||
m_disableWhileTyping.changed() ||
m_middleEmulation.changed() ||
m_pointerAcceleration.changed() ||
m_pointerAccelerationProfileFlat.changed() ||
m_pointerAccelerationProfileAdaptive.changed() ||
m_naturalScroll.changed() ||
m_horizontalScrolling.changed() ||
m_isScrollTwoFinger.changed() ||
m_isScrollEdge.changed() ||
m_isScrollOnButtonDown.changed() ||
m_scrollButton.changed() ||
m_clickMethodAreas.changed() ||
m_clickMethodClickfinger.changed();
// clang-format on
return changed;
}
int LibinputTouchpad::touchpadOff()
{
return m_enabled.val;
}
XcbAtom &LibinputTouchpad::touchpadOffAtom()
{
return *m_atoms[QLatin1String(LIBINPUT_PROP_SENDEVENTS_ENABLED)].data();
}
template<typename T>
bool LibinputTouchpad::valueLoader(Prop<T> &prop)
{
const Parameter *p = findParameter(QString::fromLatin1(prop.name));
if (!p) {
// qCCritical(KCM_TOUCHPAD) << "Error on read of " << QString::fromLatin1(prop.name);
}
QVariant reply = getParameter(p);
if (!reply.isValid()) {
prop.avail = false;
return true;
}
prop.avail = true;
m_config.beginGroup(m_name);
const T replyValue = valueLoaderPart<T>(reply);
const T loadedValue = m_config.value(prop.name, replyValue).toBool();
prop.old = replyValue;
prop.val = loadedValue;
m_config.endGroup();
return true;
}
template<typename T>
QString LibinputTouchpad::valueWriter(const Prop<T> &prop)
{
const Parameter *p = findParameter(QString::fromLatin1(prop.name));
// Reion
if (!p /*|| !prop.changed()*/) {
return QString();
}
bool error = !setParameter(p, prop.val);
if (error) {
// qCCritical(KCM_TOUCHPAD) << "Cannot set property " + QString::fromLatin1(prop.name);
return QStringLiteral("Cannot set property ") + QString::fromLatin1(prop.name);
}
m_config.beginGroup(m_name);
m_config.setValue(prop.name, prop.val);
m_config.endGroup();
m_config.sync();
return QString();
}

@ -0,0 +1,148 @@
/*
SPDX-FileCopyrightText: 2019 Atul Bisht <atulbisht26@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef LIBINPUTTOUCHPAD_H
#define LIBINPUTTOUCHPAD_H
#include "../libinputcommon.h"
#include "xlibtouchpad.h"
#include <QSettings>
class LibinputTouchpad : public LibinputCommon, public XlibTouchpad
{
Q_OBJECT
public:
LibinputTouchpad(Display *display, int deviceId);
~LibinputTouchpad() override
{
}
bool getConfig() override;
bool applyConfig() override;
bool getDefaultConfig() override;
bool isChangedConfig() override;
int touchpadOff() override;
XcbAtom &touchpadOffAtom() override;
private:
template<typename T>
bool valueLoader(Prop<T> &prop);
template<typename T>
QString valueWriter(const Prop<T> &prop);
QSettings m_config;
//
// general
QString name() const override
{
return m_name;
}
bool supportsDisableEvents() const override
{
return m_supportsDisableEvents.avail && m_supportsDisableEvents.val;
}
bool isEnabled() const override
{
return !m_enabled.val;
}
void setEnabled(bool set) override
{
m_enabled.set(!set);
}
//
// Tapping
void setLmrTapButtonMap(bool set) override
{
m_lrmTapButtonMap.set(!set);
m_lmrTapButtonMap.set(set);
}
//
// advanced
bool supportsLeftHanded() const override
{
return m_leftHanded.avail;
}
bool supportsDisableEventsOnExternalMouse() const override
{
return m_supportsDisableEventsOnExternalMouse.avail && m_supportsDisableEventsOnExternalMouse.val;
}
bool supportsDisableWhileTyping() const override
{
return m_disableWhileTyping.avail;
}
bool supportsMiddleEmulation() const override
{
return m_middleEmulation.avail;
}
//
// acceleration speed and profile
bool supportsPointerAcceleration() const override
{
return m_pointerAcceleration.avail;
}
bool supportsPointerAccelerationProfileFlat() const override
{
return m_supportsPointerAccelerationProfileFlat.avail && m_supportsPointerAccelerationProfileFlat.val;
}
bool supportsPointerAccelerationProfileAdaptive() const override
{
return m_supportsPointerAccelerationProfileAdaptive.avail && m_supportsPointerAccelerationProfileAdaptive.val;
}
//
// scrolling
bool supportsNaturalScroll() const override
{
return m_naturalScroll.avail;
}
bool supportsHorizontalScrolling() const override
{
return true;
}
bool supportsScrollTwoFinger() const override
{
return m_supportsScrollTwoFinger.avail && m_supportsScrollTwoFinger.val;
}
bool supportsScrollEdge() const override
{
return m_supportsScrollEdge.avail && m_supportsScrollEdge.val;
}
bool supportsScrollOnButtonDown() const override
{
return m_supportsScrollOnButtonDown.avail && m_supportsScrollOnButtonDown.val;
}
//
// click method
bool supportsClickMethodAreas() const override
{
return m_supportsClickMethodAreas.avail && m_supportsClickMethodAreas.val;
}
bool supportsClickMethodClickfinger() const override
{
return m_supportsClickMethodClickfinger.avail && m_supportsClickMethodClickfinger.val;
}
bool supportsScrollFactor() const override
{
return false;
}
// Tapping
Prop<bool> m_lrmTapButtonMapEnabledByDefault = Prop<bool>("lrmTapButtonMapEnabledByDefault");
Prop<bool> m_lrmTapButtonMap = Prop<bool>("lrmTapButtonMap");
//
// advanced
Prop<bool> m_disableEventsOnExternalMouse = Prop<bool>("disableEventsOnExternalMouse");
Prop<bool> m_disableEventsOnExternalMouseDefault = Prop<bool>("disableEventsOnExternalMouseDefault");
QString m_name;
};
#endif // LIBINPUTTOUCHPAD_H

@ -0,0 +1,86 @@
/*
SPDX-FileCopyrightText: 2013 Alexander Mezin <mezin.alexander@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "propertyinfo.h"
#include <QVariant>
#include <QDebug>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
void XDeleter(void *p)
{
if (p) {
XFree(p);
}
}
PropertyInfo::PropertyInfo()
: type(0)
, format(0)
, nitems(0)
, f(nullptr)
, i(nullptr)
, b(nullptr)
, display(nullptr)
, device(0)
, prop(0)
{
}
PropertyInfo::PropertyInfo(Display *display, int device, Atom prop, Atom floatType)
: type(0)
, format(0)
, nitems(0)
, f(nullptr)
, i(nullptr)
, b(nullptr)
, display(display)
, device(device)
, prop(prop)
{
unsigned char *dataPtr = nullptr;
unsigned long bytes_after;
XIGetProperty(display, device, prop, 0, 1000, False, AnyPropertyType, &type, &format, &nitems, &bytes_after, &dataPtr);
data = QSharedPointer<unsigned char>(dataPtr, XDeleter);
if (format == CHAR_BIT && type == XA_INTEGER) {
b = reinterpret_cast<char *>(dataPtr);
}
if (format == sizeof(int) * CHAR_BIT && (type == XA_INTEGER || type == XA_CARDINAL)) {
i = reinterpret_cast<int *>(dataPtr);
}
if (format == sizeof(float) * CHAR_BIT && floatType && type == floatType) {
f = reinterpret_cast<float *>(dataPtr);
}
}
QVariant PropertyInfo::value(unsigned offset) const
{
QVariant v;
if (offset >= nitems) {
return v;
}
if (b) {
v = QVariant(static_cast<int>(b[offset]));
}
if (i) {
v = QVariant(i[offset]);
}
if (f) {
v = QVariant(f[offset]);
}
return v;
}
void PropertyInfo::set()
{
XIChangeProperty(display, device, prop, type, format, XIPropModeReplace, data.data(), nitems);
}

@ -0,0 +1,37 @@
/*
SPDX-FileCopyrightText: 2013 Alexander Mezin <mezin.alexander@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef PROPERTYINFO_H
#define PROPERTYINFO_H
#include <QSharedPointer>
#include <QX11Info>
#include <X11/Xdefs.h>
void XDeleter(void *p);
struct PropertyInfo {
Atom type;
int format;
QSharedPointer<unsigned char> data;
unsigned long nitems;
float *f;
int *i;
char *b;
Display *display;
int device;
Atom prop;
PropertyInfo();
PropertyInfo(Display *display, int device, Atom prop, Atom floatType);
QVariant value(unsigned offset) const;
void set();
};
#endif // PROPERTYINFO_H

@ -0,0 +1,225 @@
/*
SPDX-FileCopyrightText: 2013 Alexander Mezin <mezin.alexander@gmail.com>
SPDX-FileContributor: 2002-2005, 2007 Peter Osterlund <petero2@telia.com>
SPDX-License-Identifier: GPL-2.0-or-later AND LicenseRef-synaptics
*/
#include <QDebug>
#include <cmath>
#include "synapticstouchpad.h"
#include <limits.h>
#include <stddef.h>
#include <synaptics-properties.h>
#define SYN_MAX_BUTTONS 12
const struct Parameter synapticsProperties[] = {
{"LeftEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_EDGES, 32, 0},
{"RightEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_EDGES, 32, 1},
{"TopEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_EDGES, 32, 2},
{"BottomEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_EDGES, 32, 3},
{"FingerLow", PT_INT, 0, 255, SYNAPTICS_PROP_FINGER, 32, 0},
{"FingerHigh", PT_INT, 0, 255, SYNAPTICS_PROP_FINGER, 32, 1},
{"MaxTapTime", PT_INT, 0, 1000, SYNAPTICS_PROP_TAP_TIME, 32, 0},
{"MaxTapMove", PT_INT, 0, 2000, SYNAPTICS_PROP_TAP_MOVE, 32, 0},
{"MaxDoubleTapTime", PT_INT, 0, 1000, SYNAPTICS_PROP_TAP_DURATIONS, 32, 1},
{"SingleTapTimeout", PT_INT, 0, 1000, SYNAPTICS_PROP_TAP_DURATIONS, 32, 0},
{"ClickTime", PT_INT, 0, 1000, SYNAPTICS_PROP_TAP_DURATIONS, 32, 2},
{"FastTaps", PT_BOOL, 0, 1, SYNAPTICS_PROP_TAP_FAST, 8, 0},
{"EmulateMidButtonTime", PT_INT, 0, 1000, SYNAPTICS_PROP_MIDDLE_TIMEOUT, 32, 0},
{"EmulateTwoFingerMinZ", PT_INT, 0, 1000, SYNAPTICS_PROP_TWOFINGER_PRESSURE, 32, 0},
{"EmulateTwoFingerMinW", PT_INT, 0, 15, SYNAPTICS_PROP_TWOFINGER_WIDTH, 32, 0},
{"VertScrollDelta", PT_INT, -1000, 1000, SYNAPTICS_PROP_SCROLL_DISTANCE, 32, 0},
{"HorizScrollDelta", PT_INT, -1000, 1000, SYNAPTICS_PROP_SCROLL_DISTANCE, 32, 1},
{"VertEdgeScroll", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_EDGE, 8, 0},
{"HorizEdgeScroll", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_EDGE, 8, 1},
{"CornerCoasting", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_EDGE, 8, 2},
{"VertTwoFingerScroll", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_TWOFINGER, 8, 0},
{"HorizTwoFingerScroll", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_TWOFINGER, 8, 1},
{"MinSpeed", PT_DOUBLE, 0, 255.0, SYNAPTICS_PROP_SPEED, 0, /*float */ 0},
{"MaxSpeed", PT_DOUBLE, 0, 255.0, SYNAPTICS_PROP_SPEED, 0, /*float */ 1},
{"AccelFactor", PT_DOUBLE, 0, 1.0, SYNAPTICS_PROP_SPEED, 0, /*float */ 2},
/*{"TouchpadOff", PT_INT, 0, 2, SYNAPTICS_PROP_OFF, 8, 0},*/
{"LockedDrags", PT_BOOL, 0, 1, SYNAPTICS_PROP_LOCKED_DRAGS, 8, 0},
{"LockedDragTimeout", PT_INT, 0, 30000, SYNAPTICS_PROP_LOCKED_DRAGS_TIMEOUT, 32, 0},
{"RTCornerButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 0},
{"RBCornerButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 1},
{"LTCornerButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 2},
{"LBCornerButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 3},
{"OneFingerTapButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 4},
{"TwoFingerTapButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 5},
{"ThreeFingerTapButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 6},
{"ClickFinger1", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION, 8, 0},
{"ClickFinger2", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION, 8, 1},
{"ClickFinger3", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION, 8, 2},
{"CircularScrolling", PT_BOOL, 0, 1, SYNAPTICS_PROP_CIRCULAR_SCROLLING, 8, 0},
{"CircScrollDelta", PT_DOUBLE, .01, 3, SYNAPTICS_PROP_CIRCULAR_SCROLLING_DIST, 0 /* float */, 0},
{"CircScrollTrigger", PT_INT, 0, 8, SYNAPTICS_PROP_CIRCULAR_SCROLLING_TRIGGER, 8, 0},
{"PalmDetect", PT_BOOL, 0, 1, SYNAPTICS_PROP_PALM_DETECT, 8, 0},
{"PalmMinWidth", PT_INT, 0, 15, SYNAPTICS_PROP_PALM_DIMENSIONS, 32, 0},
{"PalmMinZ", PT_INT, 0, 255, SYNAPTICS_PROP_PALM_DIMENSIONS, 32, 1},
{"CoastingSpeed", PT_DOUBLE, 0, 255, SYNAPTICS_PROP_COASTING_SPEED, 0 /* float*/, 0},
{"CoastingFriction", PT_DOUBLE, 0, 255, SYNAPTICS_PROP_COASTING_SPEED, 0 /* float*/, 1},
{"PressureMotionMinZ", PT_INT, 1, 255, SYNAPTICS_PROP_PRESSURE_MOTION, 32, 0},
{"PressureMotionMaxZ", PT_INT, 1, 255, SYNAPTICS_PROP_PRESSURE_MOTION, 32, 1},
{"PressureMotionMinFactor", PT_DOUBLE, 0, 10.0, SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR, 0 /*float*/, 0},
{"PressureMotionMaxFactor", PT_DOUBLE, 0, 10.0, SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR, 0 /*float*/, 1},
{"GrabEventDevice", PT_BOOL, 0, 1, SYNAPTICS_PROP_GRAB, 8, 0},
{"TapAndDragGesture", PT_BOOL, 0, 1, SYNAPTICS_PROP_GESTURES, 8, 0},
{"AreaLeftEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_AREA, 32, 0},
{"AreaRightEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_AREA, 32, 1},
{"AreaTopEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_AREA, 32, 2},
{"AreaBottomEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_AREA, 32, 3},
{"HorizHysteresis", PT_INT, 0, 10000, SYNAPTICS_PROP_NOISE_CANCELLATION, 32, 0},
{"VertHysteresis", PT_INT, 0, 10000, SYNAPTICS_PROP_NOISE_CANCELLATION, 32, 1},
{"ClickPad", PT_BOOL, 0, 1, SYNAPTICS_PROP_CLICKPAD, 8, 0},
{"RightButtonAreaLeft", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 0},
{"RightButtonAreaRight", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 1},
{"RightButtonAreaTop", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 2},
{"RightButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 3},
{"MiddleButtonAreaLeft", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 4},
{"MiddleButtonAreaRight", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 5},
{"MiddleButtonAreaTop", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 6},
{"MiddleButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 7},
{NULL, PT_INT, 0, 0, nullptr, 0, 0},
};
SynapticsTouchpad::SynapticsTouchpad(Display *display, int deviceId)
: XlibTouchpad(display, deviceId)
, m_resX(1)
, m_resY(1)
{
m_capsAtom.intern(m_connection, SYNAPTICS_PROP_CAPABILITIES);
m_touchpadOffAtom.intern(m_connection, SYNAPTICS_PROP_OFF);
XcbAtom resolutionAtom(m_connection, SYNAPTICS_PROP_RESOLUTION);
XcbAtom edgesAtom(m_connection, SYNAPTICS_PROP_EDGES);
loadSupportedProperties(synapticsProperties);
m_toRadians.append("CircScrollDelta");
PropertyInfo edges(m_display, m_deviceId, edgesAtom, 0);
if (edges.i && edges.nitems == 4) {
int w = qAbs(edges.i[1] - edges.i[0]);
int h = qAbs(edges.i[3] - edges.i[2]);
m_resX = w / 90;
m_resY = h / 50;
qDebug() << "Width: " << w << " height: " << h;
qDebug() << "Approx. resX: " << m_resX << " resY: " << m_resY;
}
PropertyInfo resolution(m_display, m_deviceId, resolutionAtom, 0);
if (resolution.i && resolution.nitems == 2 && resolution.i[0] > 1 && resolution.i[1] > 1) {
m_resY = qMin(static_cast<unsigned long>(resolution.i[0]), static_cast<unsigned long>(INT_MAX));
m_resX = qMin(static_cast<unsigned long>(resolution.i[1]), static_cast<unsigned long>(INT_MAX));
qDebug() << "Touchpad resolution: x: " << m_resX << " y: " << m_resY;
}
m_scaleByResX.append("HorizScrollDelta");
m_scaleByResY.append("VertScrollDelta");
m_scaleByResX.append("MaxTapMove");
m_scaleByResY.append("MaxTapMove");
m_resX = qMax(10, m_resX);
m_resY = qMax(10, m_resY);
qDebug() << "Final resolution x:" << m_resX << " y:" << m_resY;
m_negate["HorizScrollDelta"] = "InvertHorizScroll";
m_negate["VertScrollDelta"] = "InvertVertScroll";
m_supported.append(m_negate.values());
m_supported.append("Coasting");
PropertyInfo caps(m_display, m_deviceId, m_capsAtom.atom(), 0);
if (!caps.b) {
return;
}
enum TouchpadCapabilitiy {
TouchpadHasLeftButton,
TouchpadHasMiddleButton,
TouchpadHasRightButton,
TouchpadTwoFingerDetect,
TouchpadThreeFingerDetect,
TouchpadPressureDetect,
TouchpadPalmDetect,
TouchpadCapsCount,
};
QVector<bool> cap(TouchpadCapsCount, false);
std::copy(caps.b, caps.b + qMin(cap.size(), static_cast<int>(caps.nitems)), cap.begin());
if (!cap[TouchpadTwoFingerDetect]) {
m_supported.removeAll("HorizTwoFingerScroll");
m_supported.removeAll("VertTwoFingerScroll");
m_supported.removeAll("TwoFingerTapButton");
}
if (!cap[TouchpadThreeFingerDetect]) {
m_supported.removeAll("ThreeFingerTapButton");
}
if (!cap[TouchpadPressureDetect]) {
m_supported.removeAll("FingerHigh");
m_supported.removeAll("FingerLow");
m_supported.removeAll("PalmMinZ");
m_supported.removeAll("PressureMotionMinZ");
m_supported.removeAll("PressureMotionMinFactor");
m_supported.removeAll("PressureMotionMaxZ");
m_supported.removeAll("PressureMotionMaxFactor");
m_supported.removeAll("EmulateTwoFingerMinZ");
}
if (!cap[TouchpadPalmDetect]) {
m_supported.removeAll("PalmDetect");
m_supported.removeAll("PalmMinWidth");
m_supported.removeAll("PalmMinZ");
m_supported.removeAll("EmulateTwoFingerMinW");
}
for (QMap<QString, QString>::Iterator i = m_negate.begin(); i != m_negate.end(); ++i) {
if (!m_supported.contains(i.key())) {
m_supported.removeAll(i.value());
}
}
m_paramList = synapticsProperties;
}
void SynapticsTouchpad::setTouchpadOff(int touchpadOff)
{
PropertyInfo off(m_display, m_deviceId, m_touchpadOffAtom.atom(), 0);
if (off.b && *(off.b) != touchpadOff) {
*(off.b) = touchpadOff;
off.set();
}
flush();
}
int SynapticsTouchpad::touchpadOff()
{
PropertyInfo off(m_display, m_deviceId, m_touchpadOffAtom.atom(), 0);
return off.value(0).toInt();
}
XcbAtom &SynapticsTouchpad::touchpadOffAtom()
{
return m_touchpadOffAtom;
}
double SynapticsTouchpad::getPropertyScale(const QString &name) const
{
if (m_scaleByResX.contains(name) && m_scaleByResY.contains(name)) {
return std::sqrt(static_cast<double>(m_resX) * m_resX + static_cast<double>(m_resY) * m_resY);
} else if (m_scaleByResX.contains(name)) {
return m_resX;
} else if (m_scaleByResY.contains(name)) {
return m_resY;
} else if (m_toRadians.contains(name)) {
return M_PI_4 / 45.0;
}
return 1.0;
}

@ -0,0 +1,34 @@
/*
SPDX-FileCopyrightText: 2015 Weng Xuetian <wengxt@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef SYNAPTICSTOUCHPAD_H
#define SYNAPTICSTOUCHPAD_H
#include "xcbatom.h"
#include "xlibtouchpad.h"
class SynapticsTouchpad : public QObject, public XlibTouchpad
{
Q_OBJECT
public:
SynapticsTouchpad(Display *display, int deviceId);
void setTouchpadOff(int touchpadOff) override;
int touchpadOff() override;
XcbAtom &touchpadOffAtom() override;
protected:
double getPropertyScale(const QString &name) const override;
private:
XcbAtom m_capsAtom, m_touchpadOffAtom;
int m_resX, m_resY;
QStringList m_scaleByResX, m_scaleByResY, m_toRadians;
};
#endif // SYNAPTICSTOUCHPAD_H

@ -0,0 +1,48 @@
/*
SPDX-FileCopyrightText: 2013 Alexander Mezin <mezin.alexander@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "xcbatom.h"
#include <cstdlib>
#include <cstring>
XcbAtom::XcbAtom()
: m_connection(nullptr)
, m_reply(nullptr)
, m_fetched(false)
{
}
XcbAtom::XcbAtom(xcb_connection_t *c, const char *name, bool onlyIfExists)
: m_reply(nullptr)
, m_fetched(false)
{
intern(c, name, onlyIfExists);
}
void XcbAtom::intern(xcb_connection_t *c, const char *name, bool onlyIfExists)
{
m_connection = c;
m_cookie = xcb_intern_atom(c, onlyIfExists, std::strlen(name), name);
}
XcbAtom::~XcbAtom()
{
std::free(m_reply);
}
xcb_atom_t XcbAtom::atom()
{
if (!m_fetched) {
m_fetched = true;
m_reply = xcb_intern_atom_reply(m_connection, m_cookie, nullptr);
}
if (m_reply) {
return m_reply->atom;
} else {
return 0;
}
}

@ -0,0 +1,36 @@
/*
SPDX-FileCopyrightText: 2013 Alexander Mezin <mezin.alexander@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef XCBATOM_H
#define XCBATOM_H
#include <xcb/xcb.h>
class XcbAtom
{
public:
XcbAtom();
XcbAtom(xcb_connection_t *, const char *name, bool onlyIfExists = true);
~XcbAtom();
void intern(xcb_connection_t *, const char *name, bool onlyIfExists = true);
xcb_atom_t atom();
operator xcb_atom_t()
{
return atom();
}
private:
XcbAtom(const XcbAtom &);
XcbAtom &operator=(const XcbAtom &);
xcb_connection_t *m_connection;
xcb_intern_atom_cookie_t m_cookie;
xcb_intern_atom_reply_t *m_reply;
bool m_fetched;
};
#endif // XCBATOM_H

@ -0,0 +1,405 @@
/*
SPDX-FileCopyrightText: 2013 Alexander Mezin <mezin.alexander@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <cmath>
#include <cstring>
#include <QtAlgorithms>
#include <QDebug>
// Includes are ordered this way because of #defines in Xorg's headers
#include "xlibbackend.h" // krazy:exclude=includes
#include "xlibnotifications.h" // krazy:exclude=includes
#include "xrecordkeyboardmonitor.h" // krazy:exclude=includes
#include <X11/Xatom.h>
#include <X11/Xlib-xcb.h>
#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>
#include <synaptics-properties.h>
#include <xserver-properties.h>
struct DeviceListDeleter {
static void cleanup(XDeviceInfo *p)
{
if (p) {
XFreeDeviceList(p);
}
}
};
void XlibBackend::XDisplayCleanup::cleanup(Display *p)
{
if (p) {
XCloseDisplay(p);
}
}
XlibBackend *XlibBackend::initialize(QObject *parent)
{
XlibBackend *backend = new XlibBackend(parent);
if (!backend->m_display) {
delete backend;
return nullptr;
}
return backend;
}
XlibBackend::~XlibBackend()
{
}
XlibBackend::XlibBackend(QObject *parent)
: QObject(parent)
, m_display(XOpenDisplay(nullptr))
, m_connection(nullptr)
{
if (m_display) {
m_connection = XGetXCBConnection(m_display.data());
}
if (!m_connection) {
m_errorString = "Cannot connect to X server";
return;
}
m_mouseAtom.intern(m_connection, XI_MOUSE);
m_keyboardAtom.intern(m_connection, XI_KEYBOARD);
m_touchpadAtom.intern(m_connection, XI_TOUCHPAD);
m_enabledAtom.intern(m_connection, XI_PROP_ENABLED);
m_synapticsIdentifierAtom.intern(m_connection, SYNAPTICS_PROP_CAPABILITIES);
m_libinputIdentifierAtom.intern(m_connection, "libinput Send Events Modes Available");
m_device.reset(findTouchpad());
if (!m_device) {
m_errorString = "No touchpad found";
}
}
XlibTouchpad *XlibBackend::findTouchpad()
{
int nDevices = 0;
QScopedPointer<XDeviceInfo, DeviceListDeleter> deviceInfo(XListInputDevices(m_display.data(), &nDevices));
for (XDeviceInfo *info = deviceInfo.data(); info < deviceInfo.data() + nDevices; info++) {
// Make sure device is touchpad
if (info->type != m_touchpadAtom.atom()) {
continue;
}
int nProperties = 0;
QSharedPointer<Atom> properties(XIListProperties(m_display.data(), info->id, &nProperties), XDeleter);
Atom *atom = properties.data(), *atomEnd = properties.data() + nProperties;
for (; atom != atomEnd; atom++) {
if (*atom == m_libinputIdentifierAtom.atom()) {
// setMode(TouchpadInputBackendMode::XLibinput);
return new LibinputTouchpad(m_display.data(), info->id);
}
if (*atom == m_synapticsIdentifierAtom.atom()) {
// setMode(TouchpadInputBackendMode::XSynaptics);
return new SynapticsTouchpad(m_display.data(), info->id);
}
}
}
return nullptr;
}
bool XlibBackend::applyConfig(const QVariantHash &p)
{
if (!m_device) {
return false;
}
bool success = m_device->applyConfig(p);
if (!success) {
m_errorString = "Cannot apply touchpad configuration";
}
return success;
}
bool XlibBackend::applyConfig()
{
if (!m_device) {
return false;
}
bool success = m_device->applyConfig();
if (!success) {
m_errorString = "Cannot apply touchpad configuration";
}
return success;
}
bool XlibBackend::getConfig(QVariantHash &p)
{
if (!m_device) {
return false;
}
bool success = m_device->getConfig(p);
if (!success) {
m_errorString = "Cannot read touchpad configuration";
}
return success;
}
bool XlibBackend::getConfig()
{
if (!m_device) {
return false;
}
bool success = m_device->getConfig();
if (!success) {
m_errorString = "Cannot read touchpad configuration";
}
return success;
}
bool XlibBackend::getDefaultConfig()
{
if (!m_device) {
return false;
}
bool success = m_device->getDefaultConfig();
if (!success) {
m_errorString = "Cannot read default touchpad configuration";
}
return success;
}
bool XlibBackend::isChangedConfig() const
{
if (!m_device) {
return false;
}
return m_device->isChangedConfig();
}
void XlibBackend::setTouchpadEnabled(bool enable)
{
if (!m_device) {
return;
}
m_device->setEnabled(enable);
// FIXME? This should not be needed, m_notifications should trigger
// a propertyChanged signal when we enable/disable the touchpad,
// that will Q_EMIT touchpadStateChanged, but for some reason
// XlibNotifications is not getting the property change events
// so we just Q_EMIT touchpadStateChanged from here as a workaround
Q_EMIT touchpadStateChanged();
}
bool XlibBackend::tapToClick()
{
LibinputTouchpad *object = dynamic_cast<LibinputTouchpad *>(m_device.data());
if (!object)
return false;
return object->isTapToClick();
}
void XlibBackend::setTapToClick(bool enabled)
{
LibinputTouchpad *object = dynamic_cast<LibinputTouchpad *>(m_device.data());
if (!object)
return;
object->setTapToClick(enabled);
}
qreal XlibBackend::pointerAcceleration()
{
LibinputTouchpad *object = dynamic_cast<LibinputTouchpad *>(m_device.data());
if (!object)
return 1;
return object->pointerAcceleration();
}
void XlibBackend::setPointerAcceleration(qreal value)
{
LibinputTouchpad *object = dynamic_cast<LibinputTouchpad *>(m_device.data());
if (!object)
return;
object->setPointerAcceleration(value);
}
void XlibBackend::setTouchpadOff(XlibBackend::TouchpadOffState state)
{
if (!m_device) {
return;
}
int touchpadOff = 0;
switch (state) {
case TouchpadEnabled:
touchpadOff = 0;
break;
case TouchpadFullyDisabled:
touchpadOff = 1;
break;
case TouchpadTapAndScrollDisabled:
touchpadOff = 2;
break;
default:
qCritical() << "Unknown TouchpadOffState" << state;
return;
}
m_device->setTouchpadOff(touchpadOff);
}
bool XlibBackend::isTouchpadAvailable()
{
return m_device;
}
bool XlibBackend::isTouchpadEnabled()
{
if (!m_device) {
return false;
}
return m_device->enabled();
}
XlibBackend::TouchpadOffState XlibBackend::getTouchpadOff()
{
if (!m_device) {
return TouchpadFullyDisabled;
}
int value = m_device->touchpadOff();
switch (value) {
case 0:
return TouchpadEnabled;
case 1:
return TouchpadFullyDisabled;
case 2:
return TouchpadTapAndScrollDisabled;
default:
qCritical() << "Unknown TouchpadOff value" << value;
return TouchpadFullyDisabled;
}
}
void XlibBackend::touchpadDetached()
{
qWarning() << "Touchpad detached";
m_device.reset();
Q_EMIT touchpadReset();
}
void XlibBackend::devicePlugged(int device)
{
if (!m_device) {
m_device.reset(findTouchpad());
if (m_device) {
qWarning() << "Touchpad reset";
m_notifications.reset();
// watchForEvents(m_keyboard);
Q_EMIT touchpadReset();
}
}
if (!m_device || device != m_device->deviceId()) {
Q_EMIT mousesChanged();
}
}
void XlibBackend::propertyChanged(xcb_atom_t prop)
{
if ((m_device && prop == m_device->touchpadOffAtom().atom()) || prop == m_enabledAtom.atom()) {
Q_EMIT touchpadStateChanged();
}
}
QStringList XlibBackend::listMouses(const QStringList &blacklist)
{
int nDevices = 0;
QScopedPointer<XDeviceInfo, DeviceListDeleter> info(XListInputDevices(m_display.data(), &nDevices));
QStringList list;
for (XDeviceInfo *i = info.data(); i != info.data() + nDevices; i++) {
if (m_device && i->id == static_cast<XID>(m_device->deviceId())) {
continue;
}
if (i->use != IsXExtensionPointer && i->use != IsXPointer) {
continue;
}
// type = KEYBOARD && use = Pointer means usb receiver for both keyboard
// and mouse
if (i->type != m_mouseAtom.atom() && i->type != m_keyboardAtom.atom()) {
continue;
}
QString name(i->name);
if (blacklist.contains(name, Qt::CaseInsensitive)) {
continue;
}
PropertyInfo enabled(m_display.data(), i->id, m_enabledAtom.atom(), 0);
if (enabled.value(0) == false) {
continue;
}
list.append(name);
}
return list;
}
QVector<QObject *> XlibBackend::getDevices() const
{
QVector<QObject *> touchpads;
LibinputTouchpad *libinputtouchpad = dynamic_cast<LibinputTouchpad *>(m_device.data());
if (libinputtouchpad) {
touchpads.push_back(libinputtouchpad);
}
SynapticsTouchpad *synaptics = dynamic_cast<SynapticsTouchpad *>(m_device.data());
if (synaptics) {
touchpads.push_back(synaptics);
}
return touchpads;
}
void XlibBackend::watchForEvents(bool keyboard)
{
if (!m_notifications) {
m_notifications.reset(new XlibNotifications(m_display.data(), m_device ? m_device->deviceId() : XIAllDevices));
connect(m_notifications.data(), SIGNAL(devicePlugged(int)), SLOT(devicePlugged(int)));
connect(m_notifications.data(), SIGNAL(touchpadDetached()), SLOT(touchpadDetached()));
connect(m_notifications.data(), SIGNAL(propertyChanged(xcb_atom_t)), SLOT(propertyChanged(xcb_atom_t)));
}
if (keyboard == !m_keyboard.isNull()) {
return;
}
if (!keyboard) {
m_keyboard.reset();
return;
}
m_keyboard.reset(new XRecordKeyboardMonitor(m_display.data()));
connect(m_keyboard.data(), SIGNAL(keyboardActivityStarted()), SIGNAL(keyboardActivityStarted()));
connect(m_keyboard.data(), SIGNAL(keyboardActivityFinished()), SIGNAL(keyboardActivityFinished()));
}

@ -0,0 +1,121 @@
/*
SPDX-FileCopyrightText: 2013 Alexander Mezin <mezin.alexander@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef XLIBBACKEND_H
#define XLIBBACKEND_H
#include <QLatin1String>
#include <QMap>
#include <QScopedPointer>
#include <QSet>
#include <QSharedPointer>
#include <QStringList>
#include <QX11Info>
#include "libinputtouchpad.h"
#include "synapticstouchpad.h"
#include "xlibtouchpad.h"
#include <xcb/xcb.h>
#include "propertyinfo.h"
#include "xcbatom.h"
class XlibTouchpad;
class XlibNotifications;
class XRecordKeyboardMonitor;
class XlibBackend : public QObject
{
Q_OBJECT
Q_PROPERTY(int touchpadCount READ touchpadCount CONSTANT)
public:
enum TouchpadOffState {
TouchpadEnabled,
TouchpadTapAndScrollDisabled,
TouchpadFullyDisabled,
};
static XlibBackend *initialize(QObject *parent = nullptr);
~XlibBackend();
bool applyConfig(const QVariantHash &);
bool applyConfig();
bool getConfig(QVariantHash &);
bool getConfig();
bool getDefaultConfig();
bool isChangedConfig() const;
QStringList supportedParameters() const
{
return m_device ? m_device->supportedParameters() : QStringList();
}
QString errorString() const
{
return m_errorString;
}
int touchpadCount() const
{
return m_device ? 1 : 0;
}
void setTouchpadOff(TouchpadOffState);
TouchpadOffState getTouchpadOff();
bool isTouchpadAvailable();
bool isTouchpadEnabled();
void setTouchpadEnabled(bool);
bool tapToClick();
void setTapToClick(bool enabled);
qreal pointerAcceleration();
void setPointerAcceleration(qreal value);
void watchForEvents(bool keyboard);
QStringList listMouses(const QStringList &blacklist);
QVector<QObject *> getDevices() const;
signals:
void touchpadStateChanged();
void mousesChanged();
void touchpadReset();
void keyboardActivityStarted();
void keyboardActivityFinished();
void touchpadAdded(bool success);
void touchpadRemoved(int index);
private Q_SLOTS:
void propertyChanged(xcb_atom_t);
void touchpadDetached();
void devicePlugged(int);
protected:
explicit XlibBackend(QObject *parent);
struct XDisplayCleanup {
static void cleanup(Display *);
};
QScopedPointer<Display, XDisplayCleanup> m_display;
xcb_connection_t *m_connection;
XcbAtom m_enabledAtom, m_mouseAtom, m_keyboardAtom, m_touchpadAtom;
XcbAtom m_synapticsIdentifierAtom;
XcbAtom m_libinputIdentifierAtom;
XlibTouchpad *findTouchpad();
QScopedPointer<XlibTouchpad> m_device;
QString m_errorString;
QScopedPointer<XlibNotifications> m_notifications;
QScopedPointer<XRecordKeyboardMonitor> m_keyboard;
};
#endif // XLIBBACKEND_H

@ -0,0 +1,135 @@
/*
SPDX-FileCopyrightText: 2013 Alexander Mezin <mezin.alexander@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "xlibnotifications.h"
#include <cstring>
#include <X11/Xlib-xcb.h>
#include <X11/extensions/XI.h>
#include <X11/extensions/XI2proto.h>
#include <X11/extensions/XInput2.h>
XlibNotifications::XlibNotifications(Display *display, int device)
: m_display(display)
, m_device(device)
{
m_connection = XGetXCBConnection(display);
m_notifier = new QSocketNotifier(xcb_get_file_descriptor(m_connection), QSocketNotifier::Read, this);
xcb_query_extension_cookie_t inputExtCookie = xcb_query_extension(m_connection, std::strlen(INAME), INAME);
QScopedPointer<xcb_query_extension_reply_t, QScopedPointerPodDeleter> inputExt(xcb_query_extension_reply(m_connection, inputExtCookie, nullptr));
if (!inputExt) {
return;
}
m_inputOpcode = inputExt->major_opcode;
const xcb_setup_t *setup = xcb_get_setup(m_connection);
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
xcb_screen_t *screen = iter.data;
m_inputWindow = xcb_generate_id(m_connection);
xcb_create_window(m_connection, 0, m_inputWindow, screen->root, 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, 0, 0, nullptr);
xcb_flush(m_connection);
XIEventMask masks[2];
unsigned char touchpadMask[] = {0, 0, 0, 0};
masks[0].deviceid = device;
masks[0].mask = touchpadMask;
masks[0].mask_len = sizeof(touchpadMask);
XISetMask(touchpadMask, XI_PropertyEvent);
unsigned char allMask[] = {0, 0, 0, 0};
masks[1].deviceid = XIAllDevices;
masks[1].mask = allMask;
masks[1].mask_len = sizeof(allMask);
XISetMask(allMask, XI_HierarchyChanged);
XISelectEvents(display, XDefaultRootWindow(display), masks, sizeof(masks) / sizeof(XIEventMask));
XFlush(display);
connect(m_notifier, SIGNAL(activated(int)), SLOT(processEvents()));
m_notifier->setEnabled(true);
}
void XlibNotifications::processEvents()
{
while (XPending(m_display)) {
XEvent event;
XNextEvent(m_display, &event);
processEvent(&event);
}
}
struct XEventDataDeleter {
XEventDataDeleter(Display *display, XGenericEventCookie *cookie)
: m_display(display)
, m_cookie(cookie)
{
XGetEventData(m_display, m_cookie);
}
~XEventDataDeleter()
{
if (m_cookie->data) {
XFreeEventData(m_display, m_cookie);
}
}
Display *m_display;
XGenericEventCookie *m_cookie;
};
void XlibNotifications::processEvent(XEvent *event)
{
if (event->xcookie.type != GenericEvent) {
return;
}
if (event->xcookie.extension != m_inputOpcode) {
return;
}
if (event->xcookie.evtype == XI_PropertyEvent) {
XEventDataDeleter helper(m_display, &event->xcookie);
if (!event->xcookie.data) {
return;
}
XIPropertyEvent *propEvent = reinterpret_cast<XIPropertyEvent *>(event->xcookie.data);
Q_EMIT propertyChanged(propEvent->property);
} else if (event->xcookie.evtype == XI_HierarchyChanged) {
XEventDataDeleter helper(m_display, &event->xcookie);
if (!event->xcookie.data) {
return;
}
XIHierarchyEvent *hierarchyEvent = reinterpret_cast<XIHierarchyEvent *>(event->xcookie.data);
for (uint16_t i = 0; i < hierarchyEvent->num_info; i++) {
if (hierarchyEvent->info[i].deviceid == m_device) {
if (hierarchyEvent->info[i].flags & XISlaveRemoved) {
Q_EMIT touchpadDetached();
return;
}
}
if (hierarchyEvent->info[i].use != XISlavePointer) {
continue;
}
if (hierarchyEvent->info[i].flags & (XIDeviceEnabled | XIDeviceDisabled)) {
Q_EMIT devicePlugged(hierarchyEvent->info[i].deviceid);
}
}
}
}
XlibNotifications::~XlibNotifications()
{
xcb_destroy_window(m_connection, m_inputWindow);
xcb_flush(m_connection);
}
#include "moc_xlibnotifications.cpp"

@ -0,0 +1,42 @@
/*
SPDX-FileCopyrightText: 2013 Alexander Mezin <mezin.alexander@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef XLIBNOTIFICATIONS_H
#define XLIBNOTIFICATIONS_H
#include <QSocketNotifier>
#include <QX11Info>
#include <X11/Xlib.h>
#include <xcb/xcb.h>
class XlibNotifications : public QObject
{
Q_OBJECT
public:
XlibNotifications(Display *display, int device);
~XlibNotifications();
Q_SIGNALS:
void propertyChanged(xcb_atom_t);
void devicePlugged(int);
void touchpadDetached();
private Q_SLOTS:
void processEvents();
private:
void processEvent(XEvent *);
Display *m_display;
xcb_connection_t *m_connection;
QSocketNotifier *m_notifier;
xcb_window_t m_inputWindow;
uint8_t m_inputOpcode;
int m_device;
};
#endif // XLIBNOTIFICATIONS_H

@ -0,0 +1,257 @@
#include <cmath>
#include "xlibtouchpad.h"
#include <X11/Xlib-xcb.h>
#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>
#include <xserver-properties.h>
static QVariant negateVariant(const QVariant &value)
{
if (value.type() == QVariant::Double) {
return QVariant(-value.toDouble());
} else if (value.type() == QVariant::Int) {
return QVariant(-value.toInt());
}
return value;
}
XlibTouchpad::XlibTouchpad(Display *display, int deviceId)
: m_display(display)
, m_connection(XGetXCBConnection(display))
, m_deviceId(deviceId)
{
m_floatType.intern(m_connection, "FLOAT");
m_enabledAtom.intern(m_connection, XI_PROP_ENABLED);
}
bool XlibTouchpad::applyConfig(const QVariantHash &p)
{
m_props.clear();
bool error = false;
for (const QString &name : qAsConst(m_supported)) {
QVariantHash::ConstIterator i = p.find(name);
if (i == p.end()) {
continue;
}
const Parameter *par = findParameter(name);
if (par) {
QVariant value(i.value());
double k = getPropertyScale(name);
if (k != 1.0) {
bool ok = false;
value = QVariant(value.toDouble(&ok) * k);
if (!ok) {
error = true;
continue;
}
}
if (m_negate.contains(name)) {
QVariantHash::ConstIterator i = p.find(m_negate[name]);
if (i != p.end() && i.value().toBool()) {
value = negateVariant(value);
}
}
if (name == "CoastingSpeed") {
QVariantHash::ConstIterator coastingEnabled = p.find("Coasting");
if (coastingEnabled != p.end() && !coastingEnabled.value().toBool()) {
value = QVariant(0);
}
}
if (!setParameter(par, value)) {
error = true;
}
}
}
flush();
return !error;
}
bool XlibTouchpad::getConfig(QVariantHash &p)
{
if (m_supported.isEmpty()) {
return false;
}
m_props.clear();
bool error = false;
for (const QString &name : qAsConst(m_supported)) {
const Parameter *par = findParameter(name);
if (!par) {
continue;
}
QVariant value(getParameter(par));
if (!value.isValid()) {
error = true;
continue;
}
double k = getPropertyScale(name);
if (k != 1.0) {
bool ok = false;
value = QVariant(value.toDouble(&ok) / k);
if (!ok) {
error = true;
continue;
}
}
if (m_negate.contains(name)) {
bool negative = value.toDouble() < 0.0;
p[m_negate[name]] = QVariant(negative);
if (negative) {
value = negateVariant(value);
}
}
if (name == "CoastingSpeed") {
bool coasting = value.toDouble() != 0.0;
p["Coasting"] = QVariant(coasting);
if (!coasting) {
continue;
}
}
p[name] = value;
}
return !error;
}
void XlibTouchpad::loadSupportedProperties(const Parameter *props)
{
m_paramList = props;
for (const Parameter *param = props; param->name; param++) {
QLatin1String name(param->prop_name);
if (!m_atoms.contains(name)) {
m_atoms.insert(name, QSharedPointer<XcbAtom>(new XcbAtom(m_connection, param->prop_name)));
}
}
for (const Parameter *p = props; p->name; p++) {
if (getParameter(p).isValid()) {
m_supported.append(p->name);
}
}
}
QVariant XlibTouchpad::getParameter(const Parameter *par)
{
PropertyInfo *p = getDevProperty(QLatin1String(par->prop_name));
if (!p || par->prop_offset >= p->nitems) {
return QVariant();
}
return p->value(par->prop_offset);
}
void XlibTouchpad::flush()
{
for (const QLatin1String &name : qAsConst(m_changed)) {
m_props[name].set();
}
m_changed.clear();
XFlush(m_display);
}
double XlibTouchpad::getPropertyScale(const QString &name) const
{
Q_UNUSED(name);
return 1.0;
}
PropertyInfo *XlibTouchpad::getDevProperty(const QLatin1String &propName)
{
if (m_props.contains(propName)) {
return &m_props[propName];
}
if (!m_atoms.contains(propName) || !m_atoms[propName]) {
return nullptr;
}
xcb_atom_t prop = m_atoms[propName]->atom();
if (!prop) {
return nullptr;
}
PropertyInfo p(m_display, m_deviceId, prop, m_floatType.atom());
if (!p.b && !p.f && !p.i) {
return nullptr;
}
return &m_props.insert(propName, p).value();
}
bool XlibTouchpad::setParameter(const Parameter *par, const QVariant &value)
{
QLatin1String propName(par->prop_name);
PropertyInfo *p = getDevProperty(propName);
if (!p || par->prop_offset >= p->nitems) {
return false;
}
QVariant converted(value);
QVariant::Type convType = QVariant::Int;
if (p->f) {
convType = QVariant::Double;
} else if (value.type() == QVariant::Double) {
converted = QVariant(qRound(static_cast<qreal>(value.toDouble())));
}
if (!converted.convert(convType)) {
return false;
}
if (converted == p->value(par->prop_offset)) {
return true;
}
if (p->b) {
p->b[par->prop_offset] = static_cast<char>(converted.toInt());
} else if (p->i) {
p->i[par->prop_offset] = converted.toInt();
} else if (p->f) {
p->f[par->prop_offset] = converted.toDouble();
}
m_changed.insert(propName);
return true;
}
void XlibTouchpad::setEnabled(bool enable)
{
PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0);
if (enabled.b && *(enabled.b) != enable) {
*(enabled.b) = enable;
enabled.set();
}
flush();
}
bool XlibTouchpad::enabled()
{
PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0);
return enabled.value(0).toBool();
}
const Parameter *XlibTouchpad::findParameter(const QString &name)
{
for (const Parameter *par = m_paramList; par->name; par++) {
if (name == par->name) {
return par;
}
}
return nullptr;
}

@ -0,0 +1,101 @@
/*
SPDX-FileCopyrightText: 2015 Weng Xuetian <wengxt@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef XLIBTOUCHPAD_H
#define XLIBTOUCHPAD_H
#include <QObject>
#include <QSet>
#include <QVariantHash>
#include "propertyinfo.h"
#include "xcbatom.h"
#include <xcb/xcb.h>
enum ParaType {
PT_INT,
PT_BOOL,
PT_DOUBLE,
};
struct Parameter {
const char *name; /* Name of parameter */
enum ParaType type; /* Type of parameter */
double min_val; /* Minimum allowed value */
double max_val; /* Maximum allowed value */
const char *prop_name; /* Property name */
int prop_format; /* Property format (0 for floats) */
unsigned prop_offset; /* Offset inside property */
};
class XlibTouchpad
{
public:
XlibTouchpad(Display *display, int deviceId);
virtual ~XlibTouchpad()
{
}
int deviceId()
{
return m_deviceId;
}
const QStringList &supportedParameters() const
{
return m_supported;
}
bool applyConfig(const QVariantHash &p);
bool getConfig(QVariantHash &p);
virtual bool getConfig()
{
return false;
}
virtual bool applyConfig()
{
return false;
}
virtual bool getDefaultConfig()
{
return false;
}
virtual bool isChangedConfig()
{
return false;
}
void setEnabled(bool enable);
bool enabled();
virtual void setTouchpadOff(int /*touchpadOff*/)
{
}
virtual int touchpadOff() = 0;
virtual XcbAtom &touchpadOffAtom() = 0;
protected:
void loadSupportedProperties(const Parameter *props);
bool setParameter(const struct Parameter *, const QVariant &);
QVariant getParameter(const struct Parameter *);
struct PropertyInfo *getDevProperty(const QLatin1String &propName);
void flush();
virtual double getPropertyScale(const QString &name) const;
const Parameter *findParameter(const QString &name);
Display *m_display;
xcb_connection_t *m_connection;
int m_deviceId;
XcbAtom m_floatType, m_enabledAtom;
QMap<QLatin1String, QSharedPointer<XcbAtom>> m_atoms;
QMap<QString, QString> m_negate;
QMap<QLatin1String, struct PropertyInfo> m_props;
QSet<QLatin1String> m_changed;
QStringList m_supported;
const struct Parameter *m_paramList;
};
#endif

@ -0,0 +1,140 @@
/*
SPDX-FileCopyrightText: 2013 Alexander Mezin <mezin.alexander@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "xrecordkeyboardmonitor.h"
#include <cstdlib>
#include <limits>
#include <QScopedPointer>
#include <X11/Xlib.h>
#include <xcb/xcbext.h>
XRecordKeyboardMonitor::XRecordKeyboardMonitor(Display *display)
: m_connection(xcb_connect(XDisplayString(display), nullptr))
, m_modifiersPressed(0)
, m_keysPressed(0)
{
if (!m_connection) {
return;
}
xcb_get_modifier_mapping_cookie_t modmapCookie = xcb_get_modifier_mapping(m_connection);
m_context = xcb_generate_id(m_connection);
xcb_record_range_t range;
memset(&range, 0, sizeof(range));
range.device_events.first = XCB_KEY_PRESS;
range.device_events.last = XCB_KEY_RELEASE;
xcb_record_client_spec_t cs = XCB_RECORD_CS_ALL_CLIENTS;
xcb_record_create_context(m_connection, m_context, 0, 1, 1, &cs, &range);
xcb_flush(m_connection);
QScopedPointer<xcb_get_modifier_mapping_reply_t, QScopedPointerPodDeleter> modmap(xcb_get_modifier_mapping_reply(m_connection, modmapCookie, nullptr));
if (!modmap) {
return;
}
int nModifiers = xcb_get_modifier_mapping_keycodes_length(modmap.data());
xcb_keycode_t *modifiers = xcb_get_modifier_mapping_keycodes(modmap.data());
m_modifier.fill(false, std::numeric_limits<xcb_keycode_t>::max() + 1);
for (xcb_keycode_t *i = modifiers; i < modifiers + nModifiers; i++) {
m_modifier[*i] = true;
}
m_ignore.fill(false, std::numeric_limits<xcb_keycode_t>::max() + 1);
for (xcb_keycode_t *i = modifiers; i < modifiers + modmap->keycodes_per_modifier; i++) {
m_ignore[*i] = true;
}
m_pressed.fill(false, std::numeric_limits<xcb_keycode_t>::max() + 1);
m_cookie = xcb_record_enable_context(m_connection, m_context);
xcb_flush(m_connection);
m_notifier = new QSocketNotifier(xcb_get_file_descriptor(m_connection), QSocketNotifier::Read, this);
connect(m_notifier, &QSocketNotifier::activated, this, &XRecordKeyboardMonitor::processNextReply);
m_notifier->setEnabled(true);
}
XRecordKeyboardMonitor::~XRecordKeyboardMonitor()
{
if (!m_connection) {
return;
}
xcb_record_disable_context(m_connection, m_context);
xcb_record_free_context(m_connection, m_context);
xcb_disconnect(m_connection);
}
void XRecordKeyboardMonitor::processNextReply()
{
xcb_generic_event_t *event;
while ((event = xcb_poll_for_event(m_connection))) {
std::free(event);
}
void *reply = nullptr;
xcb_generic_error_t *error = nullptr;
while (m_cookie.sequence && xcb_poll_for_reply(m_connection, m_cookie.sequence, &reply, &error)) {
// xcb_poll_for_reply may set both reply and error to null if connection has error.
// break if xcb_connection has error, no point to continue anyway.
if (xcb_connection_has_error(m_connection)) {
break;
}
if (error) {
std::free(error);
break;
}
if (!reply) {
continue;
}
QScopedPointer<xcb_record_enable_context_reply_t, QScopedPointerPodDeleter> data(reinterpret_cast<xcb_record_enable_context_reply_t *>(reply));
process(data.data());
}
}
void XRecordKeyboardMonitor::process(xcb_record_enable_context_reply_t *reply)
{
bool prevActivity = activity();
xcb_key_press_event_t *events = reinterpret_cast<xcb_key_press_event_t *>(xcb_record_enable_context_data(reply));
int nEvents = xcb_record_enable_context_data_length(reply) / sizeof(xcb_key_press_event_t);
bool wasActivity = prevActivity;
for (xcb_key_press_event_t *e = events; e < events + nEvents; e++) {
if (e->response_type != XCB_KEY_PRESS && e->response_type != XCB_KEY_RELEASE) {
continue;
}
if (m_ignore[e->detail]) {
continue;
}
bool pressed = (e->response_type == XCB_KEY_PRESS);
if (m_pressed[e->detail] == pressed) {
continue;
}
m_pressed[e->detail] = pressed;
int &counter = m_modifier[e->detail] ? m_modifiersPressed : m_keysPressed;
if (pressed) {
counter++;
} else {
counter--;
}
wasActivity = wasActivity || activity();
}
if (!prevActivity && activity()) {
Q_EMIT keyboardActivityStarted();
} else if (!activity() && wasActivity) {
Q_EMIT keyboardActivityFinished();
}
}

@ -0,0 +1,48 @@
/*
SPDX-FileCopyrightText: 2013 Alexander Mezin <mezin.alexander@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef XRECORDKEYBOARDMONITOR_H
#define XRECORDKEYBOARDMONITOR_H
#include <QSocketNotifier>
#include <QVector>
#include <QX11Info>
#include <xcb/record.h>
#include <xcb/xcb.h>
class XRecordKeyboardMonitor : public QObject
{
Q_OBJECT
public:
XRecordKeyboardMonitor(Display *display);
~XRecordKeyboardMonitor();
Q_SIGNALS:
void keyboardActivityStarted();
void keyboardActivityFinished();
private Q_SLOTS:
void processNextReply();
private:
void process(xcb_record_enable_context_reply_t *reply);
bool activity() const
{
return m_keysPressed && !m_modifiersPressed;
}
QSocketNotifier *m_notifier;
xcb_connection_t *m_connection;
xcb_record_context_t m_context;
xcb_record_enable_context_cookie_t m_cookie;
QVector<bool> m_modifier, m_ignore, m_pressed;
int m_modifiersPressed, m_keysPressed;
};
#endif // XRECORDKEYBOARDMONITOR_H
Loading…
Cancel
Save