libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
hid_gamepad.hpp
1#pragma once
2#include <cmath>
3#include <cstdint>
4#include <cstring>
5
6#include "hid.hpp"
7
8namespace LibXR::USB
9{
10
11// 模板化 4 轴 + 8 按钮 HID 手柄报告描述符(见类内 GetReportDesc)
12// Templated 4-axes + 8-buttons HID gamepad report descriptor (see GetReportDesc in class)
13
29template <int16_t LOG_MIN = 0, int16_t LOG_MAX = 2047, uint8_t IN_EP_INTERVAL_MS = 1>
31 : public HID<50 /* desc size */, 9 /* report len */, 0 /* feature len */>
32{
33 static_assert(LOG_MIN <= LOG_MAX, "LOG_MIN must be <= LOG_MAX");
34 static_assert(LOG_MIN >= -32768 && LOG_MAX <= 32767,
35 "Axis logical range must fit in int16_t");
36
37 public:
44 : HID<50, 9, 0>(false, IN_EP_INTERVAL_MS, /*out_ep_interval*/ 1, in_ep_num,
45 Endpoint::EPNumber::EP_AUTO)
46 {
47 // 初始化上一帧:轴置中,按钮清零 / Initialize last report: axes to mid, buttons
48 // cleared
49 last_.x = Mid();
50 last_.y = Mid();
51 last_.z = Mid();
52 last_.rx = Mid();
53 last_.buttons = 0;
54 }
55
59 enum Button : uint8_t
60 {
61 BTN1 = 0x01,
62 BTN2 = 0x02,
63 BTN3 = 0x04,
64 BTN4 = 0x08,
65 BTN5 = 0x10,
66 BTN6 = 0x20,
67 BTN7 = 0x40,
68 BTN8 = 0x80,
69 };
70
71#pragma pack(push, 1)
77 struct Report
78 {
79 int16_t x;
80 int16_t y;
81 int16_t z;
82 int16_t rx;
83 uint8_t buttons;
84 };
85#pragma pack(pop)
86
87 static_assert(sizeof(Report) == 9, "Report size must be 9 bytes");
88
99 ErrorCode Send(int x, int y, int z, int rx, uint8_t buttons)
100 {
101 last_.x = Clamp(x);
102 last_.y = Clamp(y);
103 last_.z = Clamp(z);
104 last_.rx = Clamp(rx);
105 last_.buttons = buttons;
106 return SendInputReport(ConstRawData{&last_, sizeof(last_)});
107 }
108
114 ErrorCode SendButtons(uint8_t buttons)
115 {
116 last_.buttons = buttons;
117 return SendInputReport(ConstRawData{&last_, sizeof(last_)});
118 }
119
128 ErrorCode SendAxes(int x, int y, int z, int rx)
129 {
130 last_.x = Clamp(x);
131 last_.y = Clamp(y);
132 last_.z = Clamp(z);
133 last_.rx = Clamp(rx);
134 return SendInputReport(ConstRawData{&last_, sizeof(last_)});
135 }
136
137 protected:
143 ErrorCode WriteDeviceDescriptor(DeviceDescriptor& header) override
144 {
146 header.data_.bDeviceSubClass = 0;
147 header.data_.bDeviceProtocol = 0;
148 return ErrorCode::OK;
149 }
150
155 ConstRawData GetReportDesc() override { return ConstRawData{desc_, sizeof(desc_)}; }
156
157 private:
158 // 报告描述符(编译期常量 50 字节) / HID report descriptor (compile-time 50 bytes)
159 // 轴:X/Y/Z/Rx,16 位容器;按钮:8 个 / Axes: X/Y/Z/Rx, 16-bit containers; Buttons: 8
160 static constexpr uint8_t U8(uint16_t v) { return static_cast<uint8_t>(v & 0xFF); }
161 static constexpr uint8_t U8H(uint16_t v)
162 {
163 return static_cast<uint8_t>((v >> 8) & 0xFF);
164 }
165
166 static constexpr uint8_t desc_[/*50*/] = {
167 0x05, 0x01, // Usage Page (Generic Desktop)
168 0x09, 0x05, // Usage (Game Pad)
169 0xA1, 0x01, // Collection (Application)
170
171 // Axes collection
172 0x09, 0x01, // Usage (Pointer)
173 0xA1, 0x00, // Collection (Physical)
174 0x05, 0x01, // Usage Page (Generic Desktop)
175 0x09, 0x30, // Usage (X)
176 0x09, 0x31, // Usage (Y)
177 0x09, 0x32, // Usage (Z)
178 0x09, 0x33, // Usage (Rx)
179
180 // Logical Min/Max (16-bit)
181 0x16, U8(static_cast<uint16_t>(LOG_MIN)),
182 U8H(static_cast<uint16_t>(LOG_MIN)), // Logical Minimum
183 0x26, U8(static_cast<uint16_t>(LOG_MAX)),
184 U8H(static_cast<uint16_t>(LOG_MAX)), // Logical Maximum
185
186 0x75, 0x10, // Report Size (16)
187 0x95, 0x04, // Report Count (4)
188 0x81, 0x02, // Input (Data, Variable, Absolute)
189 0xC0, // End Collection (Physical)
190
191 // Buttons
192 0x05, 0x09, // Usage Page (Button)
193 0x19, 0x01, // Usage Minimum (Button 1)
194 0x29, 0x08, // Usage Maximum (Button 8)
195 0x15, 0x00, // Logical Minimum (0)
196 0x25, 0x01, // Logical Maximum (1)
197 0x95, 0x08, // Report Count (8)
198 0x75, 0x01, // Report Size (1)
199 0x81, 0x02, // Input (Data, Variable, Absolute)
200
201 0xC0 // End Collection (Application)
202 };
203
204 static_assert(sizeof(desc_) == 50,
205 "HID report descriptor size changed; update base template arg!");
206
210 static constexpr int16_t Clamp(int v)
211 {
212 return (v < LOG_MIN) ? LOG_MIN : (v > LOG_MAX ? LOG_MAX : static_cast<int16_t>(v));
213 }
214
218 static constexpr int16_t Mid()
219 {
220 return static_cast<int16_t>(
221 (static_cast<int32_t>(LOG_MIN) + static_cast<int32_t>(LOG_MAX)) / 2);
222 }
223
225};
226
230using HIDGamepad = HIDGamepadT<0, 2047, 1>;
231
235using HIDGamepadBipolar = HIDGamepadT<-2048, 2047, 1>;
236
237} // namespace LibXR::USB
常量原始数据封装类。 A class for encapsulating constant raw data.
USB描述符基类 USB descriptor base class.
Definition desc_dev.hpp:40
Data data_
设备描述符数据实例 / Internal data instance
Definition desc_dev.hpp:109
@ PER_INTERFACE
每个接口自定义类 / Per-interface
USB 端点基类 / USB Endpoint base class.
Definition ep.hpp:23
EPNumber
端点号 Endpoint number
Definition ep.hpp:41
@ EP_AUTO
自动分配端点号 / Auto allocate
模板化 4 轴 + 8 按钮 HID 手柄 / Templated 4-axis + 8-button HID gamepad
Button
按钮位掩码(8 个) / Button bit masks (8 buttons)
ErrorCode SendAxes(int x, int y, int z, int rx)
仅更新轴(保持按钮不变) / Update axes only (buttons unchanged)
ErrorCode SendButtons(uint8_t buttons)
仅更新按钮(保持轴不变) / Update buttons only (axes unchanged)
ErrorCode Send(int x, int y, int z, int rx, uint8_t buttons)
发送完整输入报告(轴 + 按钮) / Send a full input report (axes + buttons)
static constexpr int16_t Mid()
轴逻辑中点 / Logical midpoint of axes
ConstRawData GetReportDesc() override
获取报告描述符 / Get report descriptor
static constexpr int16_t Clamp(int v)
将值夹到 [LOG_MIN, LOG_MAX] / Clamp a value to [LOG_MIN, LOG_MAX]
Report last_
最近一次发送的输入报告 / Last-sent input report
HIDGamepadT(Endpoint::EPNumber in_ep_num=Endpoint::EPNumber::EP_AUTO)
构造函数 / Constructor
ErrorCode WriteDeviceDescriptor(DeviceDescriptor &header) override
写入设备描述符(Per-Interface) / Write device descriptor (Per-Interface)
USB HID(Human Interface Device)基类,支持可选 OUT 端点、自动生成描述符,适合键盘、鼠标、手柄等扩展。 USB HID (Human Interface Device)...
Definition hid.hpp:23
ErrorCode SendInputReport(ConstRawData report)
Definition hid.hpp:577
ClassID bDeviceClass
设备类代码 / Device class code
Definition desc_dev.hpp:93
uint8_t bDeviceSubClass
设备子类代码 / Device subclass code
Definition desc_dev.hpp:94
uint8_t bDeviceProtocol
协议代码 / Protocol code
Definition desc_dev.hpp:95
输入报告结构(9 字节) / Input report structure (9 bytes)
int16_t y
Y 轴 / Y axis (LOG_MIN..LOG_MAX)
int16_t x
X 轴 / X axis (LOG_MIN..LOG_MAX)
int16_t rx
Rx 轴 / Rx axis (LOG_MIN..LOG_MAX)
int16_t z
Z 轴 / Z axis (LOG_MIN..LOG_MAX)
uint8_t buttons
按钮位 / Button bits (8)