Hold-to-repeat for navigation keys across keyboard, gamepad and MIDI (v0.6.0)

Navigation and value-step actions (Nav Up/Down/Left/Right, Next/Prev
Column, Increment/Decrement) now auto-repeat while their control is held —
fire once on press, then accelerate from 320ms to 45ms per step — and stop
the instant it's released. Implemented ONCE as a shared repeater in
InputRouter (pressRepeat/releaseRepeat, keyed by the physical control id),
so all three hardware inputs get identical behaviour:
 * Keyboard: the OS's own key auto-repeat is now ignored (held notes sustain
   instead of retriggering) and holds are driven by the shared repeater;
   key-up ends it.
 * Gamepad: buttons, D-pad hat AND analog sticks repeat (they all funnel
   through controlDown/controlUp); releasing the main control stops it,
   releasing a chord modifier does not.
 * MIDI: a momentary nav CC repeats between its press (value>=64) and
   release (value<64).

One-shots (transport, tab switch, notes, clear) are unaffected — they fire
once even when held. InputRouter takes an injectable dispatcher so the new
InputRouterTest drives the accelerating schedule on a virtual clock
(verifies repeat-while-held, stop-on-release, one-shot-fires-once, and that
an unrelated release doesn't stop the active repeat). All unit tests pass;
on-device smoke confirms single-press nav + transport still work, no crash.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Reactorcoremeltdown
2026-07-18 15:14:34 +02:00
parent e0fe89d62c
commit 750d928ce1
7 changed files with 209 additions and 15 deletions

View File

@@ -22,8 +22,8 @@ android {
// (android.media.midi) and AAudio low-latency audio we rely on.
minSdk = 26
targetSdk = 34
versionCode = 17
versionName = "0.5.2"
versionCode = 18
versionName = "0.6.0"
// We provide our own instrumentation runner if/when tests are added.
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -132,4 +132,6 @@ dependencies {
// JVM unit tests for the pure model/io logic (no device needed).
testImplementation("junit:junit:4.13.2")
// Virtual-time coroutine testing (drives the input hold-to-repeat schedule).
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
}