2014-08-14 12:43:57 +00:00
|
|
|
/********************************************************************
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
|
|
|
|
|
|
|
Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*********************************************************************/
|
|
|
|
#include "connection.h"
|
|
|
|
#include "context.h"
|
[libinput] Add a wrapper class Device for a libinput_device
Summary:
The Device class wraps all the information we can get from libinput
about the device, like whether it's a keyboard, pointer, touch, etc.
In addition some more information is queried to figure out how "useful"
a device is. For a keyboard all alphanumeric keys are checked whether
they exist, for a pointer all (normal) buttons are queried.
All the information is exposed as Q_PROPERTY and used by the
DebugConsole. The DebugConsole gained a new tab "Input Devices" which
renders all devices and their properties in a tree view. When plugging
in/out a device, the model gets reset, so it's always up to date.
The new Device class can be used in future to configure the device,
e.g. disable touch pad, set mouse acceleration, etc.
Reviewers: #plasma
Subscribers: plasma-devel
Projects: #plasma
Differential Revision: https://phabricator.kde.org/D1538
2016-05-04 11:42:26 +00:00
|
|
|
#include "device.h"
|
2014-08-14 12:43:57 +00:00
|
|
|
#include "events.h"
|
2014-08-15 10:51:31 +00:00
|
|
|
#include "../logind.h"
|
2015-04-08 08:25:51 +00:00
|
|
|
#include "../udev.h"
|
2015-07-31 10:43:06 +00:00
|
|
|
#include "libinput_logging.h"
|
2014-08-14 12:43:57 +00:00
|
|
|
|
2016-05-06 07:53:36 +00:00
|
|
|
#include <KConfigGroup>
|
2016-05-06 10:28:07 +00:00
|
|
|
#include <KGlobalAccel>
|
2016-05-06 07:53:36 +00:00
|
|
|
|
2016-05-06 10:28:07 +00:00
|
|
|
#include <QDBusMessage>
|
|
|
|
#include <QDBusConnection>
|
|
|
|
#include <QDBusPendingCall>
|
2015-09-02 09:32:26 +00:00
|
|
|
#include <QMutexLocker>
|
2014-08-14 12:43:57 +00:00
|
|
|
#include <QSocketNotifier>
|
2015-09-02 08:12:18 +00:00
|
|
|
#include <QThread>
|
2014-08-14 12:43:57 +00:00
|
|
|
|
|
|
|
#include <libinput.h>
|
|
|
|
|
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
namespace LibInput
|
|
|
|
{
|
|
|
|
|
|
|
|
Connection *Connection::s_self = nullptr;
|
2015-09-02 08:12:18 +00:00
|
|
|
QThread *Connection::s_thread = nullptr;
|
2014-08-14 12:43:57 +00:00
|
|
|
|
|
|
|
static Context *s_context = nullptr;
|
|
|
|
|
2015-02-03 13:01:53 +00:00
|
|
|
Connection::Connection(QObject *parent)
|
|
|
|
: Connection(nullptr, parent)
|
|
|
|
{
|
|
|
|
// only here to fix build, using will crash, BUG 343529
|
|
|
|
}
|
2014-08-14 12:43:57 +00:00
|
|
|
|
|
|
|
Connection *Connection::create(QObject *parent)
|
|
|
|
{
|
|
|
|
Q_ASSERT(!s_self);
|
|
|
|
static Udev s_udev;
|
|
|
|
if (!s_udev.isValid()) {
|
2015-07-31 10:43:06 +00:00
|
|
|
qCWarning(KWIN_LIBINPUT) << "Failed to initialize udev";
|
2014-08-14 12:43:57 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (!s_context) {
|
|
|
|
s_context = new Context(s_udev);
|
|
|
|
if (!s_context->isValid()) {
|
2015-07-31 10:43:06 +00:00
|
|
|
qCWarning(KWIN_LIBINPUT) << "Failed to create context from udev";
|
2014-08-14 12:43:57 +00:00
|
|
|
delete s_context;
|
|
|
|
s_context = nullptr;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
// TODO: don't hardcode seat name
|
|
|
|
if (!s_context->assignSeat("seat0")) {
|
2015-07-31 10:43:06 +00:00
|
|
|
qCWarning(KWIN_LIBINPUT) << "Failed to assign seat seat0";
|
2014-08-14 12:43:57 +00:00
|
|
|
delete s_context;
|
|
|
|
s_context = nullptr;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
2015-09-02 08:12:18 +00:00
|
|
|
s_thread = new QThread();
|
|
|
|
s_self = new Connection(s_context);
|
|
|
|
s_self->moveToThread(s_thread);
|
|
|
|
s_thread->start();
|
|
|
|
QObject::connect(s_thread, &QThread::finished, s_self, &QObject::deleteLater);
|
|
|
|
QObject::connect(s_thread, &QThread::finished, s_thread, &QObject::deleteLater);
|
|
|
|
QObject::connect(parent, &QObject::destroyed, s_thread, &QThread::quit);
|
2014-08-14 12:43:57 +00:00
|
|
|
return s_self;
|
|
|
|
}
|
|
|
|
|
2016-05-06 10:28:07 +00:00
|
|
|
static const QString s_touchpadComponent = QStringLiteral("kcm_touchpad");
|
|
|
|
|
2014-08-14 12:43:57 +00:00
|
|
|
Connection::Connection(Context *input, QObject *parent)
|
|
|
|
: QObject(parent)
|
|
|
|
, m_input(input)
|
|
|
|
, m_notifier(nullptr)
|
2015-09-02 09:32:26 +00:00
|
|
|
, m_mutex(QMutex::Recursive)
|
2014-08-14 12:43:57 +00:00
|
|
|
{
|
|
|
|
Q_ASSERT(m_input);
|
2016-05-06 10:28:07 +00:00
|
|
|
|
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2016-05-06 07:53:36 +00:00
|
|
|
// 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)));
|
2014-08-14 12:43:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Connection::~Connection()
|
|
|
|
{
|
|
|
|
s_self = nullptr;
|
|
|
|
delete s_context;
|
|
|
|
s_context = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::setup()
|
2015-09-02 09:32:26 +00:00
|
|
|
{
|
|
|
|
QMetaObject::invokeMethod(this, "doSetup", Qt::QueuedConnection);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::doSetup()
|
2014-08-14 12:43:57 +00:00
|
|
|
{
|
|
|
|
Q_ASSERT(!m_notifier);
|
|
|
|
m_notifier = new QSocketNotifier(m_input->fileDescriptor(), QSocketNotifier::Read, this);
|
|
|
|
connect(m_notifier, &QSocketNotifier::activated, this, &Connection::handleEvent);
|
2014-08-15 10:51:31 +00:00
|
|
|
|
|
|
|
LogindIntegration *logind = LogindIntegration::self();
|
|
|
|
connect(logind, &LogindIntegration::sessionActiveChanged, this,
|
|
|
|
[this](bool active) {
|
2015-03-31 07:16:16 +00:00
|
|
|
if (active) {
|
2015-04-15 15:47:56 +00:00
|
|
|
if (!m_input->isSuspended()) {
|
|
|
|
return;
|
|
|
|
}
|
2015-03-31 07:16:16 +00:00
|
|
|
m_input->resume();
|
2015-09-02 09:32:26 +00:00
|
|
|
wasSuspended = true;
|
2015-03-31 07:16:16 +00:00
|
|
|
} else {
|
2015-04-15 15:47:56 +00:00
|
|
|
deactivate();
|
2015-03-31 07:16:16 +00:00
|
|
|
}
|
2014-08-15 10:51:31 +00:00
|
|
|
}
|
|
|
|
);
|
2015-03-26 15:17:51 +00:00
|
|
|
handleEvent();
|
2014-08-14 12:43:57 +00:00
|
|
|
}
|
|
|
|
|
2015-04-15 15:47:56 +00:00
|
|
|
void Connection::deactivate()
|
|
|
|
{
|
|
|
|
if (m_input->isSuspended()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_keyboardBeforeSuspend = hasKeyboard();
|
2016-05-24 10:59:57 +00:00
|
|
|
m_alphaNumericKeyboardBeforeSuspend = hasAlphaNumericKeyboard();
|
2015-04-15 15:47:56 +00:00
|
|
|
m_pointerBeforeSuspend = hasPointer();
|
|
|
|
m_touchBeforeSuspend = hasTouch();
|
|
|
|
m_input->suspend();
|
|
|
|
handleEvent();
|
|
|
|
}
|
|
|
|
|
2014-08-14 12:43:57 +00:00
|
|
|
void Connection::handleEvent()
|
|
|
|
{
|
2015-09-02 09:32:26 +00:00
|
|
|
QMutexLocker locker(&m_mutex);
|
|
|
|
const bool wasEmpty = m_eventQueue.isEmpty();
|
2014-08-14 12:43:57 +00:00
|
|
|
do {
|
|
|
|
m_input->dispatch();
|
2015-09-02 09:32:26 +00:00
|
|
|
Event *event = m_input->event();
|
|
|
|
if (!event) {
|
2014-08-14 12:43:57 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-09-02 09:32:26 +00:00
|
|
|
m_eventQueue << event;
|
|
|
|
} while (true);
|
|
|
|
if (wasEmpty && !m_eventQueue.isEmpty()) {
|
|
|
|
emit eventsRead();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::processEvents()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&m_mutex);
|
|
|
|
while (!m_eventQueue.isEmpty()) {
|
|
|
|
QScopedPointer<Event> event(m_eventQueue.takeFirst());
|
2014-08-14 12:43:57 +00:00
|
|
|
switch (event->type()) {
|
[libinput] Add a wrapper class Device for a libinput_device
Summary:
The Device class wraps all the information we can get from libinput
about the device, like whether it's a keyboard, pointer, touch, etc.
In addition some more information is queried to figure out how "useful"
a device is. For a keyboard all alphanumeric keys are checked whether
they exist, for a pointer all (normal) buttons are queried.
All the information is exposed as Q_PROPERTY and used by the
DebugConsole. The DebugConsole gained a new tab "Input Devices" which
renders all devices and their properties in a tree view. When plugging
in/out a device, the model gets reset, so it's always up to date.
The new Device class can be used in future to configure the device,
e.g. disable touch pad, set mouse acceleration, etc.
Reviewers: #plasma
Subscribers: plasma-devel
Projects: #plasma
Differential Revision: https://phabricator.kde.org/D1538
2016-05-04 11:42:26 +00:00
|
|
|
case LIBINPUT_EVENT_DEVICE_ADDED: {
|
2016-06-02 11:18:28 +00:00
|
|
|
auto device = new Device(event->nativeDevice());
|
|
|
|
device->moveToThread(s_thread);
|
|
|
|
device->setParent(this);
|
[libinput] Add a wrapper class Device for a libinput_device
Summary:
The Device class wraps all the information we can get from libinput
about the device, like whether it's a keyboard, pointer, touch, etc.
In addition some more information is queried to figure out how "useful"
a device is. For a keyboard all alphanumeric keys are checked whether
they exist, for a pointer all (normal) buttons are queried.
All the information is exposed as Q_PROPERTY and used by the
DebugConsole. The DebugConsole gained a new tab "Input Devices" which
renders all devices and their properties in a tree view. When plugging
in/out a device, the model gets reset, so it's always up to date.
The new Device class can be used in future to configure the device,
e.g. disable touch pad, set mouse acceleration, etc.
Reviewers: #plasma
Subscribers: plasma-devel
Projects: #plasma
Differential Revision: https://phabricator.kde.org/D1538
2016-05-04 11:42:26 +00:00
|
|
|
m_devices << device;
|
|
|
|
if (device->isKeyboard()) {
|
2015-03-26 15:19:26 +00:00
|
|
|
m_keyboard++;
|
2016-05-24 10:59:57 +00:00
|
|
|
if (device->isAlphaNumericKeyboard()) {
|
|
|
|
m_alphaNumericKeyboard++;
|
|
|
|
if (m_alphaNumericKeyboard == 1) {
|
|
|
|
emit hasAlphaNumericKeyboardChanged(true);
|
|
|
|
}
|
|
|
|
}
|
2015-03-26 15:19:26 +00:00
|
|
|
if (m_keyboard == 1) {
|
|
|
|
emit hasKeyboardChanged(true);
|
|
|
|
}
|
|
|
|
}
|
[libinput] Add a wrapper class Device for a libinput_device
Summary:
The Device class wraps all the information we can get from libinput
about the device, like whether it's a keyboard, pointer, touch, etc.
In addition some more information is queried to figure out how "useful"
a device is. For a keyboard all alphanumeric keys are checked whether
they exist, for a pointer all (normal) buttons are queried.
All the information is exposed as Q_PROPERTY and used by the
DebugConsole. The DebugConsole gained a new tab "Input Devices" which
renders all devices and their properties in a tree view. When plugging
in/out a device, the model gets reset, so it's always up to date.
The new Device class can be used in future to configure the device,
e.g. disable touch pad, set mouse acceleration, etc.
Reviewers: #plasma
Subscribers: plasma-devel
Projects: #plasma
Differential Revision: https://phabricator.kde.org/D1538
2016-05-04 11:42:26 +00:00
|
|
|
if (device->isPointer()) {
|
2015-03-26 15:19:26 +00:00
|
|
|
m_pointer++;
|
|
|
|
if (m_pointer == 1) {
|
|
|
|
emit hasPointerChanged(true);
|
|
|
|
}
|
|
|
|
}
|
[libinput] Add a wrapper class Device for a libinput_device
Summary:
The Device class wraps all the information we can get from libinput
about the device, like whether it's a keyboard, pointer, touch, etc.
In addition some more information is queried to figure out how "useful"
a device is. For a keyboard all alphanumeric keys are checked whether
they exist, for a pointer all (normal) buttons are queried.
All the information is exposed as Q_PROPERTY and used by the
DebugConsole. The DebugConsole gained a new tab "Input Devices" which
renders all devices and their properties in a tree view. When plugging
in/out a device, the model gets reset, so it's always up to date.
The new Device class can be used in future to configure the device,
e.g. disable touch pad, set mouse acceleration, etc.
Reviewers: #plasma
Subscribers: plasma-devel
Projects: #plasma
Differential Revision: https://phabricator.kde.org/D1538
2016-05-04 11:42:26 +00:00
|
|
|
if (device->isTouch()) {
|
2015-03-26 15:19:26 +00:00
|
|
|
m_touch++;
|
|
|
|
if (m_touch == 1) {
|
|
|
|
emit hasTouchChanged(true);
|
|
|
|
}
|
|
|
|
}
|
2016-05-06 07:53:36 +00:00
|
|
|
applyDeviceConfig(device);
|
[libinput] Add a wrapper class Device for a libinput_device
Summary:
The Device class wraps all the information we can get from libinput
about the device, like whether it's a keyboard, pointer, touch, etc.
In addition some more information is queried to figure out how "useful"
a device is. For a keyboard all alphanumeric keys are checked whether
they exist, for a pointer all (normal) buttons are queried.
All the information is exposed as Q_PROPERTY and used by the
DebugConsole. The DebugConsole gained a new tab "Input Devices" which
renders all devices and their properties in a tree view. When plugging
in/out a device, the model gets reset, so it's always up to date.
The new Device class can be used in future to configure the device,
e.g. disable touch pad, set mouse acceleration, etc.
Reviewers: #plasma
Subscribers: plasma-devel
Projects: #plasma
Differential Revision: https://phabricator.kde.org/D1538
2016-05-04 11:42:26 +00:00
|
|
|
emit deviceAdded(device);
|
2015-03-26 15:19:26 +00:00
|
|
|
break;
|
[libinput] Add a wrapper class Device for a libinput_device
Summary:
The Device class wraps all the information we can get from libinput
about the device, like whether it's a keyboard, pointer, touch, etc.
In addition some more information is queried to figure out how "useful"
a device is. For a keyboard all alphanumeric keys are checked whether
they exist, for a pointer all (normal) buttons are queried.
All the information is exposed as Q_PROPERTY and used by the
DebugConsole. The DebugConsole gained a new tab "Input Devices" which
renders all devices and their properties in a tree view. When plugging
in/out a device, the model gets reset, so it's always up to date.
The new Device class can be used in future to configure the device,
e.g. disable touch pad, set mouse acceleration, etc.
Reviewers: #plasma
Subscribers: plasma-devel
Projects: #plasma
Differential Revision: https://phabricator.kde.org/D1538
2016-05-04 11:42:26 +00:00
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_DEVICE_REMOVED: {
|
2016-05-24 08:01:48 +00:00
|
|
|
auto it = std::find_if(m_devices.begin(), m_devices.end(), [&event] (Device *d) { return event->device() == d; } );
|
[libinput] Add a wrapper class Device for a libinput_device
Summary:
The Device class wraps all the information we can get from libinput
about the device, like whether it's a keyboard, pointer, touch, etc.
In addition some more information is queried to figure out how "useful"
a device is. For a keyboard all alphanumeric keys are checked whether
they exist, for a pointer all (normal) buttons are queried.
All the information is exposed as Q_PROPERTY and used by the
DebugConsole. The DebugConsole gained a new tab "Input Devices" which
renders all devices and their properties in a tree view. When plugging
in/out a device, the model gets reset, so it's always up to date.
The new Device class can be used in future to configure the device,
e.g. disable touch pad, set mouse acceleration, etc.
Reviewers: #plasma
Subscribers: plasma-devel
Projects: #plasma
Differential Revision: https://phabricator.kde.org/D1538
2016-05-04 11:42:26 +00:00
|
|
|
if (it == m_devices.end()) {
|
|
|
|
// we don't know this device
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
auto device = *it;
|
|
|
|
m_devices.erase(it);
|
|
|
|
emit deviceRemoved(device);
|
|
|
|
|
|
|
|
if (device->isKeyboard()) {
|
2015-03-26 15:19:26 +00:00
|
|
|
m_keyboard--;
|
2016-05-24 10:59:57 +00:00
|
|
|
if (device->isAlphaNumericKeyboard()) {
|
|
|
|
m_alphaNumericKeyboard--;
|
|
|
|
if (m_alphaNumericKeyboard == 0) {
|
|
|
|
emit hasAlphaNumericKeyboardChanged(false);
|
|
|
|
}
|
|
|
|
}
|
2015-03-26 15:19:26 +00:00
|
|
|
if (m_keyboard == 0) {
|
|
|
|
emit hasKeyboardChanged(false);
|
|
|
|
}
|
|
|
|
}
|
[libinput] Add a wrapper class Device for a libinput_device
Summary:
The Device class wraps all the information we can get from libinput
about the device, like whether it's a keyboard, pointer, touch, etc.
In addition some more information is queried to figure out how "useful"
a device is. For a keyboard all alphanumeric keys are checked whether
they exist, for a pointer all (normal) buttons are queried.
All the information is exposed as Q_PROPERTY and used by the
DebugConsole. The DebugConsole gained a new tab "Input Devices" which
renders all devices and their properties in a tree view. When plugging
in/out a device, the model gets reset, so it's always up to date.
The new Device class can be used in future to configure the device,
e.g. disable touch pad, set mouse acceleration, etc.
Reviewers: #plasma
Subscribers: plasma-devel
Projects: #plasma
Differential Revision: https://phabricator.kde.org/D1538
2016-05-04 11:42:26 +00:00
|
|
|
if (device->isPointer()) {
|
2015-03-26 15:19:26 +00:00
|
|
|
m_pointer--;
|
|
|
|
if (m_pointer == 0) {
|
|
|
|
emit hasPointerChanged(false);
|
|
|
|
}
|
|
|
|
}
|
[libinput] Add a wrapper class Device for a libinput_device
Summary:
The Device class wraps all the information we can get from libinput
about the device, like whether it's a keyboard, pointer, touch, etc.
In addition some more information is queried to figure out how "useful"
a device is. For a keyboard all alphanumeric keys are checked whether
they exist, for a pointer all (normal) buttons are queried.
All the information is exposed as Q_PROPERTY and used by the
DebugConsole. The DebugConsole gained a new tab "Input Devices" which
renders all devices and their properties in a tree view. When plugging
in/out a device, the model gets reset, so it's always up to date.
The new Device class can be used in future to configure the device,
e.g. disable touch pad, set mouse acceleration, etc.
Reviewers: #plasma
Subscribers: plasma-devel
Projects: #plasma
Differential Revision: https://phabricator.kde.org/D1538
2016-05-04 11:42:26 +00:00
|
|
|
if (device->isTouch()) {
|
2015-03-26 15:19:26 +00:00
|
|
|
m_touch--;
|
|
|
|
if (m_touch == 0) {
|
|
|
|
emit hasTouchChanged(false);
|
|
|
|
}
|
|
|
|
}
|
2016-06-02 11:18:28 +00:00
|
|
|
device->deleteLater();
|
2015-03-26 15:19:26 +00:00
|
|
|
break;
|
[libinput] Add a wrapper class Device for a libinput_device
Summary:
The Device class wraps all the information we can get from libinput
about the device, like whether it's a keyboard, pointer, touch, etc.
In addition some more information is queried to figure out how "useful"
a device is. For a keyboard all alphanumeric keys are checked whether
they exist, for a pointer all (normal) buttons are queried.
All the information is exposed as Q_PROPERTY and used by the
DebugConsole. The DebugConsole gained a new tab "Input Devices" which
renders all devices and their properties in a tree view. When plugging
in/out a device, the model gets reset, so it's always up to date.
The new Device class can be used in future to configure the device,
e.g. disable touch pad, set mouse acceleration, etc.
Reviewers: #plasma
Subscribers: plasma-devel
Projects: #plasma
Differential Revision: https://phabricator.kde.org/D1538
2016-05-04 11:42:26 +00:00
|
|
|
}
|
2014-08-14 12:43:57 +00:00
|
|
|
case LIBINPUT_EVENT_KEYBOARD_KEY: {
|
|
|
|
KeyEvent *ke = static_cast<KeyEvent*>(event.data());
|
2016-05-24 08:57:57 +00:00
|
|
|
emit keyChanged(ke->key(), ke->state(), ke->time(), ke->device());
|
2014-08-14 12:43:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_POINTER_AXIS: {
|
|
|
|
PointerEvent *pe = static_cast<PointerEvent*>(event.data());
|
2015-09-02 09:49:51 +00:00
|
|
|
struct Axis {
|
|
|
|
qreal delta = 0.0;
|
|
|
|
quint32 time = 0;
|
|
|
|
};
|
|
|
|
QMap<InputRedirection::PointerAxis, Axis> deltas;
|
|
|
|
auto update = [&deltas] (PointerEvent *pe) {
|
|
|
|
const auto axis = pe->axis();
|
|
|
|
for (auto it = axis.begin(); it != axis.end(); ++it) {
|
|
|
|
deltas[*it].delta += pe->axisValue(*it);
|
|
|
|
deltas[*it].time = pe->time();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
update(pe);
|
|
|
|
auto it = m_eventQueue.begin();
|
|
|
|
while (it != m_eventQueue.end()) {
|
|
|
|
if ((*it)->type() == LIBINPUT_EVENT_POINTER_AXIS) {
|
|
|
|
QScopedPointer<PointerEvent> p(static_cast<PointerEvent*>(*it));
|
|
|
|
update(p.data());
|
|
|
|
it = m_eventQueue.erase(it);
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (auto it = deltas.constBegin(); it != deltas.constEnd(); ++it) {
|
2016-05-24 08:57:57 +00:00
|
|
|
emit pointerAxisChanged(it.key(), it.value().delta, it.value().time, pe->device());
|
2015-03-20 11:42:57 +00:00
|
|
|
}
|
2014-08-14 12:43:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_POINTER_BUTTON: {
|
|
|
|
PointerEvent *pe = static_cast<PointerEvent*>(event.data());
|
2016-05-24 08:57:57 +00:00
|
|
|
emit pointerButtonChanged(pe->button(), pe->buttonState(), pe->time(), pe->device());
|
2014-08-14 12:43:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_POINTER_MOTION: {
|
|
|
|
PointerEvent *pe = static_cast<PointerEvent*>(event.data());
|
2015-09-02 09:36:36 +00:00
|
|
|
QPointF delta = pe->delta();
|
|
|
|
quint32 latestTime = pe->time();
|
|
|
|
auto it = m_eventQueue.begin();
|
|
|
|
while (it != m_eventQueue.end()) {
|
|
|
|
if ((*it)->type() == LIBINPUT_EVENT_POINTER_MOTION) {
|
|
|
|
QScopedPointer<PointerEvent> p(static_cast<PointerEvent*>(*it));
|
|
|
|
delta += p->delta();
|
|
|
|
latestTime = p->time();
|
|
|
|
it = m_eventQueue.erase(it);
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-05-24 08:57:57 +00:00
|
|
|
emit pointerMotion(delta, latestTime, pe->device());
|
2014-08-14 12:43:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: {
|
|
|
|
PointerEvent *pe = static_cast<PointerEvent*>(event.data());
|
2016-05-24 08:57:57 +00:00
|
|
|
emit pointerMotionAbsolute(pe->absolutePos(), pe->absolutePos(m_size), pe->time(), pe->device());
|
2014-08-14 12:43:57 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-03-25 15:30:47 +00:00
|
|
|
case LIBINPUT_EVENT_TOUCH_DOWN: {
|
|
|
|
TouchEvent *te = static_cast<TouchEvent*>(event.data());
|
2016-05-24 08:57:57 +00:00
|
|
|
emit touchDown(te->id(), te->absolutePos(m_size), te->time(), te->device());
|
2015-03-25 15:30:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_TOUCH_UP: {
|
|
|
|
TouchEvent *te = static_cast<TouchEvent*>(event.data());
|
2016-05-24 08:57:57 +00:00
|
|
|
emit touchUp(te->id(), te->time(), te->device());
|
2015-03-25 15:30:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_TOUCH_MOTION: {
|
|
|
|
TouchEvent *te = static_cast<TouchEvent*>(event.data());
|
2016-05-24 08:57:57 +00:00
|
|
|
emit touchMotion(te->id(), te->absolutePos(m_size), te->time(), te->device());
|
2015-03-25 15:30:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_TOUCH_CANCEL: {
|
2016-05-24 08:57:57 +00:00
|
|
|
emit touchCanceled(event->device());
|
2015-03-25 15:30:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_TOUCH_FRAME: {
|
2016-05-24 08:57:57 +00:00
|
|
|
emit touchFrame(event->device());
|
2015-03-25 15:30:47 +00:00
|
|
|
break;
|
|
|
|
}
|
2014-08-14 12:43:57 +00:00
|
|
|
default:
|
|
|
|
// nothing
|
|
|
|
break;
|
|
|
|
}
|
2015-09-02 09:32:26 +00:00
|
|
|
}
|
|
|
|
if (wasSuspended) {
|
|
|
|
if (m_keyboardBeforeSuspend && !m_keyboard) {
|
|
|
|
emit hasKeyboardChanged(false);
|
|
|
|
}
|
2016-05-25 11:28:14 +00:00
|
|
|
if (m_alphaNumericKeyboardBeforeSuspend && !m_alphaNumericKeyboard) {
|
2016-05-24 10:59:57 +00:00
|
|
|
emit hasAlphaNumericKeyboardChanged(false);
|
|
|
|
}
|
2015-09-02 09:32:26 +00:00
|
|
|
if (m_pointerBeforeSuspend && !m_pointer) {
|
|
|
|
emit hasPointerChanged(false);
|
|
|
|
}
|
|
|
|
if (m_touchBeforeSuspend && !m_touch) {
|
|
|
|
emit hasTouchChanged(false);
|
|
|
|
}
|
|
|
|
wasSuspended = false;
|
|
|
|
}
|
2014-08-14 12:43:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::setScreenSize(const QSize &size)
|
|
|
|
{
|
|
|
|
m_size = size;
|
|
|
|
}
|
|
|
|
|
2015-03-31 07:16:16 +00:00
|
|
|
bool Connection::isSuspended() const
|
|
|
|
{
|
|
|
|
if (!s_context) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return s_context->isSuspended();
|
|
|
|
}
|
|
|
|
|
2016-05-06 07:53:36 +00:00
|
|
|
void Connection::applyDeviceConfig(Device *device)
|
|
|
|
{
|
|
|
|
if (device->isPointer()) {
|
2016-05-06 09:25:11 +00:00
|
|
|
const KConfigGroup group = m_config->group("Mouse");
|
|
|
|
device->setLeftHanded(group.readEntry("MouseButtonMapping", "RightHanded") == QLatin1String("LeftHanded"));
|
|
|
|
qreal accel = group.readEntry("Acceleration", -1.0);
|
|
|
|
if (qFuzzyCompare(accel, -1.0) || qFuzzyCompare(accel, 1.0)) {
|
|
|
|
// default value
|
|
|
|
device->setPointerAcceleration(0.0);
|
|
|
|
} else {
|
|
|
|
// the X11-based config is mapped in [0.1,20.0] with 1.0 being the "normal" setting - we assume that's the default
|
|
|
|
if (accel < 1.0) {
|
|
|
|
device->setPointerAcceleration(-1.0 + ((accel * 10.0) - 1.0) / 9.0);
|
|
|
|
} else {
|
|
|
|
device->setPointerAcceleration((accel -1.0)/19.0);
|
|
|
|
}
|
|
|
|
}
|
2016-05-06 07:53:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::slotKGlobalSettingsNotifyChange(int type, int arg)
|
|
|
|
{
|
|
|
|
if (type == 3 /**SettingsChanged**/ && arg == 0 /** SETTINGS_MOUSE **/) {
|
|
|
|
m_config->reparseConfiguration();
|
|
|
|
for (auto it = m_devices.constBegin(), end = m_devices.constEnd(); it != end; ++it) {
|
|
|
|
if ((*it)->isPointer()) {
|
|
|
|
applyDeviceConfig(*it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-06 10:28:07 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-14 12:43:57 +00:00
|
|
|
}
|
|
|
|
}
|