Skip to content

Commit c256897

Browse files
committed
enhancement: Device and Control attributes now support raw IDs (#5)
Added test for Control attribute to confirm acceptance of Enums and integers. Updated HID tables. Addressed some null reference compile warnings. Note, this is technically a breaking change as non enum/integer values passed to the Control/Device attributes may throw exceptions.
1 parent c2c8f20 commit c256897

File tree

8 files changed

+180
-23
lines changed

8 files changed

+180
-23
lines changed

HIDDevices.Sample/Samples/DependencyInjectionSample.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public override async Task ExecuteAsync(CancellationToken token = default)
3535
await using var serviceProvider = serviceCollection.BuildServiceProvider();
3636

3737
// Get the logger
38-
var logger = serviceProvider.GetService<ILogger<DependencyInjectionSample>>();
38+
var logger = serviceProvider.GetService<ILogger<DependencyInjectionSample>>()!;
3939

4040
// Grab the controllers service
4141
var controllers = serviceProvider.GetService<Devices>()!;

HIDDevices.Sample/SimpleConsoleLogger.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ public SimpleConsoleLogger(LogLevel logLevel, string? name = null)
2020
public LogLevel LogLevel { get; set; }
2121

2222
/// <inheritdoc />
23-
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception,
24-
Func<TState, Exception, string> formatter)
23+
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
24+
Func<TState, Exception?, string> formatter)
2525
{
2626
if (!IsEnabled(logLevel))
2727
{

HIDDevices.Test/Tests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
using System.Threading;
88
using System.Threading.Tasks;
99
using DevDecoder.HIDDevices;
10+
using DevDecoder.HIDDevices.Pages;
11+
using DevDecoder.HIDDevices.Usages;
1012
using Microsoft.Extensions.Logging;
1113
using Xunit;
1214
using Xunit.Abstractions;
@@ -69,5 +71,24 @@ public void TestUndefinedUsage()
6971
var usage = Usage.Get(0xffff);
7072
Assert.Equal("Reserved (0x00) - Undefined (0xFFFF)", usage.ToString());
7173
}
74+
75+
[Fact]
76+
public void TestControlAttribute()
77+
{
78+
// Confirm that the enum and raw value are identical.
79+
var attr1 = new ControlAttribute(ButtonPage.Button15);
80+
var attr2 = new ControlAttribute(0x00090010);
81+
Assert.Equal(1, attr1.Usages.Count);
82+
Assert.Equal(1, attr2.Usages.Count);
83+
Assert.Equal(attr1.Usages[0], attr2.Usages[0]);
84+
85+
// Confirm that a user defined ID is accepted.
86+
var attr3 = new ControlAttribute(0x00090011);
87+
var usage = attr3.Usages[0];
88+
Assert.Equal(UsagePage.Button, usage.Page);
89+
Assert.Equal(17, usage.Id);
90+
91+
Logger.LogInformation($"User defined usage: {usage}");
92+
}
7293
}
7394
}

HIDDevices/Attributes/ControlAttribute.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ namespace DevDecoder.HIDDevices
1313
/// Attribute that should be added to properties on a <seealso cref="Controller" /> to indicate
1414
/// that they should be bound to a <seealso cref="Control" />.
1515
/// </summary>
16+
/// <remarks>
17+
/// Note that multiple usages can be supplied, any value that can be converted to a <see langref="uint"/>
18+
/// is supported, which includes the Usage enums. Further, the value must be the full ID, and encode
19+
/// the page and ID of the usage.
20+
/// </remarks>
1621
/// <seealso cref="Controller" />
1722
/// <seealso cref="Control" />
1823
/// <seealso cref="Attribute" />
@@ -23,7 +28,9 @@ public sealed class ControlAttribute : Attribute
2328
/// Initializes a new instance of the <see cref="ControlAttribute" /> class.
2429
/// </summary>
2530
/// <param name="usages">The usages.</param>
26-
public ControlAttribute(params object[] usages) => Usages = usages.OfType<Enum>().Select(Usage.Get).ToArray();
31+
public ControlAttribute(params object[] usages) => Usages = usages
32+
.Select(o => Usage.Get(Convert.ToUInt32(o)))
33+
.ToArray();
2734

2835
/// <summary>
2936
/// Gets or sets the weight, a higher weight will increase the scoring of controls matching this attribute,

