mirror of https://github.com/cutefishos/core
SettingsDaemon: add touchpad
parent
9337102924
commit
deb2af4984
@ -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…
Reference in New Issue