[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 <KConfigGroup>
|
||||
#include <KGlobalAccel>
|
||||
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusPendingCall>
|
||||
#include <QMutexLocker>
|
||||
#include <QSocketNotifier>
|
||||
#include <QThread>
|
||||
|
@ -83,6 +87,8 @@ Connection *Connection::create(QObject *parent)
|
|||
return s_self;
|
||||
}
|
||||
|
||||
static const QString s_touchpadComponent = QStringLiteral("kcm_touchpad");
|
||||
|
||||
Connection::Connection(Context *input, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_input(input)
|
||||
|
@ -90,6 +96,47 @@ Connection::Connection(Context *input, QObject *parent)
|
|||
, 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<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
|
||||
QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"),
|
||||
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 toggleTouchpads();
|
||||
|
||||
QVector<Device*> devices() const {
|
||||
return m_devices;
|
||||
}
|
||||
|
@ -118,6 +120,7 @@ private:
|
|||
bool wasSuspended = false;
|
||||
QVector<Device*> m_devices;
|
||||
KSharedConfigPtr m_config;
|
||||
bool m_touchpadsEnabled = true;
|
||||
|
||||
KWIN_SINGLETON(Connection)
|
||||
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_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::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 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,6 +146,11 @@ public:
|
|||
**/
|
||||
void setPointerAcceleration(qreal acceleration);
|
||||
|
||||
bool isEnabled() const {
|
||||
return m_enabled;
|
||||
}
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
libinput_device *device() const {
|
||||
return m_device;
|
||||
}
|
||||
|
@ -152,6 +158,7 @@ public:
|
|||
Q_SIGNALS:
|
||||
void leftHandedChanged();
|
||||
void pointerAccelerationChanged();
|
||||
void enabledChanged();
|
||||
|
||||
private:
|
||||
libinput_device *m_device;
|
||||
|
@ -179,6 +186,7 @@ private:
|
|||
bool m_supportsDisableEventsOnExternalMouse;
|
||||
bool m_leftHanded;
|
||||
qreal m_pointerAcceleration;
|
||||
bool m_enabled;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -30,5 +30,6 @@ if (HAVE_INPUT)
|
|||
${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()
|
||||
|
|
Loading…
Reference in a new issue