input.h 16.6 KB
Newer Older
Vlad Zahorodnii's avatar
Vlad Zahorodnii committed
1 2 3
/*
    KWin - the KDE window manager
    This file is part of the KDE project.
4

Vlad Zahorodnii's avatar
Vlad Zahorodnii committed
5 6 7
    SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
    SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
    SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
8

Vlad Zahorodnii's avatar
Vlad Zahorodnii committed
9 10
    SPDX-License-Identifier: GPL-2.0-or-later
*/
11 12 13
#ifndef KWIN_INPUT_H
#define KWIN_INPUT_H
#include <kwinglobals.h>
14
#include <QAction>
15 16
#include <QObject>
#include <QPoint>
17
#include <QPointer>
18
#include <config-kwin.h>
19

20
#include <KConfigWatcher>
21
#include <KSharedConfig>
22
#include <QSet>
23

24 25
#include <functional>

26
class KGlobalAccelInterface;
27
class QKeySequence;
28 29 30
class QMouseEvent;
class QKeyEvent;
class QWheelEvent;
31

32 33
namespace KWin
{
34
class GlobalShortcutsManager;
35
class Toplevel;
36
class InputEventFilter;
37
class InputEventSpy;
38
class KeyboardInputRedirection;
39
class PointerInputRedirection;
40
class TabletInputRedirection;
41
class TouchInputRedirection;
42
class WindowSelectorFilter;
43
class SwitchEvent;
44 45
class TabletEvent;
class TabletInputFilter;
46

47 48 49 50 51
namespace Decoration
{
class DecoratedClientImpl;
}

52 53 54
namespace LibInput
{
    class Connection;
55
    class Device;
56 57
}

58 59 60 61 62 63 64
/**
 * @brief This class is responsible for redirecting incoming input to the surface which currently
 * has input or send enter/leave events.
 *
 * In addition input is intercepted before passed to the surfaces to have KWin internal areas
 * getting input first (e.g. screen edges) and filter the input event out if we currently have
 * a full input grab.
65
 */
66
class KWIN_EXPORT InputRedirection : public QObject
67 68 69 70 71 72 73 74 75 76 77
{
    Q_OBJECT
public:
    enum PointerButtonState {
        PointerButtonReleased,
        PointerButtonPressed
    };
    enum PointerAxis {
        PointerAxisVertical,
        PointerAxisHorizontal
    };
78 79 80 81 82 83 84
    enum PointerAxisSource {
        PointerAxisSourceUnknown,
        PointerAxisSourceWheel,
        PointerAxisSourceFinger,
        PointerAxisSourceContinuous,
        PointerAxisSourceWheelTilt
    };
85 86
    enum KeyboardKeyState {
        KeyboardKeyReleased,
87 88
        KeyboardKeyPressed,
        KeyboardKeyAutoRepeat
89
    };
90 91 92 93 94
    enum TabletEventType {
        Axis,
        Proximity,
        Tip
    };
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
    enum TabletToolType {
        Pen,
        Eraser,
        Brush,
        Pencil,
        Airbrush,
        Finger,
        Mouse,
        Lens,
        Totem,
    };
    enum Capability {
        Tilt,
        Pressure,
        Distance,
        Rotation,
        Slider,
        Wheel,
    };

115
    ~InputRedirection() override;
116
    void init();
117 118 119

    /**
     * @return const QPointF& The current global pointer position
120
     */
121
    QPointF globalPointer() const;
122
    Qt::MouseButtons qtButtonStates() const;
123
    Qt::KeyboardModifiers keyboardModifiers() const;
124
    Qt::KeyboardModifiers modifiersRelevantForGlobalShortcuts() const;
125

126
    void registerShortcut(const QKeySequence &shortcut, QAction *action);
127 128 129 130 131 132 133
    /**
     * @overload
     *
     * Like registerShortcut, but also connects QAction::triggered to the @p slot on @p receiver.
     * It's recommended to use this method as it ensures that the X11 timestamp is updated prior
     * to the @p slot being invoked. If not using this overload it's required to ensure that
     * registerShortcut is called before connecting to QAction's triggered signal.
134
     */
135 136
    template <typename T, typename Slot>
    void registerShortcut(const QKeySequence &shortcut, QAction *action, T *receiver, Slot slot);
137
    void registerPointerShortcut(Qt::KeyboardModifiers modifiers, Qt::MouseButton pointerButtons, QAction *action);
138
    void registerAxisShortcut(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis, QAction *action);
139
    void registerTouchpadSwipeShortcut(SwipeDirection direction, QAction *action);
140
    void registerGlobalAccel(KGlobalAccelInterface *interface);
141

142 143
    /**
     * @internal
144
     */
145 146 147
    void processPointerMotion(const QPointF &pos, uint32_t time);
    /**
     * @internal
148
     */
149 150 151
    void processPointerButton(uint32_t button, PointerButtonState state, uint32_t time);
    /**
     * @internal
152
     */
153
    void processPointerAxis(PointerAxis axis, qreal delta, qint32 discreteDelta, PointerAxisSource source, uint32_t time);
154 155
    /**
     * @internal
156
     */
157 158 159
    void processKeyboardKey(uint32_t key, KeyboardKeyState state, uint32_t time);
    /**
     * @internal
160
     */
161 162 163
    void processKeyboardModifiers(uint32_t modsDepressed, uint32_t modsLatched, uint32_t modsLocked, uint32_t group);
    /**
     * @internal
164
     */
165
    void processKeymapChange(int fd, uint32_t size);
166 167 168 169 170
    void processTouchDown(qint32 id, const QPointF &pos, quint32 time);
    void processTouchUp(qint32 id, quint32 time);
    void processTouchMotion(qint32 id, const QPointF &pos, quint32 time);
    void cancelTouch();
    void touchFrame();
171

172 173 174
    bool supportsPointerWarping() const;
    void warpPointer(const QPointF &pos);

175 176 177 178 179 180
    /**
     * Adds the @p filter to the list of event filters and makes it the first
     * event filter in processing.
     *
     * Note: the event filter will get events before the lock screen can get them, thus
     * this is a security relevant method.
181
     */
Martin Flöser's avatar
Martin Flöser committed
182
    void prependInputEventFilter(InputEventFilter *filter);
183
    void uninstallInputEventFilter(InputEventFilter *filter);
184 185 186

    /**
     * Installs the @p spy for spying on events.
187
     */
188 189 190 191
    void installInputEventSpy(InputEventSpy *spy);

    /**
     * Uninstalls the @p spy. This happens automatically when deleting an InputEventSpy.
192
     */
193 194
    void uninstallInputEventSpy(InputEventSpy *spy);

195
    Toplevel *findToplevel(const QPoint &pos);
196
    Toplevel *findManagedToplevel(const QPoint &pos);
197 198 199 200
    GlobalShortcutsManager *shortcuts() const {
        return m_shortcuts;
    }

201 202 203 204 205
    /**
     * Sends an event through all InputFilters.
     * The method @p function is invoked on each input filter. Processing is stopped if
     * a filter returns @c true for @p function.
     *
206 207 208 209 210 211
     * The UnaryPredicate is defined like the UnaryPredicate of std::any_of.
     * The signature of the function should be equivalent to the following:
     * @code
     * bool function(const InputEventFilter *spy);
     * @endcode
     *
212 213
     * The intended usage is to std::bind the method to invoke on the filter with all arguments
     * bind.
214
     */
215 216 217 218
    template <class UnaryPredicate>
    void processFilters(UnaryPredicate function) {
        std::any_of(m_filters.constBegin(), m_filters.constEnd(), function);
    }
219

220 221 222 223 224 225 226 227 228 229 230 231
    /**
     * Sends an event through all input event spies.
     * The @p function is invoked on each InputEventSpy.
     *
     * The UnaryFunction is defined like the UnaryFunction of std::for_each.
     * The signature of the function should be equivalent to the following:
     * @code
     * void function(const InputEventSpy *spy);
     * @endcode
     *
     * The intended usage is to std::bind the method to invoke on the spies with all arguments
     * bind.
232
     */
233 234 235 236 237
    template <class UnaryFunction>
    void processSpies(UnaryFunction function) {
        std::for_each(m_spies.constBegin(), m_spies.constEnd(), function);
    }

238 239 240
    KeyboardInputRedirection *keyboard() const {
        return m_keyboard;
    }
241 242 243
    PointerInputRedirection *pointer() const {
        return m_pointer;
    }
244 245 246
    TabletInputRedirection *tablet() const {
        return m_tablet;
    }
247 248 249
    TouchInputRedirection *touch() const {
        return m_touch;
    }
250

251
    bool hasAlphaNumericKeyboard();
252
    bool hasTabletModeSwitch();
253

254
    void startInteractiveWindowSelection(std::function<void(KWin::Toplevel*)> callback, const QByteArray &cursorName);
255
    void startInteractivePositionSelection(std::function<void(const QPoint &)> callback);
256 257
    bool isSelectingWindow() const;

258 259 260 261 262
Q_SIGNALS:
    /**
     * @brief Emitted when the global pointer position changed
     *
     * @param pos The new global pointer position.
263
     */
264 265 266 267 268 269
    void globalPointerChanged(const QPointF &pos);
    /**
     * @brief Emitted when the state of a pointer button changed.
     *
     * @param button The button which changed
     * @param state The new button state
270
     */
271
    void pointerButtonStateChanged(uint32_t button, InputRedirection::PointerButtonState state);
272 273 274 275 276
    /**
     * @brief Emitted when a pointer axis changed
     *
     * @param axis The axis on which the even occurred
     * @param delta The delta of the event.
277
     */
278
    void pointerAxisChanged(InputRedirection::PointerAxis axis, qreal delta);
279 280 281 282 283 284 285 286
    /**
     * @brief Emitted when the modifiers changes.
     *
     * Only emitted for the mask which is provided by Qt::KeyboardModifiers, if other modifiers
     * change signal is not emitted
     *
     * @param newMods The new modifiers state
     * @param oldMods The previous modifiers state
287
     */
288
    void keyboardModifiersChanged(Qt::KeyboardModifiers newMods, Qt::KeyboardModifiers oldMods);
289 290 291 292
    /**
     * @brief Emitted when the state of a key changed.
     *
     * @param keyCode The keycode of the key which changed
Yuri Chornoivan's avatar
Yuri Chornoivan committed
293
     * @param state The new key state
294
     */
295
    void keyStateChanged(quint32 keyCode, InputRedirection::KeyboardKeyState state);
296

297
    void hasAlphaNumericKeyboardChanged(bool set);
298
    void hasTabletModeSwitchChanged(bool set);
299

300 301 302
private Q_SLOTS:
    void handleInputConfigChanged(const KConfigGroup &group);

303
private:
304
    void setupLibInput();
305
    void setupTouchpadShortcuts();
306
    void setupLibInputWithScreens();
307
    void setupWorkspace();
308
    void reconfigure();
309 310
    void setupInputFilters();
    void installInputEventFilter(InputEventFilter *filter);
311
    KeyboardInputRedirection *m_keyboard;
312
    PointerInputRedirection *m_pointer;
313
    TabletInputRedirection *m_tablet;
314
    TouchInputRedirection *m_touch;
315
    TabletInputFilter *m_tabletSupport = nullptr;
316

317 318
    GlobalShortcutsManager *m_shortcuts;

319 320
    LibInput::Connection *m_libInput = nullptr;

321 322
    WindowSelectorFilter *m_windowSelector = nullptr;

323
    QVector<InputEventFilter*> m_filters;
324
    QVector<InputEventSpy*> m_spies;
325
    KConfigWatcher::Ptr m_inputConfigWatcher;
326

327 328
    KWIN_SINGLETON(InputRedirection)
    friend InputRedirection *input();
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
    friend class DecorationEventFilter;
    friend class InternalWindowEventFilter;
    friend class ForwardInputFilter;
};

/**
 * Base class for filtering input events inside InputRedirection.
 *
 * The idea behind the InputEventFilter is to have task oriented
 * filters. E.g. there is one filter taking care of a locked screen,
 * one to take care of interacting with window decorations, etc.
 *
 * A concrete subclass can reimplement the virtual methods and decide
 * whether an event should be filtered out or not by returning either
 * @c true or @c false. E.g. the lock screen filter can easily ensure
 * that all events are filtered out.
 *
 * As soon as a filter returns @c true the processing is stopped. If
 * a filter returns @c false the next one is invoked. This means a filter
 * installed early gets to see more events than a filter installed later on.
 *
 * Deleting an instance of InputEventFilter automatically uninstalls it from
 * InputRedirection.
352
 */
353
class KWIN_EXPORT InputEventFilter
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
{
public:
    InputEventFilter();
    virtual ~InputEventFilter();

    /**
     * Event filter for pointer events which can be described by a QMouseEvent.
     *
     * Please note that the button translation in QMouseEvent cannot cover all
     * possible buttons. Because of that also the @p nativeButton code is passed
     * through the filter. For internal areas it's fine to use @p event, but for
     * passing to client windows the @p nativeButton should be used.
     *
     * @param event The event information about the move or button press/release
     * @param nativeButton The native key code of the button, for move events 0
     * @return @c true to stop further event processing, @c false to pass to next filter
370
     */
371 372 373 374 375 376
    virtual bool pointerEvent(QMouseEvent *event, quint32 nativeButton);
    /**
     * Event filter for pointer axis events.
     *
     * @param event The event information about the axis event
     * @return @c true to stop further event processing, @c false to pass to next filter
377
     */
378 379 380 381 382 383
    virtual bool wheelEvent(QWheelEvent *event);
    /**
     * Event filter for keyboard events.
     *
     * @param event The event information about the key event
     * @return @c tru to stop further event processing, @c false to pass to next filter.
384
     */
385
    virtual bool keyEvent(QKeyEvent *event);
386 387 388
    virtual bool touchDown(qint32 id, const QPointF &pos, quint32 time);
    virtual bool touchMotion(qint32 id, const QPointF &pos, quint32 time);
    virtual bool touchUp(qint32 id, quint32 time);
389 390 391 392 393 394 395 396 397 398

    virtual bool pinchGestureBegin(int fingerCount, quint32 time);
    virtual bool pinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time);
    virtual bool pinchGestureEnd(quint32 time);
    virtual bool pinchGestureCancelled(quint32 time);

