File indexing completed on 2024-11-10 04:57:11

0001 /*
0002     SPDX-FileCopyrightText: 2022 Nicolas Fella <nicolas.fella@gmx.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "stickykeys.h"
0008 #include "keyboard_input.h"
0009 #include "xkb.h"
0010 
0011 StickyKeysFilter::StickyKeysFilter()
0012     : m_configWatcher(KConfigWatcher::create(KSharedConfig::openConfig("kaccessrc")))
0013 {
0014     const QLatin1String groupName("Keyboard");
0015     connect(m_configWatcher.get(), &KConfigWatcher::configChanged, this, [this, groupName](const KConfigGroup &group) {
0016         if (group.name() == groupName) {
0017             loadConfig(group);
0018         }
0019     });
0020     loadConfig(m_configWatcher->config()->group(groupName));
0021 
0022     for (int mod : std::as_const(m_modifiers)) {
0023         m_keyStates[mod] = None;
0024     }
0025 }
0026 
0027 Qt::KeyboardModifier keyToModifier(Qt::Key key)
0028 {
0029     if (key == Qt::Key_Shift) {
0030         return Qt::ShiftModifier;
0031     } else if (key == Qt::Key_Alt) {
0032         return Qt::AltModifier;
0033     } else if (key == Qt::Key_Control) {
0034         return Qt::ControlModifier;
0035     } else if (key == Qt::Key_AltGr) {
0036         return Qt::GroupSwitchModifier;
0037     } else if (key == Qt::Key_Meta) {
0038         return Qt::MetaModifier;
0039     }
0040 
0041     return Qt::NoModifier;
0042 }
0043 
0044 void StickyKeysFilter::loadConfig(const KConfigGroup &group)
0045 {
0046     KWin::input()->uninstallInputEventFilter(this);
0047 
0048     m_lockKeys = group.readEntry<bool>("StickyKeysLatch", true);
0049 
0050     if (!m_lockKeys) {
0051         // locking keys is deactivated, unlock all locked keys
0052         for (auto it = m_keyStates.keyValueBegin(); it != m_keyStates.keyValueEnd(); ++it) {
0053             if (it->second == KeyState::Locked) {
0054                 it->second = KeyState::None;
0055                 KWin::input()->keyboard()->xkb()->setModifierLocked(keyToModifier(static_cast<Qt::Key>(it->first)), false);
0056             }
0057         }
0058     }
0059 
0060     if (group.readEntry<bool>("StickyKeys", false)) {
0061         KWin::input()->prependInputEventFilter(this);
0062     } else {
0063         // sticky keys are deactivated, unlatch all latched keys
0064         for (auto it = m_keyStates.keyValueBegin(); it != m_keyStates.keyValueEnd(); ++it) {
0065             if (it->second != KeyState::None) {
0066                 it->second = KeyState::None;
0067                 KWin::input()->keyboard()->xkb()->setModifierLatched(keyToModifier(static_cast<Qt::Key>(it->first)), false);
0068             }
0069         }
0070     }
0071 }
0072 
0073 bool StickyKeysFilter::keyEvent(KWin::KeyEvent *event)
0074 {
0075     if (m_modifiers.contains(event->key())) {
0076 
0077         auto keyState = m_keyStates.find(event->key());
0078 
0079         if (keyState != m_keyStates.end()) {
0080             if (event->type() == QKeyEvent::KeyPress) {
0081                 // An unlatched modifier was pressed, latch it
0082                 if (keyState.value() == None) {
0083                     keyState.value() = Latched;
0084                     KWin::input()->keyboard()->xkb()->setModifierLatched(keyToModifier(static_cast<Qt::Key>(event->key())), true);
0085                 }
0086                 // A latched modifier was pressed, lock it
0087                 else if (keyState.value() == Latched && m_lockKeys) {
0088                     keyState.value() = Locked;
0089                     KWin::input()->keyboard()->xkb()->setModifierLocked(keyToModifier(static_cast<Qt::Key>(event->key())), true);
0090                 }
0091                 // A locked modifier was pressed, unlock it
0092                 else if (keyState.value() == Locked && m_lockKeys) {
0093                     keyState.value() = None;
0094                     KWin::input()->keyboard()->xkb()->setModifierLocked(keyToModifier(static_cast<Qt::Key>(event->key())), false);
0095                 }
0096             }
0097         }
0098     } else if (event->type() == QKeyEvent::KeyPress) {
0099         // a non-modifier key was pressed, unlatch all unlocked modifiers
0100         for (auto it = m_keyStates.keyValueBegin(); it != m_keyStates.keyValueEnd(); ++it) {
0101 
0102             if (it->second == Locked) {
0103                 continue;
0104             }
0105 
0106             it->second = KeyState::None;
0107 
0108             KWin::input()->keyboard()->xkb()->setModifierLatched(keyToModifier(static_cast<Qt::Key>(it->first)), false);
0109         }
0110     }
0111 
0112     return false;
0113 }
0114 
0115 #include "moc_stickykeys.cpp"