@@ -218,27 +218,9 @@ public void Devices_CanCreateGenericHID_FromDeviceWithBinaryReportDescriptor()
218
218
219
219
// The HID report descriptor is fetched from the device via an IOCTL.
220
220
var deviceId = runtime . AllocateDeviceId ( ) ;
221
- unsafe
222
- {
223
- runtime . SetDeviceCommandCallback ( deviceId ,
224
- ( id , commandPtr ) =>
225
- {
226
- if ( commandPtr ->type == HID . QueryHIDReportDescriptorSizeDeviceCommandType )
227
- return reportDescriptor . Length ;
228
221
229
- if ( commandPtr ->type == HID . QueryHIDReportDescriptorDeviceCommandType
230
- && commandPtr ->payloadSizeInBytes >= reportDescriptor . Length )
231
- {
232
- fixed( byte * ptr = reportDescriptor )
233
- {
234
- UnsafeUtility . MemCpy ( commandPtr ->payloadPtr , ptr , reportDescriptor . Length ) ;
235
- return reportDescriptor . Length ;
236
- }
237
- }
222
+ SetDeviceCommandCallbackToReturnReportDescriptor ( deviceId , reportDescriptor ) ;
238
223
239
- return InputDeviceCommand . GenericFailure ;
240
- } ) ;
241
- }
242
224
// Report device.
243
225
runtime . ReportNewInputDevice (
244
226
new InputDeviceDescription
@@ -309,6 +291,111 @@ public void Devices_CanCreateGenericHID_FromDeviceWithBinaryReportDescriptor()
309
291
////TODO: check hat switch
310
292
}
311
293
294
+ // This is used to mock out the IOCTL the HID device driver would use to return
295
+ // the report descriptor and its size.
296
+ unsafe void SetDeviceCommandCallbackToReturnReportDescriptor ( int deviceId , byte [ ] reportDescriptor )
297
+ {
298
+ runtime . SetDeviceCommandCallback ( deviceId ,
299
+ ( id , commandPtr ) =>
300
+ {
301
+ if ( commandPtr ->type == HID . QueryHIDReportDescriptorSizeDeviceCommandType )
302
+ return reportDescriptor . Length ;
303
+
304
+ if ( commandPtr ->type == HID . QueryHIDReportDescriptorDeviceCommandType
305
+ && commandPtr ->payloadSizeInBytes >= reportDescriptor . Length )
306
+ {
307
+ fixed( byte * ptr = reportDescriptor )
308
+ {
309
+ UnsafeUtility . MemCpy ( commandPtr ->payloadPtr , ptr , reportDescriptor . Length ) ;
310
+ return reportDescriptor . Length ;
311
+ }
312
+ }
313
+
314
+ return InputDeviceCommand . GenericFailure ;
315
+ } ) ;
316
+ }
317
+
318
+ [ Test ]
319
+ [ Category ( "HID Devices" ) ]
320
+ public void Devices_CanCrateGenericHID_WithSignedLogicalMinAndMaxSticks ( )
321
+ {
322
+ // This is a HID report descriptor for a simple device with two analog sticks;
323
+ // Similar to a user that reported an issue in Discussions:
324
+ // https://discussions.unity.com/t/input-system-reading-invalid-values-from-hall-effect-keyboards/1684840/3
325
+ var reportDescriptor = new byte [ ]
326
+ {
327
+ 0x05 , 0x01 , // Usage Page (Generic Desktop Ctrls)
328
+ 0x09 , 0x05 , // Usage (Game Pad)
329
+ 0xA1 , 0x01 , // Collection (Application)
330
+ 0x85 , 0x01 , // Report ID (1)
331
+ 0x05 , 0x01 , // Usage Page (Generic Desktop Ctrls)
332
+ 0x09 , 0x30 , // Usage (X)
333
+ 0x09 , 0x31 , // Usage (Y)
334
+ 0x15 , 0x81 , // Logical Minimum (-127)
335
+ 0x25 , 0x7F , // Logical Maximum (127)
336
+ 0x75 , 0x08 , // Report Size (8)
337
+ 0x95 , 0x02 , // Report Count (2)
338
+ 0x81 , 0x02 , // Input (Data,Var,Abs)
339
+ 0xC0 , // End Collection
340
+ } ;
341
+
342
+ // The HID report descriptor is fetched from the device via an IOCTL.
343
+ var deviceId = runtime . AllocateDeviceId ( ) ;
344
+
345
+ // Callback to return the desired report descriptor.
346
+ SetDeviceCommandCallbackToReturnReportDescriptor ( deviceId , reportDescriptor ) ;
347
+
348
+ // Report device.
349
+ runtime . ReportNewInputDevice (
350
+ new InputDeviceDescription
351
+ {
352
+ interfaceName = HID . kHIDInterface ,
353
+ manufacturer = "TestVendor" ,
354
+ product = "TestHID" ,
355
+ capabilities = new HID . HIDDeviceDescriptor
356
+ {
357
+ vendorId = 0x321 ,
358
+ productId = 0x432
359
+ } . ToJson ( )
360
+ } . ToJson ( ) , deviceId ) ;
361
+
362
+ InputSystem . Update ( ) ;
363
+
364
+ var device = ( Joystick ) InputSystem . GetDeviceById ( deviceId ) ;
365
+ Assert . That ( device , Is . Not . Null ) ;
366
+ Assert . That ( device , Is . TypeOf < Joystick > ( ) ) ;
367
+
368
+ // Stick vector 2 should be centered at (0,0).
369
+ Assert . That ( device . stick . ReadValue ( ) , Is . EqualTo ( new Vector2 ( 0f , 0f ) ) . Using ( Vector2EqualityComparer . Instance ) ) ;
370
+
371
+ // Queue event with stick pushed to bottom. We assume Y axis is inverted by default in HID devices.
372
+ // See HID.HIDElementDescriptor.DetermineParameters()
373
+ InputSystem . QueueStateEvent ( device , new SimpleJoystickLayoutWithStickByte { reportId = 1 , x = 0 , y = 127 } ) ;
374
+ InputSystem . Update ( ) ;
375
+
376
+ Assert . That ( device . stick . ReadValue ( ) , Is . EqualTo ( new Vector2 ( 0f , - 1f ) ) . Using ( Vector2EqualityComparer . Instance ) ) ;
377
+
378
+ InputSystem . QueueStateEvent ( device , new SimpleJoystickLayoutWithStickByte { reportId = 1 , x = 0 , y = - 127 } ) ;
379
+ InputSystem . Update ( ) ;
380
+
381
+ Assert . That ( device . stick . ReadValue ( ) , Is . EqualTo ( new Vector2 ( 0f , 1f ) ) . Using ( Vector2EqualityComparer . Instance ) ) ;
382
+
383
+ InputSystem . QueueStateEvent ( device , new SimpleJoystickLayoutWithStickByte { reportId = 1 , x = 127 , y = 0 } ) ;
384
+ InputSystem . Update ( ) ;
385
+
386
+ Assert . That ( device . stick . ReadValue ( ) , Is . EqualTo ( new Vector2 ( 1f , 0f ) ) . Using ( Vector2EqualityComparer . Instance ) ) ;
387
+
388
+ InputSystem . QueueStateEvent ( device , new SimpleJoystickLayoutWithStickByte { reportId = 1 , x = - 127 , y = 0 } ) ;
389
+ InputSystem . Update ( ) ;
390
+
391
+ Assert . That ( device . stick . ReadValue ( ) , Is . EqualTo ( new Vector2 ( - 1f , 0f ) ) . Using ( Vector2EqualityComparer . Instance ) ) ;
392
+
393
+ InputSystem . QueueStateEvent ( device , new SimpleJoystickLayoutWithStickByte { reportId = 1 , x = 127 , y = 127 } ) ;
394
+ InputSystem . Update ( ) ;
395
+
396
+ Assert . That ( device . stick . ReadValue ( ) , Is . EqualTo ( new Vector2 ( 0.7071f , - 0.7071f ) ) . Using ( Vector2EqualityComparer . Instance ) ) ;
397
+ }
398
+
312
399
[ Test ]
313
400
[ Category ( "Devices" ) ]
314
401
public void Devices_CanCreateGenericHID_FromDeviceWithParsedReportDescriptor ( )
@@ -1026,7 +1113,7 @@ public void Devices_GenericHIDConvertsXAndYUsagesToStickControl()
1026
1113
}
1027
1114
1028
1115
[ StructLayout ( LayoutKind . Explicit ) ]
1029
- struct SimpleJoystickLayout : IInputStateTypeInfo
1116
+ struct SimpleJoystickLayoutWithStickUshort : IInputStateTypeInfo
1030
1117
{
1031
1118
[ FieldOffset ( 0 ) ] public byte reportId ;
1032
1119
[ FieldOffset ( 1 ) ] public ushort x ;
@@ -1035,6 +1122,16 @@ struct SimpleJoystickLayout : IInputStateTypeInfo
1035
1122
public FourCC format => new FourCC ( 'H' , 'I' , 'D' ) ;
1036
1123
}
1037
1124
1125
+ [ StructLayout ( LayoutKind . Explicit ) ]
1126
+ struct SimpleJoystickLayoutWithStickByte : IInputStateTypeInfo
1127
+ {
1128
+ [ FieldOffset ( 0 ) ] public byte reportId ;
1129
+ [ FieldOffset ( 1 ) ] public sbyte x ;
1130
+ [ FieldOffset ( 2 ) ] public sbyte y ;
1131
+
1132
+ public FourCC format => new FourCC ( 'H' , 'I' , 'D' ) ;
1133
+ }
1134
+
1038
1135
[ Test ]
1039
1136
[ Category ( "Devices" ) ]
1040
1137
public void Devices_GenericHIDXAndYDrivesStickControl ( )
@@ -1069,7 +1166,7 @@ public void Devices_GenericHIDXAndYDrivesStickControl()
1069
1166
Assert . That ( device , Is . TypeOf < Joystick > ( ) ) ;
1070
1167
Assert . That ( device [ "Stick" ] , Is . TypeOf < StickControl > ( ) ) ;
1071
1168
1072
- InputSystem . QueueStateEvent ( device , new SimpleJoystickLayout { reportId = 1 , x = ushort . MaxValue , y = ushort . MinValue } ) ;
1169
+ InputSystem . QueueStateEvent ( device , new SimpleJoystickLayoutWithStickUshort { reportId = 1 , x = ushort . MaxValue , y = ushort . MinValue } ) ;
1073
1170
InputSystem . Update ( ) ;
1074
1171
1075
1172
Assert . That ( device [ "stick" ] . ReadValueAsObject ( ) ,
0 commit comments