1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 #include "events.h"
10 #include "device.h"
11 
12 #include <QSize>
13 
14 namespace KWin
15 {
16 namespace LibInput
17 {
18 
create(libinput_event * event)19 Event *Event::create(libinput_event *event)
20 {
21     if (!event) {
22         return nullptr;
23     }
24     const auto t = libinput_event_get_type(event);
25     // TODO: add touch events
26     // TODO: add device notify events
27     switch (t) {
28     case LIBINPUT_EVENT_KEYBOARD_KEY:
29         return new KeyEvent(event);
30     case LIBINPUT_EVENT_POINTER_AXIS:
31     case LIBINPUT_EVENT_POINTER_BUTTON:
32     case LIBINPUT_EVENT_POINTER_MOTION:
33     case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
34         return new PointerEvent(event, t);
35     case LIBINPUT_EVENT_TOUCH_DOWN:
36     case LIBINPUT_EVENT_TOUCH_UP:
37     case LIBINPUT_EVENT_TOUCH_MOTION:
38     case LIBINPUT_EVENT_TOUCH_CANCEL:
39     case LIBINPUT_EVENT_TOUCH_FRAME:
40         return new TouchEvent(event, t);
41     case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
42     case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
43     case LIBINPUT_EVENT_GESTURE_SWIPE_END:
44         return new SwipeGestureEvent(event, t);
45     case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
46     case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
47     case LIBINPUT_EVENT_GESTURE_PINCH_END:
48         return new PinchGestureEvent(event, t);
49     case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
50     case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
51     case LIBINPUT_EVENT_TABLET_TOOL_TIP:
52         return new TabletToolEvent(event, t);
53     case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
54         return new TabletToolButtonEvent(event, t);
55     case LIBINPUT_EVENT_TABLET_PAD_RING:
56         return new TabletPadRingEvent(event, t);
57     case LIBINPUT_EVENT_TABLET_PAD_STRIP:
58         return new TabletPadStripEvent(event, t);
59     case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
60         return new TabletPadButtonEvent(event, t);
61     case LIBINPUT_EVENT_SWITCH_TOGGLE:
62         return new SwitchEvent(event, t);
63     default:
64         return new Event(event, t);
65     }
66 }
67 
Event(libinput_event * event,libinput_event_type type)68 Event::Event(libinput_event *event, libinput_event_type type)
69     : m_event(event)
70     , m_type(type)
71     , m_device(nullptr)
72 {
73 }
74 
~Event()75 Event::~Event()
76 {
77     libinput_event_destroy(m_event);
78 }
79 
device() const80 Device *Event::device() const
81 {
82     if (!m_device) {
83         m_device = Device::getDevice(libinput_event_get_device(m_event));
84     }
85     return m_device;
86 }
87 
nativeDevice() const88 libinput_device *Event::nativeDevice() const
89 {
90     if (m_device) {
91         return m_device->device();
92     }
93     return libinput_event_get_device(m_event);
94 }
95 
KeyEvent(libinput_event * event)96 KeyEvent::KeyEvent(libinput_event *event)
97     : Event(event, LIBINPUT_EVENT_KEYBOARD_KEY)
98     , m_keyboardEvent(libinput_event_get_keyboard_event(event))
99 {
100 }
101 
102 KeyEvent::~KeyEvent() = default;
103 
key() const104 uint32_t KeyEvent::key() const
105 {
106     return libinput_event_keyboard_get_key(m_keyboardEvent);
107 }
108 
state() const109 InputRedirection::KeyboardKeyState KeyEvent::state() const
110 {
111     switch (libinput_event_keyboard_get_key_state(m_keyboardEvent)) {
112     case LIBINPUT_KEY_STATE_PRESSED:
113         return InputRedirection::KeyboardKeyPressed;
114     case LIBINPUT_KEY_STATE_RELEASED:
115         return InputRedirection::KeyboardKeyReleased;
116     }
117     abort();
118 }
119 
time() const120 uint32_t KeyEvent::time() const
121 {
122     return libinput_event_keyboard_get_time(m_keyboardEvent);
123 }
124 
PointerEvent(libinput_event * event,libinput_event_type type)125 PointerEvent::PointerEvent(libinput_event *event, libinput_event_type type)
126     : Event(event, type)
127     , m_pointerEvent(libinput_event_get_pointer_event(event))
128 {
129 }
130 
131 PointerEvent::~PointerEvent() = default;
132 
absolutePos() const133 QPointF PointerEvent::absolutePos() const
134 {
135     Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE);
136     return QPointF(libinput_event_pointer_get_absolute_x(m_pointerEvent),
137                    libinput_event_pointer_get_absolute_y(m_pointerEvent));
138 }
139 
absolutePos(const QSize & size) const140 QPointF PointerEvent::absolutePos(const QSize &size) const
141 {
142     Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE);
143     return QPointF(libinput_event_pointer_get_absolute_x_transformed(m_pointerEvent, size.width()),
144                    libinput_event_pointer_get_absolute_y_transformed(m_pointerEvent, size.height()));
145 }
146 
delta() const147 QSizeF PointerEvent::delta() const
148 {
149     Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION);
150     return QSizeF(libinput_event_pointer_get_dx(m_pointerEvent), libinput_event_pointer_get_dy(m_pointerEvent));
151 }
152 
deltaUnaccelerated() const153 QSizeF PointerEvent::deltaUnaccelerated() const
154 {
155     Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION);
156     return QSizeF(libinput_event_pointer_get_dx_unaccelerated(m_pointerEvent), libinput_event_pointer_get_dy_unaccelerated(m_pointerEvent));
157 }
158 
time() const159 uint32_t PointerEvent::time() const
160 {
161     return libinput_event_pointer_get_time(m_pointerEvent);
162 }
163 
timeMicroseconds() const164 quint64 PointerEvent::timeMicroseconds() const
165 {
166     return libinput_event_pointer_get_time_usec(m_pointerEvent);
167 }
168 
button() const169 uint32_t PointerEvent::button() const
170 {
171     Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_BUTTON);
172     return libinput_event_pointer_get_button(m_pointerEvent);
173 }
174 
buttonState() const175 InputRedirection::PointerButtonState PointerEvent::buttonState() const
176 {
177     Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_BUTTON);
178     switch (libinput_event_pointer_get_button_state(m_pointerEvent)) {
179     case LIBINPUT_BUTTON_STATE_PRESSED:
180         return InputRedirection::PointerButtonPressed;
181     case LIBINPUT_BUTTON_STATE_RELEASED:
182         return InputRedirection::PointerButtonReleased;
183     }
184     abort();
185 }
186 
axis() const187 QVector<InputRedirection::PointerAxis> PointerEvent::axis() const
188 {
189     Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_AXIS);
190     QVector<InputRedirection::PointerAxis> a;
191     if (libinput_event_pointer_has_axis(m_pointerEvent, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) {
192         a << InputRedirection::PointerAxisHorizontal;
193     }
194     if (libinput_event_pointer_has_axis(m_pointerEvent, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) {
195         a << InputRedirection::PointerAxisVertical;
196     }
197     return a;
198 }
199 
axisValue(InputRedirection::PointerAxis axis) const200 qreal PointerEvent::axisValue(InputRedirection::PointerAxis axis) const
201 {
202     Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_AXIS);
203     const libinput_pointer_axis a = axis == InputRedirection::PointerAxisHorizontal
204                                           ? LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL
205                                           : LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
206     return libinput_event_pointer_get_axis_value(m_pointerEvent, a) * device()->scrollFactor();
207 }
208 
discreteAxisValue(InputRedirection::PointerAxis axis) const209 qint32 PointerEvent::discreteAxisValue(InputRedirection::PointerAxis axis) const
210 {
211     Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_AXIS);
212     const libinput_pointer_axis a = (axis == InputRedirection::PointerAxisHorizontal)
213         ? LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL
214         : LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
215     return libinput_event_pointer_get_axis_value_discrete(m_pointerEvent, a) * device()->scrollFactor();
216 }
217 
axisSource() const218 InputRedirection::PointerAxisSource PointerEvent::axisSource() const
219 {
220     Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_AXIS);
221     switch (libinput_event_pointer_get_axis_source(m_pointerEvent)) {
222     case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
223         return InputRedirection::PointerAxisSourceWheel;
224     case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
225         return InputRedirection::PointerAxisSourceFinger;
226     case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
227         return InputRedirection::PointerAxisSourceContinuous;
228     case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT:
229         return InputRedirection::PointerAxisSourceWheelTilt;
230     default:
231         return InputRedirection::PointerAxisSourceUnknown;
232     }
233 }
234 
TouchEvent(libinput_event * event,libinput_event_type type)235 TouchEvent::TouchEvent(libinput_event *event, libinput_event_type type)
236     : Event(event, type)
237     , m_touchEvent(libinput_event_get_touch_event(event))
238 {
239 }
240 
241 TouchEvent::~TouchEvent() = default;
242 
time() const243 quint32 TouchEvent::time() const
244 {
245     return libinput_event_touch_get_time(m_touchEvent);
246 }
247 
absolutePos() const248 QPointF TouchEvent::absolutePos() const
249 {
250     Q_ASSERT(type() == LIBINPUT_EVENT_TOUCH_DOWN || type() == LIBINPUT_EVENT_TOUCH_MOTION);
251     return QPointF(libinput_event_touch_get_x(m_touchEvent),
252                    libinput_event_touch_get_y(m_touchEvent));
253 }
254 
absolutePos(const QSize & size) const255 QPointF TouchEvent::absolutePos(const QSize &size) const
256 {
257     Q_ASSERT(type() == LIBINPUT_EVENT_TOUCH_DOWN || type() == LIBINPUT_EVENT_TOUCH_MOTION);
258     return QPointF(libinput_event_touch_get_x_transformed(m_touchEvent, size.width()),
259                    libinput_event_touch_get_y_transformed(m_touchEvent, size.height()));
260 }
261 
id() const262 qint32 TouchEvent::id() const
263 {
264     Q_ASSERT(type() != LIBINPUT_EVENT_TOUCH_FRAME);
265 
266     return libinput_event_touch_get_seat_slot(m_touchEvent);
267 }
268 
GestureEvent(libinput_event * event,libinput_event_type type)269 GestureEvent::GestureEvent(libinput_event *event, libinput_event_type type)
270     : Event(event, type)
271     , m_gestureEvent(libinput_event_get_gesture_event(event))
272 {
273 }
274 
275 GestureEvent::~GestureEvent() = default;
276 
time() const277 quint32 GestureEvent::time() const
278 {
279     return libinput_event_gesture_get_time(m_gestureEvent);
280 }
281 
fingerCount() const282 int GestureEvent::fingerCount() const
283 {
284     return libinput_event_gesture_get_finger_count(m_gestureEvent);
285 }
286 
delta() const287 QSizeF GestureEvent::delta() const
288 {
289     return QSizeF(libinput_event_gesture_get_dx(m_gestureEvent),
290                   libinput_event_gesture_get_dy(m_gestureEvent));
291 }
292 
isCancelled() const293 bool GestureEvent::isCancelled() const
294 {
295     return libinput_event_gesture_get_cancelled(m_gestureEvent) != 0;
296 }
297 
PinchGestureEvent(libinput_event * event,libinput_event_type type)298 PinchGestureEvent::PinchGestureEvent(libinput_event *event, libinput_event_type type)
299     : GestureEvent(event, type)
300 {
301 }
302 
303 PinchGestureEvent::~PinchGestureEvent() = default;
304 
scale() const305 qreal PinchGestureEvent::scale() const
306 {
307     return libinput_event_gesture_get_scale(m_gestureEvent);
308 }
309 
angleDelta() const310 qreal PinchGestureEvent::angleDelta() const
311 {
312     return libinput_event_gesture_get_angle_delta(m_gestureEvent);
313 }
314 
SwipeGestureEvent(libinput_event * event,libinput_event_type type)315 SwipeGestureEvent::SwipeGestureEvent(libinput_event *event, libinput_event_type type)
316     : GestureEvent(event, type)
317 {
318 }
319 
320 SwipeGestureEvent::~SwipeGestureEvent() = default;
321 
SwitchEvent(libinput_event * event,libinput_event_type type)322 SwitchEvent::SwitchEvent(libinput_event *event, libinput_event_type type)
323     : Event(event, type)
324     , m_switchEvent(libinput_event_get_switch_event(event))
325 {
326 }
327 
328 SwitchEvent::~SwitchEvent() = default;
329 
state() const330 SwitchEvent::State SwitchEvent::state() const
331 {
332     switch (libinput_event_switch_get_switch_state(m_switchEvent))
333     {
334     case LIBINPUT_SWITCH_STATE_OFF:
335         return State::Off;
336     case LIBINPUT_SWITCH_STATE_ON:
337         return State::On;
338     default:
339         Q_UNREACHABLE();
340     }
341     return State::Off;
342 }
343 
time() const344 quint32 SwitchEvent::time() const
345 {
346     return libinput_event_switch_get_time(m_switchEvent);
347 }
348 
timeMicroseconds() const349 quint64 SwitchEvent::timeMicroseconds() const
350 {
351     return libinput_event_switch_get_time_usec(m_switchEvent);
352 }
353 
TabletToolEvent(libinput_event * event,libinput_event_type type)354 TabletToolEvent::TabletToolEvent(libinput_event *event, libinput_event_type type)
355     : Event(event, type)
356     , m_tabletToolEvent(libinput_event_get_tablet_tool_event(event))
357 {
358 }
359 
TabletToolButtonEvent(libinput_event * event,libinput_event_type type)360 TabletToolButtonEvent::TabletToolButtonEvent(libinput_event *event, libinput_event_type type)
361     : Event(event, type)
362     , m_tabletToolEvent(libinput_event_get_tablet_tool_event(event))
363 {
364 }
365 
TabletPadButtonEvent(libinput_event * event,libinput_event_type type)366 TabletPadButtonEvent::TabletPadButtonEvent(libinput_event *event, libinput_event_type type)
367     : Event(event, type)
368     , m_tabletPadEvent(libinput_event_get_tablet_pad_event(event))
369 {
370 }
371 
TabletPadStripEvent(libinput_event * event,libinput_event_type type)372 TabletPadStripEvent::TabletPadStripEvent(libinput_event *event, libinput_event_type type)
373     : Event(event, type)
374     , m_tabletPadEvent(libinput_event_get_tablet_pad_event(event))
375 {
376 }
377 
TabletPadRingEvent(libinput_event * event,libinput_event_type type)378 TabletPadRingEvent::TabletPadRingEvent(libinput_event *event, libinput_event_type type)
379     : Event(event, type)
380     , m_tabletPadEvent(libinput_event_get_tablet_pad_event(event))
381 {
382 }
383 }
384 }
385