From 9abd19e5d3ac9a2aa6bf4a4c3ef466ac3135b138 Mon Sep 17 00:00:00 2001 From: ericek111 Date: Thu, 15 Oct 2026 10:13:41 +0200 Subject: [PATCH] Cancel keys still down when hold-keys mode flips The surface cancels its fingers under the old rules before the switch, so a release no longer reaches the other mode (a stuck repeater or held modifier one way, a second copy of the character the other). Sticky modifiers, shift and dead keys start over. Co-Authored-By: Claude Opus 5.5 --- src/input/KeyboardController.cpp | 9 ++++++++- src/input/KeyboardController.h | 3 +++ src/input/KeyboardSurface.cpp | 4 ++++ tests/tst_keyboardsurface.cpp | 16 ++++++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/input/KeyboardController.cpp b/src/input/KeyboardController.cpp index a3404d5..9c7eb96 100644 --- a/src/input/KeyboardController.cpp +++ b/src/input/KeyboardController.cpp @@ -200,8 +200,15 @@ void KeyboardController::setContext(const TextContext &context) void KeyboardController::setOptions(const TypingOptions &options) { - if (m_options.holdKeys && !options.holdKeys) + if (options.holdKeys != m_options.holdKeys) { + Q_EMIT holdKeysAboutToChange(); m_hardware.releaseAll(); + m_backspaceRepeater.stop(); + m_keysymRepeater.stop(); + m_deadKeys.cancel(); + m_modifiers.clear(); + m_shift = {}; + } m_options = options; m_model.setShiftLevel(shiftLevel()); Q_EMIT shiftChanged(); diff --git a/src/input/KeyboardController.h b/src/input/KeyboardController.h index 149a061..cf7a94f 100644 --- a/src/input/KeyboardController.h +++ b/src/input/KeyboardController.h @@ -68,6 +68,9 @@ Q_SIGNALS: void modifiersChanged(); void dismissRequested(); void nextLayoutRequested(); // the globe key: switching is the system's job + // Hold-keys mode is about to flip: keys still down must be cancelled now, + // under the rules they were pressed with. + void holdKeysAboutToChange(); private: void typeCharacter(const KeyDef &key, KeyOutput output, const QString &alternate); diff --git a/src/input/KeyboardSurface.cpp b/src/input/KeyboardSurface.cpp index 1767730..3c4cb00 100644 --- a/src/input/KeyboardSurface.cpp +++ b/src/input/KeyboardSurface.cpp @@ -44,7 +44,11 @@ void KeyboardSurface::setController(KeyboardController *controller) if (controller == m_controller) return; cancelAll(); + if (m_controller) + disconnect(m_controller, nullptr, this, nullptr); m_controller = controller; + if (m_controller) + connect(m_controller, &KeyboardController::holdKeysAboutToChange, this, &KeyboardSurface::cancelAll); Q_EMIT controllerChanged(); } diff --git a/tests/tst_keyboardsurface.cpp b/tests/tst_keyboardsurface.cpp index acc39cb..a692f03 100644 --- a/tests/tst_keyboardsurface.cpp +++ b/tests/tst_keyboardsurface.cpp @@ -169,6 +169,22 @@ private Q_SLOTS: controller->setOptions({}); } + void switchingHoldKeysMidPressCancelsTheKey() + { + const QPoint a = keyCenter(u"a"_s); + QTest::touchEvent(&window, touchscreen).press(0, a); + controller->setOptions({.holdKeys = true}); + QTest::touchEvent(&window, touchscreen).release(0, a); + QVERIFY(engine.output.isEmpty()); + QVERIFY(engine.keyEvents.isEmpty()); + + QTest::touchEvent(&window, touchscreen).press(0, a); + controller->setOptions({}); + QTest::touchEvent(&window, touchscreen).release(0, a); + QVERIFY(engine.held.isEmpty()); + QVERIFY(engine.output.isEmpty()); // not typed a second time as a tap + } + void slideFromNumbersKeyTypesAndReturns() { const QPoint layerKey = keyCenter(u".?123"_s, u"layer"_s);