Initial support for tablets on Wayland

Summary:
This includes support for them on libinput and turns it into fake
pointer actions.
This doesn't implement zwp_tablet, this will have to happen in an
iteration later.

Test Plan:
Been playing around with it, see video.
https://www.youtube.com/watch?v=GF1WbO8FVvU

Reviewers: #plasma, #kwin, romangg

Reviewed By: #plasma, #kwin, romangg

Subscribers: zzag, davidedmundson, romangg, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D25663
This commit is contained in:
Aleix Pol 2019-12-01 18:51:15 +01:00
parent 5114494b57
commit f5a73b87e3
14 changed files with 742 additions and 7 deletions

View file

@ -479,6 +479,7 @@ set(kwin_KDEINIT_SRCS
thumbnailitem.cpp
toplevel.cpp
touch_hide_cursor_spy.cpp
tablet_input.cpp
touch_input.cpp
udev.cpp
unmanaged.cpp

View file

@ -897,3 +897,22 @@ uint64_t libinput_event_switch_get_time_usec(struct libinput_event_switch *event
{
return event->timeMicroseconds;
}
struct libinput_event_tablet_pad *libinput_event_get_tablet_pad_event(struct libinput_event *event)
{
if (event->type == LIBINPUT_EVENT_TABLET_PAD_BUTTON) {
return reinterpret_cast<libinput_event_tablet_pad *>(event);
}
return nullptr;
}
struct libinput_event_tablet_tool *
libinput_event_get_tablet_tool_event(struct libinput_event *event)
{
if (event->type == LIBINPUT_EVENT_TABLET_TOOL_AXIS ||
event->type == LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY ||
event->type == LIBINPUT_EVENT_TABLET_TOOL_TIP) {
return reinterpret_cast<libinput_event_tablet_tool *>(event);
}
return nullptr;
}

View file

@ -482,6 +482,83 @@ void DebugConsoleFilter::switchEvent(SwitchEvent *event)
m_textEdit->ensureCursorVisible();
}
void DebugConsoleFilter::tabletToolEvent(QTabletEvent *event)
{
QString typeString;
{
QDebug d(&typeString);
d << event->type();
}
QString text = s_hr + s_tableStart + tableHeaderRow(i18n("Tablet Tool"))
+ tableRow(i18n("EventType"), typeString)
+ tableRow(i18n("Position"),
QStringLiteral("%1,%2").arg(event->pos().x()).arg(event->pos().y()))
+ tableRow(i18n("Tilt"),
QStringLiteral("%1,%2").arg(event->xTilt()).arg(event->yTilt()))
+ tableRow(i18n("Rotation"), QString::number(event->rotation()))
+ tableRow(i18n("Pressure"), QString::number(event->pressure()))
+ tableRow(i18n("Buttons"), QString::number(event->buttons()))
+ tableRow(i18n("Modifiers"), QString::number(event->modifiers()))
+ s_tableEnd;
m_textEdit->insertHtml(text);
m_textEdit->ensureCursorVisible();
}
void DebugConsoleFilter::tabletToolButtonEvent(const QSet<uint> &pressedButtons)
{
QString buttons;
for (uint b : pressedButtons) {
buttons += QString::number(b) + ' ';
}
QString text = s_hr + s_tableStart + tableHeaderRow(i18n("Tablet Tool Button"))
+ tableRow(i18n("Pressed Buttons"), buttons)
+ s_tableEnd;
m_textEdit->insertHtml(text);
m_textEdit->ensureCursorVisible();
}
void DebugConsoleFilter::tabletPadButtonEvent(const QSet<uint> &pressedButtons)
{
QString buttons;
for (uint b : pressedButtons) {
buttons += QString::number(b) + ' ';
}
QString text = s_hr + s_tableStart
+ tableHeaderRow(i18n("Tablet Pad Button"))
+ tableRow(i18n("Pressed Buttons"), buttons)
+ s_tableEnd;
m_textEdit->insertHtml(text);
m_textEdit->ensureCursorVisible();
}
void DebugConsoleFilter::tabletPadStripEvent(int number, int position, bool isFinger)
{
QString text = s_hr + s_tableStart + tableHeaderRow(i18n("Tablet Pad Strip"))
+ tableRow(i18n("Number"), number)
+ tableRow(i18n("Position"), position)
+ tableRow(i18n("isFinger"), isFinger)
+ s_tableEnd;
m_textEdit->insertHtml(text);
m_textEdit->ensureCursorVisible();
}
void DebugConsoleFilter::tabletPadRingEvent(int number, int position, bool isFinger)
{
QString text = s_hr + s_tableStart + tableHeaderRow(i18n("Tablet Pad Ring"))
+ tableRow(i18n("Number"), number)
+ tableRow(i18n("Position"), position)
+ tableRow(i18n("isFinger"), isFinger)
+ s_tableEnd;
m_textEdit->insertHtml(text);
m_textEdit->ensureCursorVisible();
}
DebugConsole::DebugConsole()
: QWidget()
, m_ui(new Ui::DebugConsole)

View file

@ -153,6 +153,12 @@ public:
void switchEvent(SwitchEvent *event) override;
void tabletToolEvent(QTabletEvent *event) override;
void tabletToolButtonEvent(const QSet<uint> &pressedButtons) override;
void tabletPadButtonEvent(const QSet<uint> &pressedButtons) override;
void tabletPadStripEvent(int number, int position, bool isFinger) override;
void tabletPadRingEvent(int number, int position, bool isFinger) override;
private:
QTextEdit *m_textEdit;
};

