3.5.0: technical internals docs + screenshot refresh
Add Wii-Controllers-Internals (pairing ceremony, SDL hidapi_wii read path, rescan recovery, capability gate). Extend Input-Pipeline (mouse cursor source, shift cycle, trigger routing, source kinds + ramp, macro clipboard + cursor actions) and SDL3-Integration (Wii fork fixes, axis capability gating). Refresh all page screenshots against 3.5.0; add the Trigger Routing card shot and link it from Force Feedback and Home.
Add 3.4 developer-reference pages and cross-links
New internals pages for Remote Link, Controller Audio, Wheel force feedback,
and MIDI input, each grounded in the live source (classes, files, data flow).
Link them from the Home developer-reference index. Add the MIDI enumeration
phase and the vendor-wheel force-feedback branch to Input Pipeline, the new
persisted fields to Settings and Serialization, and the engine-side
subsystems note to Services Layer.
Also small prose fixes to the user pages: drop a defensive "not input-only"
phrasing on Remote Link, fix a link alias on Wheel, Americanize a spelling
on MIDI Input.
Steering: new page for winding / 2D angle-to-axis / motion-lean modes (#94)
Document the three steering stick modes, their tunables and defaults, the at-lock
feedback layer, and the per-stick Sticks-tab config. Add a Steering Source Kinds
section to Input-Pipeline and a feature-table row + link on Home. Math credited to
JoyShockMapper (geometry only; original C#, no GPL code incorporated).
Document the PTP reader: tip-switch, frame assembly, slot stability
Adds a full PrecisionTouchpadReader section to Engine-Library with
the four spec-mandatory behaviors (tip-switch usage 0x42, multi-report
frame assembly via contact-count, HID-contact-id-stable slot
assignment, staleness clear), per-device state fields, and the public
API. The four behaviors are what made 3- to 5-finger taps reliable on
PTP hardware.
Also:
- Engine-Library RawInputListener: note the MOUSE_MOVE_ABSOLUTE skip.
- Architecture-Overview: extend PrecisionTouchpadReader.cs line.
- Touchpad: add a PTP-reader development subsection that summarizes
the four behaviors and links to the Engine-Library field reference.
Drop a pseudo-period semicolon in the recorder paragraph.
- Input-Pipeline Step 2: show both newState paths (PTP via
_ptpReader.ReadInto, SDL via ud.Device.GetCurrentState). The
prior text only showed the SDL path.
Wiki: purge references to four classes removed from the codebase
CustomInputUpdate, CustomInputHelper, DeviceEffectItem, and
RumbleLogger no longer exist in PadForge.Engine — they were
removed at some point and the wiki still documented them in
detail across five pages. Cross-checked with grep across both
projects: zero call sites remain in source.
Removed:
- Engine-Library.md: ToC entries + full sections for all four,
plus UserDevice.InputUpdates / OldInputUpdates rows that
referenced the dead CustomInputUpdate[] type.
- Architecture-Overview.md: file-tree entries for the four .cs
files + the RumbleLogger row in the static-class table.
Added the two real Engine/Common touchpad files
(PrecisionTouchpadReader, TouchpadOverlayDevice) that were
missing from the tree.
- Settings-and-Serialization.md: UserDevice.InputUpdates and
UserDevice.DeviceEffects rows.
- Input-Pipeline.md, SDL3-Integration.md: the step-(e) buffered-
update code samples rewrote into the current per-(slot,
device, padIdx) gesture-engine tick — that's what actually
runs after the InputState swap in Step 2 today.
SDL3 rumble fn is SDL_RumbleJoystick, not SDL_RumbleGamepad (fix 5 wiki sites + release notes draft)
Architecture/Input-Pipeline: HMController.SubmitState (not HMContext); rewrite reverse data flow against per-family writer dispatch
HM SDK event is OutputReceived, not FeedbackReceived (Virtual-Controllers, Input-Pipeline)
Polish: Xbox writer HID-not-XUSB, fold ScpVBus comparison to ViGEm+vJoy, list v3.2 effect-writer files in tree, fix Adaptive-Triggers sentence
Polish: drop stale v2.2.1 version markers, banned 'Essential' wording, image-caption em-dashes
Polish: more pseudo-period semicolons fixed; correct stale v2-dev branch refs in Build-and-Publish
Input-Pipeline: correct the VID/PID-routing attribution
Last pass attributed the VID/PID early-route to
ForceFeedbackState.SetDeviceForces, but that's where SDL-rumble
devices land AFTER the Sony / Xbox One+ skip checks. The actual
early-route happens in InputManager.Step2's ApplyForceFeedback(ud)
which fans out to UserEffectsDispatcher, XboxImpulseHidWriter, or
SetDeviceForces. Rewrote the Step 2 'Output' description so the
Sony / Xbox One+ / everything-else split is attributed to the
right method.
Wiki: per-pad-family rumble routing replaces 'SDL_RumbleJoystick' claim
Two prose passages still described rumble as a single SDL_RumbleJoystick
forward, dropping the v3.x sole-writer architecture for Sony and Xbox
One+ pads.
Virtual-Controllers (HM FeedbackReceived threading note): now lists
the three writers (UserEffectsDispatcher for Sony, XboxImpulseHidWriter
for Xbox One+, SDL for everything else) and calls out that SDL is
explicitly skipped on Sony and Xbox One+ per the architecture-invariant
memory rules.
Input-Pipeline (Step 2 ForceFeedbackState.SetDeviceForces): rewrote
from 'uses SDL_RumbleJoystick' to early-routes-by-VID/PID, matching
the actual dispatch in code.
Input-Pipeline: fix Step 3 sub-bullet + pipeline-diagram stale shape
Step 3 'Type-specific raw mapping' sub-bullet still showed the
v3.0-era MapInputToExtendedRaw call with just (state, ps, cfg) and
'vJoy mappings' wording. Updated to the v3.2 6-arg signature
(SlotCustomLayouts[slot], mappingSet, deviceGuid, slot) with the
generic 'descriptor mappings' wording.
Pipeline diagram (line 1472-1483):
- 'SubmitRawState()' -> 'SubmitExtendedRawState()' (actual method name).
- 'MIDI (WinRT) (joy.cpl)' label was muddled and pointed MIDI at
joy.cpl; cleaned to 'MIDI (Windows MIDI Services)' with the right
endpoint annotation.
- Feedback path collapsed Sony/Xbox/everything-else into a single
'SDL_RumbleJoystick()' call. v3 routes per pad family:
UserEffectsDispatcher for Sony, XboxImpulseHidWriter raw HID for
Xbox One+, SDL for everything else. Architecture-invariant memory
rules already encode this; the diagram now matches.
Input-Pipeline: refresh stale v2-era ExtendedVirtualController refs
Three remaining v3-merge holdovers cleaned up:
- MapInputToExtendedRaw signature was the v3.0 form; updated to the
v3.2 form that takes CustomControllerLayout (Engine type, replaces
the dropped ExtendedVirtualController.ExtendedDeviceConfig nested
type) plus MappingSet/deviceGuid/slot for the new MappingSet eval.
- 'ExtendedVirtualController.UpdateFfbPadIndex' call no longer
exists; FeedbackPadIndex is set directly on the surviving
HMaestroVirtualController instance after a slot swap.
- Pass 3 'Submit reports' code block referenced 'ExtendedVirtualController vjoyVc' and SubmitRawState; the actual
code uses HMaestroVirtualController hmExt and SubmitExtendedRawState
with SlotCustomLayouts[]. Snippet rewritten to match production.
- SlotExtendedConfigs[] table row pointed at the dropped
ExtendedDeviceConfig type; renamed to SlotCustomLayouts (the live
array name) with CustomControllerLayout type. Added rows for the
three companion bool[] arrays (SlotExtendedIsCustom,
SlotExtendedCustomize, SlotExtendedFfbEnabled) that flank it, and
removed a duplicate SlotExtendedIsCustom row.
Dev wiki: more em-dash pseudo-colons -> periods
ViewModels.md: HmInactivityDestroyTimeoutSeconds description em-dash
attaching the 'only the live VC is destroyed' clarification.
Services-Layer.md: Profile-restore Topology step had both a
semicolon (pseudo-period) and an em-dash (pseudo-colon) attaching
slot-diff outcomes; the device-assignment step had another em-dash
attaching the unchanged-mapping promise. Three sentences each now.
Input-Pipeline.md: 'preserve nodes path is gone — HM creates and
destroys...' em-dash was a pseudo-colon attaching the v3 behavior.
Wiki dev pages: another round of prose semicolons -> periods
Architecture-Overview: drift-comp contrast, DSU 4-slot cap aside,
slot-reorder consequence sentence. Input-Pipeline: positive/negative
drift contrast, thread-safety sole-writer note. Engine-Library:
back-compat XmlEnum exception path, KBM Open() GUID derivation.
XAML-Views: MainViewModel constructor step, type-switch button
unavailable-state aside, drag-drop type-group rule, HidingToggle
side-effect list, KBM hover/recording color contrast, two
'Constructor only' code-behind glosses.
Input-Pipeline: document v3.2 MappingSet evaluator file + Step 3 hook
Wiki said 'split across eight files' but the actual codebase has 9
InputManager partial files now. New file
InputManager.Step3.MappingSetEval.cs runs ahead of the per-device
mapping pass for slots that carry a MappingSet, resolves multi-source
rows + combine modes + custom formulas + shift layers, and feeds the
synthesized PadSetting into the existing MapInputToGamepad path. Add
the file row to the partial-class table and a companion-file callout
under the Step 3 header.
Pass 27: punchy-voice sweep — drop 'various', 'not just X but Y' defensive parenthetical, 'actually' filler
Pass 10: Input-Pipeline 'Custom vJoy' / 'vJoy state' renamed to 'Extended Custom HID' / 'Extended-raw state'
v3 uses HIDMaestro for Extended profiles. The wiki kept calling those
'Custom vJoy' / 'vJoy mapping' / 'vJoy button words' which is wrong on
the driver name. Renamed throughout the active code-flow sections.
Historical-narrative sections (lines 225, 1263) still use 'v2 vJoy' to
describe what's removed; those stay.
Pass 4: drop final stale ViGEm/vJoy references (vigem_target_free, _vigemClientLock, PreInitializeVigemCounts)
Drop stale _vigemClientFailed + preserveExtendedNodes references in dev-deep-dive pages
Input-Pipeline: drop ExtendedSyncLock + _createCooldown + vJoy descriptor sync (v2 fields, removed in v3)
Input-Pipeline: drop stale 'CleanupStaleVigemDevices' + 'PreInitializeVigemCounts' sections (methods removed from code)
Input-Pipeline: align fork-filter wording with SDL3-Integration (Hardware ID parent walk, not container-ID walk)
Input-Pipeline: drop the obsolete _filteredVigemInstanceIds + IsHIDMaestroVirtualDevice docs
The in-engine filter is gone. PadForge's SDL3 fork now walks each device's
container ID to the HIDMaestro root enumerator and drops matches inside
SDL_GetJoysticks, so HM virtuals never reach the engine's open loop in the
first place. Pruned the tracking-field row, the step that referenced the set,
the cleanup IntersectWith block, and the detection-heuristics table.
Wiki: Pass 2 — dev-deep-dive accuracy + Home page voice match
Architecture-Overview: AssemblyInfo.cs → SharedVersion.cs; expanded
Data/ file list to include MappingSet/MappingSource/MappingRow/
ShiftActivator/MappingSetMigrator/DeviceTuning.
Input-Pipeline: drop preserveExtendedNodes parameter; rebuild field
table to match current InputService.
Virtual-Controllers: VendorId==0xBEEF check replaced with
DescriptorHasPidFfbBlock(descriptorHex) gate in three locations.
HIDMaestro-Deep-Dive: Microsoft.HIDMaestro.SDK → HIDMaestro.Core
(bundled at Resources/HIDMaestro/HIDMaestro.Core.dll); fix
context.CreateController(profile) call shape.
Services-Layer: drop preserveExtendedNodes from Stop(); remove the
"step 9" preserve-nodes branch.
Engine-Library: add TOUCHPAD = 0x0800 button flag row.
SDL3-Integration: SDL3 fork now filters HM virtuals at
SDL_GetJoysticks, so the engine no longer maintains
_filteredVigemInstanceIds. Updated Mermaid flowchart and renumbered
the connect-side step list.
Home: "New in 3.2" rewritten from bullet lists to story paragraphs to
match the website voice. Added Gyro / Impulse Triggers / Shift Layers
to the navigation tables.
Pass 4/25: verification pass -- fixed one broken intra-page anchor on Input Pipeline (double-dash slug)
Wiki rewrite: simple-English voice across all user-facing pages
Rewrites 18 user-facing pages and adds hooks to 7 dev-deep-dive pages.
Each user-facing page now opens with H1 then a one-sentence hook,
strips banned vocabulary, replaces em-dash pseudo-colons with periods,
and ends with a version marker.
User-facing rewrites
- Installation, Dashboard, Controller-Slots, Button-and-Axis-Mappings
- Stick-Deadzones, Trigger-Deadzones, Force-Feedback, Adaptive-Triggers, Lighting
- Macros, Profiles, Devices, DSU-Motion-Server, Web-Controller
- Settings, Driver-Management, Input-Precision, Troubleshooting
- 3D-and-2D-Visualization
New 3.2 content woven into Force-Feedback (Impulse Triggers, Audio Bass
Trigger Rumble, Constant Trigger Force) using actual in-app labels from
Strings.resx. Profiles documents the new Toggle Virtual Controllers
Disabled shortcut mode. Settings notes the stable-across-language-switch
fix. DSU Motion Server covers the Gyro Aim Engage picker subtitle.
Dev-deep-dive hooks added
- Input-Pipeline, Settings-and-Serialization, ViewModels, XAML-Views, Engine-Library
Lighting tab reset buttons + v3 terminology sweep
Refreshes pad-lighting screenshot to capture the four new reset buttons
(Lightbar Mode, LED Brightness, Player Pattern, Mute LED Mode) plus the
rest of the slot-0 PadPage tabs and slot-type config bars against the
post-deploy build.
Wiki prose: drops residual v2 phrasing (ExtendedConfig.IsGamepadPreset,
DualShock4 / Xbox 360 enum names, "Microsoft" / "Sony") and routes through
the v3 OutputType / VirtualControllerType vocabulary instead.