plugins/stickykeys: Disable when two keys are pressed
BUG: 464453
This commit is contained in:
parent
7d3f58d0ca
commit
e3ad1fa04f
3 changed files with 91 additions and 0 deletions
|
@ -37,12 +37,14 @@ private Q_SLOTS:
|
||||||
void testStick_data();
|
void testStick_data();
|
||||||
void testLock();
|
void testLock();
|
||||||
void testLock_data();
|
void testLock_data();
|
||||||
|
void testDisableTwoKeys();
|
||||||
};
|
};
|
||||||
|
|
||||||
void StickyKeysTest::initTestCase()
|
void StickyKeysTest::initTestCase()
|
||||||
{
|
{
|
||||||
KConfig kaccessConfig("kaccessrc");
|
KConfig kaccessConfig("kaccessrc");
|
||||||
kaccessConfig.group(QStringLiteral("Keyboard")).writeEntry("StickyKeys", true);
|
kaccessConfig.group(QStringLiteral("Keyboard")).writeEntry("StickyKeys", true);
|
||||||
|
kaccessConfig.group(QStringLiteral("Keyboard")).writeEntry("StickyKeysAutoOff", true);
|
||||||
kaccessConfig.sync();
|
kaccessConfig.sync();
|
||||||
|
|
||||||
// Use a keyboard layout where right alt triggers Mod5/AltGr
|
// Use a keyboard layout where right alt triggers Mod5/AltGr
|
||||||
|
@ -217,6 +219,69 @@ void StickyKeysTest::testLock()
|
||||||
|
|
||||||
Test::keyboardKeyReleased(modifierKey, ++timestamp);
|
Test::keyboardKeyReleased(modifierKey, ++timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StickyKeysTest::testDisableTwoKeys()
|
||||||
|
{
|
||||||
|
std::unique_ptr<KWayland::Client::Keyboard> keyboard(Test::waylandSeat()->createKeyboard());
|
||||||
|
|
||||||
|
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
|
||||||
|
QVERIFY(surface != nullptr);
|
||||||
|
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
|
||||||
|
QVERIFY(shellSurface != nullptr);
|
||||||
|
Window *waylandWindow = Test::renderAndWaitForShown(surface.get(), QSize(10, 10), Qt::blue);
|
||||||
|
QVERIFY(waylandWindow);
|
||||||
|
|
||||||
|
QSignalSpy modifierSpy(keyboard.get(), &KWayland::Client::Keyboard::modifiersChanged);
|
||||||
|
QVERIFY(modifierSpy.wait());
|
||||||
|
modifierSpy.clear();
|
||||||
|
|
||||||
|
quint32 timestamp = 0;
|
||||||
|
|
||||||
|
// press mod to latch it
|
||||||
|
Test::keyboardKeyPressed(KEY_LEFTSHIFT, ++timestamp);
|
||||||
|
QVERIFY(modifierSpy.wait());
|
||||||
|
// arguments are: quint32 depressed, quint32 latched, quint32 locked, quint32 group
|
||||||
|
QCOMPARE(modifierSpy.first()[0], 1); // verify that mod is depressed
|
||||||
|
QCOMPARE(modifierSpy.first()[1], 1); // verify that mod is latched
|
||||||
|
modifierSpy.clear();
|
||||||
|
|
||||||
|
// press key while modifier is pressed, this disables sticky keys
|
||||||
|
Test::keyboardKeyPressed(KEY_A, ++timestamp);
|
||||||
|
QVERIFY(modifierSpy.wait());
|
||||||
|
QCOMPARE(modifierSpy.first()[0], 1); // verify that mod is depressed
|
||||||
|
QCOMPARE(modifierSpy.first()[1], 0); // verify that mod is not latched any more
|
||||||
|
modifierSpy.clear();
|
||||||
|
|
||||||
|
Test::keyboardKeyReleased(KEY_A, ++timestamp);
|
||||||
|
|
||||||
|
// release mod, the modifier should not be depressed or latched
|
||||||
|
Test::keyboardKeyReleased(KEY_LEFTSHIFT, ++timestamp);
|
||||||
|
QVERIFY(modifierSpy.wait());
|
||||||
|
QCOMPARE(modifierSpy.first()[0], 0); // verify that mod is not depressed
|
||||||
|
QCOMPARE(modifierSpy.first()[1], 0); // verify that mod is not latched
|
||||||
|
modifierSpy.clear();
|
||||||
|
|
||||||
|
// verify that sticky keys are not enabled any more
|
||||||
|
|
||||||
|
// press mod, should be depressed but not latched
|
||||||
|
Test::keyboardKeyPressed(KEY_LEFTCTRL, ++timestamp);
|
||||||
|
QVERIFY(modifierSpy.wait());
|
||||||
|
QCOMPARE(modifierSpy.first()[0], 4); // verify that mod is depressed
|
||||||
|
QCOMPARE(modifierSpy.first()[1], 0); // verify that mod is not latched
|
||||||
|
modifierSpy.clear();
|
||||||
|
|
||||||
|
// release mod, should not be depressed any more
|
||||||
|
Test::keyboardKeyReleased(KEY_LEFTCTRL, ++timestamp);
|
||||||
|
QVERIFY(modifierSpy.wait());
|
||||||
|
QCOMPARE(modifierSpy.first()[0], 0); // verify that mod is not depressed
|
||||||
|
QCOMPARE(modifierSpy.first()[1], 0); // verify that mod is not latched
|
||||||
|
modifierSpy.clear();
|
||||||
|
|
||||||
|
Test::keyboardKeyPressed(KEY_A, ++timestamp);
|
||||||
|
QVERIFY(!modifierSpy.wait(10));
|
||||||
|
Test::keyboardKeyReleased(KEY_A, ++timestamp);
|
||||||
|
QVERIFY(!modifierSpy.wait(10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WAYLANDTEST_MAIN(KWin::StickyKeysTest)
|
WAYLANDTEST_MAIN(KWin::StickyKeysTest)
|
||||||
|
|
|
@ -66,6 +66,7 @@ void StickyKeysFilter::loadConfig(const KConfigGroup &group)
|
||||||
|
|
||||||
m_lockKeys = group.readEntry<bool>("StickyKeysLatch", true);
|
m_lockKeys = group.readEntry<bool>("StickyKeysLatch", true);
|
||||||
m_showNotificationForLockedKeys = group.readEntry<bool>("kNotifyModifiers", false);
|
m_showNotificationForLockedKeys = group.readEntry<bool>("kNotifyModifiers", false);
|
||||||
|
m_disableOnTwoKeys = group.readEntry<bool>("StickyKeysAutoOff", false);
|
||||||
|
|
||||||
if (!m_lockKeys) {
|
if (!m_lockKeys) {
|
||||||
// locking keys is deactivated, unlock all locked keys
|
// locking keys is deactivated, unlock all locked keys
|
||||||
|
@ -96,6 +97,12 @@ bool StickyKeysFilter::keyEvent(KWin::KeyEvent *event)
|
||||||
{
|
{
|
||||||
if (m_modifiers.contains(event->key())) {
|
if (m_modifiers.contains(event->key())) {
|
||||||
|
|
||||||
|
if (event->type() == QEvent::KeyPress) {
|
||||||
|
m_pressedModifiers << event->key();
|
||||||
|
} else {
|
||||||
|
m_pressedModifiers.remove(event->key());
|
||||||
|
}
|
||||||
|
|
||||||
auto keyState = m_keyStates.find(event->key());
|
auto keyState = m_keyStates.find(event->key());
|
||||||
|
|
||||||
if (keyState != m_keyStates.end()) {
|
if (keyState != m_keyStates.end()) {
|
||||||
|
@ -135,6 +142,11 @@ bool StickyKeysFilter::keyEvent(KWin::KeyEvent *event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (event->type() == QKeyEvent::KeyPress) {
|
} else if (event->type() == QKeyEvent::KeyPress) {
|
||||||
|
|
||||||
|
if (!m_pressedModifiers.isEmpty() && m_disableOnTwoKeys) {
|
||||||
|
disableStickyKeys();
|
||||||
|
}
|
||||||
|
|
||||||
// a non-modifier key was pressed, unlatch all unlocked modifiers
|
// a non-modifier key was pressed, unlatch all unlocked modifiers
|
||||||
for (auto it = m_keyStates.keyValueBegin(); it != m_keyStates.keyValueEnd(); ++it) {
|
for (auto it = m_keyStates.keyValueBegin(); it != m_keyStates.keyValueEnd(); ++it) {
|
||||||
|
|
||||||
|
@ -151,4 +163,15 @@ bool StickyKeysFilter::keyEvent(KWin::KeyEvent *event)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StickyKeysFilter::disableStickyKeys()
|
||||||
|
{
|
||||||
|
for (auto it = m_keyStates.keyValueBegin(); it != m_keyStates.keyValueEnd(); ++it) {
|
||||||
|
it->second = KeyState::None;
|
||||||
|
KWin::input()->keyboard()->xkb()->setModifierLatched(keyToModifier(static_cast<Qt::Key>(it->first)), false);
|
||||||
|
KWin::input()->keyboard()->xkb()->setModifierLocked(keyToModifier(static_cast<Qt::Key>(it->first)), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
KWin::input()->uninstallInputEventFilter(this);
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_stickykeys.cpp"
|
#include "moc_stickykeys.cpp"
|
||||||
|
|
|
@ -27,10 +27,13 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadConfig(const KConfigGroup &group);
|
void loadConfig(const KConfigGroup &group);
|
||||||
|
void disableStickyKeys();
|
||||||
|
|
||||||
KConfigWatcher::Ptr m_configWatcher;
|
KConfigWatcher::Ptr m_configWatcher;
|
||||||
QMap<int, KeyState> m_keyStates;
|
QMap<int, KeyState> m_keyStates;
|
||||||
QList<int> m_modifiers = {Qt::Key_Shift, Qt::Key_Control, Qt::Key_Alt, Qt::Key_AltGr, Qt::Key_Meta};
|
QList<int> m_modifiers = {Qt::Key_Shift, Qt::Key_Control, Qt::Key_Alt, Qt::Key_AltGr, Qt::Key_Meta};
|
||||||
bool m_lockKeys = false;
|
bool m_lockKeys = false;
|
||||||
bool m_showNotificationForLockedKeys = false;
|
bool m_showNotificationForLockedKeys = false;
|
||||||
|
bool m_disableOnTwoKeys = false;
|
||||||
|
QSet<int> m_pressedModifiers;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue