File indexing completed on 2024-12-01 13:37:33

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2016, 2017 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "modifier_only_shortcuts.h"
0010 
0011 #include <config-kwin.h>
0012 
0013 #include "input_event.h"
0014 #include "options.h"
0015 #if KWIN_BUILD_SCREENLOCKER
0016 #include "screenlockerwatcher.h"
0017 #endif
0018 #include "wayland_server.h"
0019 #include "workspace.h"
0020 
0021 #include <QDBusConnection>
0022 #include <QDBusMessage>
0023 #include <QDBusPendingCall>
0024 
0025 namespace KWin
0026 {
0027 
0028 ModifierOnlyShortcuts::ModifierOnlyShortcuts()
0029     : QObject()
0030     , InputEventSpy()
0031 {
0032 #if KWIN_BUILD_SCREENLOCKER
0033     connect(kwinApp()->screenLockerWatcher(), &ScreenLockerWatcher::locked, this, &ModifierOnlyShortcuts::reset);
0034 #endif
0035 }
0036 
0037 ModifierOnlyShortcuts::~ModifierOnlyShortcuts() = default;
0038 
0039 void ModifierOnlyShortcuts::keyEvent(KeyEvent *event)
0040 {
0041     if (event->isAutoRepeat()) {
0042         return;
0043     }
0044     if (event->type() == QEvent::KeyPress) {
0045         const bool wasEmpty = m_pressedKeys.isEmpty();
0046         m_pressedKeys.insert(event->nativeScanCode());
0047         if (wasEmpty && m_pressedKeys.size() == 1 &&
0048 #if KWIN_BUILD_SCREENLOCKER
0049             !kwinApp()->screenLockerWatcher()->isLocked() &&
0050 #endif
0051             m_pressedButtons == Qt::NoButton && m_cachedMods == Qt::NoModifier) {
0052             m_modifier = Qt::KeyboardModifier(int(event->modifiersRelevantForGlobalShortcuts()));
0053         } else {
0054             m_modifier = Qt::NoModifier;
0055         }
0056     } else if (!m_pressedKeys.isEmpty()) {
0057         m_pressedKeys.remove(event->nativeScanCode());
0058         if (m_pressedKeys.isEmpty() && event->modifiersRelevantForGlobalShortcuts() == Qt::NoModifier && workspace() && !workspace()->globalShortcutsDisabled()) {
0059             if (m_modifier != Qt::NoModifier) {
0060                 const auto list = options->modifierOnlyDBusShortcut(m_modifier);
0061                 if (list.size() >= 4) {
0062                     if (!waylandServer() || !waylandServer()->isKeyboardShortcutsInhibited()) {
0063                         auto call = QDBusMessage::createMethodCall(list.at(0), list.at(1), list.at(2), list.at(3));
0064                         QVariantList args;
0065                         for (int i = 4; i < list.size(); ++i) {
0066                             args << list.at(i);
0067                         }
0068                         call.setArguments(args);
0069                         QDBusConnection::sessionBus().asyncCall(call);
0070                     }
0071                 }
0072             }
0073         }
0074         m_modifier = Qt::NoModifier;
0075     } else {
0076         m_modifier = Qt::NoModifier;
0077     }
0078     m_cachedMods = event->modifiersRelevantForGlobalShortcuts();
0079 }
0080 
0081 void ModifierOnlyShortcuts::pointerEvent(MouseEvent *event)
0082 {
0083     if (event->type() == QEvent::MouseMove) {
0084         return;
0085     }
0086     m_pressedButtons = event->buttons();
0087     reset();
0088 }
0089 
0090 void ModifierOnlyShortcuts::wheelEvent(WheelEvent *event)
0091 {
0092     reset();
0093 }
0094 
0095 }