HIDDevices/Attributes/DeviceAttribute.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ namespace DevDecoder.HIDDevices
1515
/// <seealso cref="Device">Devices</seealso>
1616
/// that can be matched by the controller.
1717
/// </summary>
18+
/// <remarks>
19+
/// Note that multiple usages can be supplied, any value that can be converted to a <see langref="uint"/>
20+
/// is supported, which includes the Usage enums. Further, the value must be the full ID, and encode
21+
/// the page and ID of the usage.
22+
/// </remarks>
1823
/// <seealso cref="Controller" />
1924
/// <seealso cref="Device" />
2025
/// <seealso cref="Attribute" />
@@ -27,7 +32,9 @@ public sealed class DeviceAttribute : Attribute
2732
/// Initializes a new instance of the <see cref="DeviceAttribute" /> class.
2833
/// </summary>
2934
/// <param name="usages">The usages, all of which must match.</param>
30-
public DeviceAttribute(params object[] usages) => Usages = usages.OfType<Enum>().Select(Usage.Get).ToArray();
35+
public DeviceAttribute(params object[] usages) => Usages = Usages = usages
36+
.Select(o => Usage.Get(Convert.ToUInt32(o)))
37+
.ToArray();
3138

3239
/// <summary>
3340
/// Gets a list of valid usages, of which the device must match all.

HIDDevices/Usages/GenerateUsagePages.generated.cs

Lines changed: 138 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Licensed under the Apache License, Version 2.0 (the "License").
22
// See the LICENSE file in the project root for more information.
33
//
4-
// Auto Generated 2651 usages in 35 pages on 20/01/2022 13:01:03.
4+
// Auto Generated 2663 usages in 36 pages on 09/08/2022 14:11:21.
55

66
#pragma warning disable CS0108 // Member hides inherited member; missing new keyword
77

@@ -7690,7 +7690,13 @@ public enum DigitizerPage : uint
76907690
/// Transducer Switches Usage.
76917691
/// </summary>
76927692
[Description("Transducer Switches")]
7693-
TransducerSwitches = 0x000d00a5
7693+
TransducerSwitches = 0x000d00a5,
7694+
7695+
/// <summary>
7696+
/// Transducer Index Selector Usage.
7697+
/// </summary>
7698+
[Description("Transducer Index Selector")]
7699+
TransducerIndexSelector = 0x000d00a6
76947700
}
76957701

76967702
/// <summary>
@@ -7881,10 +7887,10 @@ public enum HapticsPage : uint
78817887
}
78827888

78837889
/// <summary>
7884-
/// Physical Interface Device Usage Page.
7890+
/// Physical Interput Device Usage Page.
78857891
/// </summary>
7886-
[Description("Physical Interface Device Usage Page")]
7887-
public enum PhysicalInterfaceDevicePage : uint
7892+
[Description("Physical Interput Device Usage Page")]
7893+
public enum PhysicalInterputDevicePage : uint
78887894
{
78897895
/// <summary>
78907896
/// Undefined Usage.
@@ -7893,10 +7899,10 @@ public enum PhysicalInterfaceDevicePage : uint
78937899
Undefined = 0x000f0000,
78947900

78957901
/// <summary>
7896-
/// Physical Interface Device Usage.
7902+
/// Physical Input Device Usage.
78977903
/// </summary>
7898-
[Description("Physical Interface Device")]
7899-
PhysicalInterfaceDevice = 0x000f0001,
7904+
[Description("Physical Input Device")]
7905+
PhysicalInputDevice = 0x000f0001,
79007906

79017907
/// <summary>
79027908
/// Normal Usage.
@@ -8536,6 +8542,79 @@ public enum UnicodePage : uint
85368542
Undefined = 0x00100000
85378543
}
85388544

