@@ -30,6 +30,100 @@ use usbd_hid::descriptor::generator_prelude::*;
30
30
use usbd_hid:: descriptor:: MouseReport ;
31
31
use usbd_hid:: hid_class:: HIDClass ;
32
32
33
+ #[ gen_hid_descriptor(
34
+ ( collection = APPLICATION , usage_page = GENERIC_DESKTOP , usage = 0x05 ) = {
35
+ // Button packet
36
+ ( collection = PHYSICAL , report_id = 0x20 ) = {
37
+ ( usage_page = GENERIC_DESKTOP , usage = 0x00 ) = {
38
+ #[ item_settings constant, variable, absolute] unknown=input;
39
+ } ;
40
+ ( usage_page = GENERIC_DESKTOP , usage = 0x3b ) = {
41
+ #[ item_settings data, variable, absolute] payload_size=input;
42
+ } ;
43
+ ( usage_page = BUTTON , usage_min = 1 , usage_max = 16 ) = {
44
+ #[ packed_bits 16 ] #[ item_settings data, variable, absolute] buttons=input;
45
+ } ;
46
+ ( usage_page = GENERIC_DESKTOP , ) = {
47
+ ( usage = 0x33 , ) = {
48
+ #[ item_settings data, variable, absolute] rx=input;
49
+ } ;
50
+ ( usage = 0x34 , ) = {
51
+ #[ item_settings data, variable, absolute] ry=input;
52
+ } ;
53
+ } ;
54
+ ( usage_page = GENERIC_DESKTOP , usage = POINTER , ) = {
55
+ ( collection = PHYSICAL , ) = {
56
+ ( usage_page = GENERIC_DESKTOP , ) = {
57
+ ( usage = X , ) = {
58
+ #[ item_settings data, variable, absolute] x=input;
59
+ } ;
60
+ ( usage = Y , ) = {
61
+ #[ item_settings data, variable, absolute] y=input;
62
+ } ;
63
+ } ;
64
+ } ;
65
+ } ;
66
+ ( usage_page = GENERIC_DESKTOP , usage = POINTER , ) = {
67
+ ( collection = PHYSICAL , ) = {
68
+ ( usage_page = GENERIC_DESKTOP , ) = {
69
+ ( usage = Z , ) = {
70
+ #[ item_settings data, variable, absolute] z=input;
71
+ } ;
72
+ ( usage = 0x35 , ) = {
73
+ #[ item_settings data, variable, absolute] rz=input;
74
+ } ;
75
+ } ;
76
+ } ;
77
+ } ;
78
+ } ;
79
+ // Xbox button packet
80
+ ( collection = PHYSICAL , report_id = 0x07 ) = {
81
+ ( usage_page = GENERIC_DESKTOP , usage = 0x00 ) = {
82
+ #[ item_settings constant, variable, absolute] unknown2=input;
83
+ } ;
84
+
85
+ ( usage_page = GENERIC_DESKTOP , usage = 0x3b ) = {
86
+ #[ item_settings constant, variable, absolute] payload_size2=input;
87
+ } ;
88
+
89
+ ( usage_page = BUTTON , usage = 0x10 ) = {
90
+ #[ packed_bits 1 ] #[ item_settings data, variable, absolute] xbox_button=input;
91
+ }
92
+ } ;
93
+ }
94
+ ) ]
95
+ struct GamepadReport {
96
+ // Normal buttons
97
+ unknown : [ u8 ; 2 ] ,
98
+ payload_size : u8 ,
99
+ buttons : u16 ,
100
+ rx : u16 ,
101
+ ry : u16 ,
102
+ x : i16 ,
103
+ y : i16 ,
104
+ z : i16 ,
105
+ rz : i16 ,
106
+ // Xbox button
107
+ unknown2 : [ u8 ; 2 ] ,
108
+ payload_size2 : u8 ,
109
+ xbox_button : u8 ,
110
+ }
111
+
112
+ #[ repr( C , packed) ]
113
+ struct GamepadReportButtons {
114
+ report_id : u8 ,
115
+ // Normal buttons
116
+ unknown : [ u8 ; 2 ] ,
117
+ payload_size : u8 ,
118
+ buttons : u16 ,
119
+ rx : u16 ,
120
+ ry : u16 ,
121
+ x : i16 ,
122
+ y : i16 ,
123
+ z : i16 ,
124
+ rz : i16 ,
125
+ }
126
+
33
127
#[ entry]
34
128
fn main ( ) -> ! {
35
129
info ! ( "Program start" ) ;
@@ -68,10 +162,10 @@ fn main() -> ! {
68
162
} ;
69
163
70
164
// Set up the USB HID Class Device driver, providing Mouse Reports
71
- let usb_hid = HIDClass :: new ( bus_ref, MouseReport :: desc ( ) , 60 ) ;
165
+ let usb_hid = HIDClass :: new ( bus_ref, GamepadReport :: desc ( ) , 60 ) ;
72
166
73
167
// Create a USB device with a fake VID and PID
74
- let usb_device = UsbDeviceBuilder :: new ( bus_ref, UsbVidPid ( 0x16c0 , 0x27da ) )
168
+ let usb_device = UsbDeviceBuilder :: new ( bus_ref, UsbVidPid ( 0x24c6 , 0xfafe ) )
75
169
. strings ( & [ StringDescriptors :: default ( )
76
170
. manufacturer ( "Fake company" )
77
171
. product ( "Twitchy Mousey" )
@@ -93,42 +187,52 @@ fn main() -> ! {
93
187
} ;
94
188
95
189
// Move the cursor up and down every 200ms
190
+ let mut sequence = 0 ;
191
+ let mut buttons = GamepadReportButtons {
192
+ report_id : 0x20 , // Button packet
193
+ unknown : [ 0 , sequence] ,
194
+ payload_size : 0x0e , //core::mem::size_of::<GamepadReportButtons>() as u8,
195
+ buttons : 0 ,
196
+ rx : 0 ,
197
+ ry : 0 ,
198
+ x : 0 ,
199
+ y : 0 ,
200
+ z : 0 ,
201
+ rz : 0 ,
202
+ } ;
203
+
96
204
loop {
97
205
delay. delay_ms ( 100 ) ;
98
-
99
- let rep_up = MouseReport {
100
- x : 0 ,
101
- y : 4 ,
102
- buttons : 0 ,
103
- wheel : 0 ,
104
- pan : 0 ,
105
- } ;
106
- push_mouse_movement ( rep_up) . ok ( ) . unwrap_or ( 0 ) ;
206
+ buttons. buttons = 0 ;
207
+ buttons. unknown [ 1 ] = sequence;
208
+ sequence += 1 ;
209
+ push_movement ( & buttons) . ok ( ) . unwrap_or ( 0 ) ;
107
210
108
211
delay. delay_ms ( 100 ) ;
109
212
110
- let rep_down = MouseReport {
111
- x : 0 ,
112
- y : -4 ,
113
- buttons : 0 ,
114
- wheel : 0 ,
115
- pan : 0 ,
116
- } ;
117
- push_mouse_movement ( rep_down) . ok ( ) . unwrap_or ( 0 ) ;
213
+ buttons. buttons = 0xffff ;
214
+ buttons. unknown [ 1 ] = sequence;
215
+ sequence += 1 ;
216
+ push_movement ( & buttons) . ok ( ) . unwrap_or ( 0 ) ;
118
217
}
119
218
}
120
219
220
+ unsafe fn any_as_u8_slice < T : Sized > ( p : & T ) -> & [ u8 ] {
221
+ core:: slice:: from_raw_parts ( ( p as * const T ) as * const u8 , core:: mem:: size_of :: < T > ( ) )
222
+ }
223
+
121
224
/// Submit a new mouse movement report to the USB stack.
122
225
///
123
226
/// We do this with interrupts disabled, to avoid a race hazard with the USB IRQ.
124
- fn push_mouse_movement ( report : MouseReport ) -> Result < usize , usb_device:: UsbError > {
227
+ fn push_movement ( report : & GamepadReportButtons ) -> Result < usize , usb_device:: UsbError > {
125
228
critical_section:: with ( |token| {
126
229
// Now interrupts are disabled, grab the global variable and, if
127
230
// available, send it a HID report
128
- GADGET
129
- . borrow_ref_mut ( token)
130
- . as_ref ( )
131
- . map ( |gadget| gadget. usb_hid . push_input ( & report) )
231
+ GADGET . borrow_ref_mut ( token) . as_ref ( ) . map ( |gadget| {
232
+ gadget
233
+ . usb_hid
234
+ . push_raw_input ( unsafe { any_as_u8_slice ( & report) } )
235
+ } )
132
236
} )
133
237
. unwrap ( )
134
238
}
0 commit comments