diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -479,6 +479,7 @@ thumbnailitem.cpp toplevel.cpp touch_hide_cursor_spy.cpp + tablet_input.cpp touch_input.cpp udev.cpp unmanaged.cpp diff --git a/autotests/libinput/mock_libinput.cpp b/autotests/libinput/mock_libinput.cpp --- a/autotests/libinput/mock_libinput.cpp +++ b/autotests/libinput/mock_libinput.cpp @@ -897,3 +897,22 @@ { 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(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(event); + } + return nullptr; +} diff --git a/debug_console.h b/debug_console.h --- a/debug_console.h +++ b/debug_console.h @@ -153,6 +153,12 @@ void switchEvent(SwitchEvent *event) override; + void tabletToolEvent(QTabletEvent *event) override; + void tabletToolButtonEvent(const QSet &pressedButtons) override; + void tabletPadButtonEvent(const QSet &pressedButtons) override; + void tabletPadStripEvent(int number, int position, bool isFinger) override; + void tabletPadRingEvent(int number, int position, bool isFinger) override; + private: QTextEdit *m_textEdit; }; diff --git a/debug_console.cpp b/debug_console.cpp --- a/debug_console.cpp +++ b/debug_console.cpp @@ -482,6 +482,83 @@ 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 &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 &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) diff --git a/input.h b/input.h --- a/input.h +++ b/input.h @@ -29,6 +29,7 @@ #include #include +#include #include @@ -46,6 +47,7 @@ class InputEventSpy; class KeyboardInputRedirection; class PointerInputRedirection; +class TabletInputRedirection; class TouchInputRedirection; class WindowSelectorFilter; class SwitchEvent; @@ -58,6 +60,7 @@ namespace LibInput { class Connection; + class Device; } /** @@ -92,6 +95,11 @@ KeyboardKeyPressed, KeyboardKeyAutoRepeat }; + enum TabletEventType { + Axis, + Proximity, + Tip + }; ~InputRedirection() override; void init(); @@ -221,6 +229,9 @@ PointerInputRedirection *pointer() const { return m_pointer; } + TabletInputRedirection *tablet() const { + return m_tablet; + } TouchInputRedirection *touch() const { return m_touch; } @@ -284,6 +295,7 @@ void installInputEventFilter(InputEventFilter *filter); KeyboardInputRedirection *m_keyboard; PointerInputRedirection *m_pointer; + TabletInputRedirection *m_tablet; TouchInputRedirection *m_touch; GlobalShortcutsManager *m_shortcuts; @@ -370,6 +382,12 @@ virtual bool switchEvent(SwitchEvent *event); + virtual bool tabletToolEvent(QTabletEvent *event); + virtual bool tabletToolButtonEvent(const QSet &buttons); + virtual bool tabletPadButtonEvent(const QSet &buttons); + virtual bool tabletPadStripEvent(int number, int position, bool isFinger); + virtual bool tabletPadRingEvent(int number, int position, bool isFinger); + protected: void passToWaylandServer(QKeyEvent *event); }; diff --git a/input.cpp b/input.cpp --- a/input.cpp +++ b/input.cpp @@ -20,18 +20,19 @@ along with this program. If not, see . *********************************************************************/ #include "input.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 "touch_input.h" +#include "tablet_input.h" #include "touch_hide_cursor_spy.h" +#include "touch_input.h" #include "x11client.h" -#include "effects.h" -#include "gestures.h" -#include "globalshortcuts.h" -#include "logind.h" -#include "main.h" #ifdef KWIN_BUILD_TABBOX #include "tabbox/tabbox.h" #endif @@ -176,6 +177,40 @@ return false; } +bool InputEventFilter::tabletToolEvent(QTabletEvent *event) +{ + Q_UNUSED(event) + return false; +} + +bool InputEventFilter::tabletToolButtonEvent(const QSet &pressedButtons) +{ + Q_UNUSED(pressedButtons) + return false; +} + +bool InputEventFilter::tabletPadButtonEvent(const QSet &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 @@ : 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 @@ m_keyboard->init(); m_pointer->init(); m_touch->init(); + m_tablet->init(); } setupInputFilters(); } @@ -1934,6 +1971,18 @@ 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 { diff --git a/input_event_spy.h b/input_event_spy.h --- a/input_event_spy.h +++ b/input_event_spy.h @@ -25,6 +25,7 @@ class QPointF; class QSizeF; +class QTabletEvent; namespace KWin { @@ -84,6 +85,11 @@ virtual void switchEvent(SwitchEvent *event); + virtual void tabletToolEvent(QTabletEvent *event); + virtual void tabletToolButtonEvent(const QSet &pressedButtons); + virtual void tabletPadButtonEvent(const QSet &pressedButtons); + virtual void tabletPadStripEvent(int number, int position, bool isFinger); + virtual void tabletPadRingEvent(int number, int position, bool isFinger); }; diff --git a/input_event_spy.cpp b/input_event_spy.cpp --- a/input_event_spy.cpp +++ b/input_event_spy.cpp @@ -121,4 +121,32 @@ Q_UNUSED(event) } +void InputEventSpy::tabletToolEvent(QTabletEvent *event) +{ + Q_UNUSED(event) +} + +void InputEventSpy::tabletToolButtonEvent(const QSet &pressedButtons) +{ + Q_UNUSED(pressedButtons) +} + +void InputEventSpy::tabletPadButtonEvent(const QSet &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) +} } diff --git a/libinput/connection.h b/libinput/connection.h --- a/libinput/connection.h +++ b/libinput/connection.h @@ -131,6 +131,15 @@ 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: diff --git a/libinput/connection.cpp b/libinput/connection.cpp --- a/libinput/connection.cpp +++ b/libinput/connection.cpp @@ -463,6 +463,62 @@ } break; } + case LIBINPUT_EVENT_TABLET_TOOL_AXIS: + case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: + case LIBINPUT_EVENT_TABLET_TOOL_TIP: { + auto *tte = static_cast(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(event.data()); + emit tabletToolButtonEvent(tabletEvent->buttonId(), + tabletEvent->isButtonPressed()); + break; + } + case LIBINPUT_EVENT_TABLET_PAD_BUTTON: { + auto *tabletEvent = static_cast(event.data()); + emit tabletPadButtonEvent(tabletEvent->buttonId(), + tabletEvent->isButtonPressed()); + break; + } + case LIBINPUT_EVENT_TABLET_PAD_RING: { + auto *tabletEvent = static_cast(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(event.data()); + emit tabletPadStripEvent(tabletEvent->number(), + tabletEvent->position(), + tabletEvent->source() == + LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER); + break; + } default: // nothing break; diff --git a/libinput/events.h b/libinput/events.h --- a/libinput/events.h +++ b/libinput/events.h @@ -191,6 +191,177 @@ 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 { diff --git a/libinput/events.cpp b/libinput/events.cpp --- a/libinput/events.cpp +++ b/libinput/events.cpp @@ -57,6 +57,18 @@ 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 @@ 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)) +{ +} } } diff --git a/tablet_input.h b/tablet_input.h new file mode 100644 --- /dev/null +++ b/tablet_input.h @@ -0,0 +1,91 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2019 Aleix Pol Gonzalez + +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 . +*********************************************************************/ + +#ifndef KWIN_TABLET_INPUT_H +#define KWIN_TABLET_INPUT_H +#include "input.h" + +#include +#include +#include +#include +#include + +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 m_toolPressedButtons; + QSet m_padPressedButtons; +}; + +} + +#endif diff --git a/tablet_input.cpp b/tablet_input.cpp new file mode 100644 --- /dev/null +++ b/tablet_input.cpp @@ -0,0 +1,163 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2019 Aleix Pol Gonzalez + +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 . +*********************************************************************/ +#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 +// KWayland +#include +// screenlocker +#include +// Qt +#include +#include + +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) +} + +}