View file

@ -20,18 +20,19 @@ 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 "input.h"
#include "input_event.h"
#include "input_event_spy.h"
#include "keyboard_input.h"
#include "pointer_input.h"
#include "touch_input.h"
#include "touch_hide_cursor_spy.h"
#include "x11client.h"
#include "effects.h"
#include "gestures.h"
#include "globalshortcuts.h"
#include "input_event.h"
#include "input_event_spy.h"
#include "keyboard_input.h"
#include "logind.h"
#include "main.h"
#include "pointer_input.h"
#include "tablet_input.h"
#include "touch_hide_cursor_spy.h"
#include "touch_input.h"
#include "x11client.h"
#ifdef KWIN_BUILD_TABBOX
#include "tabbox/tabbox.h"
#endif
@ -176,6 +177,40 @@ bool InputEventFilter::switchEvent(SwitchEvent *event)
return false;
}
bool InputEventFilter::tabletToolEvent(QTabletEvent *event)
{
Q_UNUSED(event)
return false;
}
bool InputEventFilter::tabletToolButtonEvent(const QSet<uint> &pressedButtons)
{
Q_UNUSED(pressedButtons)
return false;
}
bool InputEventFilter::tabletPadButtonEvent(const QSet<uint> &pressedButtons)
{
Q_UNUSED(pressedButtons)
return false;
}
bool InputEventFilter::tabletPadStripEvent(int number, int position, bool isFinger)
{
Q_UNUSED(number)
Q_UNUSED(position)
Q_UNUSED(isFinger)
return false;
}
bool InputEventFilter::tabletPadRingEvent(int number, int position, bool isFinger)
{
Q_UNUSED(number)
Q_UNUSED(position)
Q_UNUSED(isFinger)
return false;
}
void InputEventFilter::passToWaylandServer(QKeyEvent *event)
{
Q_ASSERT(waylandServer());
@ -1623,6 +1658,7 @@ InputRedirection::InputRedirection(QObject *parent)
: QObject(parent)
, m_keyboard(new KeyboardInputRedirection(this))
, m_pointer(new PointerInputRedirection(this))
, m_tablet(new TabletInputRedirection(this))
, m_touch(new TouchInputRedirection(this))
, m_shortcuts(new GlobalShortcutsManager(this))
{
@ -1807,6 +1843,7 @@ void InputRedirection::setupWorkspace()
m_keyboard->init();
m_pointer->init();
m_touch->init();
m_tablet->init();
}
setupInputFilters();
}
@ -1934,6 +1971,18 @@ void InputRedirection::setupLibInput()
std::bind(handleSwitchEvent, SwitchEvent::State::On, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
connect(conn, &LibInput::Connection::switchToggledOff, this,
std::bind(handleSwitchEvent, SwitchEvent::State::Off, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
connect(conn, &LibInput::Connection::tabletToolEvent,
m_tablet, &TabletInputRedirection::tabletToolEvent);
connect(conn, &LibInput::Connection::tabletToolButtonEvent,
m_tablet, &TabletInputRedirection::tabletToolButtonEvent);
connect(conn, &LibInput::Connection::tabletPadButtonEvent,
m_tablet, &TabletInputRedirection::tabletPadButtonEvent);
connect(conn, &LibInput::Connection::tabletPadRingEvent,
m_tablet, &TabletInputRedirection::tabletPadRingEvent);
connect(conn, &LibInput::Connection::tabletPadStripEvent,
m_tablet, &TabletInputRedirection::tabletPadStripEvent);
if (screens()) {
setupLibInputWithScreens();
} else {

18
input.h
View file

@ -29,6 +29,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <config-kwin.h>
#include <KSharedConfig>
#include <QSet>
#include <functional>
@ -46,6 +47,7 @@ class InputEventFilter;
class InputEventSpy;
class KeyboardInputRedirection;
class PointerInputRedirection;
class TabletInputRedirection;
class TouchInputRedirection;
class WindowSelectorFilter;
class SwitchEvent;
@ -58,6 +60,7 @@ class DecoratedClientImpl;
namespace LibInput
{
class Connection;
class Device;
}
/**
@ -92,6 +95,11 @@ public:
KeyboardKeyPressed,
KeyboardKeyAutoRepeat
};
enum TabletEventType {
Axis,
Proximity,
Tip
};
~InputRedirection() override;
void init();
@ -221,6 +229,9 @@ public:
PointerInputRedirection *pointer() const {
return m_pointer;
}
TabletInputRedirection *tablet() const {
return m_tablet;
}
TouchInputRedirection *touch() const {
return m_touch;
}
@ -284,6 +295,7 @@ private:
void installInputEventFilter(InputEventFilter *filter);
KeyboardInputRedirection *m_keyboard;
PointerInputRedirection *m_pointer;
TabletInputRedirection *m_tablet;
TouchInputRedirection *m_touch;
GlobalShortcutsManager *m_shortcuts;
@ -370,6 +382,12 @@ public:
virtual bool switchEvent(SwitchEvent *event);
virtual bool tabletToolEvent(QTabletEvent *event);
virtual bool tabletToolButtonEvent(const QSet<uint> &buttons);
virtual bool tabletPadButtonEvent(const QSet<uint> &buttons);
virtual bool tabletPadStripEvent(int number, int position, bool isFinger);
virtual bool tabletPadRingEvent(int number, int position, bool isFinger);
protected:
void passToWaylandServer(QKeyEvent *event);
};

View file

@ -121,4 +121,32 @@ void InputEventSpy::switchEvent(SwitchEvent *event)
Q_UNUSED(event)
}
void InputEventSpy::tabletToolEvent(QTabletEvent *event)
{
Q_UNUSED(event)
}
void InputEventSpy::tabletToolButtonEvent(const QSet<uint> &pressedButtons)
{
Q_UNUSED(pressedButtons)
}
void InputEventSpy::tabletPadButtonEvent(const QSet<uint> &pressedButtons)
{
Q_UNUSED(pressedButtons)
}
void InputEventSpy::tabletPadStripEvent(int number, int position, bool isFinger)
{
Q_UNUSED(number)
Q_UNUSED(position)
Q_UNUSED(isFinger)
}
void InputEventSpy::tabletPadRingEvent(int number, int position, bool isFinger)
{
Q_UNUSED(number)
Q_UNUSED(position)
Q_UNUSED(isFinger)
}
}

View file

@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
class QPointF;
class QSizeF;
class QTabletEvent;
namespace KWin
{
@ -84,6 +85,11 @@ public:
virtual void switchEvent(SwitchEvent *event);
virtual void tabletToolEvent(QTabletEvent *event);
virtual void tabletToolButtonEvent(const QSet<uint> &pressedButtons);
virtual void tabletPadButtonEvent(const QSet<uint> &pressedButtons);
virtual void tabletPadStripEvent(int number, int position, bool isFinger);
virtual void tabletPadRingEvent(int number, int position, bool isFinger);
};

View file

@ -463,6 +463,62 @@ void Connection::processEvents()
}
break;
}
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;
}
auto serial = libinput_tablet_tool_get_serial(tte->tool());
auto toolId = libinput_tablet_tool_get_tool_id(tte->tool());
emit tabletToolEvent(tabletEventType,
tte->transformedPosition(m_size), tte->pressure(),
tte->xTilt(), tte->yTilt(), tte->rotation(),
tte->isTipDown(), tte->isNearby(), serial,
toolId, event->device());
break;
}
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: {
auto *tabletEvent = static_cast<TabletToolButtonEvent *>(event.data());
emit tabletToolButtonEvent(tabletEvent->buttonId(),
tabletEvent->isButtonPressed());
break;
}
case LIBINPUT_EVENT_TABLET_PAD_BUTTON: {
auto *tabletEvent = static_cast<TabletPadButtonEvent *>(event.data());
emit tabletPadButtonEvent(tabletEvent->buttonId(),
tabletEvent->isButtonPressed());
break;
}
case LIBINPUT_EVENT_TABLET_PAD_RING: {
auto *tabletEvent = static_cast<TabletPadRingEvent *>(event.data());
emit tabletPadRingEvent(tabletEvent->number(),
tabletEvent->position(),
tabletEvent->source() ==
LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER);
break;
}
case LIBINPUT_EVENT_TABLET_PAD_STRIP: {
auto *tabletEvent = static_cast<TabletPadStripEvent *>(event.data());
emit tabletPadStripEvent(tabletEvent->number(),
tabletEvent->position(),
tabletEvent->source() ==
LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER);
break;
}
default:
// nothing
break;

View file

@ -131,6 +131,15 @@ Q_SIGNALS:
void switchToggledOn(quint32 time, quint64 timeMicroseconds, KWin::LibInput::Device *device);
void switchToggledOff(quint32 time, quint64 timeMicroseconds, KWin::LibInput::Device *device);
void tabletToolEvent(KWin::InputRedirection::TabletEventType type, const QPointF &pos,
qreal pressure, int xTilt, int yTilt, qreal rotation, bool tipDown,
bool tipNear, quint64 serialId, quint64 toolId, LibInput::Device *device);
void tabletToolButtonEvent(uint button, bool isPressed);
void tabletPadButtonEvent(uint button, bool isPressed);
void tabletPadStripEvent(int number, int position, bool isFinger);
void tabletPadRingEvent(int number, int position, bool isFinger);
void eventsRead();
private Q_SLOTS:

View file

@ -57,6 +57,18 @@ Event *Event::create(libinput_event *event)
case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
case LIBINPUT_EVENT_GESTURE_PINCH_END:
return new PinchGestureEvent(event, t);
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
return new TabletToolEvent(event, t);
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
return new TabletToolButtonEvent(event, t);
case LIBINPUT_EVENT_TABLET_PAD_RING:
return new TabletPadRingEvent(event, t);
case LIBINPUT_EVENT_TABLET_PAD_STRIP:
return new TabletPadStripEvent(event, t);
case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
return new TabletPadButtonEvent(event, t);
case LIBINPUT_EVENT_SWITCH_TOGGLE:
return new SwitchEvent(event, t);
default:
@ -352,5 +364,34 @@ quint64 SwitchEvent::timeMicroseconds() const
return libinput_event_switch_get_time_usec(m_switchEvent);
}
TabletToolEvent::TabletToolEvent(libinput_event *event, libinput_event_type type)
: Event(event, type)
, m_tabletToolEvent(libinput_event_get_tablet_tool_event(event))
{
}
TabletToolButtonEvent::TabletToolButtonEvent(libinput_event *event, libinput_event_type type)
: Event(event, type)
, m_tabletToolEvent(libinput_event_get_tablet_tool_event(event))
{
}
TabletPadButtonEvent::TabletPadButtonEvent(libinput_event *event, libinput_event_type type)
: Event(event, type)
, m_tabletPadEvent(libinput_event_get_tablet_pad_event(event))
{
}
TabletPadStripEvent::TabletPadStripEvent(libinput_event *event, libinput_event_type type)
: Event(event, type)
, m_tabletPadEvent(libinput_event_get_tablet_pad_event(event))
{
}
TabletPadRingEvent::TabletPadRingEvent(libinput_event *event, libinput_event_type type)
: Event(event, type)
, m_tabletPadEvent(libinput_event_get_tablet_pad_event(event))
{
}
}
}

View file

@ -191,6 +191,177 @@ private:
libinput_event_switch *m_switchEvent;
};
class TabletToolEvent : public Event
{
public:
TabletToolEvent(libinput_event *event, libinput_event_type type);
bool xHasChanged() const {
return libinput_event_tablet_tool_x_has_changed(m_tabletToolEvent);
}
bool yHasChanged() const {
return libinput_event_tablet_tool_y_has_changed(m_tabletToolEvent);
}
bool pressureHasChanged() const {
return libinput_event_tablet_tool_pressure_has_changed(m_tabletToolEvent);
}
bool distanceHasChanged() const {
return libinput_event_tablet_tool_distance_has_changed(m_tabletToolEvent);
}
bool tiltXHasChanged() const {
return libinput_event_tablet_tool_tilt_x_has_changed(m_tabletToolEvent);
}
bool tiltYHasChanged() const {
return libinput_event_tablet_tool_tilt_y_has_changed(m_tabletToolEvent);
}
bool rotationHasChanged() const {
return libinput_event_tablet_tool_rotation_has_changed(m_tabletToolEvent);
}
bool sliderHasChanged() const {
return libinput_event_tablet_tool_slider_has_changed(m_tabletToolEvent);
}
// uncomment when depending on libinput 1.14 or when implementing totems
// bool sizeMajorHasChanged() const { return
// libinput_event_tablet_tool_size_major_has_changed(m_tabletToolEvent); } bool
// sizeMinorHasChanged() const { return
// libinput_event_tablet_tool_size_minor_has_changed(m_tabletToolEvent); }
bool wheelHasChanged() const {
return libinput_event_tablet_tool_wheel_has_changed(m_tabletToolEvent);
}
QPointF position() const {
return {libinput_event_tablet_tool_get_x(m_tabletToolEvent),
libinput_event_tablet_tool_get_y(m_tabletToolEvent)};
}
QPointF delta() const {
return {libinput_event_tablet_tool_get_dx(m_tabletToolEvent),
libinput_event_tablet_tool_get_dy(m_tabletToolEvent)};
}
qreal pressure() const {
return libinput_event_tablet_tool_get_pressure(m_tabletToolEvent);
}
qreal distance() const {
return libinput_event_tablet_tool_get_distance(m_tabletToolEvent);
}
int xTilt() const {
return libinput_event_tablet_tool_get_tilt_x(m_tabletToolEvent);
}
int yTilt() const {
return libinput_event_tablet_tool_get_tilt_y(m_tabletToolEvent);
}
qreal rotation() const {
return libinput_event_tablet_tool_get_rotation(m_tabletToolEvent);
}
qreal sliderPosition() const {
return libinput_event_tablet_tool_get_slider_position(m_tabletToolEvent);
}
// Uncomment when depending on libinput 1.14 or when implementing totems
// qreal sizeMajor() const { return
// libinput_event_tablet_tool_get_size_major(m_tabletToolEvent); }
// qreal sizeMinor() const {
// return libinput_event_tablet_tool_get_size_minor(m_tabletToolEvent); }
qreal wheelDelta() const {
return libinput_event_tablet_tool_get_wheel_delta(m_tabletToolEvent);
}
int wheelDeltaDiscrete() const {
return libinput_event_tablet_tool_get_wheel_delta_discrete(m_tabletToolEvent);
}
bool isTipDown() const {
const auto state = libinput_event_tablet_tool_get_tip_state(m_tabletToolEvent);
return state == LIBINPUT_TABLET_TOOL_TIP_DOWN;
}
bool isNearby() const {
const auto state = libinput_event_tablet_tool_get_proximity_state(m_tabletToolEvent);
return state == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN;
}
QPointF transformedPosition(const QSize &size) const {
return {libinput_event_tablet_tool_get_x_transformed(m_tabletToolEvent, size.width()),
libinput_event_tablet_tool_get_y_transformed(m_tabletToolEvent, size.height())};
}
struct libinput_tablet_tool *tool() {
return libinput_event_tablet_tool_get_tool(m_tabletToolEvent);
}
private:
libinput_event_tablet_tool *m_tabletToolEvent;
};
class TabletToolButtonEvent : public Event
{
public:
TabletToolButtonEvent(libinput_event *event, libinput_event_type type);
uint buttonId() const {
return libinput_event_tablet_tool_get_button(m_tabletToolEvent);
}
bool isButtonPressed() const {
const auto state = libinput_event_tablet_tool_get_button_state(m_tabletToolEvent);
return state == LIBINPUT_BUTTON_STATE_PRESSED;
}
private:
libinput_event_tablet_tool *m_tabletToolEvent;
};
class TabletPadRingEvent : public Event
{
public:
TabletPadRingEvent(libinput_event *event, libinput_event_type type);
int position() const {
return libinput_event_tablet_pad_get_ring_position(m_tabletPadEvent);
}
int number() const {
return libinput_event_tablet_pad_get_ring_number(m_tabletPadEvent);
}
libinput_tablet_pad_ring_axis_source source() const {
return libinput_event_tablet_pad_get_ring_source(m_tabletPadEvent);
}
private:
libinput_event_tablet_pad *m_tabletPadEvent;
};
class TabletPadStripEvent : public Event
{
public:
TabletPadStripEvent(libinput_event *event, libinput_event_type type);
int position() const {
return libinput_event_tablet_pad_get_strip_position(m_tabletPadEvent);
}
int number() const {
return libinput_event_tablet_pad_get_strip_number(m_tabletPadEvent);
}
libinput_tablet_pad_strip_axis_source source() const {
return libinput_event_tablet_pad_get_strip_source(m_tabletPadEvent);
}
private:
libinput_event_tablet_pad *m_tabletPadEvent;
};
class TabletPadButtonEvent : public Event
{
public:
TabletPadButtonEvent(libinput_event *event, libinput_event_type type);
uint buttonId() const {
return libinput_event_tablet_pad_get_button_number(m_tabletPadEvent);
}
bool isButtonPressed() const {
const auto state = libinput_event_tablet_pad_get_button_state(m_tabletPadEvent);
return state == LIBINPUT_BUTTON_STATE_PRESSED;
}
private:
libinput_event_tablet_pad *m_tabletPadEvent;
};
inline
libinput_event_type Event::type() const
{

163
tablet_input.cpp Normal file
View file

@ -0,0 +1,163 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2019 Aleix Pol Gonzalez <aleixpol@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 "tablet_input.h"
#include "abstract_client.h"
#include "decorations/decoratedclient.h"
#include "input.h"
#include "input_event_spy.h"
#include "libinput/device.h"
#include "pointer_input.h"
#include "toplevel.h"
#include "wayland_server.h"
#include "workspace.h"
// KDecoration
#include <KDecoration2/Decoration>
// KWayland
#include <KWayland/Server/seat_interface.h>
// screenlocker
#include <KScreenLocker/KsldApp>
// Qt
#include <QHoverEvent>
#include <QWindow>
namespace KWin
{
TabletInputRedirection::TabletInputRedirection(InputRedirection *parent)
: InputDeviceHandler(parent)
{
}
TabletInputRedirection::~TabletInputRedirection() = default;
void TabletInputRedirection::init()
{
Q_ASSERT(!inited());
setInited(true);
InputDeviceHandler::init();
connect(workspace(), &QObject::destroyed, this, [this] { setInited(false); });
connect(waylandServer(), &QObject::destroyed, this, [this] { setInited(false); });
}
void TabletInputRedirection::tabletToolEvent(KWin::InputRedirection::TabletEventType type,
const QPointF &pos, qreal pressure,
int xTilt, int yTilt, qreal rotation,
bool tipDown, bool tipNear, quint64 serialId,
quint64 toolId, LibInput::Device *device)
{
Q_UNUSED(device)
Q_UNUSED(toolId)
if (!inited()) {
return;
}
m_lastPosition = pos;
QEvent::Type t;
switch (type) {
case InputRedirection::Axis:
t = QEvent::TabletMove;
break;
case InputRedirection::Tip:
t = tipDown ? QEvent::TabletPress : QEvent::TabletRelease;
break;
case InputRedirection::Proximity:
t = tipNear ? QEvent::TabletEnterProximity : QEvent::TabletLeaveProximity;
break;
}
const auto button = m_tipDown ? Qt::LeftButton : Qt::NoButton;
QTabletEvent ev(t, pos, pos, QTabletEvent::Stylus, QTabletEvent::Pen, pressure,
xTilt, yTilt,
0, // tangentialPressure
rotation,
0, // z
Qt::NoModifier, serialId, button, button);
input()->processSpies(std::bind(&InputEventSpy::tabletToolEvent, std::placeholders::_1, &ev));
input()->processFilters(
std::bind(&InputEventFilter::tabletToolEvent, std::placeholders::_1, &ev));
m_tipDown = tipDown;
m_tipNear = tipNear;
}
void KWin::TabletInputRedirection::tabletToolButtonEvent(uint button, bool isPressed)
{
if (isPressed)
m_toolPressedButtons.insert(button);
else
m_toolPressedButtons.remove(button);
input()->processSpies(std::bind(&InputEventSpy::tabletToolButtonEvent,
std::placeholders::_1, m_toolPressedButtons));
input()->processFilters(std::bind( &InputEventFilter::tabletToolButtonEvent,
std::placeholders::_1, m_toolPressedButtons));
}
void KWin::TabletInputRedirection::tabletPadButtonEvent(uint button, bool isPressed)
{
if (isPressed) {
m_padPressedButtons.insert(button);
} else {
m_padPressedButtons.remove(button);
}
input()->processSpies(std::bind( &InputEventSpy::tabletPadButtonEvent,
std::placeholders::_1, m_padPressedButtons));
input()->processFilters(std::bind( &InputEventFilter::tabletPadButtonEvent,
std::placeholders::_1, m_padPressedButtons));
}
void KWin::TabletInputRedirection::tabletPadStripEvent(int number, int position, bool isFinger)
{
input()->processSpies(std::bind( &InputEventSpy::tabletPadStripEvent,
std::placeholders::_1, number, position, isFinger));
input()->processFilters(std::bind( &InputEventFilter::tabletPadStripEvent,
std::placeholders::_1, number, position, isFinger));
}
void KWin::TabletInputRedirection::tabletPadRingEvent(int number, int position, bool isFinger)
{
input()->processSpies(std::bind( &InputEventSpy::tabletPadRingEvent,
std::placeholders::_1, number, position, isFinger));
input()->processFilters(std::bind( &InputEventFilter::tabletPadRingEvent,
std::placeholders::_1, number, position, isFinger));
}
void TabletInputRedirection::cleanupDecoration(Decoration::DecoratedClientImpl *old,
Decoration::DecoratedClientImpl *now)
{
Q_UNUSED(old)
Q_UNUSED(now)
}
void TabletInputRedirection::cleanupInternalWindow(QWindow *old, QWindow *now)
{
Q_UNUSED(old)
Q_UNUSED(now)
}
void TabletInputRedirection::focusUpdate(KWin::Toplevel *old, KWin::Toplevel *now)
{
Q_UNUSED(old)
Q_UNUSED(now)
}
}

91
tablet_input.h Normal file
View file

@ -0,0 +1,91 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2019 Aleix Pol Gonzalez <aleixpol@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/>.
*********************************************************************/
#ifndef KWIN_TABLET_INPUT_H
#define KWIN_TABLET_INPUT_H
#include "input.h"
#include <QHash>
#include <QObject>
#include <QPointF>
#include <QPointer>
#include <QTabletEvent>
namespace KWin
{
class InputRedirection;
class Toplevel;
namespace Decoration
{
class DecoratedClientImpl;
}
namespace LibInput
{
class Device;
}
class TabletInputRedirection : public InputDeviceHandler
{
Q_OBJECT
public:
explicit TabletInputRedirection(InputRedirection *parent);
~TabletInputRedirection() override;
void tabletPad();
void tabletToolEvent(KWin::InputRedirection::TabletEventType type, const QPointF &pos,
qreal pressure, int xTilt, int yTilt, qreal rotation, bool tipDown,
bool tipNear, quint64 serialId, quint64 toolId, LibInput::Device *device);
void tabletToolButtonEvent(uint button, bool isPressed);
void tabletPadButtonEvent(uint button, bool isPressed);
void tabletPadStripEvent(int number, int position, bool isFinger);
void tabletPadRingEvent(int number, int position, bool isFinger);
bool positionValid() const override
{
return !m_lastPosition.isNull();
}
void init() override;
QPointF position() const override
{
return m_lastPosition;
}
private:
void cleanupDecoration(Decoration::DecoratedClientImpl *old,
Decoration::DecoratedClientImpl *now) override;
void cleanupInternalWindow(QWindow *old, QWindow *now) override;
void focusUpdate(KWin::Toplevel *old, KWin::Toplevel *now) override;
bool m_tipDown = false;
bool m_tipNear = false;
QPointF m_lastPosition;
QSet<uint> m_toolPressedButtons;
QSet<uint> m_padPressedButtons;
};
}
#endif