8545+
/// <summary>
8546+
/// SoC Usage Page.
8547+
/// </summary>
8548+
[Description("SoC Usage Page")]
8549+
public enum SoCPage : uint
8550+
{
8551+
/// <summary>
8552+
/// Undefined Usage.
8553+
/// </summary>
8554+
[Description("Undefined")]
8555+
Undefined = 0x00110000,
8556+
8557+
/// <summary>
8558+
/// SoC Control Usage.
8559+
/// </summary>
8560+
[Description("SoC Control")]
8561+
SoCControl = 0x00110001,
8562+
8563+
/// <summary>
8564+
/// Firmware Transfer Usage.
8565+
/// </summary>
8566+
[Description("Firmware Transfer")]
8567+
FirmwareTransfer = 0x00110002,
8568+
8569+
/// <summary>
8570+
/// Firmware File Id Usage.
8571+
/// </summary>
8572+
[Description("Firmware File Id")]
8573+
FirmwareFileId = 0x00110003,
8574+
8575+
/// <summary>
8576+
/// File Offset In Bytes Usage.
8577+
/// </summary>
8578+
[Description("File Offset In Bytes")]
8579+
FileOffsetInBytes = 0x00110004,
8580+
8581+
/// <summary>
8582+
/// File Transfer Size Max In Bytes Usage.
8583+
/// </summary>
8584+
[Description("File Transfer Size Max In Bytes")]
8585+
FileTransferSizeMaxInBytes = 0x00110005,
8586+
8587+
/// <summary>
8588+
/// File Payload Usage.
8589+
/// </summary>
8590+
[Description("File Payload")]
8591+
FilePayload = 0x00110006,
8592+
8593+
/// <summary>
8594+
/// File Payload Size In Bytes Usage.
8595+
/// </summary>
8596+
[Description("File Payload Size In Bytes")]
8597+
FilePayloadSizeInBytes = 0x00110007,
8598+
8599+
/// <summary>
8600+
/// File Payload Contains Last Bytes Usage.
8601+
/// </summary>
8602+
[Description("File Payload Contains Last Bytes")]
8603+
FilePayloadContainsLastBytes = 0x00110008,
8604+
8605+
/// <summary>
8606+
/// File Transfer Stop Usage.
8607+
/// </summary>
8608+
[Description("File Transfer Stop")]
8609+
FileTransferStop = 0x00110009,
8610+
8611+
/// <summary>
8612+
/// File Transfer Till End Usage.
8613+
/// </summary>
8614+
[Description("File Transfer Till End")]
8615+
FileTransferTillEnd = 0x0011000a
8616+
}
8617+
85398618
/// <summary>
85408619
/// Eye and Head Trackers Usage Page.
85418620
/// </summary>
@@ -18621,8 +18700,9 @@ public partial class UsagePage
1862118700
[0x000c] = ConsumerUsagePage.Instance,
1862218701
[0x000d] = DigitizerUsagePage.Instance,
1862318702
[0x000e] = HapticsUsagePage.Instance,
18624-
[0x000f] = PhysicalInterfaceDeviceUsagePage.Instance,
18703+
[0x000f] = PhysicalInterputDeviceUsagePage.Instance,
1862518704
[0x0010] = UnicodeUsagePage.Instance,
18705+
[0x0011] = SoCUsagePage.Instance,
1862618706
[0x0012] = EyeAndHeadTrackersUsagePage.Instance,
1862718707
[0x0014] = AuxiliaryDisplayUsagePage.Instance,
1862818708
[0x0020] = SensorUsagePage.Instance,
@@ -18715,15 +18795,20 @@ public partial class UsagePage
1871518795
public static readonly HapticsUsagePage Haptics = HapticsUsagePage.Instance;
1871618796

1871718797
/// <summary>
18718-
/// Physical Interface Device Usage Page.
18798+
/// Physical Interput Device Usage Page.
1871918799
/// </summary>
18720-
public static readonly PhysicalInterfaceDeviceUsagePage PhysicalInterfaceDevice = PhysicalInterfaceDeviceUsagePage.Instance;
18800+
public static readonly PhysicalInterputDeviceUsagePage PhysicalInterputDevice = PhysicalInterputDeviceUsagePage.Instance;
1872118801

1872218802
/// <summary>
1872318803
/// Unicode Usage Page.
1872418804
/// </summary>
1872518805
public static readonly UnicodeUsagePage Unicode = UnicodeUsagePage.Instance;
1872618806

18807+
/// <summary>
18808+
/// SoC Usage Page.
18809+
/// </summary>
18810+
public static readonly SoCUsagePage SoC = SoCUsagePage.Instance;
18811+
1872718812
/// <summary>
1872818813
/// Eye and Head Trackers Usage Page.
1872918814
/// </summary>
@@ -20411,6 +20496,7 @@ protected override Usage CreateUsage(ushort id)
2041120496
case 0x00a3: return new Usage(this, id, "Switch Disabled", UsageTypes.Sel);
2041220497
case 0x00a4: return new Usage(this, id, "Switch Unimplemented", UsageTypes.Sel);
2041320498
case 0x00a5: return new Usage(this, id, "Transducer Switches", UsageTypes.CL);
20499+
case 0x00a6: return new Usage(this, id, "Transducer Index Selector", UsageTypes.DV);
2041420500
}
2041520501

