presentation/AltHoldDetector.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | #include <QChar> | ||
| 3 | #include <Qt> | ||
| 4 | |||
| 5 | // Sprint 105 S105.7.5: the "hold Alt to see the keys" state model of | ||
| 6 | // docs/design/sprint-105/ux.md §2, as a pure unit. Input: key presses and | ||
| 7 | // releases with timestamps, pointer presses, window changes and timer ticks; | ||
| 8 | // output: what the overlay must do. The router owns the timer and calls | ||
| 9 | // tick() at nextDeadline(). | ||
| 10 | // | ||
| 11 | // Invariants: | ||
| 12 | // - AltGr (Key_AltGr, or Alt reported together with Ctrl) never starts a hold | ||
| 13 | // and never activates a letter. | ||
| 14 | // - Autorepeat presses never restart the delay or count as another key. | ||
| 15 | // - A key pressed while Alt is down before the overlay shows (Alt+Up, | ||
| 16 | // Alt+Tab) suppresses the overlay until Alt is released. | ||
| 17 | class AltHoldDetector { | ||
| 18 | public: | ||
| 19 | enum class State { Idle, Holding, Keys, Explained, Acting, Suppressed }; | ||
| 20 | enum class Action { | ||
| 21 | None, | ||
| 22 | HoldStarted, // Alt went down alone: show the hold ring | ||
| 23 | HoldCancelled, // the ring goes away, nothing else | ||
| 24 | Show, // stage 1 (keys) | ||
| 25 | ShowExplained, // stage 2 directly (setting "at once") | ||
| 26 | Explain, // stage 1 -> stage 2 | ||
| 27 | Hide, | ||
| 28 | Activate, // press the element whose tip letter is `letter` | ||
| 29 | Recompute // after an action with Alt still held (D-21) | ||
| 30 | }; | ||
| 31 | enum class ExplainMode { AfterHold, AtOnce, Never }; | ||
| 32 | struct Settings { | ||
| 33 | bool holdEnabled = true; | ||
| 34 | int delayMs = 300; // 0..1000; 0 = show at once | ||
| 35 | int explainAfterMs = 700; // after the overlay showed | ||
| 36 | ExplainMode explain = ExplainMode::AfterHold; | ||
| 37 | }; | ||
| 38 | struct Result { | ||
| 39 | Action action = Action::None; | ||
| 40 | QChar letter; | ||
| 41 | // True when the key event must not reach the application (a tip | ||
| 42 | // letter that activates an element). | ||
| 43 | bool consume = false; | ||
| 44 | }; | ||
| 45 | |||
| 46 | 878 | void setSettings(const Settings &settings) { m_settings = settings; } | |
| 47 | 1790 | const Settings &settings() const { return m_settings; } | |
| 48 | 16664 | State state() const { return m_state; } | |
| 49 |
6/6✓ Branch 2 → 3 taken 1199 times.
✓ Branch 2 → 5 taken 9 times.
✓ Branch 3 → 4 taken 1132 times.
✓ Branch 3 → 5 taken 67 times.
✓ Branch 4 → 5 taken 8 times.
✓ Branch 4 → 6 taken 1124 times.
|
1208 | bool shown() const { return m_state == State::Keys || m_state == State::Explained || m_state == State::Acting; } |
| 50 | ✗ | bool explained() const { return m_explained; } | |
| 51 | // Opened with Ctrl+? (D-12): letters work without Alt, Esc closes. | ||
| 52 | 72 | bool toggled() const { return m_toggled; } | |
| 53 | // -1 when no timer is needed. | ||
| 54 | 16644 | qint64 nextDeadline() const { return m_deadline; } | |
| 55 | |||
| 56 | // `tipLetter`: the caller's answer to "is this key's letter shown on a | ||
| 57 | // badge now" (only asked while the overlay is shown). | ||
| 58 | Result keyPress(int key, Qt::KeyboardModifiers modifiers, bool autoRepeat, qint64 now, QChar letter = {}, | ||
| 59 | bool tipLetter = false); | ||
| 60 | Result keyRelease(int key, Qt::KeyboardModifiers modifiers, bool autoRepeat, qint64 now); | ||
| 61 | Result pointerPress(); | ||
| 62 | Result windowDeactivated(); | ||
| 63 | // The window was resized, a modal opened, the IME started a pre-edit … | ||
| 64 | Result cancel(); | ||
| 65 | Result tick(qint64 now); | ||
| 66 | // Ctrl+?: open in stage 2 without holding, or close. | ||
| 67 | Result toggle(); | ||
| 68 | // The caller ran the activated element; Alt may still be held. | ||
| 69 | Result actionDone(); | ||
| 70 | |||
| 71 | private: | ||
| 72 | Result hide(); | ||
| 73 | Result enterKeys(qint64 now); | ||
| 74 | Settings m_settings; | ||
| 75 | State m_state = State::Idle; | ||
| 76 | qint64 m_deadline = -1; | ||
| 77 | bool m_altDown = false; | ||
| 78 | bool m_explained = false; | ||
| 79 | bool m_toggled = false; | ||
| 80 | }; | ||
| 81 |