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"