2041620502
return base.CreateUsage(id);
@@ -20475,14 +20561,14 @@ protected override Usage CreateUsage(ushort id)
2047520561
/// <summary>
2047620562
/// Base class for all usage pages.
2047720563
/// </summary>
20478-
public sealed class PhysicalInterfaceDeviceUsagePage : UsagePage
20564+
public sealed class PhysicalInterputDeviceUsagePage : UsagePage
2047920565
{
2048020566
/// <summary>
20481-
/// Singleton instance of PhysicalInterfaceDevice Usage Page.
20567+
/// Singleton instance of PhysicalInterputDevice Usage Page.
2048220568
/// </summary>
20483-
public static readonly PhysicalInterfaceDeviceUsagePage Instance = new PhysicalInterfaceDeviceUsagePage();
20569+
public static readonly PhysicalInterputDeviceUsagePage Instance = new PhysicalInterputDeviceUsagePage();
2048420570

20485-
private PhysicalInterfaceDeviceUsagePage() : base(0x000f, "PhysicalInterfaceDevice")
20571+
private PhysicalInterputDeviceUsagePage() : base(0x000f, "PhysicalInterputDevice")
2048620572
{
2048720573
}
2048820574

@@ -20492,7 +20578,7 @@ protected override Usage CreateUsage(ushort id)
2049220578
switch (id)
2049320579
{
2049420580
case 0x0000: return new Usage(this, id, "Undefined", UsageTypes.None);
20495-
case 0x0001: return new Usage(this, id, "Physical Interface Device", UsageTypes.CA);
20581+
case 0x0001: return new Usage(this, id, "Physical Input Device", UsageTypes.CA);
2049620582
case 0x0020: return new Usage(this, id, "Normal", UsageTypes.DV);
2049720583
case 0x0021: return new Usage(this, id, "Set Effect Report", UsageTypes.CL);
2049820584
case 0x0022: return new Usage(this, id, "Effect Block Index", UsageTypes.DV);
@@ -20629,6 +20715,42 @@ protected override Usage CreateUsage(ushort id)
2062920715
}
2063020716
}
2063120717

20718+
/// <summary>
20719+
/// Base class for all usage pages.
20720+
/// </summary>
20721+
public sealed class SoCUsagePage : UsagePage
20722+
{
20723+
/// <summary>
20724+
/// Singleton instance of SoC Usage Page.
20725+
/// </summary>
20726+
public static readonly SoCUsagePage Instance = new SoCUsagePage();
20727+
20728+
private SoCUsagePage() : base(0x0011, "SoC")
20729+
{
20730+
}
20731+
20732+
/// <inheritdoc />
20733+
protected override Usage CreateUsage(ushort id)
20734+
{
20735+
switch (id)
20736+
{
20737+
case 0x0000: return new Usage(this, id, "Undefined", UsageTypes.None);
20738+
case 0x0001: return new Usage(this, id, "SoC Control", UsageTypes.CA);
20739+
case 0x0002: return new Usage(this, id, "Firmware Transfer", UsageTypes.CL);
20740+
case 0x0003: return new Usage(this, id, "Firmware File Id", UsageTypes.DV);
20741+
case 0x0004: return new Usage(this, id, "File Offset In Bytes", UsageTypes.DV);
20742+
case 0x0005: return new Usage(this, id, "File Transfer Size Max In Bytes", UsageTypes.DV);
20743+
case 0x0006: return new Usage(this, id, "File Payload", UsageTypes.DV);
20744+
case 0x0007: return new Usage(this, id, "File Payload Size In Bytes", UsageTypes.DV);
20745+
case 0x0008: return new Usage(this, id, "File Payload Contains Last Bytes", UsageTypes.DF);
20746+
case 0x0009: return new Usage(this, id, "File Transfer Stop", UsageTypes.DF);
20747+
case 0x000a: return new Usage(this, id, "File Transfer Till End", UsageTypes.DF);
20748+
}
20749+
20750+
return base.CreateUsage(id);
20751+
}
20752+
}
20753+
2063220754
/// <summary>
2063320755
/// Base class for all usage pages.
2063420756
/// </summary>

version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema":
33
"https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
4-
"version": "2.2",
4+
"version": "2.3",
55
"publicReleaseRefSpec": [
66
"^refs/heads/master$",
77
"^refs/heads/v\\d+(?:\\.\\d+)?$"

0 commit comments

Comments
 (0)