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 };