File indexing completed on 2024-12-08 07:59:26

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #pragma once
0010 // KWin
0011 #include "effect/globals.h"
0012 // Qt
0013 #include <QKeySequence>
0014 
0015 #include <memory>
0016 
0017 class QAction;
0018 class KGlobalAccelD;
0019 class KGlobalAccelInterface;
0020 
0021 namespace KWin
0022 {
0023 class GlobalShortcut;
0024 class SwipeGesture;
0025 class PinchGesture;
0026 class GestureRecognizer;
0027 
0028 enum class DeviceType {
0029     Touchpad,
0030     Touchscreen
0031 };
0032 
0033 /**
0034  * @brief Manager for the global shortcut system inside KWin.
0035  *
0036  * This class is responsible for holding all the global shortcuts and to process a key press event.
0037  * That is trigger a shortcut if there is a match.
0038  *
0039  * For internal shortcut handling (those which are delivered inside KWin) QActions are used and
0040  * triggered if the shortcut matches. For external shortcut handling a DBus interface is used.
0041  */
0042 class GlobalShortcutsManager : public QObject
0043 {
0044     Q_OBJECT
0045 public:
0046     explicit GlobalShortcutsManager(QObject *parent = nullptr);
0047     ~GlobalShortcutsManager() override;
0048     void init();
0049 
0050     /**
0051      * @brief Registers an internal global pointer shortcut
0052      *
0053      * @param action The action to trigger if the shortcut is pressed
0054      * @param modifiers The modifiers which need to be hold to trigger the action
0055      * @param pointerButtons The pointer button which needs to be pressed
0056      */
0057     void registerPointerShortcut(QAction *action, Qt::KeyboardModifiers modifiers, Qt::MouseButtons pointerButtons);
0058     /**
0059      * @brief Registers an internal global axis shortcut
0060      *
0061      * @param action The action to trigger if the shortcut is triggered
0062      * @param modifiers The modifiers which need to be hold to trigger the action
0063      * @param axis The pointer axis
0064      */
0065     void registerAxisShortcut(QAction *action, Qt::KeyboardModifiers modifiers, PointerAxisDirection axis);
0066 
0067     void registerTouchpadSwipe(SwipeDirection direction, uint32_t fingerCount, QAction *action, std::function<void(qreal)> progressCallback = {});
0068     void registerTouchpadPinch(PinchDirection direction, uint32_t fingerCount, QAction *action, std::function<void(qreal)> progressCallback = {});
0069     void registerTouchscreenSwipe(SwipeDirection direction, uint32_t fingerCount, QAction *action, std::function<void(qreal)> progressCallback = {});
0070     void forceRegisterTouchscreenSwipe(SwipeDirection direction, uint32_t fingerCount, QAction *action, std::function<void(qreal)> progressCallback = {});
0071 
0072     /**
0073      * @brief Processes a key event to decide whether a shortcut needs to be triggered.
0074      *
0075      * If a shortcut triggered this method returns @c true to indicate to the caller that the event
0076      * should not be further processed. If there is no shortcut which triggered for the key, then
0077      * @c false is returned.
0078      *
0079      * @param modifiers The current hold modifiers
0080      * @param keyQt The Qt::Key which got pressed
0081      * @return @c true if a shortcut triggered, @c false otherwise
0082      */
0083     bool processKey(Qt::KeyboardModifiers modifiers, int keyQt);
0084     bool processKeyRelease(Qt::KeyboardModifiers modifiers, int keyQt);
0085     bool processPointerPressed(Qt::KeyboardModifiers modifiers, Qt::MouseButtons pointerButtons);
0086     /**
0087      * @brief Processes a pointer axis event to decide whether a shortcut needs to be triggered.
0088      *
0089      * If a shortcut triggered this method returns @c true to indicate to the caller that the event
0090      * should not be further processed. If there is no shortcut which triggered for the key, then
0091      * @c false is returned.
0092      *
0093      * @param modifiers The current hold modifiers
0094      * @param axis The axis direction which has triggered this event
0095      * @return @c true if a shortcut triggered, @c false otherwise
0096      */
0097     bool processAxis(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis);
0098 
0099     void processSwipeStart(DeviceType device, uint fingerCount);
0100     void processSwipeUpdate(DeviceType device, const QPointF &delta);
0101     void processSwipeCancel(DeviceType device);
0102     void processSwipeEnd(DeviceType device);
0103 
0104     void processPinchStart(uint fingerCount);
0105     void processPinchUpdate(qreal scale, qreal angleDelta, const QPointF &delta);
0106     void processPinchCancel();
0107     void processPinchEnd();
0108 
0109     void setKGlobalAccelInterface(KGlobalAccelInterface *interface)
0110     {
0111         m_kglobalAccelInterface = interface;
0112     }
0113 
0114 private:
0115     void objectDeleted(QObject *object);
0116     bool add(GlobalShortcut sc, DeviceType device = DeviceType::Touchpad);
0117 
0118     QList<GlobalShortcut> m_shortcuts;
0119 
0120     std::unique_ptr<KGlobalAccelD> m_kglobalAccel;
0121     KGlobalAccelInterface *m_kglobalAccelInterface = nullptr;
0122     std::unique_ptr<GestureRecognizer> m_touchpadGestureRecognizer;
0123     std::unique_ptr<GestureRecognizer> m_touchscreenGestureRecognizer;
0124 };
0125 
0126 struct KeyboardShortcut
0127 {
0128     QKeySequence sequence;
0129     bool operator==(const KeyboardShortcut &rhs) const
0130     {
0131         return sequence == rhs.sequence;
0132     }
0133 };
0134 struct PointerButtonShortcut
0135 {
0136     Qt::KeyboardModifiers pointerModifiers;
0137     Qt::MouseButtons pointerButtons;
0138     bool operator==(const PointerButtonShortcut &rhs) const
0139     {
0140         return pointerModifiers == rhs.pointerModifiers && pointerButtons == rhs.pointerButtons;
0141     }
0142 };
0143 struct PointerAxisShortcut
0144 {
0145     Qt::KeyboardModifiers axisModifiers;
0146     PointerAxisDirection axisDirection;
0147     bool operator==(const PointerAxisShortcut &rhs) const
0148     {
0149         return axisModifiers == rhs.axisModifiers && axisDirection == rhs.axisDirection;
0150     }
0151 };
0152 struct RealtimeFeedbackSwipeShortcut
0153 {
0154     DeviceType device;
0155     SwipeDirection direction;
0156     std::function<void(qreal)> progressCallback;
0157     uint fingerCount;
0158 
0159     template<typename T>
0160     bool operator==(const T &rhs) const
0161     {
0162         return direction == rhs.direction && fingerCount == rhs.fingerCount && device == rhs.device;
0163     }
0164 };
0165 struct RealtimeFeedbackPinchShortcut
0166 {
0167     PinchDirection direction;
0168     std::function<void(qreal)> scaleCallback;
0169     uint fingerCount;
0170 
0171     template<typename T>
0172     bool operator==(const T &rhs) const
0173     {
0174         return direction == rhs.direction && fingerCount == rhs.fingerCount;
0175     }
0176 };
0177 
0178 using Shortcut = std::variant<KeyboardShortcut, PointerButtonShortcut, PointerAxisShortcut, RealtimeFeedbackSwipeShortcut, RealtimeFeedbackPinchShortcut>;
0179 
0180 class GlobalShortcut
0181 {
0182 public:
0183     GlobalShortcut(Shortcut &&shortcut, QAction *action);
0184     ~GlobalShortcut();
0185 
0186     void invoke() const;
0187     QAction *action() const;
0188     const Shortcut &shortcut() const;
0189     SwipeGesture *swipeGesture() const;
0190     PinchGesture *pinchGesture() const;
0191 
0192 private:
0193     std::shared_ptr<SwipeGesture> m_swipeGesture;
0194     std::shared_ptr<PinchGesture> m_pinchGesture;
0195     Shortcut m_shortcut = {};
0196     QAction *m_action = nullptr;
0197 };
0198 
0199 } // namespace