1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QWAYLANDINPUTDEVICE_H
5#define QWAYLANDINPUTDEVICE_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtWaylandClient/private/qtwaylandclientglobal_p.h>
19#include <QtWaylandClient/private/qwaylandwindow_p.h>
20
21#include <QtCore/QScopedPointer>
22#include <QSocketNotifier>
23#include <QObject>
24#include <QTimer>
25#include <qpa/qplatformintegration.h>
26#include <qpa/qplatformscreen.h>
27#include <qpa/qwindowsysteminterface.h>
28
29#include <QtWaylandClient/private/qwayland-wayland.h>
30#include <QtWaylandClient/private/qwayland-pointer-gestures-unstable-v1.h>
31
32#if QT_CONFIG(xkbcommon)
33#include <QtGui/private/qxkbcommon_p.h>
34#endif
35
36#include <QtCore/QDebug>
37#include <QtCore/QElapsedTimer>
38#include <QtCore/QPointer>
39
40#if QT_CONFIG(cursor)
41struct wl_cursor_image;
42#endif
43
44QT_BEGIN_NAMESPACE
45
46namespace QtWayland {
47class zwp_primary_selection_device_v1;
48} //namespace QtWayland
49
50namespace QtWaylandClient {
51
52class QWaylandDataDevice;
53class QWaylandDisplay;
54#if QT_CONFIG(wayland_client_primary_selection)
55class QWaylandPrimarySelectionDeviceV1;
56#endif
57#if QT_CONFIG(tabletevent)
58class QWaylandTabletSeatV2;
59#endif
60class QWaylandPointerGestures;
61class QWaylandPointerGestureSwipe;
62class QWaylandPointerGesturePinch;
63class QWaylandTextInputInterface;
64class QWaylandTextInputMethod;
65#if QT_CONFIG(cursor)
66class QWaylandCursorTheme;
67class QWaylandCursorShape;
68class CursorSurface;
69#endif
70
71Q_DECLARE_LOGGING_CATEGORY(lcQpaWaylandInput);
72
73class Q_WAYLANDCLIENT_EXPORT QWaylandInputDevice
74 : public QObject
75 , public QtWayland::wl_seat
76{
77 Q_OBJECT
78public:
79 class Keyboard;
80 class Pointer;
81 class Touch;
82
83 QWaylandInputDevice(QWaylandDisplay *display, int version, uint32_t id);
84 ~QWaylandInputDevice() override;
85
86 uint32_t capabilities() const { return mCaps; }
87
88 QWaylandDisplay *display() const { return mQDisplay; }
89 struct ::wl_seat *wl_seat() { return QtWayland::wl_seat::object(); }
90
91#if QT_CONFIG(cursor)
92 void setCursor(const QCursor *cursor, const QSharedPointer<QWaylandBuffer> &cachedBuffer = {}, int fallbackOutputScale = 1);
93#endif
94 void handleEndDrag();
95
96#if QT_CONFIG(wayland_datadevice)
97 void setDataDevice(QWaylandDataDevice *device);
98 QWaylandDataDevice *dataDevice() const;
99#endif
100
101#if QT_CONFIG(wayland_client_primary_selection)
102 void setPrimarySelectionDevice(QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice);
103 QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice() const;
104#endif
105
106#if QT_CONFIG(tabletevent)
107 void setTabletSeat(QWaylandTabletSeatV2 *tabletSeat);
108 QWaylandTabletSeatV2* tabletSeat() const;
109#endif
110
111 void setTextInput(QWaylandTextInputInterface *textInput);
112 QWaylandTextInputInterface *textInput() const;
113
114 void setTextInputMethod(QWaylandTextInputMethod *textInputMethod);
115 QWaylandTextInputMethod *textInputMethod() const;
116
117 void removeMouseButtonFromState(Qt::MouseButton button);
118
119 QWaylandWindow *pointerFocus() const;
120 QWaylandWindow *keyboardFocus() const;
121 QWaylandWindow *touchFocus() const;
122
123 QList<int> possibleKeys(const QKeyEvent *event) const;
124
125 QPointF pointerSurfacePosition() const;
126
127 Qt::KeyboardModifiers modifiers() const;
128
129 uint32_t serial() const;
130
131 virtual Keyboard *createKeyboard(QWaylandInputDevice *device);
132 virtual Pointer *createPointer(QWaylandInputDevice *device);
133 virtual Touch *createTouch(QWaylandInputDevice *device);
134
135 Keyboard *keyboard() const;
136 Pointer *pointer() const;
137 QWaylandPointerGestureSwipe *pointerGestureSwipe() const;
138 QWaylandPointerGesturePinch *pointerGesturePinch() const;
139 Touch *touch() const;
140
141protected:
142 QWaylandDisplay *mQDisplay = nullptr;
143 struct wl_display *mDisplay = nullptr;
144
145 uint32_t mCaps = 0;
146
147#if QT_CONFIG(cursor)
148 struct CursorState {
149 QSharedPointer<QWaylandBuffer> bitmapBuffer; // not used with shape cursors
150 int bitmapScale = 1;
151 Qt::CursorShape shape = Qt::ArrowCursor;
152 int fallbackOutputScale = 1;
153 QPoint hotspot;
154 QElapsedTimer animationTimer;
155 } mCursor;
156#endif
157
158#if QT_CONFIG(wayland_datadevice)
159 QWaylandDataDevice *mDataDevice = nullptr;
160#endif
161
162#if QT_CONFIG(wayland_client_primary_selection)
163 QScopedPointer<QWaylandPrimarySelectionDeviceV1> mPrimarySelectionDevice;
164#endif
165
166 QScopedPointer<Keyboard> mKeyboard;
167 QScopedPointer<Pointer> mPointer;
168 QScopedPointer<QWaylandPointerGestureSwipe> mPointerGestureSwipe;
169 QScopedPointer<QWaylandPointerGesturePinch> mPointerGesturePinch;
170 QScopedPointer<Touch> mTouch;
171
172 QScopedPointer<QWaylandTextInputInterface> mTextInput;
173 QScopedPointer<QWaylandTextInputMethod> mTextInputMethod;
174#if QT_CONFIG(tabletevent)
175 QScopedPointer<QWaylandTabletSeatV2> mTabletSeat;
176#endif
177
178 uint32_t mTime = 0;
179 uint32_t mSerial = 0;
180
181 void seat_capabilities(uint32_t caps) override;
182 void handleTouchPoint(int id, QEventPoint::State state, const QPointF &surfacePosition = QPoint());
183
184 QPointingDevice *mTouchDevice = nullptr;
185 QPointingDevice *mTouchPadDevice = nullptr;
186
187 friend class QWaylandTouchExtension;
188 friend class QWaylandQtKeyExtension;
189 friend class QWaylandPointerGestureSwipe;
190 friend class QWaylandPointerGesturePinch;
191 friend class QWaylandWindow;
192};
193
194inline uint32_t QWaylandInputDevice::serial() const
195{
196 return mSerial;
197}
198
199
200class Q_WAYLANDCLIENT_EXPORT QWaylandInputDevice::Keyboard : public QObject, public QtWayland::wl_keyboard
201{
202 Q_OBJECT
203
204public:
205 Keyboard(QWaylandInputDevice *p);
206 ~Keyboard() override;
207
208 QWaylandWindow *focusWindow() const;
209
210 void keyboard_keymap(uint32_t format,
211 int32_t fd,
212 uint32_t size) override;
213 void keyboard_enter(uint32_t time,
214 struct wl_surface *surface,
215 struct wl_array *keys) override;
216 void keyboard_leave(uint32_t time,
217 struct wl_surface *surface) override;
218 void keyboard_key(uint32_t serial, uint32_t time,
219 uint32_t key, uint32_t state) override;
220 void keyboard_modifiers(uint32_t serial,
221 uint32_t mods_depressed,
222 uint32_t mods_latched,
223 uint32_t mods_locked,
224 uint32_t group) override;
225 void keyboard_repeat_info(int32_t rate, int32_t delay) override;
226
227 QWaylandInputDevice *mParent = nullptr;
228 QPointer<QWaylandSurface> mFocus;
229
230 uint32_t mNativeModifiers = 0;
231
232 struct repeatKey {
233 int key;
234 uint32_t code;
235 uint32_t time;
236 QString text;
237 Qt::KeyboardModifiers modifiers;
238 uint32_t nativeVirtualKey;
239 uint32_t nativeModifiers;
240 } mRepeatKey;
241
242 QTimer mRepeatTimer;
243 int mRepeatRate = 25;
244 int mRepeatDelay = 400;
245
246 uint32_t mKeymapFormat = WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1;
247
248 Qt::KeyboardModifiers modifiers() const;
249
250 struct ::wl_keyboard *wl_keyboard() { return QtWayland::wl_keyboard::object(); }
251
252#if QT_CONFIG(xkbcommon)
253 virtual int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers, xkb_state *state, xkb_keycode_t code) {
254 return QXkbCommon::keysymToQtKey(keysym, modifiers, state, code);
255 }
256#endif
257
258private slots:
259 void handleFocusDestroyed();
260 void handleFocusLost();
261
262private:
263#if QT_CONFIG(xkbcommon)
264 bool createDefaultKeymap();
265#endif
266 void handleKey(ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
267 quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers,
268 const QString &text, bool autorepeat = false, ushort count = 1);
269
270#if QT_CONFIG(xkbcommon)
271 QXkbCommon::ScopedXKBKeymap mXkbKeymap;
272 QXkbCommon::ScopedXKBState mXkbState;
273#endif
274 friend class QWaylandInputDevice;
275};
276
277class Q_WAYLANDCLIENT_EXPORT QWaylandInputDevice::Pointer : public QObject, public QtWayland::wl_pointer
278{
279 Q_OBJECT
280public:
281 explicit Pointer(QWaylandInputDevice *seat);
282 ~Pointer() override;
283 QWaylandWindow *focusWindow() const;
284#if QT_CONFIG(cursor)
285 int idealCursorScale() const;
286 void updateCursorTheme();
287 void updateCursor();
288 void cursorTimerCallback();
289 void cursorFrameCallback();
290 CursorSurface *getOrCreateCursorSurface();
291#endif
292 QWaylandInputDevice *seat() const { return mParent; }
293
294 struct ::wl_pointer *wl_pointer() { return QtWayland::wl_pointer::object(); }
295
296protected:
297 void pointer_enter(uint32_t serial, struct wl_surface *surface,
298 wl_fixed_t sx, wl_fixed_t sy) override;
299 void pointer_leave(uint32_t time, struct wl_surface *surface) override;
300 void pointer_motion(uint32_t time,
301 wl_fixed_t sx, wl_fixed_t sy) override;
302 void pointer_button(uint32_t serial, uint32_t time,
303 uint32_t button, uint32_t state) override;
304 void pointer_axis(uint32_t time,
305 uint32_t axis,
306 wl_fixed_t value) override;
307 void pointer_axis_source(uint32_t source) override;
308 void pointer_axis_stop(uint32_t time, uint32_t axis) override;
309 void pointer_axis_discrete(uint32_t axis, int32_t value) override;
310 void pointer_frame() override;
311 void pointer_axis_value120(uint32_t axis, int32_t value120) override;
312
313private slots:
314 void handleFocusDestroyed() { invalidateFocus(); }
315
316private:
317 void invalidateFocus();
318
319public:
320 void releaseButtons();
321
322 QWaylandInputDevice *mParent = nullptr;
323 QPointer<QWaylandSurface> mFocus;
324 uint32_t mEnterSerial = 0;
325#if QT_CONFIG(cursor)
326 struct {
327 QScopedPointer<QWaylandCursorShape> shape;
328 QWaylandCursorTheme *theme = nullptr;
329 int themeBufferScale = 0;
330 QScopedPointer<CursorSurface> surface;
331 QTimer frameTimer;
332 bool gotFrameCallback = false;
333 bool gotTimerCallback = false;
334 } mCursor;
335#endif
336 QPointF mSurfacePos;
337 QPointF mGlobalPos;
338 Qt::MouseButtons mButtons = Qt::NoButton;
339#if QT_CONFIG(cursor)
340 wl_buffer *mCursorBuffer = nullptr;
341 Qt::CursorShape mCursorShape = Qt::BitmapCursor;
342#endif
343
344 struct FrameData {
345 QWaylandPointerEvent *event = nullptr;
346
347 QPointF delta;
348 QPoint delta120;
349 axis_source axisSource = axis_source_wheel;
350
351 void resetScrollData();
352 bool hasPixelDelta() const;
353 QPoint pixelDeltaAndError(QPointF *accumulatedError) const;
354 QPoint pixelDelta() const { return hasPixelDelta() ? delta.toPoint() : QPoint(); }
355 QPoint angleDelta() const;
356 Qt::MouseEventSource wheelEventSource() const;
357 } mFrameData;
358
359 bool mScrollBeginSent = false;
360 QPointF mScrollDeltaRemainder;
361
362 void setFrameEvent(QWaylandPointerEvent *event);
363 void flushScrollEvent();
364 void flushFrameEvent();
365private: //TODO: should other methods be private as well?
366 bool isDefinitelyTerminated(axis_source source) const;
367};
368
369class Q_WAYLANDCLIENT_EXPORT QWaylandInputDevice::Touch : public QtWayland::wl_touch
370{
371public:
372 Touch(QWaylandInputDevice *p);
373 ~Touch() override;
374
375 void touch_down(uint32_t serial,
376 uint32_t time,
377 struct wl_surface *surface,
378 int32_t id,
379 wl_fixed_t x,
380 wl_fixed_t y) override;
381 void touch_up(uint32_t serial,
382 uint32_t time,
383 int32_t id) override;
384 void touch_motion(uint32_t time,
385 int32_t id,
386 wl_fixed_t x,
387 wl_fixed_t y) override;
388 void touch_frame() override;
389 void touch_cancel() override;
390
391 bool allTouchPointsReleased();
392 void releasePoints();
393
394 struct ::wl_touch *wl_touch() { return QtWayland::wl_touch::object(); }
395
396 QWaylandInputDevice *mParent = nullptr;
397 QPointer<QWaylandWindow> mFocus;
398 QList<QWindowSystemInterface::TouchPoint> mPendingTouchPoints;
399};
400
401class QWaylandPointerEvent
402{
403 Q_GADGET
404public:
405 inline QWaylandPointerEvent(QEvent::Type type, Qt::ScrollPhase phase, QWaylandWindow *surface,
406 ulong timestamp, const QPointF &localPos, const QPointF &globalPos,
407 Qt::MouseButtons buttons, Qt::MouseButton button,
408 Qt::KeyboardModifiers modifiers)
409 : type(type)
410 , phase(phase)
411 , timestamp(timestamp)
412 , local(localPos)
413 , global(globalPos)
414 , buttons(buttons)
415 , button(button)
416 , modifiers(modifiers)
417 , surface(surface)
418 {}
419 inline QWaylandPointerEvent(QEvent::Type type, Qt::ScrollPhase phase, QWaylandWindow *surface,
420 ulong timestamp, const QPointF &local, const QPointF &global,
421 const QPoint &pixelDelta, const QPoint &angleDelta,
422 Qt::MouseEventSource source,
423 Qt::KeyboardModifiers modifiers)
424 : type(type)
425 , phase(phase)
426 , timestamp(timestamp)
427 , local(local)
428 , global(global)
429 , modifiers(modifiers)
430 , pixelDelta(pixelDelta)
431 , angleDelta(angleDelta)
432 , source(source)
433 , surface(surface)
434 {}
435
436 QEvent::Type type = QEvent::None;
437 Qt::ScrollPhase phase = Qt::NoScrollPhase;
438 ulong timestamp = 0;
439 QPointF local;
440 QPointF global;
441 Qt::MouseButtons buttons;
442 Qt::MouseButton button = Qt::NoButton; // Button that caused the event (QMouseEvent::button)
443 Qt::KeyboardModifiers modifiers;
444 QPoint pixelDelta;
445 QPoint angleDelta;
446 Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
447 QPointer<QWaylandWindow> surface;
448};
449
450#ifndef QT_NO_GESTURES
451class QWaylandPointerGestureSwipeEvent
452{
453 Q_GADGET
454public:
455 inline QWaylandPointerGestureSwipeEvent(QWaylandWindow *surface, Qt::GestureState state,
456 ulong timestamp, const QPointF &local,
457 const QPointF &global, uint fingers, const QPointF& delta)
458 : surface(surface)
459 , state(state)
460 , timestamp(timestamp)
461 , local(local)
462 , global(global)
463 , fingers(fingers)
464 , delta(delta)
465 {}
466
467 QPointer<QWaylandWindow> surface;
468 Qt::GestureState state = Qt::GestureState::NoGesture;
469 ulong timestamp = 0;
470 QPointF local;
471 QPointF global;
472 uint fingers = 0;
473 QPointF delta;
474};
475
476class QWaylandPointerGesturePinchEvent
477{
478 Q_GADGET
479public:
480 inline QWaylandPointerGesturePinchEvent(QWaylandWindow *surface, Qt::GestureState state,
481 ulong timestamp, const QPointF &local,
482 const QPointF &global, uint fingers, const QPointF& delta,
483 qreal scale_delta, qreal rotation_delta)
484 : surface(surface)
485 , state(state)
486 , timestamp(timestamp)
487 , local(local)
488 , global(global)
489 , fingers(fingers)
490 , delta(delta)
491 , scale_delta(scale_delta)
492 , rotation_delta(rotation_delta)
493 {}
494
495 QPointer<QWaylandWindow> surface;
496 Qt::GestureState state = Qt::GestureState::NoGesture;
497 ulong timestamp = 0;
498 QPointF local;
499 QPointF global;
500 uint fingers = 0;
501 QPointF delta;
502 qreal scale_delta = 0;
503 qreal rotation_delta = 0;
504};
505#endif // #ifndef QT_NO_GESTURES
506
507}
508
509QT_END_NAMESPACE
510
511#endif
512

source code of qtwayland/src/client/qwaylandinputdevice_p.h