-
Notifications
You must be signed in to change notification settings - Fork 6
Engine Library
The PadForge.Engine assembly is a shared class library containing data types, interfaces, and enums used by both the Engine (input pipeline) and App (UI/ViewModel) assemblies. It has no UI dependencies and targets net10.0-windows.
Project file: PadForge.Engine/PadForge.Engine.csproj
Namespace: PadForge.Engine
File: PadForge.Engine/Common/GamepadTypes.cs
Minimal struct matching the XInput XINPUT_GAMEPAD layout. Used as the output of the mapping pipeline (Step 3 -> Step 4 -> Step 5).
public struct Gamepad
{
public ushort Buttons;
public ushort LeftTrigger;
public ushort RightTrigger;
public short ThumbLX;
public short ThumbLY;
public short ThumbRX;
public short ThumbRY;
public bool IsButtonPressed(ushort flag);
public void SetButton(ushort flag, bool pressed);
public void Clear();
}| Constant | Value | Description |
|---|---|---|
DPAD_UP |
0x0001 |
D-pad up |
DPAD_DOWN |
0x0002 |
D-pad down |
DPAD_LEFT |
0x0004 |
D-pad left |
DPAD_RIGHT |
0x0008 |
D-pad right |
START |
0x0010 |
Start button |
BACK |
0x0020 |
Back button |
LEFT_THUMB |
0x0040 |
Left stick click |
RIGHT_THUMB |
0x0080 |
Right stick click |
LEFT_SHOULDER |
0x0100 |
Left bumper |
RIGHT_SHOULDER |
0x0200 |
Right bumper |
GUIDE |
0x0400 |
Guide/home button |
A |
0x1000 |
A button |
B |
0x2000 |
B button |
X |
0x4000 |
X button |
Y |
0x8000 |
Y button |
File: PadForge.Engine/Common/GamepadTypes.cs
Raw vJoy output state for custom (non-gamepad) configurations. Bypasses the fixed Gamepad struct to support arbitrary axis/button/POV counts.
public struct VJoyRawState
{
public short[] Axes; // Up to 8 axes (signed short range -32768..32767)
public uint[] Buttons; // Button state as 4 x 32-bit words = 128 buttons max
public int[] Povs; // Up to 4 POV hat switches (-1=centered, 0-35900=direction)
public static VJoyRawState Create(int nAxes, int nButtons, int nPovs);
public void SetButton(int index, bool pressed);
public bool IsButtonPressed(int index);
public void Clear();
}public static VJoyRawState Create(int nAxes, int nButtons, int nPovs)Creates a zeroed state with specified capacities. Axes clamped to max 8, buttons to max 128 (stored as (N+31)/32 uint words), POVs to max 4.
Buttons use a 128-bit bitmask stored as uint[4]. Each uint holds 32 buttons. Index calculation:
word = index / 32bit = index % 32
POV values are in hundredths of degrees:
-
0= North -
4500= NE -
9000= East -
13500= SE -
18000= South -
22500= SW -
27000= West -
31500= NW -
0xFFFFFFFF(-1) = Centered
Resets axes to 0, buttons to 0, POVs to -1 (centered).
File: PadForge.Engine/Common/GamepadTypes.cs
Dynamic-sized MIDI output state for MidiVirtualController. Bypasses the fixed Gamepad struct to support arbitrary CC and note counts.
public struct MidiRawState
{
public byte[] CcValues; // CC values 0-127 per CC slot
public bool[] Notes; // Note on/off per note slot
public static MidiRawState Create(int ccCount, int noteCount);
}Create() allocates arrays of the specified sizes with CC values initialized to 0. Clear() resets CC values to 64 (center for axes).
File: PadForge.Engine/Common/GamepadTypes.cs
Raw keyboard + mouse output state for the KeyboardMouseVirtualController. Key states are packed into 4 x 64-bit words covering 256 Windows virtual key codes. Mouse axes are signed short range for delta movement per frame.
public struct KbmRawState
{
public ulong Keys0, Keys1, Keys2, Keys3; // 256 VK codes (4 × 64-bit words)
public short MouseDeltaX; // Mouse X delta (signed)
public short MouseDeltaY; // Mouse Y delta (signed)
public short ScrollDelta; // Scroll delta (positive = up)
public byte MouseButtons; // Bit 0=LMB, 1=RMB, 2=MMB, 3=X1, 4=X2
public short PreDzMouseDeltaX; // Mouse X before deadzone (UI preview)
public short PreDzMouseDeltaY; // Mouse Y before deadzone (UI preview)
public short PreDzScrollDelta; // Scroll before deadzone (UI preview)
public bool GetKey(byte vk);
public void SetKey(byte vk, bool pressed);
public bool GetMouseButton(int index);
public void SetMouseButton(int index, bool pressed);
public void Clear();
public static KbmRawState Combine(KbmRawState a, KbmRawState b);
}Keys use a 256-bit bitmask stored as ulong[4]. Each ulong holds 64 virtual key codes. Index calculation:
word = vk / 64bit = vk % 64
Merges two KBM states for multi-device assignment:
- Keys and mouse buttons: OR'd
- Mouse deltas and scroll: largest absolute magnitude wins
PreDzMouseDeltaX, PreDzMouseDeltaY, and PreDzScrollDelta store mouse/scroll values before center offset and deadzone processing. Used by the UI layer to display raw stick and trigger previews for KBM slots.
File: PadForge.Engine/Common/VirtualControllerTypes.cs
public enum VirtualControllerType
{
Xbox360 = 0,
DualShock4 = 1,
VJoy = 2,
Midi = 3,
KeyboardMouse = 4
}File: PadForge.Engine/Common/VirtualControllerTypes.cs
public interface IVirtualController : IDisposable
{
VirtualControllerType Type { get; }
bool IsConnected { get; }
int FeedbackPadIndex { get; set; }
void Connect();
void Disconnect();
void SubmitGamepadState(Gamepad gp);
void RegisterFeedbackCallback(int padIndex, Vibration[] vibrationStates);
}FeedbackPadIndex tracks which slot this VC occupies so feedback callbacks write to the correct VibrationStates element after a slot reorder via SwapSlotData.
Abstraction over virtual controller operations. Concrete implementations live in the App assembly:
-
Xbox360VirtualController(ViGEm) -
DS4VirtualController(ViGEm) -
VJoyVirtualController(direct P/Invoke tovJoyInterface.dll) -
MidiVirtualController(Windows MIDI Services SDK) -
KeyboardMouseVirtualController(Win32 SendInput)
File: PadForge.Engine/Common/CustomInputState.cs
API-agnostic snapshot of a device's complete input state at a single point in time.
public class CustomInputState
{
public const int MaxAxis = 24;
public const int MaxSliders = 8;
public const int MaxPovs = 4;
public const int MaxButtons = 256;
public int[] Axis; // 0-65535, center = 32767
public int[] Sliders; // 0-65535
public int[] Povs; // centidegrees 0-35900, or -1 for centered
public bool[] Buttons; // true = pressed
public float[] Gyro; // [X, Y, Z] radians per second
public float[] Accel; // [X, Y, Z] meters per second squared
}public CustomInputState()
public CustomInputState(int[] axes, int[] sliders, int[] povs, bool[] buttons)Default constructor creates zeroed arrays with default sizes. POVs initialize to -1 (centered). Copy constructor copies arrays up to max lengths (snapshot isolation).
public CustomInputState Clone()Deep copy of all arrays.
public static void GetAxisMask(
DeviceObjectItem[] items, int numAxes,
out int axisMask, out int actuatorMask, out int actuatorCount)Scans device object items to build axis and force-feedback actuator bitmasks. Bit N set = axis/actuator N exists.
| Array | Range | Center | Description |
|---|---|---|---|
Axis |
0-65535 | 32767 | Indices 0-5 = X, Y, Z, Rx, Ry, Rz. 6-23 = additional |
Sliders |
0-65535 | 32767 | Overflow or dedicated slider controls |
Povs |
0-35900 or -1 | -1 | Centidegrees. -1 = centered |
Buttons |
bool | false | 256 max (covers full Windows VK code range) |
Gyro |
float[3] | 0.0 | Radians/second. Only for gyro-capable devices |
Accel |
float[3] | 0.0 | m/s^2. Only for accelerometer-capable devices |
File: PadForge.Engine/Common/ISdlInputDevice.cs
Common interface for all SDL-based input device wrappers (joystick/gamepad, keyboard, mouse).
public interface ISdlInputDevice : IDisposable
{
// Identity
uint SdlInstanceId { get; }
string Name { get; }
Guid InstanceGuid { get; }
Guid ProductGuid { get; }
string DevicePath { get; }
string SerialNumber { get; }
ushort VendorId { get; }
ushort ProductId { get; }
// Capabilities
int NumAxes { get; }
int NumButtons { get; }
int RawButtonCount { get; }
int NumHats { get; }
bool HasRumble { get; }
bool HasHaptic { get; }
bool HasGyro { get; }
bool HasAccel { get; }
bool IsAttached { get; }
// Haptic
HapticEffectStrategy HapticStrategy { get; }
IntPtr HapticHandle { get; }
uint HapticFeatures { get; }
int NumHapticAxes { get; }
// State reading
CustomInputState GetCurrentState(bool forceRaw = false);
DeviceObjectItem[] GetDeviceObjects();
int GetInputDeviceType();
// Force feedback
bool SetRumble(ushort low, ushort high, uint durationMs = uint.MaxValue);
bool StopRumble();
}public enum HapticEffectStrategy
{
None,
LeftRight,
Sine,
Constant
}Priority order chosen at haptic open time based on SDL_GetHapticFeatures:
- LeftRight — Best match for dual-motor rumble (low + high frequency).
- Sine — Periodic effect. Period varies by which motor is stronger.
- Constant — Fallback. Level from dominant motor.
File: PadForge.Engine/Common/WebControllerDevice.cs
Virtual input device representing a browser-connected gamepad. Implements ISdlInputDevice so it integrates with the standard input pipeline.
| Property | Value |
|---|---|
| VID / PID |
0xBEEF / 0xCA7E
|
| Axes | 6 (LX, LY, LT, RX, RY, RT — 0-65535 range) |
| Buttons | 11 (standard Xbox layout: A, B, X, Y, LB, RB, Back, Start, LS, RS, Guide) |
| POV Hats | 1 |
| HasRumble | true (via browser Vibration API) |
State is written by the WebSocket thread and read by the polling thread via volatile reference swaps.
File: PadForge.Engine/Common/DeviceObjectItem.cs
Describes a single input object (axis, button, hat, slider) on a device. Used by the mapping UI and pipeline.
public class DeviceObjectItem
{
// Identity
public string Name { get; set; }
public Guid ObjectTypeGuid { get; set; }
public DeviceObjectTypeFlags ObjectType { get; set; }
// Position
public int InputIndex { get; set; }
public int Offset { get; set; }
// Aspect
public ObjectAspect Aspect { get; set; }
// Computed helpers
public bool IsForceActuator { get; }
public bool IsAxis { get; }
public bool IsButton { get; }
public bool IsPov { get; }
public bool IsSlider { get; }
}| Property | Type | Default | Description |
|---|---|---|---|
Name |
string |
"" |
Human-readable name (e.g., "X Axis", "Button 3") |
ObjectTypeGuid |
Guid |
Guid.Empty |
Well-known GUID from ObjectGuid
|
ObjectType |
DeviceObjectTypeFlags |
All |
Classification flags |
InputIndex |
int |
0 |
Zero-based index into CustomInputState arrays |
Offset |
int |
0 |
Byte offset for legacy mapping compatibility |
Aspect |
ObjectAspect |
Position |
Object aspect (only Position is defined) |
-
IsForceActuator:(ObjectType & ForceFeedbackActuator) != 0 -
IsAxis:(ObjectType & Axis) != 0 -
IsButton:(ObjectType & Button) != 0 -
IsPov:(ObjectType & PointOfViewController) != 0 -
IsSlider:ObjectTypeGuid == ObjectGuid.Slider
Returns "{Name} ({TypeLabel}, Index {InputIndex})" where TypeLabel is "Axis", "Slider", "POV", "Button", or "Object".
File: PadForge.Engine/Common/InputTypes.cs
[Flags]
public enum DeviceObjectTypeFlags : int
{
All = 0,
RelativeAxis = 1,
AbsoluteAxis = 2,
Axis = 3, // RelativeAxis | AbsoluteAxis
PushButton = 4,
ToggleButton = 8,
Button = 12, // PushButton | ToggleButton
PointOfViewController = 16,
Collection = 64,
NoData = 128,
ForceFeedbackActuator = 0x01000000,
ForceFeedbackEffectTrigger = 0x02000000
}[Flags]
public enum ObjectAspect : int
{
Position = 0x100
}[Flags]
public enum EffectParameterFlags : int
{
None = 0
}Static class providing well-known GUIDs for device object types. Values match DirectInput GUID constants.
public static class ObjectGuid
{
public static readonly Guid XAxis; // {A36D02E0-C9F3-11CF-BFC7-444553540000}
public static readonly Guid YAxis; // {A36D02E1-...}
public static readonly Guid ZAxis; // {A36D02E2-...}
public static readonly Guid RxAxis; // {A36D02F4-...}
public static readonly Guid RyAxis; // {A36D02F5-...}
public static readonly Guid RzAxis; // {A36D02E3-...}
public static readonly Guid Slider; // {A36D02E4-...}
public static readonly Guid Button; // {A36D02F0-...}
public static readonly Guid Key; // {55728220-D33C-11CF-BFC7-444553540000}
public static readonly Guid PovController; // {A36D02F2-...}
public static readonly Guid Unknown; // Guid.Empty
}Integer constants matching DirectInput device type values. Used for UserDevice.CapType.
public static class InputDeviceType
{
public const int Device = 17;
public const int Mouse = 18;
public const int Keyboard = 19;
public const int Joystick = 20;
public const int Gamepad = 21;
public const int Driving = 22;
public const int Flight = 23;
public const int FirstPerson = 24;
public const int Supplemental = 25;
}public enum MapType : int
{
None = 0,
Axis = 1,
Button = 2,
Slider = 3,
POV = 4
}File: PadForge.Engine/Common/ForceFeedbackState.cs
Manages force feedback (rumble) state for a single device with change detection.
public class ForceFeedbackState
{
// Public state
public ushort LeftMotorSpeed { get; } // 0-65535
public ushort RightMotorSpeed { get; } // 0-65535
public bool IsActive { get; }
// Methods
public void SetDeviceForces(UserDevice ud, ISdlInputDevice device, PadSetting ps, Vibration v);
public void StopDeviceForces(ISdlInputDevice device);
public bool Changed(PadSetting ps);
}public void SetDeviceForces(UserDevice ud, ISdlInputDevice device, PadSetting ps, Vibration v)- Reads gain settings from
PadSetting:ForceOverall,LeftMotorStrength,RightMotorStrength(all 0-100). - Applies per-motor and overall gain scaling to raw XInput motor speeds.
- Swaps motors if
ForceSwapMotoris configured. -
Change detection: Only sends to hardware when values differ from cached values. Each
SDL_RumbleJoystickcall restarts the hardware rumble, causing brief gaps. By only sending on change withuint.MaxValueduration (~49 days), rumble stays continuous. - Routes to either
SetHapticForces()(for haptic devices) orSetRumble()(for rumble devices).
private bool SetHapticForces(ISdlInputDevice device, ushort left, ushort right)Translates dual-motor rumble to SDL haptic effects based on the device's HapticEffectStrategy:
| Strategy | SDL Effect | Large Motor | Small Motor |
|---|---|---|---|
| LeftRight | SDL_HAPTIC_LEFTRIGHT |
large_magnitude = left |
small_magnitude = right |
| Sine | SDL_HAPTIC_SINE |
magnitude = max/2, period = 120
|
period = 40 |
| Constant | SDL_HAPTIC_CONSTANT |
level = max/2 |
N/A |
Creates effect on first call via SDL_CreateHapticEffect, updates in-place on subsequent calls via SDL_UpdateHapticEffect.
public bool Changed(PadSetting ps)Returns true if any force feedback setting in the PadSetting has changed since last call. Caches: ForceType, ForceSwapMotor, LeftMotorStrength, RightMotorStrength, ForceOverall.
File: PadForge.Engine/Common/ForceFeedbackState.cs
public class Vibration
{
// Scalar (used by ViGEm Xbox/DS4 callbacks and rumble path)
public ushort LeftMotorSpeed { get; set; } // Low-frequency, heavy rumble. 0-65535
public ushort RightMotorSpeed { get; set; } // High-frequency, light buzz. 0-65535
// Directional FFB (populated by vJoy FFB callback for haptic devices)
public bool HasDirectionalData { get; set; }
public uint EffectType { get; set; }
public short SignedMagnitude { get; set; } // -10000 to +10000
public ushort Direction { get; set; } // Polar 0-32767 (0=North)
public uint Period { get; set; } // ms, for periodic effects
public byte DeviceGain { get; set; } = 255; // 0-255
// Condition effect data (spring/damper/friction/inertia)
public bool HasConditionData { get; set; }
public ConditionAxisData[] ConditionAxes { get; set; }
public int ConditionAxisCount { get; set; } // 1 for wheels, 2 for joysticks
public Vibration();
public Vibration(ushort leftMotor, ushort rightMotor);
}The scalar fields (LeftMotorSpeed, RightMotorSpeed) are set by ViGEm FeedbackReceived callbacks and the vJoy FFB rumble fallback path. The directional fields are populated by the vJoy FFB callback for devices with haptic support (constant force, periodic effects, ramp). The condition fields carry per-axis Spring/Damper/Friction/Inertia parameters. Read by Step 2 on the polling thread.
public struct ConditionAxisData
{
public short PositiveCoefficient; // 0-10000
public short NegativeCoefficient; // 0-10000
public short Offset; // -10000 to +10000
public uint DeadBand; // 0-10000
public uint PositiveSaturation; // 0-10000
public uint NegativeSaturation; // 0-10000
}Per-axis condition parameters for spring/damper/friction/inertia effects. Index 0 = X axis, Index 1 = Y axis.
File: PadForge.Engine/Common/RumbleLogger.cs
public static class RumbleLogger
{
public static bool Enabled { get; set; }
public static void Log(string message);
}Diagnostic logger for force feedback debugging. Disabled by default. Set Enabled = true in InputService.Start() to activate. Thread-safe. Writes timestamped messages to a log file using Stopwatch for high-resolution timing.
File: PadForge.Engine/Common/InputHookManager.cs
Manages WH_KEYBOARD_LL and WH_MOUSE_LL low-level Windows hooks for suppressing mapped inputs from keyboards and mice. Only suppresses inputs that are in the active suppression sets — non-mapped keys/buttons pass through normally.
public class InputHookManager : IDisposable
{
void Start();
void Stop();
void SetSuppressedKeys(HashSet<int> vkCodes);
void SetSuppressedMouseButtons(HashSet<int> buttons);
bool HasAnySuppression { get; }
void MoveMouse(int dx, int dy);
void ScrollMouse(int clicks);
}void MoveMouse(int dx, int dy)Moves the mouse cursor by the given delta using SendInput with MOUSEINPUT (MOUSEEVENTF_MOVE). Called by macro mouse move actions.
void ScrollMouse(int clicks)Scrolls the mouse wheel by the given number of clicks using SendInput with MOUSEINPUT (MOUSEEVENTF_WHEEL). Positive = scroll up, negative = scroll down. Called by macro mouse scroll actions.
Hooks require a thread with a message pump. InputHookManager creates a dedicated background thread running a GetMessage loop. Hooks are installed on this thread via SetWindowsHookExW.
-
Start()creates the thread and waits (viaManualResetEventSlim) until hooks are installed before returning. -
Stop()postsWM_QUITto the hook thread to exit the message loop, then joins the thread.
Suppression sets use volatile reference swap for thread safety — the hook callbacks read the current set reference without locking, and updates replace the entire HashSet atomically.
void SetSuppressedKeys(HashSet<int> vkCodes) // Virtual key codes to suppress
void SetSuppressedMouseButtons(HashSet<int> buttons) // 0=Left, 1=Right, 2=Middle, 3=XButton1, 4=XButton2-
Keyboard: Intercepts
WM_KEYDOWN,WM_KEYUP,WM_SYSKEYDOWN,WM_SYSKEYUP. ReadsKBDLLHOOKSTRUCT.vkCodeand checks against the suppression set. Returns(IntPtr)1to suppress, orCallNextHookExto pass through. -
Mouse: Intercepts button messages (
WM_LBUTTONDOWN/UP,WM_RBUTTONDOWN/UP,WM_MBUTTONDOWN/UP,WM_XBUTTONDOWN/UP). Converts the message to a button ID viaMouseMessageToButtonId()and checks against the suppression set. Mouse movement and wheel events always pass through.
| Mouse Message | Button ID |
|---|---|
WM_LBUTTONDOWN/UP |
0 (Left) |
WM_RBUTTONDOWN/UP |
1 (Right) |
WM_MBUTTONDOWN/UP |
2 (Middle) |
WM_XBUTTONDOWN/UP (XBUTTON1) |
3 |
WM_XBUTTONDOWN/UP (XBUTTON2) |
4 |
| Other (move, wheel) | -1 (pass through) |
| Function | DLL | Purpose |
|---|---|---|
SetWindowsHookExW |
user32.dll | Install low-level hook |
UnhookWindowsHookEx |
user32.dll | Remove hook |
CallNextHookEx |
user32.dll | Pass input to next hook |
GetModuleHandleW |
kernel32.dll | Get module handle for hook registration |
GetMessageW |
user32.dll | Message pump loop |
PostThreadMessageW |
user32.dll | Post WM_QUIT to hook thread |
GetCurrentThreadId |
kernel32.dll | Get hook thread ID |
File: PadForge.Engine/Common/RawInputListener.cs
Manages Windows Raw Input registration and message processing for keyboard and mouse devices. Runs on a dedicated message-pump thread.
Key capabilities:
- Enumerates keyboards and mice via
GetRawInputDeviceList - Processes
WM_INPUTmessages for per-device input state - Mouse scroll wheel axis support: captures
WM_MOUSEWHEELdata and exposes scroll delta as an axis value
File: PadForge.App/Common/Input/SdlMouseWrapper.cs
Wraps a physical mouse device for the input pipeline. Implements ISdlInputDevice.
- Reads mouse state from
RawInputListenerper-device buffers - Scroll wheel intensity tracking: maintains scroll wheel delta as an axis value with decay, allowing scroll speed to be mapped like a proportional axis
File: PadForge.Engine/Data/MappingTranslation.cs
Namespace: PadForge.Engine.Data
Static class that translates mapping property names between different virtual controller layouts using positional equivalence. When copying mappings from one slot to another with a different output type (e.g., Xbox 360 to vJoy custom, or DS4 to MIDI), property names must be translated because each layout uses different naming conventions for the same logical control.
public enum ControlCategory { Button, Axis, AxisNeg, DPad }
public record MappingSlot(ControlCategory Category, int Position);A MappingSlot represents a canonical position within a control category (e.g., "3rd button", "1st axis negative"). Translation works by converting a source property name to a MappingSlot, then converting that slot to the target layout's property name.
| Method | Description |
|---|---|
GetPosition(string propertyName, VirtualControllerType type, bool isCustomVJoy) |
Maps a layout-specific property name to its canonical MappingSlot
|
GetPropertyName(MappingSlot slot, VirtualControllerType type, bool isCustomVJoy) |
Maps a canonical MappingSlot to a layout-specific property name |
IsSameLayout(srcType, srcIsCustomVJoy, tgtType, tgtIsCustomVJoy) |
Returns true if source and target use the same property names (no translation needed) |
GetLayoutLabel(VirtualControllerType type, bool isCustomVJoy) |
Returns display label (e.g., "Xbox 360", "vJoy", "MIDI", "KB+M") |
| Layout | Property Name Examples | Notes |
|---|---|---|
| Gamepad (Xbox 360 / DS4 / vJoy gamepad preset) |
ButtonA, LeftThumbAxisX, DPadUp
|
Xbox 360 and DS4 share the same property names |
| vJoy Custom |
VJoyBtn0, VJoyAxis2, VJoyPov0Up
|
Indexed by position |
| MIDI |
MidiNote0, MidiCC3, MidiCC3Neg
|
No D-Pad support |
| KB+M |
KbmMBtn0, KbmMouseX, KbmKey20
|
Mouse buttons 0-4, then keyboard VK codes |
| Field | Type | Description |
|---|---|---|
LeftThumbCenterOffsetX |
string |
Left stick X center offset (-100 to 100%). Default "0". |
LeftThumbCenterOffsetY |
string |
Left stick Y center offset. Default "0". |
RightThumbCenterOffsetX |
string |
Right stick X center offset. Default "0". |
RightThumbCenterOffsetY |
string |
Right stick Y center offset. Default "0". |
LeftThumbMaxRangeX |
string |
Left stick X max range (1-100%). Default "100". |
LeftThumbMaxRangeY |
string |
Left stick Y max range. Default "100". |
RightThumbMaxRangeX |
string |
Right stick X max range. Default "100". |
RightThumbMaxRangeY |
string |
Right stick Y max range. Default "100". |
Center offset is applied in Step 3 before dead zone processing. Max range scales the output range.
| Field | Type | Description |
|---|---|---|
AudioRumbleEnabled |
string |
Enable audio bass rumble. "0" = off, "1" = on. Default "0". |
AudioRumbleSensitivity |
string |
Bass detection sensitivity. Default "4". |
AudioRumbleCutoffHz |
string |
Low-pass cutoff frequency in Hz. Default "80". |
AudioRumbleLeftMotor |
string |
Left motor strength percentage for audio rumble (0-100). Default "100". |
AudioRumbleRightMotor |
string |
Right motor strength percentage for audio rumble (0-100). Default "100". |
| Field | Type | Description |
|---|---|---|
HidHideEnabled |
bool |
Whether this device is hidden from games via HidHide |
ConsumeInputEnabled |
bool |
Whether mapped keyboard/mouse inputs are suppressed via hooks |
ForceRawJoystickMode |
bool |
Bypass SDL3 gamepad remapping, read raw joystick indices |
HidHideInstanceIds |
List<string> |
Cached HID instance IDs for blacklisting (persisted for offline devices) |