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

source code of qtbase/src/plugins/platforms/wayland/qwaylandinputdevice_p.h