2020-08-02 22:22:19 +00:00
|
|
|
/*
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
2014-08-14 12:43:57 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
2014-08-14 12:43:57 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
2014-08-14 12:43:57 +00:00
|
|
|
#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"
|
2019-12-12 14:41:12 +00:00
|
|
|
|
|
|
|
// TODO: Make it compile also in testing environment
|
2017-11-10 17:07:15 +00:00
|
|
|
#ifndef KWIN_BUILD_TESTING
|
2020-08-11 16:13:57 +00:00
|
|
|
#include "../abstract_wayland_output.h"
|
2019-12-12 14:41:12 +00:00
|
|
|
#include "../main.h"
|
|
|
|
#include "../platform.h"
|
2020-12-22 16:34:10 +00:00
|
|
|
#include "../workspace.h"
|
|
|
|
#include "../abstract_client.h"
|
2017-11-10 17:07:15 +00:00
|
|
|
#include "../screens.h"
|
|
|
|
#endif
|
2019-12-12 14:41:12 +00:00
|
|
|
|
2020-11-20 01:28:05 +00:00
|
|
|
#include "../input_event.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 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>
|
2017-12-24 11:54:27 +00:00
|
|
|
#include <cmath>
|
2014-08-14 12:43:57 +00:00
|
|
|
|
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
namespace LibInput
|
|
|
|
{
|
|
|
|
|
2017-01-12 07:16:04 +00:00
|
|
|
class ConnectionAdaptor : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.InputDeviceManager")
|
|
|
|
Q_PROPERTY(QStringList devicesSysNames READ devicesSysNames CONSTANT)
|
|
|
|
|
|
|
|
private:
|
|
|
|
Connection *m_con;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ConnectionAdaptor(Connection *con)
|
|
|
|
: m_con(con)
|
|
|
|
{
|
|
|
|
connect(con, &Connection::deviceAddedSysName, this, &ConnectionAdaptor::deviceAdded, Qt::QueuedConnection);
|
|
|
|
connect(con, &Connection::deviceRemovedSysName, this, &ConnectionAdaptor::deviceRemoved, Qt::QueuedConnection);
|
|
|
|
|
|
|
|
QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin/InputDevice"),
|
|
|
|
QStringLiteral("org.kde.KWin.InputDeviceManager"),
|
|
|
|
this,
|
|
|
|
QDBusConnection::ExportAllProperties | QDBusConnection::ExportAllSignals
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
Run clang-tidy with modernize-use-override check
Summary:
Currently code base of kwin can be viewed as two pieces. One is very
ancient, and the other one is more modern, which uses new C++ features.
The main problem with the ancient code is that it was written before
C++11 era. So, no override or final keywords, lambdas, etc.
Quite recently, KDE compiler settings were changed to show a warning if
a virtual method has missing override keyword. As you might have already
guessed, this fired back at us because of that ancient code. We had
about 500 new compiler warnings.
A "solution" was proposed to that problem - disable -Wno-suggest-override
and the other similar warning for clang. It's hard to call a solution
because those warnings are disabled not only for the old code, but also
for new. This is not what we want!
The main argument for not actually fixing the problem was that git
history will be screwed as well because of human factor. While good git
history is a very important thing, we should not go crazy about it and
block every change that somehow alters git history. git blame allows to
specify starting revision for a reason.
The other argument (human factor) can be easily solved by using tools
such as clang-tidy. clang-tidy is a clang-based linter for C++. It can
be used for various things, e.g. fixing coding style(e.g. add missing
braces to if statements, readability-braces-around-statements check),
or in our case add missing override keywords.
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, apol, romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D22371
2019-07-22 16:52:26 +00:00
|
|
|
~ConnectionAdaptor() override {
|
2017-01-12 07:16:04 +00:00
|
|
|
QDBusConnection::sessionBus().unregisterObject(QStringLiteral("/org/kde/KWin/InputDeviceManager"));
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList devicesSysNames() {
|
|
|
|
// TODO: is this allowed? directly calling function of object in another thread!?
|
|
|
|
// otherwise use signal-slot mechanism
|
|
|
|
return m_con->devicesSysNames();
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_SIGNALS:
|
|
|
|
void deviceAdded(QString sysName);
|
|
|
|
void deviceRemoved(QString sysName);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2014-08-14 12:43:57 +00:00
|
|
|
Connection *Connection::s_self = nullptr;
|
2017-09-30 07:36:30 +00:00
|
|
|
QPointer<QThread> Connection::s_thread;
|
2014-08-14 12:43:57 +00:00
|
|
|
|
2017-01-12 07:16:04 +00:00
|
|
|
static ConnectionAdaptor *s_adaptor = nullptr;
|
2014-08-14 12:43:57 +00:00
|
|
|
static Context *s_context = nullptr;
|
|
|
|
|
2016-10-05 09:50:20 +00:00
|
|
|
static quint32 toLibinputLEDS(Xkb::LEDs leds)
|
|
|
|
{
|
|
|
|
quint32 libinputLeds = 0;
|
|
|
|
if (leds.testFlag(Xkb::LED::NumLock)) {
|
|
|
|
libinputLeds = libinputLeds | LIBINPUT_LED_NUM_LOCK;
|
|
|
|
}
|
|
|
|
if (leds.testFlag(Xkb::LED::CapsLock)) {
|
|
|
|
libinputLeds = libinputLeds | LIBINPUT_LED_CAPS_LOCK;
|
|
|
|
}
|
|
|
|
if (leds.testFlag(Xkb::LED::ScrollLock)) {
|
|
|
|
libinputLeds = libinputLeds | LIBINPUT_LED_SCROLL_LOCK;
|
|
|
|
}
|
|
|
|
return libinputLeds;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2017-09-30 07:36:30 +00:00
|
|
|
void Connection::createThread()
|
|
|
|
{
|
|
|
|
if (s_thread) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
s_thread = new QThread();
|
|
|
|
s_thread->setObjectName(QStringLiteral("libinput-connection"));
|
|
|
|
s_thread->start();
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
2018-04-22 15:28:05 +00:00
|
|
|
if (!s_context->assignSeat(LogindIntegration::self()->seat().toUtf8().constData())) {
|
|
|
|
qCWarning(KWIN_LIBINPUT) << "Failed to assign seat" << LogindIntegration::self()->seat();
|
2014-08-14 12:43:57 +00:00
|
|
|
delete s_context;
|
|
|
|
s_context = nullptr;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
2017-09-30 07:36:30 +00:00
|
|
|
Connection::createThread();
|
2015-09-02 08:12:18 +00:00
|
|
|
s_self = new Connection(s_context);
|
|
|
|
s_self->moveToThread(s_thread);
|
|
|
|
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);
|
2017-01-12 07:16:04 +00:00
|
|
|
if (!s_adaptor) {
|
|
|
|
s_adaptor = new ConnectionAdaptor(s_self);
|
|
|
|
}
|
2016-12-02 13:58:56 +00:00
|
|
|
|
2014-08-14 12:43:57 +00:00
|
|
|
return s_self;
|
|
|
|
}
|
|
|
|
|
2016-05-06 10:28:07 +00:00
|
|
|
|
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)
|
2016-10-05 09:50:20 +00:00
|
|
|
, m_leds()
|
2014-08-14 12:43:57 +00:00
|
|
|
{
|
|
|
|
Q_ASSERT(m_input);
|
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()
|
|
|
|
{
|
2017-01-12 07:16:04 +00:00
|
|
|
delete s_adaptor;
|
|
|
|
s_adaptor = nullptr;
|
2014-08-14 12:43:57 +00:00
|
|
|
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
|
|
|
{
|
2017-01-12 07:16:04 +00:00
|
|
|
connect(s_self, &Connection::deviceAdded, s_self, [](Device* device) {
|
|
|
|
emit s_self->deviceAddedSysName(device->sysName());
|
|
|
|
});
|
|
|
|
connect(s_self, &Connection::deviceRemoved, s_self, [](Device* device) {
|
|
|
|
emit s_self->deviceRemovedSysName(device->sysName());
|
|
|
|
});
|
|
|
|
|
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();
|
Expose if the tablet mode switch is available
Summary:
expose in the libinput wrapper a property that tells whether
a tablet mode switch input device is present on the machine,
expose it trough dbus
Test Plan:
still not complete, I need a way to either access the connection
from TabletModeManager or setting to TabletModeManager from input.cpp
Reviewers: #kwin, #plasma, graesslin
Reviewed By: #kwin, #plasma, graesslin
Subscribers: graesslin, ngraham, davidedmundson, plasma-devel, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D9944
2018-01-24 10:36:56 +00:00
|
|
|
m_tabletModeSwitchBeforeSuspend = hasTabletModeSwitch();
|
2015-04-15 15:47:56 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-12 14:41:12 +00:00
|
|
|
#ifndef KWIN_BUILD_TESTING
|
|
|
|
QPointF devicePointToGlobalPosition(const QPointF &devicePos, const AbstractWaylandOutput *output)
|
|
|
|
{
|
|
|
|
using Transform = AbstractWaylandOutput::Transform;
|
|
|
|
|
|
|
|
QPointF pos = devicePos;
|
|
|
|
// TODO: Do we need to handle the flipped cases differently?
|
|
|
|
switch (output->transform()) {
|
|
|
|
case Transform::Normal:
|
|
|
|
case Transform::Flipped:
|
|
|
|
break;
|
|
|
|
case Transform::Rotated90:
|
|
|
|
case Transform::Flipped90:
|
|
|
|
pos = QPointF(output->modeSize().height() - devicePos.y(), devicePos.x());
|
|
|
|
break;
|
|
|
|
case Transform::Rotated180:
|
|
|
|
case Transform::Flipped180:
|
|
|
|
pos = QPointF(output->modeSize().width() - devicePos.x(),
|
|
|
|
output->modeSize().height() - devicePos.y());
|
|
|
|
break;
|
|
|
|
case Transform::Rotated270:
|
|
|
|
case Transform::Flipped270:
|
|
|
|
pos = QPointF(devicePos.y(), output->modeSize().width() - devicePos.x());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Q_UNREACHABLE();
|
|
|
|
}
|
|
|
|
return output->geometry().topLeft() + pos / output->scale();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-12-22 16:34:10 +00:00
|
|
|
KWin::TabletToolId createTabletId(libinput_tablet_tool *tool, void *userData)
|
2020-11-20 01:28:05 +00:00
|
|
|
{
|
|
|
|
auto serial = libinput_tablet_tool_get_serial(tool);
|
|
|
|
auto toolId = libinput_tablet_tool_get_tool_id(tool);
|
|
|
|
auto type = libinput_tablet_tool_get_type(tool);
|
|
|
|
InputRedirection::TabletToolType toolType;
|
|
|
|
switch (type) {
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_PEN:
|
|
|
|
toolType = InputRedirection::Pen;
|
|
|
|
break;
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_ERASER:
|
|
|
|
toolType = InputRedirection::Eraser;
|
|
|
|
break;
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:
|
|
|
|
toolType = InputRedirection::Brush;
|
|
|
|
break;
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
|
|
|
|
toolType = InputRedirection::Pencil;
|
|
|
|
break;
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
|
|
|
|
toolType = InputRedirection::Airbrush;
|
|
|
|
break;
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
|
|
|
|
toolType = InputRedirection::Mouse;
|
|
|
|
break;
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_LENS:
|
|
|
|
toolType = InputRedirection::Lens;
|
|
|
|
break;
|
|
|
|
#ifdef LIBINPUT_HAS_TOTEM
|
|
|
|
case LIBINPUT_TABLET_TOOL_TYPE_TOTEM:
|
|
|
|
toolType = InputRedirection::Totem;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
QVector<InputRedirection::Capability> capabilities;
|
|
|
|
if (libinput_tablet_tool_has_pressure(tool)) {
|
|
|
|
capabilities << InputRedirection::Pressure;
|
|
|
|
}
|
|
|
|
if (libinput_tablet_tool_has_distance(tool)) {
|
|
|
|
capabilities << InputRedirection::Distance;
|
|
|
|
}
|
|
|
|
if (libinput_tablet_tool_has_rotation(tool)) {
|
|
|
|
capabilities << InputRedirection::Rotation;
|
|
|
|
}
|
|
|
|
if (libinput_tablet_tool_has_tilt(tool)) {
|
|
|
|
capabilities << InputRedirection::Tilt;
|
|
|
|
}
|
|
|
|
if (libinput_tablet_tool_has_slider(tool)) {
|
|
|
|
capabilities << InputRedirection::Slider;
|
|
|
|
}
|
|
|
|
if (libinput_tablet_tool_has_wheel(tool)) {
|
|
|
|
capabilities << InputRedirection::Wheel;
|
|
|
|
}
|
2020-12-22 16:34:10 +00:00
|
|
|
return {toolType, capabilities, serial, toolId, userData};
|
2020-11-20 01:28:05 +00:00
|
|
|
}
|
|
|
|
|
2015-09-02 09:32:26 +00:00
|
|
|
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);
|
[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);
|
|
|
|
}
|
|
|
|
}
|
Expose if the tablet mode switch is available
Summary:
expose in the libinput wrapper a property that tells whether
a tablet mode switch input device is present on the machine,
expose it trough dbus
Test Plan:
still not complete, I need a way to either access the connection
from TabletModeManager or setting to TabletModeManager from input.cpp
Reviewers: #kwin, #plasma, graesslin
Reviewed By: #kwin, #plasma, graesslin
Subscribers: graesslin, ngraham, davidedmundson, plasma-devel, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D9944
2018-01-24 10:36:56 +00:00
|
|
|
if (device->isTabletModeSwitch()) {
|
|
|
|
m_tabletModeSwitch++;
|
|
|
|
if (m_tabletModeSwitch == 1) {
|
|
|
|
emit hasTabletModeSwitchChanged(true);
|
|
|
|
}
|
|
|
|
}
|
2016-05-06 07:53:36 +00:00
|
|
|
applyDeviceConfig(device);
|
2017-11-10 17:07:15 +00:00
|
|
|
applyScreenToDevice(device);
|
2016-10-05 09:50:20 +00:00
|
|
|
|
|
|
|
// enable possible leds
|
|
|
|
libinput_device_led_update(device->device(), static_cast<libinput_led>(toLibinputLEDS(m_leds)));
|
|
|
|
|
[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);
|
|
|
|
}
|
|
|
|
}
|
Expose if the tablet mode switch is available
Summary:
expose in the libinput wrapper a property that tells whether
a tablet mode switch input device is present on the machine,
expose it trough dbus
Test Plan:
still not complete, I need a way to either access the connection
from TabletModeManager or setting to TabletModeManager from input.cpp
Reviewers: #kwin, #plasma, graesslin
Reviewed By: #kwin, #plasma, graesslin
Subscribers: graesslin, ngraham, davidedmundson, plasma-devel, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D9944
2018-01-24 10:36:56 +00:00
|
|
|
if (device->isTabletModeSwitch()) {
|
|
|
|
m_tabletModeSwitch--;
|
|
|
|
if (m_tabletModeSwitch == 0) {
|
|
|
|
emit hasTabletModeSwitchChanged(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());
|
Send axis_source, axis_discrete, and axis_stop
Summary:
So far KWin didn't send axis_source, axis_discrete, and axis_stop. Even
though most of those events are optional, clients need them to work as
expected. For example, one needs axis_source and axis_stop to implement
kinetic scrolling; Xwayland needs axis_discrete to prevent multiple
scroll events when the compositor sends axis deltas greater than 10, etc.
BUG: 404152
FIXED-IN: 5.17.0
Test Plan:
* Content of a webpage in Firefox is moved by one line per each mouse
wheel "click";
* Scrolled gedit using 2 fingers on GNOME Shell, sway, and KDE Plasma;
in all three cases wayland debug looked the same (except diagonal scroll
motions).
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19000
2019-02-12 09:14:51 +00:00
|
|
|
const auto axes = pe->axis();
|
|
|
|
for (const InputRedirection::PointerAxis &axis : axes) {
|
|
|
|
emit pointerAxisChanged(axis, pe->axisValue(axis), pe->discreteAxisValue(axis),
|
|
|
|
pe->axisSource(), pe->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());
|
2016-10-07 12:47:25 +00:00
|
|
|
auto delta = pe->delta();
|
|
|
|
auto deltaNonAccel = pe->deltaUnaccelerated();
|
2015-09-02 09:36:36 +00:00
|
|
|
quint32 latestTime = pe->time();
|
2016-10-07 12:47:25 +00:00
|
|
|
quint64 latestTimeUsec = pe->timeMicroseconds();
|
2015-09-02 09:36:36 +00:00
|
|
|
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();
|
2016-10-07 12:47:25 +00:00
|
|
|
deltaNonAccel += p->deltaUnaccelerated();
|
2015-09-02 09:36:36 +00:00
|
|
|
latestTime = p->time();
|
2016-10-07 12:47:25 +00:00
|
|
|
latestTimeUsec = p->timeMicroseconds();
|
2015-09-02 09:36:36 +00:00
|
|
|
it = m_eventQueue.erase(it);
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-10-07 12:47:25 +00:00
|
|
|
emit pointerMotion(delta, deltaNonAccel, latestTime, latestTimeUsec, 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: {
|
2017-11-10 17:07:15 +00:00
|
|
|
#ifndef KWIN_BUILD_TESTING
|
2015-03-25 15:30:47 +00:00
|
|
|
TouchEvent *te = static_cast<TouchEvent*>(event.data());
|
2019-12-12 14:41:12 +00:00
|
|
|
const auto *output = static_cast<AbstractWaylandOutput*>(
|
|
|
|
kwinApp()->platform()->enabledOutputs()[te->device()->screenId()]);
|
|
|
|
const QPointF globalPos =
|
|
|
|
devicePointToGlobalPosition(te->absolutePos(output->modeSize()),
|
|
|
|
output);
|
|
|
|
emit touchDown(te->id(), globalPos, te->time(), te->device());
|
2015-03-25 15:30:47 +00:00
|
|
|
break;
|
2017-11-10 17:07:15 +00:00
|
|
|
#endif
|
2015-03-25 15:30:47 +00:00
|
|
|
}
|
|
|
|
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: {
|
2017-11-10 17:07:15 +00:00
|
|
|
#ifndef KWIN_BUILD_TESTING
|
2015-03-25 15:30:47 +00:00
|
|
|
TouchEvent *te = static_cast<TouchEvent*>(event.data());
|
2019-12-12 14:41:12 +00:00
|
|
|
const auto *output = static_cast<AbstractWaylandOutput*>(
|
|
|
|
kwinApp()->platform()->enabledOutputs()[te->device()->screenId()]);
|
|
|
|
const QPointF globalPos =
|
|
|
|
devicePointToGlobalPosition(te->absolutePos(output->modeSize()),
|
|
|
|
output);
|
|
|
|
emit touchMotion(te->id(), globalPos, te->time(), te->device());
|
2015-03-25 15:30:47 +00:00
|
|
|
break;
|
2017-11-10 17:07:15 +00:00
|
|
|
#endif
|
2015-03-25 15:30:47 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
2016-08-05 12:35:33 +00:00
|
|
|
case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: {
|
|
|
|
PinchGestureEvent *pe = static_cast<PinchGestureEvent*>(event.data());
|
|
|
|
emit pinchGestureBegin(pe->fingerCount(), pe->time(), pe->device());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: {
|
|
|
|
PinchGestureEvent *pe = static_cast<PinchGestureEvent*>(event.data());
|
|
|
|
emit pinchGestureUpdate(pe->scale(), pe->angleDelta(), pe->delta(), pe->time(), pe->device());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_GESTURE_PINCH_END: {
|
|
|
|
PinchGestureEvent *pe = static_cast<PinchGestureEvent*>(event.data());
|
|
|
|
if (pe->isCancelled()) {
|
|
|
|
emit pinchGestureCancelled(pe->time(), pe->device());
|
|
|
|
} else {
|
|
|
|
emit pinchGestureEnd(pe->time(), pe->device());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: {
|
|
|
|
SwipeGestureEvent *se = static_cast<SwipeGestureEvent*>(event.data());
|
|
|
|
emit swipeGestureBegin(se->fingerCount(), se->time(), se->device());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: {
|
|
|
|
SwipeGestureEvent *se = static_cast<SwipeGestureEvent*>(event.data());
|
|
|
|
emit swipeGestureUpdate(se->delta(), se->time(), se->device());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_GESTURE_SWIPE_END: {
|
|
|
|
SwipeGestureEvent *se = static_cast<SwipeGestureEvent*>(event.data());
|
|
|
|
if (se->isCancelled()) {
|
|
|
|
emit swipeGestureCancelled(se->time(), se->device());
|
|
|
|
} else {
|
|
|
|
emit swipeGestureEnd(se->time(), se->device());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2017-12-27 16:57:00 +00:00
|
|
|
case LIBINPUT_EVENT_SWITCH_TOGGLE: {
|
|
|
|
SwitchEvent *se = static_cast<SwitchEvent*>(event.data());
|
|
|
|
switch (se->state()) {
|
|
|
|
case SwitchEvent::State::Off:
|
|
|
|
emit switchToggledOff(se->time(), se->timeMicroseconds(), se->device());
|
|
|
|
break;
|
|
|
|
case SwitchEvent::State::On:
|
|
|
|
emit switchToggledOn(se->time(), se->timeMicroseconds(), se->device());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Q_UNREACHABLE();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2019-12-01 17:51:15 +00:00
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_TIP: {
|
|
|
|
auto *tte = static_cast<TabletToolEvent *>(event.data());
|
|
|
|
|
|
|
|
KWin::InputRedirection::TabletEventType tabletEventType;
|
|
|
|
switch (event->type()) {
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
|
|
|
|
tabletEventType = KWin::InputRedirection::Axis;
|
|
|
|
break;
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
|
|
|
|
tabletEventType = KWin::InputRedirection::Proximity;
|
|
|
|
break;
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
|
|
|
|
default:
|
|
|
|
tabletEventType = KWin::InputRedirection::Tip;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-08-11 16:13:57 +00:00
|
|
|
#ifndef KWIN_BUILD_TESTING
|
2020-12-22 16:34:10 +00:00
|
|
|
auto client = workspace()->activeClient();
|
2020-07-26 16:07:56 +00:00
|
|
|
const auto *output = static_cast<AbstractWaylandOutput*>(
|
2020-12-22 16:34:10 +00:00
|
|
|
kwinApp()->platform()->enabledOutputs()[client->screen()]);
|
2020-07-26 16:07:56 +00:00
|
|
|
const QPointF globalPos =
|
|
|
|
devicePointToGlobalPosition(tte->transformedPosition(output->modeSize()),
|
|
|
|
output);
|
2020-08-11 16:13:57 +00:00
|
|
|
#else
|
|
|
|
const QPointF globalPos;
|
|
|
|
#endif
|
2019-12-01 17:51:15 +00:00
|
|
|
emit tabletToolEvent(tabletEventType,
|
2020-07-26 16:07:56 +00:00
|
|
|
globalPos, tte->pressure(),
|
2019-12-01 17:51:15 +00:00
|
|
|
tte->xTilt(), tte->yTilt(), tte->rotation(),
|
2020-12-22 16:34:10 +00:00
|
|
|
tte->isTipDown(), tte->isNearby(), createTabletId(tte->tool(), event->device()->groupUserData()), tte->time());
|
2019-12-01 17:51:15 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: {
|
|
|
|
auto *tabletEvent = static_cast<TabletToolButtonEvent *>(event.data());
|
|
|
|
emit tabletToolButtonEvent(tabletEvent->buttonId(),
|
2020-11-20 01:28:05 +00:00
|
|
|
tabletEvent->isButtonPressed(),
|
2020-12-22 16:34:10 +00:00
|
|
|
createTabletId(tabletEvent->tool(), event->device()->groupUserData()));
|
2019-12-01 17:51:15 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_TABLET_PAD_BUTTON: {
|
|
|
|
auto *tabletEvent = static_cast<TabletPadButtonEvent *>(event.data());
|
|
|
|
emit tabletPadButtonEvent(tabletEvent->buttonId(),
|
2020-11-20 01:28:05 +00:00
|
|
|
tabletEvent->isButtonPressed(),
|
2020-12-22 16:34:10 +00:00
|
|
|
{ event->device()->groupUserData() });
|
2019-12-01 17:51:15 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_TABLET_PAD_RING: {
|
|
|
|
auto *tabletEvent = static_cast<TabletPadRingEvent *>(event.data());
|
2020-11-20 01:28:05 +00:00
|
|
|
tabletEvent->position();
|
2019-12-01 17:51:15 +00:00
|
|
|
emit tabletPadRingEvent(tabletEvent->number(),
|
|
|
|
tabletEvent->position(),
|
2020-12-22 16:34:10 +00:00
|
|
|
tabletEvent->source() == LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER,
|
|
|
|
{ event->device()->groupUserData() });
|
2019-12-01 17:51:15 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LIBINPUT_EVENT_TABLET_PAD_STRIP: {
|
|
|
|
auto *tabletEvent = static_cast<TabletPadStripEvent *>(event.data());
|
|
|
|
emit tabletPadStripEvent(tabletEvent->number(),
|
|
|
|
tabletEvent->position(),
|
2020-12-22 16:34:10 +00:00
|
|
|
tabletEvent->source() == LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER,
|
|
|
|
{ event->device()->groupUserData() });
|
2019-12-01 17:51:15 +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);
|
|
|
|
}
|
Expose if the tablet mode switch is available
Summary:
expose in the libinput wrapper a property that tells whether
a tablet mode switch input device is present on the machine,
expose it trough dbus
Test Plan:
still not complete, I need a way to either access the connection
from TabletModeManager or setting to TabletModeManager from input.cpp
Reviewers: #kwin, #plasma, graesslin
Reviewed By: #kwin, #plasma, graesslin
Subscribers: graesslin, ngraham, davidedmundson, plasma-devel, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D9944
2018-01-24 10:36:56 +00:00
|
|
|
if (m_tabletModeSwitchBeforeSuspend && !m_tabletModeSwitch) {
|
|
|
|
emit hasTabletModeSwitchChanged(false);
|
|
|
|
}
|
2015-09-02 09:32:26 +00:00
|
|
|
wasSuspended = false;
|
|
|
|
}
|
2014-08-14 12:43:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::setScreenSize(const QSize &size)
|
|
|
|
{
|
|
|
|
m_size = size;
|
|
|
|
}
|
|
|
|
|
2017-11-10 17:07:15 +00:00
|
|
|
void Connection::updateScreens()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&m_mutex);
|
|
|
|
for (auto device: qAsConst(m_devices)) {
|
|
|
|
applyScreenToDevice(device);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Connection::applyScreenToDevice(Device *device)
|
|
|
|
{
|
|
|
|
#ifndef KWIN_BUILD_TESTING
|
|
|
|
QMutexLocker locker(&m_mutex);
|
|
|
|
if (!device->isTouch()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int id = -1;
|
|
|
|
// let's try to find a screen for it
|
|
|
|
if (screens()->count() == 1) {
|
|
|
|
id = 0;
|
|
|
|
}
|
|
|
|
if (id == -1 && !device->outputName().isEmpty()) {
|
|
|
|
// we have an output name, try to find a screen with matching name
|
|
|
|
for (int i = 0; i < screens()->count(); i++) {
|
|
|
|
if (screens()->name(i) == device->outputName()) {
|
|
|
|
id = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (id == -1) {
|
|
|
|
// do we have an internal screen?
|
|
|
|
int internalId = -1;
|
|
|
|
for (int i = 0; i < screens()->count(); i++) {
|
|
|
|
if (screens()->isInternal(i)) {
|
|
|
|
internalId = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto testScreenMatches = [device] (int id) {
|
|
|
|
const auto &size = device->size();
|
|
|
|
const auto &screenSize = screens()->physicalSize(id);
|
|
|
|
return std::round(size.width()) == std::round(screenSize.width())
|
|
|
|
&& std::round(size.height()) == std::round(screenSize.height());
|
|
|
|
};
|
|
|
|
if (internalId != -1 && testScreenMatches(internalId)) {
|
|
|
|
id = internalId;
|
|
|
|
}
|
|
|
|
// let's compare all screens for size
|
|
|
|
for (int i = 0; i < screens()->count(); i++) {
|
|
|
|
if (testScreenMatches(i)) {
|
|
|
|
id = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (id == -1) {
|
|
|
|
// still not found
|
|
|
|
if (internalId != -1) {
|
|
|
|
// we have an internal id, so let's use that
|
|
|
|
id = internalId;
|
|
|
|
} else {
|
|
|
|
// just take first screen, we have no clue
|
|
|
|
id = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
device->setScreenId(id);
|
2019-12-15 19:28:23 +00:00
|
|
|
|
|
|
|
// TODO: this is currently non-functional even on DRM. Needs orientation() override there.
|
2017-11-10 17:07:15 +00:00
|
|
|
device->setOrientation(screens()->orientation(id));
|
|
|
|
#else
|
|
|
|
Q_UNUSED(device)
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2016-11-04 14:31:35 +00:00
|
|
|
// pass configuration to Device
|
|
|
|
device->setConfig(m_config->group("Libinput").group(QString::number(device->vendor())).group(QString::number(device->product())).group(device->name()));
|
|
|
|
device->loadConfiguration();
|
2016-05-06 07:53:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::slotKGlobalSettingsNotifyChange(int type, int arg)
|
|
|
|
{
|
2019-07-29 18:58:33 +00:00
|
|
|
if (type == 3 /**SettingsChanged**/ && arg == 0 /** SETTINGS_MOUSE */) {
|
2016-05-06 07:53:36 +00:00
|
|
|
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;
|
2016-12-02 13:58:56 +00:00
|
|
|
if (!device->isTouchpad()) {
|
2016-05-06 10:28:07 +00:00
|
|
|
continue;
|
|
|
|
}
|
2016-12-02 13:58:56 +00:00
|
|
|
const bool old = device->isEnabled();
|
|
|
|
device->setEnabled(m_touchpadsEnabled);
|
|
|
|
if (old != device->isEnabled()) {
|
|
|
|
changed = true;
|
2016-05-06 10:28:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-06 23:40:48 +00:00
|
|
|
void Connection::enableTouchpads()
|
|
|
|
{
|
|
|
|
if (m_touchpadsEnabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
toggleTouchpads();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::disableTouchpads()
|
|
|
|
{
|
|
|
|
if (!m_touchpadsEnabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
toggleTouchpads();
|
|
|
|
}
|
|
|
|
|
2016-10-05 09:50:20 +00:00
|
|
|
void Connection::updateLEDs(Xkb::LEDs leds)
|
|
|
|
{
|
|
|
|
if (m_leds == leds) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_leds = leds;
|
|
|
|
// update on devices
|
|
|
|
const libinput_led l = static_cast<libinput_led>(toLibinputLEDS(leds));
|
|
|
|
for (auto it = m_devices.constBegin(), end = m_devices.constEnd(); it != end; ++it) {
|
|
|
|
libinput_device_led_update((*it)->device(), l);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-02 13:58:56 +00:00
|
|
|
QStringList Connection::devicesSysNames() const {
|
|
|
|
QStringList sl;
|
|
|
|
foreach (Device *d, m_devices) {
|
|
|
|
sl.append(d->sysName());
|
|
|
|
}
|
|
|
|
return sl;
|
|
|
|
}
|
|
|
|
|
2014-08-14 12:43:57 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-12 07:16:04 +00:00
|
|
|
|
|
|
|
#include "connection.moc"
|