    virtual bool swipeGestureBegin(int fingerCount, quint32 time);
    virtual bool swipeGestureUpdate(const QSizeF &delta, quint32 time);
    virtual bool swipeGestureEnd(quint32 time);
    virtual bool swipeGestureCancelled(quint32 time);
399

400 401
    virtual bool switchEvent(SwitchEvent *event);

402
    virtual bool tabletToolEvent(TabletEvent *event);
403 404 405 406 407
    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);

408 409
protected:
    void passToWaylandServer(QKeyEvent *event);
410 411
};

412
class KWIN_EXPORT InputDeviceHandler : public QObject
413 414 415
{
    Q_OBJECT
public:
416
    ~InputDeviceHandler() override;
417
    virtual void init();
418

419 420 421 422 423 424
    void update();

    /**
     * @brief First Toplevel currently at the position of the input device
     * according to the stacking order.
     * @return Toplevel* at device position.
425 426
     *
     * This will be null if no toplevel is at the position
427
     */
428
    Toplevel *at() const;
429 430 431 432
    /**
     * @brief Toplevel currently having pointer input focus (this might
     * be different from the Toplevel at the position of the pointer).
     * @return Toplevel* with pointer focus.
433 434
     *
     * This will be null if no toplevel has focus
435
     */
436 437
    Toplevel *focus() const;

438 439 440
    /**
     * @brief The Decoration currently receiving events.
     * @return decoration with pointer focus.
441
     */
442
    QPointer<Decoration::DecoratedClientImpl> decoration() const {
443
        return m_focus.decoration;
444
    }
445 446 447
    /**
     * @brief The internal window currently receiving events.
     * @return QWindow with pointer focus.
448
     */
449
    QPointer<QWindow> internalWindow() const {
450
        return m_focus.internalWindow;
451
    }
452

453 454 455 456 457 458
    virtual QPointF position() const = 0;

    void setFocus(Toplevel *toplevel);
    void setDecoration(QPointer<Decoration::DecoratedClientImpl> decoration);
    void setInternalWindow(QWindow *window);

459
Q_SIGNALS:
460
    void atChanged(Toplevel *old, Toplevel *now);
461 462 463 464
    void decorationChanged();

protected:
    explicit InputDeviceHandler(InputRedirection *parent);
465 466 467 468 469 470

    virtual void cleanupInternalWindow(QWindow *old, QWindow *now) = 0;
    virtual void cleanupDecoration(Decoration::DecoratedClientImpl *old, Decoration::DecoratedClientImpl *now) = 0;

    virtual void focusUpdate(Toplevel *old, Toplevel *now) = 0;

Vlad Zahorodnii's avatar
Vlad Zahorodnii committed
471 472
    /**
     * Certain input devices can be in a state of having no valid
473 474
     * position. An example are touch screens when no finger/pen
     * is resting on the surface (no touch point).
475
     */
476 477 478
    virtual bool positionValid() const {
        return false;
    }
479 480
    virtual bool focusUpdatesBlocked() {
        return false;
481
    }
482 483 484

    inline bool inited() const {
        return m_inited;
485
    }
486 487
    inline void setInited(bool set) {
        m_inited = set;
488 489 490
    }

private:
491 492 493 494 495 496 497
    bool setAt(Toplevel *toplevel);
    void updateFocus();
    bool updateDecoration();
    void updateInternalWindow(QWindow *window);

    QWindow* findInternalWindow(const QPoint &pos) const;

498 499 500 501 502
    struct {
        QPointer<Toplevel> at;
        QMetaObject::Connection surfaceCreatedConnection;
    } m_at;

503 504 505 506 507 508 509
    struct {
        QPointer<Toplevel> focus;
        QPointer<Decoration::DecoratedClientImpl> decoration;
        QPointer<QWindow> internalWindow;
    } m_focus;

    bool m_inited = false;
510 511
};

512 513 514 515 516 517
inline
InputRedirection *input()
{
    return InputRedirection::s_self;
}

518
template <typename T, typename Slot>
519
inline
520
void InputRedirection::registerShortcut(const QKeySequence &shortcut, QAction *action, T *receiver, Slot slot) {
521 522 523 524
    registerShortcut(shortcut, action);
    connect(action, &QAction::triggered, receiver, slot);
}

525 526
} // namespace KWin

527 528 529
Q_DECLARE_METATYPE(KWin::InputRedirection::KeyboardKeyState)
Q_DECLARE_METATYPE(KWin::InputRedirection::PointerButtonState)
Q_DECLARE_METATYPE(KWin::InputRedirection::PointerAxis)
530
Q_DECLARE_METATYPE(KWin::InputRedirection::PointerAxisSource)
531

532
#endif // KWIN_INPUT_H