lib: send each feedback history event in its own packet #823

Open
aoleg94 wants to merge 0 commits from aoleg94/lib-feedback-history-per-event into main
aoleg94 commented 2026-10-03 17:41:36 -05:00 (Migrated from github.com)

Summary

Button and touchpad events reach the console in "feedback history" packets. The console
appears to apply only one new event per packet, but FeedbackSender puts every event of a
controller state change into a single packet. Whenever two things change in the same update,
all but the newest event are dropped:

  • simultaneous L2 + R2 registers as R2 only (R2 is pushed last);
  • a touchpad tap, which releases the click and lifts the finger in the same update, leaves
    either the finger or the click held on the console, depending on the order. With the current
    order (#748: touches before buttons) the finger lift is lost and the touch sticks; with the
    reverse order the click release is lost, and after the next game switch the new game ignores
    all input while the home screen still works.

This is likely why #748 changed the swipe behaviour ("unsure why this breaks swipe"): the order
only decides which event is lost.

Evidence

  • I logged every history packet (the existing commented-out hexdump in
    feedback_sender_send_history_packet) while reproducing on a PS5 from Android. A tap ended
    with one packet containing both 80 91 (click up) and c0 … (touch up), and the console kept
    whichever came first as held. L2 and R2 changes in one packet behaved the same way.
  • pyremoteplay, an independent implementation, adds one event and sends one packet each time
    (Controller._button() → _add_event_buffer() → _send_event()), so it never batches.
  • Real DualSense input almost never changes two things in one report, which is why desktop
    rarely hits this. It does with L2+R2 pressed together and with touchscreen tap emulation.

Change

  • chiaki_feedback_history_buffer_record_state() (new, feedback.c) records a state change and
    calls back after each pushed event; FeedbackSender formats and queues one packet per
    callback, so every event gets its own sequence number. The resend window (last 4 events) is
    unchanged.
  • Order within a change: button releases, then touch changes, then button presses. For a press
    the finger lands before the click, for a release the click lets go before the finger lifts,
    like a real pad.

Testing

  • New test/feedback.c (4 tests): tap release → 2 packets, click up first; touch + click press
    → 2 packets, touch first; L2 + R2 → 2 packets; no change → no packet. Reverting to one packet
    per state change fails 3 of them. chiaki-unit: 114/114.
  • On a PS5 (Astro's Playroom touchpad page, Ratchet & Clank, GTA V) from Android: taps and holds
    no longer stick, touchpad clicks show up in Astro's touchpad test, L2+R2 together register both,
    switching games after a touchpad click no longer leaves the new game ignoring input.

Notes

Developed with the assistance of Claude Code, and tested on real hardware as described above.

🤖 Generated with Claude Code

### Summary Button and touchpad events reach the console in "feedback history" packets. The console appears to apply only **one new event per packet**, but `FeedbackSender` puts every event of a controller state change into a single packet. Whenever two things change in the same update, all but the newest event are dropped: - **simultaneous L2 + R2** registers as R2 only (R2 is pushed last); - a **touchpad tap**, which releases the click and lifts the finger in the same update, leaves either the finger or the click held on the console, depending on the order. With the current order (#748: touches before buttons) the finger lift is lost and the touch sticks; with the reverse order the click release is lost, and after the next game switch the new game ignores all input while the home screen still works. This is likely why #748 changed the swipe behaviour ("unsure why this breaks swipe"): the order only decides *which* event is lost. ### Evidence - I logged every history packet (the existing commented-out hexdump in `feedback_sender_send_history_packet`) while reproducing on a PS5 from Android. A tap ended with one packet containing both `80 91` (click up) and `c0 …` (touch up), and the console kept whichever came first as held. L2 and R2 changes in one packet behaved the same way. - pyremoteplay, an independent implementation, adds one event and sends one packet each time (`Controller._button()` → `_add_event_buffer()` → `_send_event()`), so it never batches. - Real DualSense input almost never changes two things in one report, which is why desktop rarely hits this. It does with L2+R2 pressed together and with touchscreen tap emulation. ### Change - `chiaki_feedback_history_buffer_record_state()` (new, `feedback.c`) records a state change and calls back after **each** pushed event; `FeedbackSender` formats and queues one packet per callback, so every event gets its own sequence number. The resend window (last 4 events) is unchanged. - Order within a change: button releases, then touch changes, then button presses. For a press the finger lands before the click, for a release the click lets go before the finger lifts, like a real pad. ### Testing - New `test/feedback.c` (4 tests): tap release → 2 packets, click up first; touch + click press → 2 packets, touch first; L2 + R2 → 2 packets; no change → no packet. Reverting to one packet per state change fails 3 of them. `chiaki-unit`: 114/114. - On a PS5 (Astro's Playroom touchpad page, Ratchet & Clank, GTA V) from Android: taps and holds no longer stick, touchpad clicks show up in Astro's touchpad test, L2+R2 together register both, switching games after a touchpad click no longer leaves the new game ignoring input. ### Notes Developed with the assistance of Claude Code, and tested on real hardware as described above. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This pull request is broken due to missing fork information.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin 'aoleg94/lib-feedback-history-per-event:aoleg94/lib-feedback-history-per-event'
git switch 'aoleg94/lib-feedback-history-per-event'

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch 'main'
git merge --no-ff 'aoleg94/lib-feedback-history-per-event'
git switch 'aoleg94/lib-feedback-history-per-event'
git rebase 'main'
git switch 'main'
git merge --ff-only 'aoleg94/lib-feedback-history-per-event'
git switch 'aoleg94/lib-feedback-history-per-event'
git rebase 'main'
git switch 'main'
git merge --no-ff 'aoleg94/lib-feedback-history-per-event'
git switch 'main'
git merge --squash 'aoleg94/lib-feedback-history-per-event'
git switch 'main'
git merge --ff-only 'aoleg94/lib-feedback-history-per-event'
git switch 'main'
git merge 'aoleg94/lib-feedback-history-per-event'
git push origin 'main'
Sign in to join this conversation.
No description provided.