diff --git a/libinput/connection.h b/libinput/connection.h --- a/libinput/connection.h +++ b/libinput/connection.h @@ -73,6 +73,8 @@ void processEvents(); + void toggleTouchpads(); + QVector devices() const { return m_devices; } @@ -118,6 +120,7 @@ bool wasSuspended = false; QVector m_devices; KSharedConfigPtr m_config; + bool m_touchpadsEnabled = true; KWIN_SINGLETON(Connection) static QThread *s_thread; diff --git a/libinput/connection.cpp b/libinput/connection.cpp --- a/libinput/connection.cpp +++ b/libinput/connection.cpp @@ -26,7 +26,11 @@ #include "libinput_logging.h" #include +#include +#include +#include +#include #include #include #include @@ -83,13 +87,56 @@ return s_self; } +static const QString s_touchpadComponent = QStringLiteral("kcm_touchpad"); + Connection::Connection(Context *input, QObject *parent) : QObject(parent) , m_input(input) , m_notifier(nullptr) , m_mutex(QMutex::Recursive) { 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{Qt::Key_TouchpadToggle}); + KGlobalAccel::self()->setShortcut(touchpadToggleAction, QList{Qt::Key_TouchpadToggle}); + KGlobalAccel::self()->setDefaultShortcut(touchpadOnAction, QList{Qt::Key_TouchpadOn}); + KGlobalAccel::self()->setShortcut(touchpadOnAction, QList{Qt::Key_TouchpadOn}); + KGlobalAccel::self()->setDefaultShortcut(touchpadOffAction, QList{Qt::Key_TouchpadOff}); + KGlobalAccel::self()->setShortcut(touchpadOffAction, QList{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 QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"), QStringLiteral("notifyChange"), this, SLOT(slotKGlobalSettingsNotifyChange(int,int))); @@ -371,5 +418,41 @@ } } +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); + } +} + } } diff --git a/libinput/device.h b/libinput/device.h --- a/libinput/device.h +++ b/libinput/device.h @@ -57,6 +57,7 @@ Q_PROPERTY(bool supportsDisableEventsOnExternalMouse READ supportsDisableEventsOnExternalMouse CONSTANT) Q_PROPERTY(bool leftHanded READ isLeftHanded WRITE setLeftHanded NOTIFY leftHandedChanged) Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration NOTIFY pointerAccelerationChanged) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) public: explicit Device(libinput_device *device, QObject *parent = nullptr); virtual ~Device(); @@ -145,13 +146,19 @@ **/ void setPointerAcceleration(qreal acceleration); + bool isEnabled() const { + return m_enabled; + } + void setEnabled(bool enabled); + libinput_device *device() const { return m_device; } Q_SIGNALS: void leftHandedChanged(); void pointerAccelerationChanged(); + void enabledChanged(); private: libinput_device *m_device; @@ -179,6 +186,7 @@ bool m_supportsDisableEventsOnExternalMouse; bool m_leftHanded; qreal m_pointerAcceleration; + bool m_enabled; }; } diff --git a/libinput/device.cpp b/libinput/device.cpp --- a/libinput/device.cpp +++ b/libinput/device.cpp @@ -82,6 +82,7 @@ , 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_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); @@ -153,5 +154,18 @@ } } +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(); + } + } +} + } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,5 +30,6 @@ ${KWIN_SOURCE_DIR}/udev.cpp ) 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()