### Initialize Virtual Controller Source: https://hidmaestro.org/docs/start/installation A minimal example to load profiles, install the driver, and create a virtual controller. The controller is automatically removed when the scope ends. ```csharp using var ctx = new HMContext(); ctx.LoadDefaultProfiles(); ctx.InstallDriver(); using var ctrl = ctx.CreateController(ctx.GetProfile("xbox-360-wired")!); ctrl.SubmitState(new HMGamepadState { Axes = HMGamepadStateHelpers.StandardAxes(ctrl.Profile, leftStickX: 1.0f), }); ``` -------------------------------- ### Check and install USB/IP backend Source: https://hidmaestro.org/docs/sdk/usb-audio-composite Two optional APIs: check if the transport is already installed via HMContext.IsUsbipBackendAvailable, and perform the one-time install with progress reporting via HMContext.InstallUsbipBackend. Both are idempotent and not required for CreateController. ```csharp // Informational: has this machine already got the transport? bool ready = HMContext.IsUsbipBackendAvailable; // Do the one-time install now (onboarding step, settings toggle) instead // of on the first composite create. Idempotent. HMContext.InstallUsbipBackend(status => Console.WriteLine(status)); ``` -------------------------------- ### Create a composite persona with HMContext Source: https://hidmaestro.org/docs/sdk/usb-audio-composite Shows the minimal setup to create a composite controller: load default profiles, install the driver, and create the controller using the 'dualsense-composite' profile. Requires elevation for InstallDriver. ```csharp using var ctx = new HMContext(); ctx.LoadDefaultProfiles(); ctx.InstallDriver(); using var ctrl = ctx.CreateController(ctx.GetProfile("dualsense-composite")!); ``` -------------------------------- ### Cold-start flow process and timing Source: https://hidmaestro.org/docs/reference/driver-install-and-signing A breakdown of the HIDMaestro installation pipeline steps and their approximate execution times on a clean development machine. ```text Process A: Time ───────────────────────────────────────────── ──── 1. using var ctx = new HMContext(); ~10 ms Background prewarm tasks fire-and-forget 2. ctx.LoadDefaultProfiles(); ~100 ms Parse 228 embedded JSONs 3. ctx.InstallDriver(); ~1.7 s on a clean machine 3a. RemoveAllVirtualControllers (no-op) ~50 ms 3b. Compute hash, IsDriverInstalled? no <50 ms 3c. Extract embedded payload to %TEMP% ~20 ms 3d. Remove any prior package (idempotent) ~100 ms 3e. Generate self-signed cert (first-ever) ~500 ms (one-time per machine) 3f. Install cert to Root + TrustedPublisher ~50 ms (one-time per machine) 3g. Sign DLLs + INFs (signtool, batched) ~130 ms 3h. Generate .cat catalogs (Inf2Cat, batched) ~840 ms (largest single step, AV-sensitive) 3i. pnputil /add-driver, both INFs ~580 ms total 3j. Delete %TEMP% extraction <50 ms 3k. Write marker file <1 ms 4. ctx.CreateController(profile); ~200-700 ms SetupController for one Xbox 360 Wired ───────────────────────────────────────────── ──── Total: ~2.5-3 s on a clean dev machine ~5-20 s on a corporate workstation (PnP tree depth scales pnputil) ``` -------------------------------- ### Run SDK consumer and test application Source: https://hidmaestro.org/docs/start/installation Commands to run the SDK consumer example and the full test application for emulation. ```batch :: Smallest possible SDK consumer (5 seconds) dotnet run --project example\SdkDemo :: Full test app (admin required for create; cleans up on exit) dotnet build test test\bin\Release\net10.0-windows10.0.26100.0\win-x64\HIDMaestroTest.exe emulate xbox-360-wired ``` -------------------------------- ### Populating HMGamepadState Axes Source: https://hidmaestro.org/docs/sdk/sdk-reference Example of populating the Axes dictionary for a HOTAS setup. Values are normalized to [0.0, 1.0]. ```csharp // HOTAS with stick + slider + rudder + throttle, all in one dict state.Axes = new Dictionary { [HMAxis.X] = 0.55f, // stick X, slightly right of center [HMAxis.Y] = 0.35f, // stick Y, slightly below center [HMAxis.Slider] = 0.75f, // throttle slider [HMAxis.Rudder] = 0.25f, // rudder pedal [HMAxis.Throttle] = 1.00f, // secondary throttle full }; ``` -------------------------------- ### CreateController(HMProfile profile) Source: https://hidmaestro.org/docs/sdk/sdk-reference Creates a new HMController with the next free index, runs the full setup orchestration, and returns a live controller. Requires admin. ```APIDOC ## CreateController(HMProfile profile) ### Description Allocates the next free controller index, runs the per-archetype setup orchestration, and returns a live HMController ready to receive input. Requires admin. ### Method CreateController ### Parameters - **profile** (HMProfile) - Required - The profile to use for the controller. Must not be null and must have a descriptor. ### Return Value - **HMController** - A live controller instance. ### Exceptions - **ArgumentNullException** - If `profile` is null. - **ArgumentException** - If the profile has no descriptor (not deployable). - **InvalidOperationException** - If device-node creation fails or the driver install fails. ### Remarks The returned controller is live. Dispose it to remove the device, or dispose the entire context to remove all controllers it owns. ``` -------------------------------- ### HID Maestro Suffix Mapping Example Source: https://hidmaestro.org/docs/reference/swdevice-and-pnp An example showing the naming convention for HID Maestro virtual devices, including controller index, device type, and sequence numbers. ```text SWD\HIDMAESTRO\A7B40001_0000 ← controller 0 (Xbox 360 Wired companion), seq=1 SWD\HIDMAESTRO\A7B40002_0001 ← controller 1 (Xbox Series BT main HID), seq=2 SWD\HIDMAESTRO_VID_045E_PID_0B13&IG_00\A7B40002_0001 ← (xinputhid path uses different enumerator) SWD\HIDMAESTRO\A7B40003_0002 ← controller 2 (DualSense), if it had a companion (it doesn't) ... ``` -------------------------------- ### FullDeploy steps Source: https://hidmaestro.org/docs/reference/driver-install-and-signing Numbered list of steps performed by FullDeploy. Idempotent: if payload hash matches installed, returns immediately. Requires admin; otherwise UnauthorizedAccessException. ```text 1. Compute payload hash (SHA-256 of every embedded resource) 2. IsDriverInstalled? → check DriverStore for matching hash → if yes, return 3. EnsureExtracted: extract embedded resources to %TEMP%\HIDMaestro\\ 4. Generate self-signed certificate if not in Cert:\LocalMachine\Root 5. Install certificate to Cert:\LocalMachine\Root and \TrustedPublisher 6. Generate .cat catalogs via Inf2Cat for both INFs 7. Sign HIDMaestro.dll, HMXInput.dll, hmswd.exe, both .cat files 8. pnputil /add-driver hidmaestro.inf /install 9. pnputil /add-driver hidmaestro_xusb.inf /install 10. Delete %TEMP%\HIDMaestro\\ (leave nothing behind) ``` -------------------------------- ### Install drivers with pnputil /add-driver Source: https://hidmaestro.org/docs/reference/driver-install-and-signing Adds and installs HIDMaestro INF drivers to the DriverStore. The /install flag makes the driver boot-critical and loadable; without it the driver is only staged. Requires admin and returns exit code 0 on success, non-zero on failure. A partial match with an existing package can trigger integrity verification errors that the self-heal sweep prevents. ```batch pnputil /add-driver hidmaestro.inf /install pnputil /add-driver hidmaestro_xusb.inf /install ``` -------------------------------- ### HMContext.InstallDriver Source: https://hidmaestro.org/docs/sdk/sdk-reference Installs the embedded driver files, generating and installing a self-signed code-signing certificate, signing the binaries, and registering them with pnputil. Requires admin. ```APIDOC ## HMContext.InstallDriver ### Description Extracts the embedded driver files to %TEMP%, generates/installs a self-signed code-signing certificate, signs the binaries, and registers them with pnputil. Idempotent — if the same hash is already installed, returns immediately. The temp extraction is deleted on success. Requires admin. ### Method Method ### Endpoint `public void InstallDriver()` ### Parameters None. ### Throws - **UnauthorizedAccessException** - If the process is not elevated. - **InvalidOperationException** - If any signing or pnputil step fails. ### Remarks - Always runs `RemoveAllVirtualControllers` first as a self-heal so a stale INF can't pin the install. ``` -------------------------------- ### Create a custom HOTAS device profile Source: https://hidmaestro.org/docs/sdk/hid-descriptor-builder This example demonstrates how to use HidDescriptorBuilder to define device capabilities and HMProfileBuilder to create a profile, followed by initializing the controller and handling FFB output. ```csharp var desc = new HidDescriptorBuilder() .Joystick() // Joystick TLC for FFB compatibility .AddStick("Left", 16) // primary X/Y .AddTrigger("Left", 8) // throttle .AddTrigger("Right", 8) // brake .AddButtons(20) // 20 buttons (rounded up to 24) .AddHat(positions: 16) // 22.5° hat .AddPidFfbBlock(); // full PID FFB var profile = new HMProfileBuilder() .Id("custom-hotas-stick") .Name("Custom HOTAS Stick") .Vendor("MyCo") .Vid(0x0483).Pid(0x5740) .ProductString("Custom HOTAS") .Type("hotas") .Connection("usb") .FromDescriptorBuilder(desc) // descriptor bytes + correct InputReportSize .Build(); using var ctx = new HMContext(); ctx.LoadDefaultProfiles(); ctx.InstallDriver(); using var ctrl = ctx.CreateController(profile); // FFB now works: declare pool, drive any DirectInput game with this virtual ctrl.PublishPidPool(ramPoolSize: 0x0400, simultaneousEffectsMax: 16, deviceManagedPool: false, sharedParameterBlocks: false); // Wire output to your physical HOTAS ctrl.OutputReceived += (sender, packet) => RouteFFBToHardware(packet); // 16-position hat at full descriptor resolution ctrl.SubmitState(new HMGamepadState { HatDegrees = 22.5f }); ``` -------------------------------- ### HMVR.SteamVRPath Source: https://hidmaestro.org/docs/sdk/vr-controllers Gets the file system path to the SteamVR installation. ```APIDOC ## HMVR.SteamVRPath ### Description Gets the file system path to the SteamVR installation. ### Property `public static string? SteamVRPath { get; }` ### Returns - **string?** - The path to the SteamVR installation, or `null` if not available. ``` -------------------------------- ### Install the HIDMaestro driver Source: https://hidmaestro.org/docs/start/quickstart Installs the driver idempotently. Requires elevated privileges and throws UnauthorizedAccessException if not elevated, or InvalidOperationException if signing or pnputil steps fail. ```csharp ctx.InstallDriver(); ``` -------------------------------- ### Example usage of DisposeControllersInParallel Source: https://hidmaestro.org/docs/reference/lifecycle-and-teardown Example call to DisposeControllersInParallel with four controllers and a callback that logs each controller's profile ID and disposal time in milliseconds. ```csharp ctx.DisposeControllersInParallel( new[] { ctrl0, ctrl1, ctrl2, ctrl3 }, perControllerCallback: (c, ms) => Logger.Info($" {c.Profile.Id}: {ms} ms")); ``` -------------------------------- ### Controller Profile JSON Schema Source: https://hidmaestro.org/docs/profiles/profile-system Example of a complete controller profile configuration file. ```json { "id": "xbox-360-wired", "name": "Xbox 360 Controller (Wired)", "vendor": "Microsoft", "vid": "0x045E", "pid": "0x028E", "productString": "Controller (XBOX 360 For Windows)", "manufacturerString": "©Microsoft Corporation", "type": "gamepad", "connection": "usb", "descriptor": "05010905a101a10009300931150026ffff350046ffff950275108102c0...", "nativeDescriptor": "05010905a101...", "inputReportSize": 18, "deviceDescription": "Controller (XBOX 360 For Windows)", "triggerMode": "combined", "driverMode": null, "buttonMap": null, "axisMap": null, "triggerButtons": null, "notes": null } ``` -------------------------------- ### Driver Lifecycle Methods Source: https://hidmaestro.org/docs/sdk/sdk-reference Methods for checking driver status, installing the driver (requires admin), and removing all virtual controllers from the system. ```csharp public bool IsDriverInstalled { get; } public void InstallDriver(); public static void RemoveAllVirtualControllers(); ``` -------------------------------- ### Force-kill recovery self-heal example Source: https://hidmaestro.org/docs/reference/lifecycle-and-teardown Shows the self-heal sequence when a new process starts after a crash. The HMContext constructor does not sweep, but InstallDriver triggers RemoveAllVirtualControllers to clean up orphaned controllers from the previous process. ```csharp // Process A creates 3 controllers, then crashes // Process B starts: using var ctx = new HMContext(); // constructor doesn't sweep yet ctx.InstallDriver(); // ← RemoveAllVirtualControllers runs here, sweeps process A's orphans ctrl0 = ctx.CreateController(...); // fresh state ``` -------------------------------- ### InstallDriver method Source: https://hidmaestro.org/docs/reference/driver-install-and-signing Public method that orchestrates driver installation. Calls RemoveAllVirtualControllers for self-healing, then FullDeploy. Throws InvalidOperationException on failure, advising to run elevated and check pnputil output. ```csharp public void InstallDriver() { Internal.DeviceOrchestrator.RemoveAllVirtualControllers(); // self-heal sweep if (!DriverBuilder.FullDeploy()) throw new InvalidOperationException( "Driver install failed. Run elevated and check pnputil output."); } ``` -------------------------------- ### XInput slot-1-skip output example Source: https://hidmaestro.org/docs/reference/swdevice-and-pnp Shows the observed output when the slot-1-skip bug occurs: slot 0 is empty while slots 1-3 are assigned. This is the reported behavior from consumers. ```text Slot 0: NOT CONNECTED Slot 1: HM-CTL-0001 (Xbox 360 Wired) Slot 2: NOT CONNECTED Slot 3: NOT CONNECTED ``` -------------------------------- ### Install SteamVR without Steam client using steamcmd Source: https://hidmaestro.org/docs/sdk/vr-controllers Commands to install SteamVR on a machine without the Steam client, using Valve's command-line tool with no account needed. The first command downloads steamcmd.zip, the second installs SteamVR (app ID 250820) to C:\SteamVR anonymously. ```bash curl -L -o steamcmd.zip https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip steamcmd +force_install_dir "C:\SteamVR" +login anonymous +app_update 250820 validate +quit ``` -------------------------------- ### HMVR.SetSteamVRPathHint Source: https://hidmaestro.org/docs/sdk/vr-controllers Sets a hint for the SteamVR installation directory. Requires administrator privileges. ```APIDOC ## HMVR.SetSteamVRPathHint ### Description Sets a hint for the SteamVR installation directory. Requires administrator privileges. ### Method `public static void SetSteamVRPathHint(string steamVrDir)` ### Parameters - **steamVrDir** (string) - Required - The directory containing the SteamVR installation. ``` -------------------------------- ### Run verify.py with specific filters Source: https://hidmaestro.org/docs/reference/testing-and-verification Commands to run verify.py with --filter to test only a specific API check. Examples: --filter directinput for the 5 axes/10 button check on Xbox 360 Wired, --filter browser for browser-only, and --controllers 6 --filter order for multi-controller ordering. ```batch :: Just the 5 axes / 10 button check on Xbox 360 Wired HIDMaestroTest.exe emulate xbox-360-wired python scripts\verify.py --filter directinput :: Browser-only check python scripts\verify.py --filter browser :: Multi-controller ordering python scripts\verify.py --controllers 6 --filter order ``` -------------------------------- ### HIDMaestro repository file and source layout Source: https://hidmaestro.org/docs/reference/architecture-overview Shows the complete repository layout for the HIDMaestro project, including the native UMDF2 driver sources, the C# SDK (HIDMaestro.Core), tools, examples, tests, profiles, scripts, build outputs, and documentation. Use this to understand where each component lives and what each file is responsible for. ```text HIDMaestro/ ├── driver/ ; native UMDF2 sources │ ├── driver.c ; main HID driver (1,574 lines) │ ├── driver.h ; device context, IOCTL constants, shared-section types │ ├── companion.c ; XUSB companion (745 lines) │ ├── hidmaestro.inf ; main HID INF │ ├── hidmaestro_xusb.inf ; XUSB companion INF │ └── hmswd/hmswd.c ; SwDevice helper (286 lines) │ ├── sdk/HIDMaestro.Core/ ; the C# SDK │ ├── HMContext.cs ; entry point, profile catalog, controller alloc │ ├── HMController.cs ; live virtual, SubmitState, OutputReceived, PID FFB │ ├── HMProfile.cs ; immutable profile handle │ ├── HMProfileBuilder.cs ; fluent profile builder │ ├── HMGamepadState.cs ; abstract input frame │ ├── HidDescriptorBuilder.cs ; fluent HID descriptor builder │ ├── HMDeviceExtractor.cs ; extract from physical HID │ ├── HMOemNameOverride.cs ; joy.cpl label override │ ├── HMOutputPacket.cs ; output packet types │ ├── HMPidState.cs ; PID FFB enums + structs │ ├── HMHidDeviceInfo.cs ; HID device info from extractor │ ├── Internal/ │ │ ├── DeviceOrchestrator.cs ; SetupController / TeardownController (2,363 lines) │ │ ├── DeviceManager.cs ; PnP device tree management (1,024 lines) │ │ ├── SwdDeviceFactory.cs ; hmswd.exe wrapping (397 lines) │ │ ├── DriverBuilder.cs ; embedded payload extract + sign (509 lines) │ │ ├── HidReportBuilder.cs ; HID descriptor parse + report encode (600 lines) │ │ ├── HidDescriptorReconstructor.cs ; preparsed → descriptor (1,002 lines) │ │ ├── SharedMemoryIO.cs ; shared section wire format (669 lines) │ │ ├── OemNameOverrideStore.cs ; crash-safe OEM name registry writes (325 lines) │ │ ├── PnputilHelper.cs ; pnputil + devcon shell-out helpers (275 lines) │ │ ├── ControllerProfile.cs ; internal profile model (321 lines) │ │ ├── HidDeviceEnumerator.cs ; SetupDi enumerate connected HIDs (233 lines) │ │ ├── HidPreparsedData.cs ; HidD_GetPreparsedData wrapper (150 lines) │ │ ├── DeviceProperties.cs ; DEVPKEY_* read/write (292 lines) │ │ ├── DeviceNodeCreator.cs ; SetupDiCreateDeviceInfoW path (335 lines) │ │ ├── EmbeddedManifest.cs ; SHA-256 of embedded payload │ │ └── TimeoutScale.cs ; HIDMAESTRO_TIMEOUT_SCALE env var │ └── Resources/ ; embedded driver payload │ ├── HIDMaestro.dll ; main driver │ ├── HMXInput.dll ; companion driver │ ├── hmswd.exe ; SwDevice helper │ ├── hidmaestro.inf ; main INF (stamped at build time) │ ├── hidmaestro_xusb.inf ; companion INF (stamped at build time) │ ├── signtool.exe ; signing │ ├── Inf2Cat.exe ; catalog generation │ └── Microsoft.UniversalStore.HardwareWorkflow.*.dll ; Inf2Cat dependencies │ ├── tools/HIDMaestroProfileExtractor/ ; standalone WPF extractor GUI ├── example/SdkDemo/ ; minimal SDK consumer ├── test/ ; HIDMaestroTest CLI + regression battery + probes ├── profiles/ ; 228 profile JSONs ├── scripts/ ; build, signing, verification, multi-pad-check ├── build/ ; build outputs (driver DLLs, hmswd.exe, stamped INFs) └── docs/ ; README screenshots, investigation notes ``` -------------------------------- ### Verify Virtual Controller Installation Source: https://hidmaestro.org/docs/start/quickstart Commands to validate controller existence across APIs, check PnP device status, and open the Windows game controller GUI. ```powershell :: Cross-API validation: DInput axes, XInput slots, HIDAPI bus, browser, WGI python scripts\verify.py --controllers 2 :: Pretty PnP tree powershell -c "Get-PnpDevice -Status OK | Where-Object FriendlyName -like '*Game*'" :: GUI verification joy.cpl ``` -------------------------------- ### Example output from verify.py showing per-API status Source: https://hidmaestro.org/docs/reference/testing-and-verification Sample output from scripts/verify.py when all checks pass. Shows per-API status lines for XInput, DirectInput, HIDAPI, Browser, WGI, and Order, followed by PASS. The Browser order check is reported as SKIP due to Chromium's alphabetical ordering quirk. ```text [XInput] 4 slots active. LT/RT separate. Slots 0..3. OK [DirectInput] 4 axes-and-buttons enumerations. Identities match. OK [HIDAPI] 6 HID interfaces, 4 with &IG_, 2 with bus_type=BT. OK [Browser] 4 STANDARD_GAMEPAD, separate triggers, no dupes. OK [WGI] 4 RawGameController. 4 Gamepad. Single-entry each. OK [Order] Creation order matches across XInput/DI/HIDAPI/WGI. OK [Order] Browser order is alphabetical (Chromium quirk). SKIP PASS ``` -------------------------------- ### Generate driver catalog with Inf2Cat Source: https://hidmaestro.org/docs/reference/driver-install-and-signing Runs Inf2Cat to hash all files referenced by the INF and produce a .cat catalog. The /os flag specifies target OS versions. This is the largest install cost at ~840 ms total for both catalogs. ```plaintext Inf2Cat.exe /driver:%TEMP%\HIDMaestro\ /os:10_X64,Server10_X64 /uselocaltime ``` -------------------------------- ### Submit gamepad input states Source: https://hidmaestro.org/docs/start/quickstart This example demonstrates submitting gamepad states for two controllers within a loop, using standard axis helpers and button flags. The loop runs for 5 seconds at approximately 125 Hz. ```csharp var sw = System.Diagnostics.Stopwatch.StartNew(); while (sw.Elapsed < TimeSpan.FromSeconds(5)) { float t = (float)(sw.Elapsed.TotalSeconds % 2.0 / 2.0); float angle = t * 2 * MathF.PI; ctrl0.SubmitState(new HMGamepadState { Axes = HMGamepadStateHelpers.StandardAxes(ctrl0.Profile, leftStickX: (MathF.Cos(angle) + 1) / 2, // [0..1] uniform; 0.5 = center leftStickY: (MathF.Sin(angle) + 1) / 2), Buttons = HMButton.Cross, // Sony alias for HMButton.A Hat = HMHat.North, }); ctrl1.SubmitState(new HMGamepadState { Axes = HMGamepadStateHelpers.StandardAxes(ctrl1.Profile, leftTrigger: t, rightTrigger: 1 - t), Buttons = HMButton.A | HMButton.Start, }); Thread.Sleep(8); // 125 Hz; consumers typically run at the rate of their input source } ``` -------------------------------- ### Structure of Global\HIDMaestroInput3 View Source: https://hidmaestro.org/docs/reference/shared-memory-protocol Example memory layout for a DualSense controller input frame at index 3, showing sequence numbers, data size, and the report layout. ```text Global\HIDMaestroInput3 view (after SDK write): Offset Bytes Field ─────── ─────────────────────────────── ────────────────────── 0 42 00 00 00 SeqNo = 0x42 (66 — even, stable) 4 40 00 00 00 DataSize = 64 bytes 8 01 ff bf 00 80 00 80 ... Data[0..63] (DualSense report 0x01 layout): [0] = Report ID (1) [1] = LX = 0xBF (192, ≈75%) [2] = LY = 0x80 (centered) [3] = RX = 0x80 [4] = RY = 0x80 [5] = LT = 0x00 [6] = RT = 0xB3 (≈70%) [9] = buttons low byte = 0x11 (A + LB) [10..] = remaining DualSense state 264 00 ... Data[64..255] (zero-padded) 264 00 80 00 80 00 80 00 80 ... GipData[0..13] (zeroed for non-Xbox-VID) ``` -------------------------------- ### ActiveControllers Source: https://hidmaestro.org/docs/sdk/sdk-reference Gets a snapshot of all live controllers owned by this context, in creation order. ```APIDOC ## ActiveControllers ### Description Returns a snapshot of every live controller this context owns, in creation order. ### Property Type - **IReadOnlyCollection** - A read-only collection of live controllers. ``` -------------------------------- ### Xbox 360 Wired Profile JSON Source: https://hidmaestro.org/docs/profiles/profile-system A verbatim example of a profile definition file for an Xbox 360 Wired controller. ```json { "id": "xbox-360-wired", "name": "Xbox 360 Controller (Wired)", "vendor": "Microsoft", "vid": "0x045E", "pid": "0x028E", "productString": "Controller (XBOX 360 For Windows)", "manufacturerString": "©Microsoft Corporation", "type": "gamepad", "connection": "usb", "descriptor": "05010905a101a10009300931150026ffff350046ffff950275108102c0a10009330934150026ffff350046ffff950275108102c0a1000932150026ffff350046ffff950175108102c0a10009400941150026ffff350046ffff950275108102c005091901290a950a7501810205010939150125083500463b10660e00750495018142750295018103750895028103c0", "nativeDescriptor": "05010905A1018501093009311500270000000075109502810209330934810209320935810205091901290A150025017501950281027506950181010501093915012508350046C03C660E007504950181428503060046ED01950E091001110050B5", "inputReportSize": 18, "deviceDescription": "Controller (XBOX 360 For Windows)", "triggerMode": "combined" } ``` -------------------------------- ### HIDMaestro INF Configuration Sections Source: https://hidmaestro.org/docs/reference/umdf2-driver-internals Key INF sections for HIDMaestro installation, including hardware filters, service registration, and WDF settings. Note that UmdfHostProcessSharing is set to ProcessSharingDisabled to ensure each device instance runs in its own WUDFHost process. ```ini [HIDMaestro_Install.NT.HW] HKR,,"LowerFilters",0x00010008,"WUDFRd" HKR,,Security,, "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;WD)" [HIDMaestro_Install.NT.Services] AddService = mshidumdf,0x000001fa,mshidumdf_Service AddService = WUDFRd,0x000001f8,WUDFRD_Service [HIDMaestro_Install.NT.Wdf] UmdfService = HIDMaestro, HIDMaestro_UmdfService UmdfKernelModeClientPolicy = AllowKernelModeClients UmdfFileObjectPolicy = AllowNullAndUnknownFileObjects UmdfMethodNeitherAction = Copy UmdfFsContextUsePolicy = CanUseFsContext2 UmdfHostProcessSharing = ProcessSharingDisabled ← critical ``` -------------------------------- ### Failure output showing leftover instance ID Source: https://hidmaestro.org/docs/reference/testing-and-verification Example output printed by the test script when a scenario fails, showing the leftover instance ID in the format SWD\HIDMAESTRO_VID_045E_PID_0B13&IG_00\_0001. Use this to grep the teardown diagnostic log for deeper inspection. ```text [FAIL] S08_Multi_SwapOneSlot 47832ms Leftover: SWD\HIDMAESTRO_VID_045E_PID_0B13&IG_00\_0001 ``` -------------------------------- ### HMVR.IsSteamVRInstalled Source: https://hidmaestro.org/docs/sdk/vr-controllers Gets a value indicating whether SteamVR is installed. ```APIDOC ## HMVR.IsSteamVRInstalled ### Description Gets a value indicating whether SteamVR is installed. ### Property `public static bool IsSteamVRInstalled { get; }` ### Returns - **bool** - `true` if SteamVR is installed; otherwise, `false`. ``` -------------------------------- ### Run the SDK Demo Source: https://hidmaestro.org/docs/start/quickstart Execute the minimal SDK consumer to verify virtual controller creation and rumble capture. ```bash dotnet run --project example\SdkDemo ``` -------------------------------- ### Unpack GIP buffer to XINPUT_GAMEPAD Source: https://hidmaestro.org/docs/reference/xusb-companion Reads the 14-byte GIP buffer and maps button states, hat switch positions, and stick axes to the XINPUT_GAMEPAD structure. This implementation includes the v1.3.3 fix for Xbox 360 d-pad support and maps the Guide button to the undocumented 0x0400 bit. ```cpp USHORT buttons = 0; // btnLow byte → wButtons low nibble UCHAR btnLow = gipBuf[12]; if (btnLow & 0x01) buttons |= XINPUT_GAMEPAD_A; if (btnLow & 0x02) buttons |= XINPUT_GAMEPAD_B; if (btnLow & 0x04) buttons |= XINPUT_GAMEPAD_X; if (btnLow & 0x08) buttons |= XINPUT_GAMEPAD_Y; if (btnLow & 0x10) buttons |= XINPUT_GAMEPAD_LEFT_SHOULDER; if (btnLow & 0x20) buttons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; if (btnLow & 0x40) buttons |= XINPUT_GAMEPAD_LEFT_THUMB; if (btnLow & 0x80) buttons |= XINPUT_GAMEPAD_RIGHT_THUMB; // btnHigh byte → Back, Start, hat (bits 2-5), Guide (bit 6) UCHAR btnHigh = gipBuf[13]; if (btnHigh & 0x01) buttons |= XINPUT_GAMEPAD_BACK; if (btnHigh & 0x02) buttons |= XINPUT_GAMEPAD_START; UCHAR hatNybble = (btnHigh >> 2) & 0x0F; switch (hatNybble) { case 1: buttons |= XINPUT_GAMEPAD_DPAD_UP; break; // North case 2: buttons |= XINPUT_GAMEPAD_DPAD_UP | XINPUT_GAMEPAD_DPAD_RIGHT; break; case 3: buttons |= XINPUT_GAMEPAD_DPAD_RIGHT; break; // ... 8-way hat translation } if (btnHigh & 0x40) buttons |= 0x0400; // XINPUT_GAMEPAD_GUIDE (undocumented) // Sticks: 16-bit unsigned [0..65535] → signed [-32768..32767] SHORT lx = (SHORT)(gipBuf[0] | (gipBuf[1] << 8)) - 0x8000; // ... LX/LY/RX/RY same shape ``` -------------------------------- ### Non-sentinel pContainerId for SwDeviceCreate Source: https://hidmaestro.org/docs/reference/swdevice-and-pnp The GUID format passed as pContainerId to SwDeviceCreate to fix the bug. The base GUID decodes to ASCII 'HIDMAESTRO' plus a 16-bit big-endian controller index appended, so each controller gets a unique non-sentinel ID. ```text {48494430-4D41-4553-5452-4F0000000000} // base ^^^^ ← 16-bit controller index appended ``` -------------------------------- ### Build phases overview Source: https://hidmaestro.org/docs/reference/build-and-release A breakdown of the four phases executed by build_all.cmd, including native compilation, INF stamping, and SDK resource packaging. ```text Phase 1: Native driver scripts\build.cmd → cl.exe driver.c, companion.c, hmswd.c → link.exe → build\HIDMaestro.dll, build\HMXInput.dll, build\hmswd.exe → scripts\stamp_inf.ps1 hidmaestro.inf → build\hidmaestro.inf → scripts\stamp_inf.ps1 hidmaestro_xusb.inf → build\hidmaestro_xusb.inf Phase 2: Native companion (separate build script for parallelism) scripts\build_companion.cmd → cl.exe companion.c → build\HMXInput.dll (Note: build.cmd builds the main + hmswd; build_companion.cmd builds only HMXInput) Phase 3: SDK build #1 — populates Resources/ from build/ dotnet build sdk\HIDMaestro.Core\HIDMaestro.Core.csproj → PackResources MSBuild target copies build/* into sdk/HIDMaestro.Core/Resources/ → embedded resource glob picks them up → output: sdk\HIDMaestro.Core\bin\Release\net10.0-windows10.0.26100.0\HIDMaestro.Core.dll Phase 4: SDK build #2 — embeds fresh driver bytes dotnet build sdk\HIDMaestro.Core\HIDMaestro.Core.csproj → PackResources rebuilds Resources/ (idempotent) → embedded resource glob has fresh content → output: HIDMaestro.Core.dll with current driver bytes embedded ``` -------------------------------- ### Configure Target Framework and Platform Source: https://hidmaestro.org/docs/start/installation Set the target framework and platform in your csproj file. Note that only x64 is supported. ```xml net10.0-windows10.0.26100.0 x64 ``` -------------------------------- ### Run one-shot build Source: https://hidmaestro.org/docs/reference/build-and-release Execute the build_all.cmd script from the HIDMaestro directory to trigger the full build process. ```batch cd HIDMaestro scripts\build_all.cmd ``` -------------------------------- ### Loading and Enumerating Profiles Source: https://hidmaestro.org/docs/profiles/profile-system Demonstrates how to load default or custom profiles into the context and how to enumerate the loaded catalog. ```csharp // Embedded catalog (228 profiles) ctx.LoadDefaultProfiles(); // Custom directory of JSON profiles ctx.LoadProfilesFromDirectory(@"C:\my-profiles"); // Mix both — embedded first, then custom (custom IDs win on collision) ctx.LoadDefaultProfiles(); ctx.LoadProfilesFromDirectory(@"C:\my-overrides"); // Lookup HMProfile? p = ctx.GetProfile("xbox-360-wired"); // Enumerate foreach (var profile in ctx.AllProfiles) Console.WriteLine($"{profile.Id} — {profile.Name}"); ``` -------------------------------- ### Initialize Shared Memory Sections in SetupController Source: https://hidmaestro.org/docs/reference/shared-memory-protocol The SDK consumer initializes input and output mappings in the SetupController before binding the driver. The PID state section is created lazily upon the first call to PublishPidPool. ```csharp // In DeviceOrchestrator.SetupController SharedMemoryIO.EnsureInputMapping(controllerIndex); // creates Global\HIDMaestroInput + Event SharedMemoryIO.EnsureOutputMapping(controllerIndex); // creates Global\HIDMaestroOutput // PID state section is lazy — only created on first HMController.PublishPidPool call ``` -------------------------------- ### CRC32 scope JSON example Source: https://hidmaestro.org/docs/profiles/profile-system Example JSON for the CRC32 scope field, specifying the prefix bytes and the byte range covered by the CRC. Used in extendedReport fields of type crc32-le. ```json "scope": { "prefix": [161, 49], // two bytes for Sony BT input: [0xA1, 0x31] "from": 1, // first byte covered (after report ID) "to": 73 // last byte covered (before CRC field) } ``` -------------------------------- ### HMVRController.GetHmdPose Source: https://hidmaestro.org/docs/sdk/vr-controllers Gets the real headset pose, useful for head-as-input. ```APIDOC ## HMVRController.GetHmdPose ### Description Gets the real headset pose, useful for head-as-input. ### Method `public HMVRHmdPose GetHmdPose()` ### Returns - **HMVRHmdPose** - The current headset pose. ``` -------------------------------- ### Gamepad() Source: https://hidmaestro.org/docs/sdk/hid-descriptor-builder Opens an Application Collection with Usage Page Generic Desktop and Usage Game Pad (0x05). Use for XInput/WGI rumble paths that don't go through DirectInput PID FFB. ```APIDOC ## Gamepad() ### Description Opens an Application Collection with Usage Page Generic Desktop and Usage Game Pad (0x05). This TLC is suitable for XInput/WGI rumble paths that don't use DirectInput PID FFB. ### Method Gamepad() ### Usage ```csharp var desc = new HidDescriptorBuilder() .Gamepad() .AddStick("Left", 16).AddStick("Right", 16) .AddTrigger("Left", 8).AddTrigger("Right", 8) .AddButtons(10).AddHat(); ``` ### Notes - Opens an Application Collection (`A1 01`). - DirectInput/WGI classification: surfaces as a Gamepad with 5-axis Xbox 360 convention. - Browser Gamepad's `STANDARD_GAMEPAD` mapping resolves only for Gamepad TLC devices that match its expected layout. - `AddPidFfbBlock` rejects Gamepad TLC because DirectInput's `pid.dll` AVs inside `PID_EffectOperation+0x52` when `CreateEffect` is called against a Gamepad TLC. Always use `Joystick()` for FFB-capable virtuals. - `Build()` auto-closes the Application Collection if you forgot to. ``` -------------------------------- ### HMVRController.ControllersLive Source: https://hidmaestro.org/docs/sdk/vr-controllers Gets a value indicating whether both hands are registered. ```APIDOC ## HMVRController.ControllersLive ### Description Gets a value indicating whether both hands are registered. ### Property `public bool ControllersLive { get; }` ### Returns - **bool** - `true` if both hands are registered; otherwise, `false`. ``` -------------------------------- ### Create virtual controllers Source: https://hidmaestro.org/docs/start/quickstart Allocates controller indices and initializes devices. Using the 'using' statement is required to ensure proper disposal and release of kernel slots. ```csharp var ds = ctx.GetProfile("dualsense") ?? throw new InvalidOperationException(); var x360 = ctx.GetProfile("xbox-360-wired") ?? throw new InvalidOperationException(); using var ctrl0 = ctx.CreateController(ds); using var ctrl1 = ctx.CreateController(x360); ``` -------------------------------- ### Accessing and configuring USB audio Source: https://hidmaestro.org/docs/sdk/usb-audio-composite Demonstrates how to access the UsbAudio controller, handle output frames, manage streaming state, submit microphone data, and listen for control changes. ```csharp var audio = controller.UsbAudio!; // Host → consumer: the game's speaker + haptic PCM, paced at the wire rate. audio.Output.FramesReceived += (output, pcm) => { // Interleaved 16-bit little-endian PCM. output.ChannelRoles maps the // channels: ["speakerLeft", "speakerRight", "hapticLeft", "hapticRight"]. // The memory is only valid during the callback; copy to retain. }; audio.Output.StreamingChanged += (_, open) => { /* audio session opened/parked */ }; // Consumer → host: feed the microphone. Silence when the buffer runs dry. int accepted = audio.Microphone.Submit(pcmBytes); // interleaved 16-bit LE at the declared format if (accepted < pcmBytes.Length) { /* buffer full: the rest was dropped */ } // Volume/mute writes from Windows (volume mixer, control panel): audio.ControlChanged += (_, e) => Console.WriteLine($"{e.Function}: {(e.IsMute ? $"mute={e.MuteValue}" : $"{e.VolumeDb:F1} dB")}"); ``` -------------------------------- ### HMVR.IsSteamVRRunning Source: https://hidmaestro.org/docs/sdk/vr-controllers Gets a value indicating whether SteamVR is currently running. ```APIDOC ## HMVR.IsSteamVRRunning ### Description Gets a value indicating whether SteamVR is currently running. ### Property `public static bool IsSteamVRRunning { get; }` ### Returns - **bool** - `true` if SteamVR is running; otherwise, `false`. ``` -------------------------------- ### Verify SWD migration build Source: https://hidmaestro.org/docs/troubleshooting Run the test executable to confirm the driver mode and SWD-enumerated companion path. ```batch HIDMaestroTest.exe info xbox-360-wired :: should show "driverMode: null" and the SWD-enumerated companion path ``` -------------------------------- ### HMVRController.DriverConnected Source: https://hidmaestro.org/docs/sdk/vr-controllers Gets a value indicating whether the driver is attached inside vrserver. ```APIDOC ## HMVRController.DriverConnected ### Description Gets a value indicating whether the driver is attached inside vrserver. ### Property `public bool DriverConnected { get; }` ### Returns - **bool** - `true` if the driver is connected; otherwise, `false`. ``` -------------------------------- ### Initialize HMContext and Load Profiles Source: https://hidmaestro.org/docs/start/quickstart Create the process-wide entry point and load embedded profiles. HMContext performs background prewarm tasks upon instantiation. ```csharp using var ctx = new HMContext(); int loaded = ctx.LoadDefaultProfiles(); // returns 228 ``` -------------------------------- ### Build output directory structure Source: https://hidmaestro.org/docs/reference/build-and-release Lists the files generated in the build directory after running build_all.cmd. ```text build/ HIDMaestro.dll ← main HID driver HIDMaestroCompanion.dll ← (legacy alias for HMXInput.dll, kept for compat) HMXInput.dll ← XUSB companion hmswd.exe ← SwDevice helper hidmaestro.inf ← stamped main INF hidmaestro_xusb.inf ← stamped companion INF driver.obj / companion.obj / hmswd.obj ← intermediate objects *.exp / *.lib ← linker exports sdk/HIDMaestro.Core/Resources/ (mirrored copy of build/, plus WDK tooling) sdk/HIDMaestro.Core/bin/Release/net10.0-windows10.0.26100.0/ HIDMaestro.Core.dll ← THE SDK ASSEMBLY (embeds everything above) test/bin/Release/net10.0-windows10.0.26100.0/win-x64/ HIDMaestroTest.exe ← test app example/SdkDemo/bin/Release/net10.0-windows10.0.26100.0/ SdkDemo.dll / .exe ← minimal SDK consumer tools/HIDMaestroProfileExtractor/bin/Release/net10.0-windows10.0.26100.0/win-x64/publish/ HIDMaestroProfileExtractor.exe ← single-file WPF extractor ``` -------------------------------- ### extendedReport JSON example for Sony BT DualSense Source: https://hidmaestro.org/docs/profiles/profile-system Example profile JSON defining an extendedReport for a Sony BT DualSense input report (report ID 0x31, 78 bytes). Shows field definitions for sticks, triggers, hat, buttons, and CRC32. The SDK walks this field list as a generic codec. ```json "extendedReport": { "reportId": "0x31", // hex string; emitted as the report ID byte "size": 78, // total bytes including report ID at byte 0 "fields": [ { "byte": 1, "type": "uint8-rolling", "semantic": "btSeqTag", "initial": 0 }, { "byte": 2, "type": "uint8-axis", "semantic": "leftStickX", "center": 128 }, { "byte": 3, "type": "uint8-axis", "semantic": "leftStickY", "center": 128 }, { "byte": 6, "type": "uint8-trigger", "semantic": "leftTrigger" }, { "byte": 9, "bits": "0-3", "type": "hat-octant", "semantic": "hat", "neutralValue": 8 }, { "byte": 9, "bits": "4-7", "type": "button-mask", "buttons": ["X","A","B","Y"] }, { "byte": 10, "type": "button-mask", "buttons": ["LeftBumper","RightBumper","_","_","Back","Start","LeftStick","RightStick"] }, { "bytes": "74-77", "type": "crc32-le", "scope": { "prefix": [161, 49], "from": 1, "to": 73 } } ] } ``` -------------------------------- ### Initialize PID FFB with PublishPidPool Source: https://hidmaestro.org/docs/troubleshooting Enable FFB by calling PublishPidPool and verify the status by reading the current PID block load. ```csharp // Required for FFB to enable ctrl.PublishPidPool(0x0400, 16, deviceManagedPool: false, sharedParameterBlocks: false); // Verify by reading back var bl = ctrl.GetCurrentPidBlockLoad(); Console.WriteLine($"PID FFB enabled (load status: {bl.LoadStatus})"); ``` -------------------------------- ### Register XUSB Device Interface Source: https://hidmaestro.org/docs/reference/xusb-companion Registers the XUSB device interface using the GUID_DEVINTERFACE_XUSB. Note that this should not be used with WinExInput GUIDs. ```c WdfDeviceCreateDeviceInterface(device, &XUSB_GUID, NULL); ```