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
Drafted with Claude Code.
Summary
The hotplug callback documentation added in #790 specifies:
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
Related
Drafted with Claude Code.