File indexing completed on 2024-04-14 15:33:38

0001 /*
0002 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004 SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 #pragma once
0007 
0008 #include <KGlobalShortcutInfo>
0009 
0010 #include <QMap>
0011 #include <QObject>
0012 
0013 class QDBusPendingCallWatcher;
0014 class QKeyEvent;
0015 
0016 struct xcb_key_press_event_t;
0017 typedef struct _XCBKeySymbols xcb_key_symbols_t;
0018 
0019 /**
0020  * @short Interaction with KGlobalAccel.
0021  *
0022  * While the screen is locked, we want a few white listed global shortcuts to activate.
0023  * While the screen is locked KGlobalAcceld is not functional as the screen locker holds an
0024  * active X11 key grab and KGlobalAcceld does not get the key events. This prevents useful keys,
0025  * like volume control to no longer function.
0026  *
0027  * This class circumvents the problem by interacting with KGlobalAccel when the screen is locked
0028  * to still allow a few white listed shortcuts (like volume control) to function.
0029  *
0030  * As the screen is locked we can operate on a few assumptions which simplifies the interaction:
0031  * shortcuts won't change. The user cannot interact with the system thus the global shortcut won't
0032  * change while the screen is locked. This allows us to fetch the allowed shortcut information from
0033  * KGlobalAcceld when the screen gets locked and keep these information around till the screen is
0034  * unlocked. We do not need to update the information while the screen is locked.
0035  *
0036  * As the information is fetched in an async way from KGlobalAcceld there is a short time window
0037  * when the screen is locked, but the shortcut information is not fetched. This is considered a
0038  * not relevant corner case as we can assume that right when the screen locks (due to e.g. idle)
0039  * no user is in front of the system and is not able to press the shortcut or that the user directly
0040  * wants to cancel the lock screen again (grace time).
0041  *
0042  * Components are just registered by name in KGlobalAccel. This would in theory allow a malicious
0043  * application to register under a white listed name with white listed shortcuts and bind enough
0044  * shortcuts to turn this functionality into a key grabber to read the users password. To prevent such
0045  * attacks the shortcuts which can be invoked are restricted: the triggered key may not be a single
0046  * key in alphanumeric area with or without the shift keys. If a global shortcut contains an
0047  * alphanumeric key it will only be handled if also an additional modifier like Alt of Meta is pressed.
0048  **/
0049 class GlobalAccel : public QObject
0050 {
0051     Q_OBJECT
0052 public:
0053     explicit GlobalAccel(QObject *parent = nullptr);
0054 
0055     /**
0056      * Starts interacting with KGlobalAccel and fetches the up-to-date shortcut information.
0057      **/
0058     void prepare();
0059     /**
0060      * Discards all knowing shortcut information.
0061      **/
0062     void release();
0063 
0064     /**
0065      * Checks whether a global shortcut is triggered for the given @p event.
0066      * If there is a global shortcut it gets invoked and @c true is returned.
0067      * If there is no matching global shortcut @c false is returned.
0068      **/
0069     bool checkKeyPress(xcb_key_press_event_t *event);
0070 
0071     bool keyEvent(QKeyEvent *event);
0072 
0073 private:
0074     void components(QDBusPendingCallWatcher *watcher);
0075     /**
0076      * Recursion check: for each DBus call to KGlobalAccel this counter is
0077      * increased, on each reply decreased. As long as we have running DBus
0078      * calls, we do not enter prepare again.
0079      *
0080      * This ensures that if the screen gets locked, unlocked, locked in a short
0081      * time while we are still fetching information from KGlobalAccel we do not
0082      * enter an incorrect state.
0083      **/
0084     uint m_updatingInformation = 0;
0085     /**
0086      * The shortcuts which got fetched from KGlobalAccel and can be operated on.
0087      * The key of contains the component DBus object path, the value the list of
0088      * allowed shortcuts.
0089      **/
0090     QMap<QString, QList<KGlobalShortcutInfo>> m_shortcuts;
0091     xcb_key_symbols_t *m_keySymbols = nullptr;
0092 };