libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
hid_gamepad.hpp
1#pragma once
2#include <cstdint>
3#include <cstring>
4#include <cmath>
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
27template<int16_t LOG_MIN = 0,
28 int16_t LOG_MAX = 2047,
29 uint8_t IN_EP_INTERVAL_MS = 1>
30class HIDGamepadT : public HID<50 /* desc size */, 9 /* report len */, 0 /* feature len */>
31{
32 static_assert(LOG_MIN <= LOG_MAX, "LOG_MIN must be <= LOG_MAX");
33 static_assert(LOG_MIN >= -32768 && LOG_MAX <= 32767, "Axis logical range must fit in int16_t");
34
35 public:
42 : HID<50, 9, 0>(false, IN_EP_INTERVAL_MS, /*out_ep_interval*/1,
43 in_ep_num, Endpoint::EPNumber::EP_AUTO)
44 {
45 // 初始化上一帧:轴置中,按钮清零 / Initialize last report: axes to mid, buttons cleared
46 last_.x = Mid();
47 last_.y = Mid();
48 last_.z = Mid();
49 last_.rx = Mid();
50 last_.buttons = 0;
51 }
52
56 enum Button : uint8_t
57 {
58 BTN1 = 0x01, BTN2 = 0x02, BTN3 = 0x04, BTN4 = 0x08,
59 BTN5 = 0x10, BTN6 = 0x20, BTN7 = 0x40, BTN8 = 0x80,
60 };
61
62#pragma pack(push, 1)
67 struct Report
68 {
69 int16_t x;
70 int16_t y;
71 int16_t z;
72 int16_t rx;
73 uint8_t buttons;
74 };
75#pragma pack(pop)
76
77 static_assert(sizeof(Report) == 9, "Report size must be 9 bytes");
78
89 ErrorCode Send(int x, int y, int z, int rx, uint8_t buttons)
90 {
91 last_.x = Clamp(x);
92 last_.y = Clamp(y);
93 last_.z = Clamp(z);
94 last_.rx = Clamp(rx);
95 last_.buttons = buttons;
96 return SendInputReport(ConstRawData{&last_, sizeof(last_)});
97 }
98
104 ErrorCode SendButtons(uint8_t buttons)
105 {
106 last_.buttons = buttons;
107 return SendInputReport(ConstRawData{&last_, sizeof(last_)});
108 }
109
118 ErrorCode SendAxes(int x, int y, int z, int rx)
119 {
120 last_.x = Clamp(x);
121 last_.y = Clamp(y);
122 last_.z = Clamp(z);
123 last_.rx = Clamp(rx);
124 return SendInputReport(ConstRawData{&last_, sizeof(last_)});
125 }
126
127 protected:
133 ErrorCode WriteDeviceDescriptor(DeviceDescriptor& header) override
134 {
136 header.data_.bDeviceSubClass = 0;
137 header.data_.bDeviceProtocol = 0;
138 return ErrorCode::OK;
139 }
140
146 {
147 return ConstRawData{desc_, sizeof(desc_)};
148 }
149
150 private:
151 // 报告描述符(编译期常量 50 字节) / HID report descriptor (compile-time 50 bytes)
152 // 轴:X/Y/Z/Rx,16 位容器;按钮:8 个 / Axes: X/Y/Z/Rx, 16-bit containers; Buttons: 8
153 static constexpr uint8_t U8(uint16_t v) { return static_cast<uint8_t>(v & 0xFF); }
154 static constexpr uint8_t U8H(uint16_t v) { return static_cast<uint8_t>((v >> 8) & 0xFF); }
155
156 static constexpr uint8_t desc_[/*50*/] = {
157 0x05, 0x01, // Usage Page (Generic Desktop)
158 0x09, 0x05, // Usage (Game Pad)
159 0xA1, 0x01, // Collection (Application)
160
161 // Axes collection
162 0x09, 0x01, // Usage (Pointer)
163 0xA1, 0x00, // Collection (Physical)
164 0x05, 0x01, // Usage Page (Generic Desktop)
165 0x09, 0x30, // Usage (X)
166 0x09, 0x31, // Usage (Y)
167 0x09, 0x32, // Usage (Z)
168 0x09, 0x33, // Usage (Rx)
169
170 // Logical Min/Max (16-bit)
171 0x16, U8(static_cast<uint16_t>(LOG_MIN)), U8H(static_cast<uint16_t>(LOG_MIN)), // Logical Minimum
172 0x26, U8(static_cast<uint16_t>(LOG_MAX)), U8H(static_cast<uint16_t>(LOG_MAX)), // Logical Maximum
173
174 0x75, 0x10, // Report Size (16)
175 0x95, 0x04, // Report Count (4)
176 0x81, 0x02, // Input (Data, Variable, Absolute)
177 0xC0, // End Collection (Physical)
178
179 // Buttons
180 0x05, 0x09, // Usage Page (Button)
181 0x19, 0x01, // Usage Minimum (Button 1)
182 0x29, 0x08, // Usage Maximum (Button 8)
183 0x15, 0x00, // Logical Minimum (0)
184 0x25, 0x01, // Logical Maximum (1)
185 0x95, 0x08, // Report Count (8)
186 0x75, 0x01, // Report Size (1)
187 0x81, 0x02, // Input (Data, Variable, Absolute)
188
189 0xC0 // End Collection (Application)
190 };
191
192 static_assert(sizeof(desc_) == 50, "HID report descriptor size changed; update base template arg!");
193
197 static constexpr int16_t Clamp(int v)
198 {
199 return (v < LOG_MIN) ? LOG_MIN : (v > LOG_MAX ? LOG_MAX : static_cast<int16_t>(v));
200 }
201
205 static constexpr int16_t Mid()
206 {
207 return static_cast<int16_t>((static_cast<int32_t>(LOG_MIN) + static_cast<int32_t>(LOG_MAX)) / 2);
208 }
209
211};
212
216using HIDGamepad = HIDGamepadT<0, 2047, 1>;
217
221using HIDGamepadBipolar = HIDGamepadT<-2048, 2047, 1>;
222
223} // namespace LibXR::USB
常量原始数据封装类。 A class for encapsulating constant raw data.
USB描述符基类 USB descriptor base class.
Definition desc_dev.hpp:37
Data data_
设备描述符数据实例 / Internal data instance
Definition desc_dev.hpp:106
@ PER_INTERFACE
每个接口自定义类 / Per-interface
USB端点基类 / USB Endpoint base class.
Definition ep.hpp:22
EPNumber
端点号 / Endpoint number
Definition ep.hpp:39
@ 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:560
ClassID bDeviceClass
设备类代码 / Device class code
Definition desc_dev.hpp:90
uint8_t bDeviceSubClass
设备子类代码 / Device subclass code
Definition desc_dev.hpp:91
uint8_t bDeviceProtocol
协议代码 / Protocol code
Definition desc_dev.hpp:92
输入报告结构(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)