Skip to content

[ux] Restore keyboard shortcut use after slider nudges#1952

Merged
ten9876 merged 1 commit intoten9876:mainfrom
jensenpat:aether/applet-slider-focus-timeout
Apr 25, 2026
Merged

[ux] Restore keyboard shortcut use after slider nudges#1952
ten9876 merged 1 commit intoten9876:mainfrom
jensenpat:aether/applet-slider-focus-timeout

Conversation

@jensenpat
Copy link
Copy Markdown
Collaborator

Summary

  • Replace the permanent slider-focus shortcut suppression with a short slider keyboard lease.
  • Let focused sliders consume Arrow, Page Up, Page Down, Home, and End while the lease is active, renewing the lease on each nudge.
  • Clear slider focus after two idle seconds so global operating shortcuts resume automatically.

Root Cause
Applet and sidebar sliders previously disabled all operating QShortcuts whenever a QAbstractSlider had keyboard focus. A clicked slider can remain the focus widget indefinitely, so tuning shortcuts such as Left Arrow and Right Arrow stayed suppressed until the user manually clicked somewhere else.

User Impact
Operators can still click volume, AGC, AF, or similar sliders and make a few keyboard nudges. After a brief idle period, keyboard control returns to normal tuning behavior without an extra click, preventing the session from feeling stuck after any applet-slider adjustment.

Implementation Notes

  • Added a two-second slider shortcut lease in MainWindow.
  • The lease disables global shortcuts only while the slider is actively being adjusted or recently nudged.
  • The shortcut guard now treats sliders as captured only while the lease is active; text input and combo boxes remain protected as before.
  • The timeout clears focus from the slider only when it is safe to do so, avoiding interruption during mouse drags.

Validation

  • Built successfully with cmake --build build --parallel 10.
  • Ran ctest --test-dir build --output-on-failure -j10; no tests were registered in this build directory.
  • Manual verification by @jensenpat: clicking applet sliders, nudging with arrows, waiting briefly, then confirming arrow-key tuning resumes.

👨🏼‍💻 Generated with OpenAI Codex (GPT-5.5 Pro 4/23) and tested by @jensenpat

@jensenpat jensenpat changed the title Restore shortcuts after slider nudges [ux] Restore keyboard shortcut use after slider nudges Apr 25, 2026
@jensenpat jensenpat marked this pull request as ready for review April 25, 2026 13:06
@jensenpat jensenpat requested a review from ten9876 as a code owner April 25, 2026 13:06
Copy link
Copy Markdown
Contributor

@aethersdr-agent aethersdr-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tackling this, @jensenpat — the "stuck slider" behavior is a real papercut for operators, and the lease-based approach is a solid design choice over the permanent suppression.

I read through the full diff and compared against main. The implementation is clean and well-scoped (only MainWindow.cpp / .h, no scope creep). A few observations:

Looks good

  • Lease pattern is sound. The beginSliderShortcutLeaserenewSliderShortcutLeasereleaseSliderShortcutLease lifecycle is clear. Using QPointer for m_sliderShortcutLease is the right call — safely handles slider destruction mid-lease.
  • Mouse-drag safety. isSliderDown() check in both renewSliderShortcutLease (stops the timer) and releaseSliderShortcutLease (defers the clear) correctly prevents yanking focus during an active drag. Nice detail.
  • PageUp/Down and Home/End handling. The old code only intercepted arrow keys. Adding these makes the slider feel complete before the lease expires.
  • No convention violations. Uses AppSettings pattern (not QSettings), QPointer for RAII-safe weak reference, constexpr for the timeout constant. Files changed match stated scope.

Questions / potential issues

  1. Double disable on focus change. When a slider is clicked, the eventFilter fires beginSliderShortcutLease (via MouseButtonPress), which calls setShortcutsEnabled(false). Then the focusChanged signal fires for the same slider and calls beginSliderShortcutLease again, which calls setShortcutsEnabled(false) a second time. This is idempotent and harmless, but the timer restart in renewSliderShortcutLease means the 2-second clock resets from the focus event rather than the click — which is actually fine since they're nearly simultaneous. Just flagging that the double-entry is intentional/benign.

  2. s_sliderShortcutLeaseActive static vs. member. The lease state is tracked in both a file-static s_sliderShortcutLeaseActive (for shortcutInputCaptured()) and the member m_sliderShortcutLease pointer. This works because there's only ever one MainWindow, but it's worth a brief comment noting the static is needed because shortcutInputCaptured() is a free function called from the shortcutGuard callback. (Not blocking — just a readability note.)

  3. Keyboard-only focus. If a user Tabs into a slider (no mouse click), the focusChanged path calls beginSliderShortcutLease, which starts the timer. After 2 seconds of idle, releaseSliderShortcutLease(true) calls slider->clearFocus(). This means Tab-focused sliders lose focus after 2s even if the user hasn't interacted with them yet. In practice this may be fine for this app (operators rarely Tab to sliders), but worth considering whether the clearFocus should only happen if there was an actual key nudge. A simple guard like m_sliderHadKeyNudge would do it.

  4. Thread safety note. All paths run on the GUI thread (event filter, focus signal, QTimer), so the static flag is safe. No issue here, just confirming.

Overall this is a well-considered improvement. The core approach is correct and the edge cases are handled. Item 3 above is the only thing I'd suggest addressing before merge — the Tab-focus scenario could surprise users who use keyboard navigation. The rest is ready.


Reviewed by AetherClaude

@ten9876 ten9876 merged commit cae3cfb into ten9876:main Apr 25, 2026
5 checks passed
@aethersdr-agent aethersdr-agent Bot mentioned this pull request Apr 26, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants