[libinput] Support toggleTouchpad
Summary: The LibInput::Device provides a way to enable/disable the device. This is used by the Connection to toggle all touchpad devices on/off when the touchpad key is pressed. For this KWin "steals" the global shortcuts from the touchpad kded. Detecting what is a touchpad is unfortunately not tivial. The code uses the following approach: * it's a pointer * it's not also a keyboard or touch screen * it's at least one of the following: ** supports multiple tap fingers ** supports disable while typing ** supports disable on external mouse If the code finds a touchpad and changes it's state successfully, it triggers the touchpadEnabledChanged on Plasma's osdService. Test Plan: Tested on notebook with toggle touchpad button Reviewers: #plasma Subscribers: plasma-devel Projects: #plasma Differential Revision: https://phabricator.kde.org/D1545
This commit is contained in:
parent
78c70a0775
commit
5e284224ee
5 changed files with 110 additions and 1 deletions
|
@ -26,7 +26,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "libinput_logging.h"
|
#include "libinput_logging.h"
|
||||||
|
|
||||||
#include <KConfigGroup>
|
#include <KConfigGroup>
|
||||||
|
#include <KGlobalAccel>
|
||||||
|
|
||||||
|
#include <QDBusMessage>
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QDBusPendingCall>
|
||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
#include <QSocketNotifier>
|
#include <QSocketNotifier>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
@ -83,6 +87,8 @@ Connection *Connection::create(QObject *parent)
|
||||||
return s_self;
|
return s_self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const QString s_touchpadComponent = QStringLiteral("kcm_touchpad");
|
||||||
|
|
||||||
Connection::Connection(Context *input, QObject *parent)
|
Connection::Connection(Context *input, QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_input(input)
|
, m_input(input)
|
||||||
|
@ -90,6 +96,47 @@ Connection::Connection(Context *input, QObject *parent)
|
||||||
, m_mutex(QMutex::Recursive)
|
, m_mutex(QMutex::Recursive)
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_input);
|
Q_ASSERT(m_input);
|
||||||
|
|
||||||
|
// steal touchpad shortcuts
|
||||||
|
QAction *touchpadToggleAction = new QAction(this);
|
||||||
|
QAction *touchpadOnAction = new QAction(this);
|
||||||
|
QAction *touchpadOffAction = new QAction(this);
|
||||||
|
|
||||||
|
touchpadToggleAction->setObjectName(QStringLiteral("Toggle Touchpad"));
|
||||||
|
touchpadToggleAction->setProperty("componentName", s_touchpadComponent);
|
||||||
|
touchpadOnAction->setObjectName(QStringLiteral("Enable Touchpad"));
|
||||||
|
touchpadOnAction->setProperty("componentName", s_touchpadComponent);
|
||||||
|
touchpadOffAction->setObjectName(QStringLiteral("Disable Touchpad"));
|
||||||
|
touchpadOffAction->setProperty("componentName", s_touchpadComponent);
|
||||||
|
KGlobalAccel::self()->setDefaultShortcut(touchpadToggleAction, QList<QKeySequence>{Qt::Key_TouchpadToggle});
|
||||||
|
KGlobalAccel::self()->setShortcut(touchpadToggleAction, QList<QKeySequence>{Qt::Key_TouchpadToggle});
|
||||||
|
KGlobalAccel::self()->setDefaultShortcut(touchpadOnAction, QList<QKeySequence>{Qt::Key_TouchpadOn});
|
||||||
|
KGlobalAccel::self()->setShortcut(touchpadOnAction, QList<QKeySequence>{Qt::Key_TouchpadOn});
|
||||||
|
KGlobalAccel::self()->setDefaultShortcut(touchpadOffAction, QList<QKeySequence>{Qt::Key_TouchpadOff});
|
||||||
|
KGlobalAccel::self()->setShortcut(touchpadOffAction, QList<QKeySequence>{Qt::Key_TouchpadOff});
|
||||||
|
#ifndef KWIN_BUILD_TESTING
|
||||||
|
InputRedirection::self()->registerShortcut(Qt::Key_TouchpadToggle, touchpadToggleAction);
|
||||||
|
InputRedirection::self()->registerShortcut(Qt::Key_TouchpadOn, touchpadOnAction);
|
||||||
|
InputRedirection::self()->registerShortcut(Qt::Key_TouchpadOff, touchpadOffAction);
|
||||||
|
#endif
|
||||||
|
connect(touchpadToggleAction, &QAction::triggered, this, &Connection::toggleTouchpads);
|
||||||
|
connect(touchpadOnAction, &QAction::triggered, this,
|
||||||
|
[this] {
|
||||||
|
if (m_touchpadsEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toggleTouchpads();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(touchpadOffAction, &QAction::triggered, this,
|
||||||
|
[this] {
|
||||||
|
if (!m_touchpadsEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toggleTouchpads();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// need to connect to KGlobalSettings as the mouse KCM does not emit a dedicated signal
|
// need to connect to KGlobalSettings as the mouse KCM does not emit a dedicated signal
|
||||||
QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"),
|
QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"),
|
||||||
QStringLiteral("notifyChange"), this, SLOT(slotKGlobalSettingsNotifyChange(int,int)));
|
QStringLiteral("notifyChange"), this, SLOT(slotKGlobalSettingsNotifyChange(int,int)));
|
||||||
|
@ -371,5 +418,41 @@ void Connection::slotKGlobalSettingsNotifyChange(int type, int arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Connection::toggleTouchpads()
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
m_touchpadsEnabled = !m_touchpadsEnabled;
|
||||||
|
for (auto it = m_devices.constBegin(); it != m_devices.constEnd(); ++it) {
|
||||||
|
auto device = *it;
|
||||||
|
if (!device->isPointer()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (device->isKeyboard() || device->isTouch() || device->isTabletPad() || device->isTabletTool()) {
|
||||||
|
// ignore all combined devices. E.g. a touchpad on a keyboard we don't want to toggle
|
||||||
|
// as that would result in the keyboard going off as well
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// is this a touch pad? We don't really know, let's do some assumptions
|
||||||
|
if (device->tapFingerCount() > 0 || device->supportsDisableWhileTyping() || device->supportsDisableEventsOnExternalMouse()) {
|
||||||
|
const bool old = device->isEnabled();
|
||||||
|
device->setEnabled(m_touchpadsEnabled);
|
||||||
|
if (old != device->isEnabled()) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
// send OSD message
|
||||||
|
QDBusMessage msg = QDBusMessage::createMethodCall(
|
||||||
|
QStringLiteral("org.kde.plasmashell"),
|
||||||
|
QStringLiteral("/org/kde/osdService"),
|
||||||
|
QStringLiteral("org.kde.osdService"),
|
||||||
|
QStringLiteral("touchpadEnabledChanged")
|
||||||
|
);
|
||||||
|
msg.setArguments({m_touchpadsEnabled});
|
||||||
|
QDBusConnection::sessionBus().asyncCall(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,8 @@ public:
|
||||||
|
|
||||||
void processEvents();
|
void processEvents();
|
||||||
|
|
||||||
|
void toggleTouchpads();
|
||||||
|
|
||||||
QVector<Device*> devices() const {
|
QVector<Device*> devices() const {
|
||||||
return m_devices;
|
return m_devices;
|
||||||
}
|
}
|
||||||
|
@ -118,6 +120,7 @@ private:
|
||||||
bool wasSuspended = false;
|
bool wasSuspended = false;
|
||||||
QVector<Device*> m_devices;
|
QVector<Device*> m_devices;
|
||||||
KSharedConfigPtr m_config;
|
KSharedConfigPtr m_config;
|
||||||
|
bool m_touchpadsEnabled = true;
|
||||||
|
|
||||||
KWIN_SINGLETON(Connection)
|
KWIN_SINGLETON(Connection)
|
||||||
static QThread *s_thread;
|
static QThread *s_thread;
|
||||||
|
|
|
@ -82,6 +82,7 @@ Device::Device(libinput_device *device, QObject *parent)
|
||||||
, m_supportsDisableEventsOnExternalMouse(libinput_device_config_send_events_get_modes(m_device) & LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
|
, m_supportsDisableEventsOnExternalMouse(libinput_device_config_send_events_get_modes(m_device) & LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
|
||||||
, m_leftHanded(m_supportsLeftHanded ? libinput_device_config_left_handed_get(m_device) : false)
|
, m_leftHanded(m_supportsLeftHanded ? libinput_device_config_left_handed_get(m_device) : false)
|
||||||
, m_pointerAcceleration(libinput_device_config_accel_get_speed(m_device))
|
, m_pointerAcceleration(libinput_device_config_accel_get_speed(m_device))
|
||||||
|
, m_enabled(m_supportsDisableEvents ? libinput_device_config_send_events_get_mode(m_device) == LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : true)
|
||||||
{
|
{
|
||||||
libinput_device_ref(m_device);
|
libinput_device_ref(m_device);
|
||||||
|
|
||||||
|
@ -153,5 +154,18 @@ void Device::setPointerAcceleration(qreal acceleration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Device::setEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
if (!m_supportsDisableEvents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (libinput_device_config_send_events_set_mode(m_device, enabled ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : LIBINPUT_CONFIG_SEND_EVENTS_DISABLED) == LIBINPUT_CONFIG_STATUS_SUCCESS) {
|
||||||
|
if (m_enabled != enabled) {
|
||||||
|
m_enabled = enabled;
|
||||||
|
emit enabledChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ class Device : public QObject
|
||||||
Q_PROPERTY(bool supportsDisableEventsOnExternalMouse READ supportsDisableEventsOnExternalMouse CONSTANT)
|
Q_PROPERTY(bool supportsDisableEventsOnExternalMouse READ supportsDisableEventsOnExternalMouse CONSTANT)
|
||||||
Q_PROPERTY(bool leftHanded READ isLeftHanded WRITE setLeftHanded NOTIFY leftHandedChanged)
|
Q_PROPERTY(bool leftHanded READ isLeftHanded WRITE setLeftHanded NOTIFY leftHandedChanged)
|
||||||
Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration NOTIFY pointerAccelerationChanged)
|
Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration NOTIFY pointerAccelerationChanged)
|
||||||
|
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
|
||||||
public:
|
public:
|
||||||
explicit Device(libinput_device *device, QObject *parent = nullptr);
|
explicit Device(libinput_device *device, QObject *parent = nullptr);
|
||||||
virtual ~Device();
|
virtual ~Device();
|
||||||
|
@ -145,6 +146,11 @@ public:
|
||||||
**/
|
**/
|
||||||
void setPointerAcceleration(qreal acceleration);
|
void setPointerAcceleration(qreal acceleration);
|
||||||
|
|
||||||
|
bool isEnabled() const {
|
||||||
|
return m_enabled;
|
||||||
|
}
|
||||||
|
void setEnabled(bool enabled);
|
||||||
|
|
||||||
libinput_device *device() const {
|
libinput_device *device() const {
|
||||||
return m_device;
|
return m_device;
|
||||||
}
|
}
|
||||||
|
@ -152,6 +158,7 @@ public:
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void leftHandedChanged();
|
void leftHandedChanged();
|
||||||
void pointerAccelerationChanged();
|
void pointerAccelerationChanged();
|
||||||
|
void enabledChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
libinput_device *m_device;
|
libinput_device *m_device;
|
||||||
|
@ -179,6 +186,7 @@ private:
|
||||||
bool m_supportsDisableEventsOnExternalMouse;
|
bool m_supportsDisableEventsOnExternalMouse;
|
||||||
bool m_leftHanded;
|
bool m_leftHanded;
|
||||||
qreal m_pointerAcceleration;
|
qreal m_pointerAcceleration;
|
||||||
|
bool m_enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,5 +30,6 @@ if (HAVE_INPUT)
|
||||||
${KWIN_SOURCE_DIR}/udev.cpp
|
${KWIN_SOURCE_DIR}/udev.cpp
|
||||||
)
|
)
|
||||||
add_executable(libinputtest ${libinputtest_SRCS})
|
add_executable(libinputtest ${libinputtest_SRCS})
|
||||||
target_link_libraries(libinputtest Qt5::Core Qt5::DBus Libinput::Libinput ${UDEV_LIBS} KF5::ConfigCore KF5::WindowSystem)
|
add_definitions(-DKWIN_BUILD_TESTING)
|
||||||
|
target_link_libraries(libinputtest Qt5::Core Qt5::DBus Libinput::Libinput ${UDEV_LIBS} KF5::ConfigCore KF5::GlobalAccel KF5::WindowSystem)
|
||||||
endif()
|
endif()
|
||||||
|
|
Loading…
Reference in a new issue