rawinput, touch: discard invalid touch points from device in hybrid mode (#649)

## Link to GitHub Issue or related Pull Request, if one exists
Fixes #648

## Description of change
Deal with devices in hybrid packet mode that send garbage data in second
packet when it's out of bounds (outside the number of contact points).
MSDN says they're supposed to be (0, 0), but some devices don't follow
the spec.

## Testing
I don't have a device that reports garbage values but this should fix it
in theory.

I tested on my Dell touch monitor which is in hybrid mode & sends 5
touches at a time, but can split across two packets to send up to 10
touches. It sends (0, 0) for the remaining slots when there are 6-9
touch points, but confirmed that there was no regression.
This commit is contained in:
bicarus
2026-04-18 16:22:00 -07:00
committed by GitHub
parent aadd2bdd59
commit 26b3b64794
+8 -11
View File
@@ -192,8 +192,10 @@ namespace rawinput::touch {
contact_count = std::max(contact_count, (size_t) hid->value_states_raw[index]);
}
// https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/touchscreen-packet-reporting-modes
// hybrid mode devices will report a contact count of 0 for subsequent reports that are
// part of the same initial frame
// most laptops and touchscreens are like this - they have the contact count set to 5 but can actually report up to 10 fingers
if (contact_count > 0) {
if (contact_count > touch_report_count) {
touch.remaining_contact_count = contact_count - touch_report_count;
@@ -216,6 +218,12 @@ namespace rawinput::touch {
touch_points.reserve(touch.elements_x.size());
for (size_t i = 0; i < touch.elements_x.size(); i++) {
// if there are no more touch events to handle, exit out early
if (touch_report_count == 0) {
break;
}
touch_report_count--;
// build touch point
HIDTouchPoint hid_tp{};
auto pos_x = hid->value_states[touch.elements_x[i]];
@@ -247,17 +255,6 @@ namespace rawinput::touch {
hid_tp.y = 1.f - hid_tp.y;
}
// check if this touch point should be considered valid
//
// If "Contact count" reports there are no touch reports remaining and the X and Y
// coordinates of this touch point are zero, then this report element should be
// skipped.
if (touch_report_count == 0 && hid_tp.x == 0.f && hid_tp.y == 0.f) {
continue;
} else if (touch_report_count > 0) {
touch_report_count--;
}
// generate ID (hopefully unique)
hid_tp.id = (DWORD) hid->value_states_raw[touch.elements_contact_identifier[i]];
hid_tp.id += (DWORD) (0xFFFFFF + device->id * 512);