ComboEngine and cross-device combo resolution
The ComboEngine is the most complex piece of MapXr's core logic. It has to correctly distinguish between a single tap, a double tap, and a two-handed combo. All from a stream of raw tap events arriving over Bluetooth with no inherent timing guarantees.
The resolution problem
When a tap event arrives, the engine can't immediately know whether it's:
- A standalone single tap
- The first tap of a double-tap
- The first half of a cross-device combo
It has to wait for a short window to see if more events arrive before resolving. This window (300 ms by default) is long enough to catch intentional combos but short enough that single taps feel instantaneous.
State machine
The engine tracks a TapPending state per profile type:
- None: no pending events
- One(event, deadline): one event received, waiting for a possible second
- Two(event1, event2): two events received, resolving as double-tap or combo
When the deadline passes without a second event, the pending single tap resolves. When a second event arrives before the deadline, the engine checks whether they form a valid cross-device combo (different devices, matching a combo trigger) or a double-tap (same device, same fingers).
Deterministic tests with tokio::time
Timing-sensitive tests use tokio::time::pause() and tokio::time::advance(Duration) to control the clock without actually sleeping.
This makes the test suite fast and deterministic. The 300 ms combo window can be "waited out"
in zero real time.
The test suite covers single, double, cross-device combos, timeout resolution, rapid alternating events, and the dual-profile stacking behaviour where same-device events intentionally accumulate.