| 1 | /* |
| 2 | This file is part of the KDE libraries |
| 3 | SPDX-FileCopyrightText: 2001, 2002 Ellis Whitehead <ellis@kde.org> |
| 4 | SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org> |
| 5 | SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com> |
| 6 | |
| 7 | SPDX-License-Identifier: LGPL-2.0-or-later |
| 8 | */ |
| 9 | |
| 10 | #ifndef _KGLOBALACCEL_H_ |
| 11 | #define _KGLOBALACCEL_H_ |
| 12 | |
| 13 | #include "kglobalshortcutinfo.h" |
| 14 | #include <kglobalaccel_export.h> |
| 15 | |
| 16 | #include <QKeySequence> |
| 17 | #include <QList> |
| 18 | #include <QObject> |
| 19 | |
| 20 | class QAction; |
| 21 | class OrgKdeKglobalaccelComponentInterface; |
| 22 | |
| 23 | /*! |
| 24 | * \class KGlobalAccel |
| 25 | * \inmodule KGlobalAccel |
| 26 | * \brief Configurable global shortcut support. |
| 27 | * |
| 28 | * KGlobalAccel allows you to have global accelerators that are independent of |
| 29 | * the focused window. Unlike regular shortcuts, the application's window does not need focus |
| 30 | * for them to be activated. |
| 31 | * |
| 32 | * Here's an example how to register the Meta + E global shortcut: |
| 33 | * |
| 34 | * \code |
| 35 | * QAction *action = new QAction(); |
| 36 | * action->setObjectName(QStringLiteral("actionId")); |
| 37 | * action->setText(QStringLiteral("human readable name")); |
| 38 | * KGlobalAccel::self()->setDefaultShortcut(action, QList<QKeySequence>() << (Qt::META | Qt::Key_E)); |
| 39 | * KGlobalAccel::self()->setShortcut(action, QList<QKeySequence>() << (Qt::META | Qt::Key_E)); |
| 40 | * connect(action, &QAction::triggered, []() { |
| 41 | * qDebug() << "global shortcut trigerred"; |
| 42 | * }); |
| 43 | * \endcode |
| 44 | * |
| 45 | * \sa KKeySequenceRecorder |
| 46 | */ |
| 47 | class KGLOBALACCEL_EXPORT KGlobalAccel : public QObject |
| 48 | { |
| 49 | Q_OBJECT |
| 50 | |
| 51 | public: |
| 52 | /*! |
| 53 | * \enum KGlobalAccel::GlobalShortcutLoading |
| 54 | * |
| 55 | * An enum about global shortcut setter semantics |
| 56 | * |
| 57 | * \value Autoloading |
| 58 | * Look up the action in global settings (using its main component's name and text()) and |
| 59 | * set the shortcut as saved there. |
| 60 | * \sa setGlobalShortcut() |
| 61 | * \value NoAutoloading |
| 62 | * Prevent autoloading of saved global shortcut for action. |
| 63 | */ |
| 64 | enum GlobalShortcutLoading { |
| 65 | Autoloading = 0x0, |
| 66 | NoAutoloading = 0x4, |
| 67 | }; |
| 68 | |
| 69 | /*! |
| 70 | * \enum KGlobalAccel::actionIdFields |
| 71 | * |
| 72 | * Index for actionId QStringLists |
| 73 | * |
| 74 | * \value ComponentUnique |
| 75 | * Components Unique Name (ID). |
| 76 | * \value ActionUnique |
| 77 | * Actions Unique Name (ID). |
| 78 | * \value ComponentFriendly |
| 79 | * Components Friendly Translated Name |
| 80 | * \value ActionFriendly |
| 81 | * Actions Friendly Translated Name |
| 82 | */ |
| 83 | enum actionIdFields { |
| 84 | ComponentUnique = 0, |
| 85 | ActionUnique = 1, |
| 86 | ComponentFriendly = 2, |
| 87 | ActionFriendly = 3, |
| 88 | }; |
| 89 | |
| 90 | /*! |
| 91 | * \enum KGlobalAccel::MatchType |
| 92 | * |
| 93 | * Keysequence match semantics. |
| 94 | * |
| 95 | * Assuming we have an Emacs-style shortcut, for example (Alt+B, Alt+F, Alt+G) already assigned, |
| 96 | * how a new shortcut is compared depends on which value of the enum is used. |
| 97 | * |
| 98 | * \value Equal Exact matching: (Alt+B, Alt+F, Alt+G) |
| 99 | * \value Shadows Sequence shadowing: (Alt+B, Alt+F), (Alt+F, Alt+G) |
| 100 | * \value Shadowed Sequence being shadowed: (Alt+B, Alt+F, Alt+G, <any key>), (<any key>, Alt+B, Alt+F, Alt+G) |
| 101 | * |
| 102 | * \since 5.90 |
| 103 | */ |
| 104 | enum MatchType { |
| 105 | Equal, |
| 106 | Shadows, |
| 107 | Shadowed, |
| 108 | }; |
| 109 | Q_ENUM(MatchType) |
| 110 | |
| 111 | /*! |
| 112 | * Returns (and creates if necessary) the singleton instance |
| 113 | */ |
| 114 | static KGlobalAccel *self(); |
| 115 | |
| 116 | /*! |
| 117 | * Take away the given shortcut \a seq from the named action it belongs to. |
| 118 | * This applies to all actions with global shortcuts in any KDE application. |
| 119 | * |
| 120 | * \sa promptStealShortcutSystemwide() |
| 121 | */ |
| 122 | static void stealShortcutSystemwide(const QKeySequence &seq); |
| 123 | |
| 124 | /*! |
| 125 | * Clean the shortcuts for component \a componentUnique. |
| 126 | * |
| 127 | * If the component is not active all global shortcut registrations are |
| 128 | * purged and the component is removed completely. |
| 129 | * |
| 130 | * If the component is active all global shortcut registrations not in use |
| 131 | * will be purged. If there is no shortcut registration left the component |
| 132 | * is purged too. |
| 133 | * |
| 134 | * If a purged component or shortcut is activated the next time it will |
| 135 | * reregister itself. All you probably will lose on wrong usage are the |
| 136 | * user's set shortcuts. |
| 137 | * |
| 138 | * If you make sure your component is running and all global shortcuts it |
| 139 | * has are active this function can be used to clean up the registry. |
| 140 | * |
| 141 | * Handle with care! |
| 142 | * |
| 143 | * If the method return \c true at least one shortcut was purged so handle |
| 144 | * all previously acquired information with care. |
| 145 | */ |
| 146 | static bool cleanComponent(const QString &componentUnique); |
| 147 | |
| 148 | /*! |
| 149 | * Returns \c true if the component with the given \a componentName exists; otherwise returns \c false. |
| 150 | */ |
| 151 | static bool isComponentActive(const QString &componentName); |
| 152 | |
| 153 | /*! |
| 154 | * Returns a list of global shortcuts registered for the shortcut \a seq using |
| 155 | * the given matching \a type. |
| 156 | * |
| 157 | * If the list contains more that one entry it means the component |
| 158 | * that registered the shortcuts uses global shortcut contexts. All |
| 159 | * returned shortcuts belong to the same component. |
| 160 | * |
| 161 | * \since 5.90 |
| 162 | */ |
| 163 | static QList<KGlobalShortcutInfo> globalShortcutsByKey(const QKeySequence &seq, MatchType type = Equal); |
| 164 | |
| 165 | /*! |
| 166 | * Returns \c true if the shortcut \a seq is available for the \a component; otherwise returns |
| 167 | * \c false. |
| 168 | * |
| 169 | * The component is only of interest if the current application uses global shortcut |
| 170 | * contexts. In that case a global shortcut by \a component in an inactive |
| 171 | * global shortcut contexts does not block the \a seq for us. |
| 172 | * |
| 173 | * \since 4.2 |
| 174 | */ |
| 175 | static bool isGlobalShortcutAvailable(const QKeySequence &seq, const QString &component = QString()); |
| 176 | |
| 177 | /*! |
| 178 | * Show a messagebox to inform the user that a global shortcut is already occupied, |
| 179 | * and ask to take it away from its current action(s). This is GUI only, so nothing will |
| 180 | * be actually changed. |
| 181 | * |
| 182 | * Returns \c true if user confirms that it is okay to re-assign the global shorcut; |
| 183 | * otherwise returns \c false. |
| 184 | * |
| 185 | * \sa stealShortcutSystemwide() |
| 186 | * |
| 187 | * \since 4.2 |
| 188 | */ |
| 189 | static bool promptStealShortcutSystemwide(QWidget *parent, const QList<KGlobalShortcutInfo> &shortcuts, const QKeySequence &seq); |
| 190 | |
| 191 | /*! |
| 192 | * Assign a default global \a shortcut for a given \a action. |
| 193 | * |
| 194 | * For more information about global shortcuts and \a loadFlag, see setShortcut(). |
| 195 | * |
| 196 | * Upon shortcut change the globalShortcutChanged() will be triggered so other applications get notified. |
| 197 | * |
| 198 | * Returns \c true if the shortcut has been set successfully; otherwise returns \c false. |
| 199 | * |
| 200 | * \sa globalShortcutChanged() |
| 201 | * |
| 202 | * \since 5.0 |
| 203 | */ |
| 204 | bool setDefaultShortcut(QAction *action, const QList<QKeySequence> &shortcut, GlobalShortcutLoading loadFlag = Autoloading); |
| 205 | |
| 206 | /*! |
| 207 | * Assign a global shortcut for the given action. |
| 208 | * |
| 209 | * Global shortcuts allow an action to respond to key shortcuts independently of the focused window, |
| 210 | * i.e. the action will trigger if the keys were pressed no matter where in the X session. |
| 211 | * |
| 212 | * The action must have a per main component unique |
| 213 | * action->objectName() to enable cross-application bookkeeping. If the action->objectName() is |
| 214 | * empty this method will do nothing and will return false. |
| 215 | * |
| 216 | * It is mandatory that the action->objectName() doesn't change once the shortcut has been |
| 217 | * successfully registered. |
| 218 | * |
| 219 | * \note KActionCollection::insert(name, action) will set action's objectName to name so you often |
| 220 | * don't have to set an objectName explicitly. |
| 221 | * |
| 222 | * When an action, identified by main component name and objectName(), is assigned |
| 223 | * a global shortcut for the first time on a KDE installation the assignment will |
| 224 | * be saved. The shortcut will then be restored every time setGlobalShortcut() is |
| 225 | * called with \a loadFlag == Autoloading. |
| 226 | * |
| 227 | * If you actually want to change the global shortcut you have to set |
| 228 | * \a loadFlag to NoAutoloading. The new shortcut will be automatically saved again. |
| 229 | * |
| 230 | * \a action specifies the action for which the shortcut will be assigned. |
| 231 | * |
| 232 | * \a shortcut specifies the global shortcut(s) to assign. Will be ignored unless \a loadFlag is |
| 233 | * set to NoAutoloading or this is the first time ever you call this method (see above). |
| 234 | * |
| 235 | * If \a loadFlag is KGlobalAccel::Autoloading, assign the global shortcut this action has |
| 236 | * previously had if any. That way user preferences and changes made to avoid clashes will be |
| 237 | * conserved. If KGlobalAccel::NoAutoloading the given shortcut will be assigned without |
| 238 | * looking up old values. You should only do this if the user wants to change the shortcut or |
| 239 | * if you have another very good reason. Key combinations that clash with other shortcuts will be |
| 240 | * dropped. |
| 241 | * |
| 242 | * \note the default shortcut will never be influenced by autoloading - it will be set as given. |
| 243 | * \sa shortcut(), globalShortcutChanged() |
| 244 | * \since 5.0 |
| 245 | */ |
| 246 | bool setShortcut(QAction *action, const QList<QKeySequence> &shortcut, GlobalShortcutLoading loadFlag = Autoloading); |
| 247 | |
| 248 | /*! |
| 249 | * Sets both active and default \a shortcuts for the given \a action. |
| 250 | * |
| 251 | * If more control for loading the shortcuts is needed use the variants offering more control. |
| 252 | * |
| 253 | * Returns \c true if the shortcut has been set successfully; otherwise returns \c false. |
| 254 | * |
| 255 | * \sa setShortcut(), setDefaultShortcut() |
| 256 | * \since 5.0 |
| 257 | */ |
| 258 | static bool setGlobalShortcut(QAction *action, const QList<QKeySequence> &shortcuts); |
| 259 | |
| 260 | /*! |
| 261 | * Sets both active and default \a shortcut for the given \a action. |
| 262 | * |
| 263 | * This method is suited for the case that only one shortcut is to be configured. |
| 264 | * |
| 265 | * If more control for loading the shortcuts is needed use the variants offering more control. |
| 266 | * |
| 267 | * Returns \c true if the shortcut has been set successfully; otherwise returns \c false. |
| 268 | * |
| 269 | * \sa setShortcut(), setDefaultShortcut() |
| 270 | * \since 5.0 |
| 271 | */ |
| 272 | static bool setGlobalShortcut(QAction *action, const QKeySequence &shortcut); |
| 273 | |
| 274 | /*! |
| 275 | * Get the global default shortcut for this \a action, if one exists. Global shortcuts |
| 276 | * allow your actions to respond to accellerators independently of the focused window. |
| 277 | * Unlike regular shortcuts, the application's window does not need focus |
| 278 | * for them to be activated. |
| 279 | * |
| 280 | * \sa setDefaultShortcut() |
| 281 | * \since 5.0 |
| 282 | */ |
| 283 | QList<QKeySequence> defaultShortcut(const QAction *action) const; |
| 284 | |
| 285 | /*! |
| 286 | * Get the global shortcut for this \a action, if one exists. Global shortcuts |
| 287 | * allow your actions to respond to accellerators independently of the focused window. |
| 288 | * Unlike regular shortcuts, the application's window does not need focus |
| 289 | * for them to be activated. |
| 290 | * |
| 291 | * \note that this method only works together with setShortcut() because the action pointer |
| 292 | * is used to retrieve the result. If you would like to retrieve the shortcut as stored |
| 293 | * in the global settings, use the globalShortcut(componentName, actionId) instead. |
| 294 | * |
| 295 | * \sa setShortcut() |
| 296 | * \since 5.0 |
| 297 | */ |
| 298 | QList<QKeySequence> shortcut(const QAction *action) const; |
| 299 | |
| 300 | /*! |
| 301 | * Retrieves the shortcut as defined in global settings by |
| 302 | * \a componentName (e.g. "kwin") and \a actionId (e.g. "Kill Window"). |
| 303 | * |
| 304 | * \since 5.10 |
| 305 | */ |
| 306 | QList<QKeySequence> globalShortcut(const QString &componentName, const QString &actionId) const; |
| 307 | |
| 308 | /*! |
| 309 | * Unregister and remove all defined global shortcuts for the given \a action. |
| 310 | * |
| 311 | * \since 5.0 |
| 312 | */ |
| 313 | void removeAllShortcuts(QAction *action); |
| 314 | |
| 315 | /*! |
| 316 | * Returns true if a shortcut or a default shortcut has been registered for the given \a action. |
| 317 | * |
| 318 | * \since 5.0 |
| 319 | */ |
| 320 | bool hasShortcut(const QAction *action) const; |
| 321 | |
| 322 | Q_SIGNALS: |
| 323 | /*! |
| 324 | * Emitted when the global shortcut is changed. A global shortcut is subject to be changed by |
| 325 | * the global shortcuts kcm. |
| 326 | * |
| 327 | * \a action specifies the action for which the changed shortcut was registered. |
| 328 | * |
| 329 | * \a seq indicates the key sequence that corresponds to the changed shortcut. |
| 330 | * |
| 331 | * \sa setGlobalShortcut(), setDefaultShortcut() |
| 332 | * \since 5.0 |
| 333 | */ |
| 334 | void globalShortcutChanged(QAction *action, const QKeySequence &seq); |
| 335 | /*! |
| 336 | * Emitted when a global shortcut for the given \a action is activated or deactivated. |
| 337 | * |
| 338 | * The global shorcut will be activated when the keys are pressed and deactivated when the |
| 339 | * keys are released. \a active indicates whether the global shortcut is active. |
| 340 | * |
| 341 | * \since 5.94 |
| 342 | */ |
| 343 | void globalShortcutActiveChanged(QAction *action, bool active); |
| 344 | |
| 345 | private: |
| 346 | KGLOBALACCEL_NO_EXPORT KGlobalAccel(); |
| 347 | KGLOBALACCEL_NO_EXPORT ~KGlobalAccel() override; |
| 348 | |
| 349 | KGLOBALACCEL_NO_EXPORT OrgKdeKglobalaccelComponentInterface *getComponent(const QString &componentUnique); |
| 350 | |
| 351 | class KGlobalAccelPrivate *const d; |
| 352 | |
| 353 | friend class KGlobalAccelSingleton; |
| 354 | }; |
| 355 | |
| 356 | KGLOBALACCEL_EXPORT QDBusArgument &operator<<(QDBusArgument &argument, const KGlobalAccel::MatchType &type); |
| 357 | KGLOBALACCEL_EXPORT const QDBusArgument &operator>>(const QDBusArgument &argument, KGlobalAccel::MatchType &type); |
| 358 | |
| 359 | #endif // _KGLOBALACCEL_H_ |
| 360 | |