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:
parent
5114494b57
commit
f5a73b87e3
14 changed files with 742 additions and 7 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
63
input.cpp
63
input.cpp
|
@ -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
18
input.h
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
163
tablet_input.cpp
Normal 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
91
tablet_input.h
Normal 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
|
Loading…
Reference in a new issue