MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
HIDBackend.hpp
Go to the documentation of this file.
1#pragma once
2
4
5using hid_device = struct hid_device_;
6
7namespace MayaFlux::Core {
8
9/**
10 * @brief Extended HID device information
11 */
13 uint16_t usage_page {}; ///< HID usage page
14 uint16_t usage {}; ///< HID usage
15 uint16_t release_number {}; ///< Device release number
16 int interface_number {}; ///< USB interface number (-1 if unknown)
17 std::string path; ///< Platform-specific device path
18};
19
20/**
21 * @brief Internal state for an open HID device
22 */
24 hid_device* handle { nullptr };
26 std::vector<uint8_t> read_buffer;
27 std::atomic<bool> active { false };
28};
29
30/**
31 * @class HIDBackend
32 * @brief HIDAPI-based HID input backend
33 *
34 * Provides access to generic HID devices including:
35 * - Game controllers (Xbox, PlayStation, Switch Pro, etc.)
36 * - Custom HID hardware
37 * - Joysticks and flight sticks
38 *
39 * Uses HIDAPI for cross-platform HID communication.
40 *
41 * Threading model:
42 * - Device enumeration: Main thread safe
43 * - Input polling: Dedicated poll thread
44 * - Callbacks: Called from poll thread (use synchronization!)
45 *
46 * Example usage:
47 * @code
48 * HIDBackend hid;
49 * hid.add_device_filter(HIDDeviceFilter::controller());
50 * hid.initialize();
51 *
52 * hid.set_input_callback([](const InputValue& val) {
53 * // Handle input (called from poll thread!)
54 * });
55 *
56 * auto devices = hid.get_devices();
57 * if (!devices.empty()) {
58 * hid.open_device(devices[0].id);
59 * }
60 *
61 * hid.start();
62 * // ... application runs ...
63 * hid.shutdown();
64 * @endcode
65 */
66class MAYAFLUX_API HIDBackend : public IInputBackend {
67public:
68 /**
69 * @brief Configuration for HID backend
70 */
71 struct Config {
72 std::vector<HIDDeviceFilter> filters; ///< Device filters (empty = all devices)
73 size_t read_buffer_size { 64 }; ///< Per-device read buffer size
74 int poll_timeout_ms { 10 }; ///< Timeout for hid_read_timeout
75 bool auto_reconnect { true }; ///< Auto-reopen disconnected devices
76 uint32_t reconnect_interval_ms { 1000 }; ///< Reconnection attempt interval
77 };
78
79 HIDBackend();
80 explicit HIDBackend(Config config);
81 ~HIDBackend() override;
82
83 // Non-copyable, non-movable (owns thread and device handles)
84 HIDBackend(const HIDBackend&) = delete;
85 HIDBackend& operator=(const HIDBackend&) = delete;
88
89 // ─────────────────────────────────────────────────────────────────────
90 // IInputBackend Implementation
91 // ─────────────────────────────────────────────────────────────────────
92
93 bool initialize() override;
94 void start() override;
95 void stop() override;
96 void shutdown() override;
97
98 [[nodiscard]] bool is_initialized() const override { return m_initialized.load(); }
99 [[nodiscard]] bool is_running() const override { return m_running.load(); }
100
101 [[nodiscard]] std::vector<InputDeviceInfo> get_devices() const override;
102 size_t refresh_devices() override;
103
104 bool open_device(uint32_t device_id) override;
105 void close_device(uint32_t device_id) override;
106 [[nodiscard]] bool is_device_open(uint32_t device_id) const override;
107 [[nodiscard]] std::vector<uint32_t> get_open_devices() const override;
108
109 void set_input_callback(InputCallback callback) override;
110 void set_device_callback(DeviceCallback callback) override;
111
112 [[nodiscard]] InputType get_type() const override { return InputType::HID; }
113 [[nodiscard]] std::string get_name() const override { return "HID (HIDAPI)"; }
114 [[nodiscard]] std::string get_version() const override;
115
116 // ─────────────────────────────────────────────────────────────────────
117 // HID-specific API
118 // ─────────────────────────────────────────────────────────────────────
119
120 /**
121 * @brief Add a device filter for enumeration
122 * @param filter Filter to add
123 *
124 * Call before initialize() or call refresh_devices() after.
125 */
126 void add_device_filter(const HIDDeviceFilter& filter);
127
128 /**
129 * @brief Clear all device filters
130 */
131 void clear_device_filters();
132
133 /**
134 * @brief Get extended HID device info
135 * @param device_id Device identifier
136 * @return Extended info, or nullopt if device not found
137 */
138 [[nodiscard]] std::optional<HIDDeviceInfoExt> get_device_info_ext(uint32_t device_id) const;
139
140 /**
141 * @brief Send a feature report to a device
142 * @param device_id Target device
143 * @param data Report data (first byte is report ID)
144 * @return Number of bytes sent, or -1 on error
145 */
146 int send_feature_report(uint32_t device_id, std::span<const uint8_t> data);
147
148 /**
149 * @brief Get a feature report from a device
150 * @param device_id Target device
151 * @param report_id Report ID to get
152 * @param buffer Buffer to receive data
153 * @return Number of bytes received, or -1 on error
154 */
155 int get_feature_report(uint32_t device_id, uint8_t report_id, std::span<uint8_t> buffer);
156
157 /**
158 * @brief Send an output report to a device
159 * @param device_id Target device
160 * @param data Report data
161 * @return Number of bytes sent, or -1 on error
162 */
163 int write(uint32_t device_id, std::span<const uint8_t> data);
164
165private:
167
168 std::atomic<bool> m_initialized { false };
169 std::atomic<bool> m_running { false };
170 std::atomic<bool> m_stop_requested { false };
171
172 mutable std::mutex m_devices_mutex;
173 std::unordered_map<uint32_t, HIDDeviceInfoExt> m_enumerated_devices;
174 std::unordered_map<uint32_t, std::shared_ptr<HIDDeviceState>> m_open_devices;
175 uint32_t m_next_device_id { 1 };
176
177 std::thread m_poll_thread;
180 mutable std::mutex m_callback_mutex;
181
182 void poll_thread_func();
183 void poll_device(uint32_t device_id, HIDDeviceState& state);
184
185 bool matches_any_filter(uint16_t vid, uint16_t pid, uint16_t usage_page, uint16_t usage) const;
186 uint32_t find_or_assign_device_id(const std::string& path);
187
188 void notify_input(const InputValue& value);
189 void notify_device_change(const InputDeviceInfo& info, bool connected);
190
191 InputValue parse_hid_report(uint32_t device_id, std::span<const uint8_t> report);
192};
193
194} // namespace MayaFlux::Core
hid_device_ hid_device
Definition HIDBackend.hpp:5
HIDBackend(const HIDBackend &)=delete
HIDBackend & operator=(const HIDBackend &)=delete
HIDBackend(HIDBackend &&)=delete
bool is_running() const override
Check if backend is actively listening.
bool is_initialized() const override
Check if backend is initialized.
HIDBackend & operator=(HIDBackend &&)=delete
DeviceCallback m_device_callback
std::unordered_map< uint32_t, HIDDeviceInfoExt > m_enumerated_devices
std::string get_name() const override
Get backend name/identifier string.
InputType get_type() const override
Get backend type.
std::unordered_map< uint32_t, std::shared_ptr< HIDDeviceState > > m_open_devices
HIDAPI-based HID input backend.
Abstract interface for input device backends.
void initialize()
Definition main.cpp:11
InputType
Input backend type enumeration.
std::function< void(const InputValue &)> InputCallback
Callback signature for input events.
std::function< void(const InputDeviceInfo &, bool connected)> DeviceCallback
Callback signature for device connection/disconnection events.
std::vector< HIDDeviceFilter > filters
Device filters (empty = all devices)
Configuration for HID backend.
Filter for HID device enumeration.
uint16_t release_number
Device release number.
uint16_t usage_page
HID usage page.
std::string path
Platform-specific device path.
int interface_number
USB interface number (-1 if unknown)
Extended HID device information.
std::vector< uint8_t > read_buffer
std::atomic< bool > active
Internal state for an open HID device.
Information about a connected input device.
Generic input value container.