rawinput: fix ttl logic in raw touch (#806)

## Link to GitHub Issue or related Pull Request, if one exists
n/a

## Description of change
Fixes held touch contacts briefly dropping under rapid multi-touch (e.g.
holding several jubeat buttons and tapping elsewhere many times would
make the holds briefly release and the hold again).

A HID digitizer reports a fixed number of contact slots per report and
cycles the rest through later reports, so the touch layer keeps an
unreported contact alive for a few reports (a per-contact TTL). The TTL
was only set for contacts in the current report and had no slack, so
when the contact count rose (from the rapid taps) the reporting cycle
got longer and stationary holds were expired before the device cycled
back to them.

Now, the cycle length is recomputed every report and every tracked
contact's TTL is extended to it (never shrunk), so a rising contact
count can't starve a currently held contact. The 50 ms last-report
timeout still removes genuinely lifted contacts.

## Testing
Tested on jb, rb.
This commit is contained in:
bicarus
2026-07-14 23:46:17 -07:00
committed by GitHub
parent a9a943fbfe
commit 5c3617c05f
+17 -2
View File
@@ -511,13 +511,28 @@ namespace rawinput::touch {
} }
// set TTL and last report time // set TTL and last report time
if (!touch.elements_x.empty() && !touch_modifications.empty()) { if (!touch.elements_x.empty()) {
// a HID digitizer reports only a fixed number of contacts per report and
// cycles the remaining ones through following reports, so a contact can be
// absent for up to this many reports before it comes back around
auto ttl = touch.touch_points.size() / touch.elements_x.size() + 1; auto ttl = touch.touch_points.size() / touch.elements_x.size() + 1;
auto system_time_ms = get_system_milliseconds(); auto system_time_ms = get_system_milliseconds();
// extend every tracked contact to the current cycle length without ever
// shrinking it; otherwise a rising contact count (e.g. rapid taps) lengthens
// the cycle and can starve a stationary held contact into being reaped before
// it is reported again. the 50ms last-report timeout remains the hard backstop
for (auto &hid_tp : touch.touch_points) {
if (hid_tp.ttl < ttl) {
hid_tp.ttl = ttl;
}
}
// only contacts actually seen this report refresh their last-report time
for (auto &hid_tp_id : touch_modifications) { for (auto &hid_tp_id : touch_modifications) {
for (auto &hid_tp : touch.touch_points) { for (auto &hid_tp : touch.touch_points) {
if (hid_tp.id == hid_tp_id) { if (hid_tp.id == hid_tp_id) {
hid_tp.ttl = ttl;
hid_tp.last_report = system_time_ms; hid_tp.last_report = system_time_ms;
} }
} }