Hotplug: HID_API_HOTPLUG_ENUMERATE should honour callback return value #793

Open
opened 2026-04-24 09:18:17 -05:00 by Youw · 0 comments
Youw commented 2026-04-24 09:18:17 -05:00 (Migrated from github.com)

Summary

The hotplug callback documentation added in #790 specifies:

Return 0 to keep the callback registered. Return any non-zero value to have HIDAPI deregister the callback; no further events for this handle will be delivered, and the handle is freed as if hid_hotplug_deregister_callback() had been called. This applies to both live events and to the synthetic "arrived" events delivered during registration when HID_API_HOTPLUG_ENUMERATE is set.

The current implementation discards the return value during the synthetic initial-enumeration pass. In `libusb/hid.c` for example: https://github.com/libusb/hidapi/blob/connection-callback/libusb/hid.c#L1393

```c
(*hotplug_cb->callback)(hotplug_cb->handle, device, HID_API_HOTPLUG_EVENT_DEVICE_ARRIVED, hotplug_cb->user_data);
```

— return value is assigned to nothing; the callback cannot self-deregister during initial enumeration.

Why this matters

The natural idiom "find the first device matching this VID/PID, react to it, and stop listening" — `return 1` on match — silently fails when `HID_API_HOTPLUG_ENUMERATE` delivers the first match synchronously during `hid_hotplug_register_callback()`. Users write the obvious thing and get unexpected extra invocations.

Proposed fix

Treat the synthetic arrival events identically to live events: capture the return value, mark the callback for removal if non-zero, and stop delivering further synthetic events for it. All four backends share the same pattern.

Scope

  • `libusb/hid.c`, `linux/hid.c`, `mac/hid.c`, `windows/hid.c`
  • hidtest: consider a test case that self-deregisters from an ENUMERATE event.
  • Documentation: #790
  • Original RFC: #674

Drafted with Claude Code.

## Summary The hotplug callback documentation added in #790 specifies: > Return 0 to keep the callback registered. Return any non-zero value to have HIDAPI deregister the callback; no further events for this handle will be delivered, and the handle is freed as if hid_hotplug_deregister_callback() had been called. **This applies to both live events and to the synthetic \"arrived\" events delivered during registration when HID_API_HOTPLUG_ENUMERATE is set.** The current implementation discards the return value during the synthetic initial-enumeration pass. In \`libusb/hid.c\` for example: https://github.com/libusb/hidapi/blob/connection-callback/libusb/hid.c#L1393 \`\`\`c (*hotplug_cb->callback)(hotplug_cb->handle, device, HID_API_HOTPLUG_EVENT_DEVICE_ARRIVED, hotplug_cb->user_data); \`\`\` — return value is assigned to nothing; the callback cannot self-deregister during initial enumeration. ## Why this matters The natural idiom \"find the first device matching this VID/PID, react to it, and stop listening\" — \`return 1\` on match — silently fails when \`HID_API_HOTPLUG_ENUMERATE\` delivers the first match synchronously during \`hid_hotplug_register_callback()\`. Users write the obvious thing and get unexpected extra invocations. ## Proposed fix Treat the synthetic arrival events identically to live events: capture the return value, mark the callback for removal if non-zero, and stop delivering further synthetic events for it. All four backends share the same pattern. ## Scope - \`libusb/hid.c\`, \`linux/hid.c\`, \`mac/hid.c\`, \`windows/hid.c\` - hidtest: consider a test case that self-deregisters from an ENUMERATE event. ## Related - Documentation: #790 - Original RFC: #674 --- _Drafted with Claude Code._
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-libusb/hidapi#793
No description provided.