-
Notifications
You must be signed in to change notification settings - Fork 2
Engine Library
Shared class library of data types, interfaces, and enums used by both the Engine (input pipeline) and App (UI/ViewModel) assemblies. No UI dependencies. Targets net10.0-windows.
graph TB
subgraph "Data Models — PadForge.Engine.Data"
PS[PadSetting<br/>mapping config · dead zones · curves]
US[UserSetting<br/>device-to-slot linkage]
UD[UserDevice<br/>physical device record]
MT[MappingTranslation<br/>cross-layout Copy From]
VJM[VJoyMappingEntry<br/>custom axis/button/POV maps]
end
subgraph "Output State Types — PadForge.Engine"
GP[Gamepad<br/>XInput-layout struct]
VRS[VJoyRawState<br/>arbitrary axes · 128 buttons · 4 POVs]
KRS[KbmRawState<br/>256 VK codes · mouse deltas]
MRS[MidiRawState<br/>128 notes · 128 CCs · pitch bend]
end
subgraph "Device Wrappers — PadForge.Engine.Common"
ISDI[ISdlInputDevice<br/>common interface]
SDW[SdlDeviceWrapper<br/>joystick/gamepad · rumble · haptic · sensors]
SKW[SdlKeyboardWrapper<br/>per-device keyboard]
SMW[SdlMouseWrapper<br/>per-device mouse]
WCD[WebControllerDevice<br/>browser gamepad]
end
subgraph "Force Feedback"
FFS[ForceFeedbackState<br/>per-device FFB tracking]
VIB[Vibration<br/>left + right motor]
end
subgraph "Interfaces"
IVC[IVirtualController<br/>Create · Submit · Destroy]
end
US -->|references| PS
US -->|references| UD
PS -->|contains| VJM
PS -->|uses| MT
UD -->|runtime: Device| ISDI
SDW -.->|implements| ISDI
SKW -.->|implements| ISDI
SMW -.->|implements| ISDI
WCD -.->|implements| ISDI
IVC -->|accepts| GP
IVC -->|accepts| VRS
IVC -->|accepts| KRS
IVC -->|accepts| MRS
FFS -->|outputs| VIB
style GP fill:#e1f5fe
style PS fill:#e8f5e9
style SDW fill:#f3e5f5
style IVC fill:#fff3e0
style FFS fill:#fce4ec
Project file: PadForge.Engine/PadForge.Engine.csproj
| Namespace | Contents |
|---|---|
PadForge.Engine |
Common types |
PadForge.Engine.Data |
Data models |
PadForge.Engine.Common |
InputHookManager |
SDL3 |
P/Invoke |
- Gamepad (GamepadTypes.cs)
- VJoyRawState (GamepadTypes.cs)
- KbmRawState (GamepadTypes.cs)
- MidiRawState (GamepadTypes.cs)
- VirtualControllerType (VirtualControllerTypes.cs)
- IVirtualController (VirtualControllerTypes.cs)
- CustomInputState (CustomInputState.cs)
- CustomInputUpdate (CustomInputUpdate.cs)
- CustomInputHelper (CustomInputHelper.cs)
- ISdlInputDevice (ISdlInputDevice.cs)
- SdlDeviceWrapper (SdlDeviceWrapper.cs)
- HapticEffectStrategy (SdlDeviceWrapper.cs)
- SdlKeyboardWrapper (SdlKeyboardWrapper.cs)
- SdlMouseWrapper (SdlMouseWrapper.cs)
- WebControllerDevice (WebControllerDevice.cs)
- DeviceObjectItem (DeviceObjectItem.cs)
- DeviceEffectItem (DeviceEffectItem.cs)
- InputTypes (InputTypes.cs)
- ForceFeedbackState (ForceFeedbackState.cs)
- FfbEffectTypes (ForceFeedbackState.cs)
- Vibration (ForceFeedbackState.cs)
- ConditionAxisData (ForceFeedbackState.cs)
- RumbleLogger (RumbleLogger.cs)
- InputHookManager (InputHookManager.cs)
- RawInputListener (RawInputListener.cs)
- PadSetting (Data/PadSetting.cs)
- VJoyMappingEntry (Data/PadSetting.cs)
- UserSetting (Data/UserSetting.cs)
- UserDevice (Data/UserDevice.cs)
- DeadZoneShape (Data/DeadZoneShape.cs)
- MappingTranslation (Data/MappingTranslation.cs)
- SDL3 P/Invoke (SDL3Minimal.cs)
File: PadForge.Engine/Common/GamepadTypes.cs
Namespace: PadForge.Engine
Minimal struct matching the XInput XINPUT_GAMEPAD layout. Output of the mapping pipeline (Step 3 → Step 4 → Step 5).
public struct Gamepad
{
// Fields
public ushort Buttons; // Bitmask of button flags
public ushort LeftTrigger; // 0-65535
public ushort RightTrigger; // 0-65535
public short ThumbLX; // -32768 to 32767
public short ThumbLY; // -32768 to 32767
public short ThumbRX; // -32768 to 32767
public short ThumbRY; // -32768 to 32767
// Methods
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 |
| Method | Signature | Description |
|---|---|---|
IsButtonPressed |
bool IsButtonPressed(ushort flag) |
true if the button flag bit is set in Buttons
|
SetButton |
void SetButton(ushort flag, bool pressed) |
Sets or clears a button flag bit via bitwise OR/AND |
Clear |
void Clear() |
Resets all fields to zero |
File: PadForge.Engine/Common/GamepadTypes.cs
Namespace: PadForge.Engine
Raw vJoy output state for custom (non-gamepad) configurations. Bypasses the fixed Gamepad struct to support arbitrary axis, button, and 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();
}| Method | Signature | Description |
|---|---|---|
Create |
static VJoyRawState Create(int nAxes, int nButtons, int nPovs) |
Factory. Clamps axes to 8, buttons to 128 (stored as (N+31)/32 uint words), POVs to 4. All zeroed. |
SetButton |
void SetButton(int index, bool pressed) |
Sets button by 0-based index (word = index/32, bit = index%32). No-op if out of range. |
IsButtonPressed |
bool IsButtonPressed(int index) |
true if button at index is set. false if out of range. |
Clear |
void Clear() |
Resets axes to 0, buttons to 0, POVs to −1 (centered). |
Buttons use a 128-bit bitmask stored as uint[4] (32 buttons per word).
Hundredths of degrees: 0=N, 4500=NE, 9000=E, 13500=SE, 18000=S, 22500=SW, 27000=W, 31500=NW, 0xFFFFFFFF (−1) = centered.
File: PadForge.Engine/Common/GamepadTypes.cs
Namespace: PadForge.Engine
Raw keyboard + mouse output state for KeyboardMouseVirtualController. Key states packed into 4 × 64-bit words covering 256 Windows VK codes. Mouse axes are signed shorts (delta per frame).
public struct KbmRawState
{
// Key state (256 VK codes packed into 4 ulongs)
public ulong Keys0; // VK 0-63
public ulong Keys1; // VK 64-127
public ulong Keys2; // VK 128-191
public ulong Keys3; // VK 192-255
// Mouse output
public short MouseDeltaX; // Mouse X delta (signed, pixels per frame)
public short MouseDeltaY; // Mouse Y delta (signed, pixels per frame)
public short ScrollDelta; // Mouse scroll delta (positive = up)
public byte MouseButtons; // Bit 0=LMB, 1=RMB, 2=MMB, 3=X1, 4=X2
// Pre-deadzone values (for UI stick/trigger preview)
public short PreDzMouseDeltaX; // Mouse X before center offset + deadzone
public short PreDzMouseDeltaY; // Mouse Y before center offset + deadzone
public short PreDzScrollDelta; // Scroll before deadzone
// Methods
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);
}| Method | Signature | Description |
|---|---|---|
GetKey |
bool GetKey(byte vk) |
true if VK code bit is set (word = vk/64, bit = vk%64). |
SetKey |
void SetKey(byte vk, bool pressed) |
Sets or clears a VK code bit. |
GetMouseButton |
bool GetMouseButton(int index) |
true if mouse button bit is set (0=LMB, 1=RMB, 2=MMB, 3=X1, 4=X2). |
SetMouseButton |
void SetMouseButton(int index, bool pressed) |
Sets or clears a mouse button bit. |
Clear |
void Clear() |
Zeros all keys, mouse deltas, scroll, mouse buttons, and pre-deadzone fields. |
Combine |
static KbmRawState Combine(KbmRawState a, KbmRawState b) |
Merges two KBM states. Keys and mouse buttons OR'd. Deltas and scroll use largest absolute magnitude. |
File: PadForge.Engine/Common/GamepadTypes.cs
Namespace: PadForge.Engine
Dynamic-sized MIDI output state for MidiVirtualController. CC values: 0–127 (MIDI range). Notes: boolean (on/off).
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);
public void Clear();
public static MidiRawState Combine(MidiRawState a, MidiRawState b);
}| Method | Signature | Description |
|---|---|---|
Create |
static MidiRawState Create(int ccCount, int noteCount) |
Allocates arrays. CC values initialized to 0. |
Clear |
void Clear() |
Resets CCs to 64 (center), notes to false. |
Combine |
static MidiRawState Combine(MidiRawState a, MidiRawState b) |
Merges two states. CCs take the value furthest from center (64); notes OR'd. |
File: PadForge.Engine/Common/VirtualControllerTypes.cs
Namespace: PadForge.Engine
public enum VirtualControllerType
{
Xbox360 = 0,
DualShock4 = 1,
VJoy = 2,
Midi = 3,
KeyboardMouse = 4
}File: PadForge.Engine/Common/VirtualControllerTypes.cs
Namespace: PadForge.Engine
Abstraction for virtual controller operations. Implementations (in App assembly):
| Class | Backend |
|---|---|
Xbox360VirtualController |
ViGEm |
DS4VirtualController |
ViGEm |
VJoyVirtualController |
P/Invoke to vJoyInterface.dll
|
MidiVirtualController |
Windows MIDI Services SDK |
KeyboardMouseVirtualController |
Win32 SendInput
|
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);
}| Member | Type | Description |
|---|---|---|
Type |
VirtualControllerType |
Virtual controller type |
IsConnected |
bool |
Whether the VC is connected |
FeedbackPadIndex |
int |
Slot index for feedback callbacks into VibrationStates[] (updated on SwapSlotData) |
Connect() |
void |
Creates and plugs in the VC |
Disconnect() |
void |
Unplugs and destroys the VC |
SubmitGamepadState(Gamepad) |
void |
Sends gamepad state to the VC |
RegisterFeedbackCallback(int, Vibration[]) |
void |
Registers a callback writing rumble to VibrationStates[] at the given index |
File: PadForge.Engine/Common/CustomInputState.cs
Namespace: PadForge.Engine
API-agnostic snapshot of a device's full input state at one point in time.
public class CustomInputState
{
// Constants
public const int MaxAxis = 24;
public const int MaxSliders = 8;
public const int MaxPovs = 4;
public const int MaxButtons = 256;
// Fields
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
// Constructors
public CustomInputState();
public CustomInputState(int[] axes, int[] sliders, int[] povs, bool[] buttons);
// Methods
public CustomInputState Clone();
public static void GetAxisMask(DeviceObjectItem[] items, int numAxes,
out int axisMask, out int actuatorMask, out int actuatorCount);
}| Constructor | Description |
|---|---|
CustomInputState() |
Zeroed arrays at default sizes. POVs init to −1 (centered). Gyro/Accel are float[3]. |
CustomInputState(int[], int[], int[], bool[]) |
Copies arrays up to max lengths (snapshot isolation). POVs init to −1 before copy. |
| Method | Signature | Description |
|---|---|---|
Clone |
CustomInputState Clone() |
Deep copy of all arrays (including Gyro and Accel). |
GetAxisMask |
static void GetAxisMask(DeviceObjectItem[], int, out int, out int, out int) |
Scans device objects to build axis and FFB actuator bitmasks. Bit N = axis/actuator N exists. |
| Array | Range | Center | Description |
|---|---|---|---|
Axis |
0–65535 | 32767 | 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 range) |
Gyro |
float[3] | 0.0 | Radians/s. Gyro-capable devices only |
Accel |
float[3] | 0.0 | m/s². Accelerometer-capable devices only |
File: PadForge.Engine/Common/CustomInputUpdate.cs
Namespace: PadForge.Engine
Single buffered input change between two CustomInputState snapshots. Used by the input recorder and update pipeline.
public struct CustomInputUpdate
{
public MapType Type; // Axis, Button, Slider, or POV
public int Index; // Zero-based index within the type's array
public int Value; // New value after the change
public override string ToString(); // Returns "Type Index = Value"
}| Field | Type | Description |
|---|---|---|
Type |
MapType |
Input source type that changed |
Index |
int |
Zero-based index in the type's array (e.g., Axis[0], Buttons[5]) |
Value |
int |
New value. Axes/sliders: 0–65535. POVs: centidegrees or −1. Buttons: 1/0. |
File: PadForge.Engine/Common/CustomInputHelper.cs
Namespace: PadForge.Engine
Static constants and utility methods for CustomInputState.
| Constant | Type | Value | Description |
|---|---|---|---|
MaxAxis |
int |
24 | Mirrors CustomInputState.MaxAxis
|
MaxSliders |
int |
8 | Mirrors CustomInputState.MaxSliders
|
MaxPovs |
int |
4 | Mirrors CustomInputState.MaxPovs
|
MaxButtons |
int |
256 | Mirrors CustomInputState.MaxButtons
|
AxisCenter |
int |
32767 | Unsigned axis center value |
AxisMin |
int |
0 | Unsigned axis minimum |
AxisMax |
int |
65535 | Unsigned axis maximum |
PovCentered |
int |
-1 | POV centered value (no direction pressed) |
| Method | Signature | Description |
|---|---|---|
GetUpdates |
static CustomInputUpdate[] GetUpdates(CustomInputState oldState, CustomInputState newState) |
Returns all differences between two states (axes, sliders, POVs, buttons). Null states treated as all-zero. Empty array if unchanged. |
File: PadForge.Engine/Common/ISdlInputDevice.cs
Namespace: PadForge.Engine
Common interface for all SDL-based input device wrappers (joystick/gamepad, keyboard, mouse, web controller). Lets the pipeline (Steps 2–5) read state from any device type uniformly.
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();
}| Property | Type | Description |
|---|---|---|
SdlInstanceId |
uint |
SDL instance ID (unique per connection session; 0 = invalid) |
Name |
string |
Human-readable device name |
InstanceGuid |
Guid |
Deterministic GUID for settings matching (from path/serial/VID+PID) |
ProductGuid |
Guid |
Product GUID from VID/PID for device family identification |
DevicePath |
string |
Device path (may be empty) |
SerialNumber |
string |
Serial number, e.g., Bluetooth MAC (may be empty) |
VendorId |
ushort |
USB Vendor ID |
ProductId |
ushort |
USB Product ID |
NumAxes |
int |
Axis count (6 for gamepads) |
NumButtons |
int |
Button count (11 for gamepads) |
RawButtonCount |
int |
Raw joystick button count before gamepad remapping; may exceed NumButtons
|
NumHats |
int |
POV hat count (1 for gamepads) |
HasRumble |
bool |
Supports simple rumble |
HasHaptic |
bool |
Has an SDL haptic handle open |
HasGyro |
bool |
Has gyroscope sensor |
HasAccel |
bool |
Has accelerometer sensor |
IsAttached |
bool |
Handle still valid and connected |
HapticStrategy |
HapticEffectStrategy |
Best haptic strategy chosen at open time |
HapticHandle |
IntPtr |
SDL haptic handle (IntPtr.Zero if none) |
HapticFeatures |
uint |
Bitmask of SDL_HAPTIC_* flags |
NumHapticAxes |
int |
Haptic axes (1 = wheel, 2+ = joystick) |
| Method | Signature | Description |
|---|---|---|
GetCurrentState |
CustomInputState GetCurrentState(bool forceRaw = false) |
Reads input state. forceRaw=true bypasses gamepad remapping. |
GetDeviceObjects |
DeviceObjectItem[] GetDeviceObjects() |
Returns metadata for each axis, hat, and button. |
GetInputDeviceType |
int GetInputDeviceType() |
Returns an InputDeviceType constant. |
SetRumble |
bool SetRumble(ushort low, ushort high, uint durationMs) |
Sends rumble. Default duration uint.MaxValue (~49 days). |
StopRumble |
bool StopRumble() |
Stops all rumble (SetRumble(0, 0, 0)). |
File: PadForge.Engine/Common/SdlDeviceWrapper.cs
Namespace: PadForge.Engine
Wraps an SDL joystick (and optionally its Gamepad overlay) for unified device access: open/close, state polling, rumble, GUID construction, and object enumeration. Implements ISdlInputDevice.
| Property | Type | Default | Description |
|---|---|---|---|
Joystick |
IntPtr |
IntPtr.Zero |
Raw SDL joystick handle. Always valid when open. |
GameController |
IntPtr |
IntPtr.Zero |
SDL Gamepad handle. Zero if not a gamepad. |
Haptic |
IntPtr |
IntPtr.Zero |
SDL haptic handle. Non-zero when haptic FFB available. |
ProductVersion |
ushort |
0 | USB Product Version |
JoystickType |
SDL_JoystickType |
UNKNOWN |
SDL joystick type classification |
IsGameController |
bool |
(computed) |
true if opened as an SDL Gamepad |
| Method | Signature | Description |
|---|---|---|
Open |
bool Open(uint instanceId) |
Opens SDL device. Tries Gamepad first, falls back to Joystick. Populates all properties. |
GetCurrentState |
CustomInputState GetCurrentState(bool forceRaw = false) |
Routes to GetGamepadState() (remapped) or GetJoystickState() (raw) based on device type and forceRaw. |
GetDeviceObjects |
DeviceObjectItem[] GetDeviceObjects() |
Builds DeviceObjectItem[] for each axis, hat, button. First 6 axes use standard GUIDs; extras use Slider. |
GetInputDeviceType |
int GetInputDeviceType() |
Maps SDL_JoystickType to InputDeviceType. |
SetRumble |
bool SetRumble(ushort lowFreq, ushort highFreq, uint durationMs) |
Sends rumble via SDL_RumbleJoystick. false if unsupported. |
StopRumble |
bool StopRumble() |
SetRumble(0, 0, 0). |
| Method | Signature | Description |
|---|---|---|
BuildProductGuid |
static Guid BuildProductGuid(ushort vid, ushort pid) |
Synthetic GUID from VID+PID. bytes[0–1]=VID LE, [2–3]=PID LE, [4–15]=0x00. |
BuildInstanceGuid |
static Guid BuildInstanceGuid(string devicePath, ushort vid, ushort pid, uint instanceId, string serial = null) |
Deterministic GUID via MD5. Priority: VID+PID+Serial (stable), device path (wired), VID+PID+SDL ID (session-only). |
HatToCentidegrees |
static int HatToCentidegrees(byte hat) |
SDL hat bitmask to centidegrees (−1 for centered). |
DpadToCentidegrees |
static int DpadToCentidegrees(bool up, bool down, bool left, bool right) |
4 D-pad booleans to centidegrees (supports 8-way diagonals). |
GetGamepadState() reads through SDL's gamecontrollerdb mapping layer, producing a standardized layout:
| Output | Indices |
|---|---|
| Axes | [0]=LX, [1]=LY, [2]=LT, [3]=RX, [4]=RY, [5]=RT |
| Buttons | [0]=A, [1]=B, [2]=X, [3]=Y, [4]=LB, [5]=RB, [6]=Back, [7]=Start, [8]=LS, [9]=RS, [10]=Guide |
| POV[0] | Synthesized from gamepad D-pad buttons |
| Sensors | Gyro and Accel populated if available |
Guide suppression: When Back+Start+Guide are all pressed, Guide is suppressed (Windows/XInput synthesizes Guide from this combo).
Extra raw buttons: Raw joystick buttons beyond index 10 are appended (e.g., DualSense touchpad click), excluding indices consumed by the gamepad mapping (ParseMappedButtonIndices()).
GetJoystickState() reads raw joystick input (no gamepad remapping):
-
Axes: SDL signed (−32768..32767) converted to unsigned (0..65535) via
- short.MinValue. FirstMaxAxisgo toAxis[], overflow toSliders[]. -
Hats: SDL bitmask to centidegrees via
HatToCentidegrees. -
Buttons: Uses
RawButtonCount(notNumButtons) for full raw coverage.
SDL3 may return a raw VID/PID string (e.g., "0x16c0/0x05e1") for unknown devices. IsRawVidPidName() detects this; TryGetHidProductString() queries the HID product string via CreateFile + HidD_GetProductString P/Invoke.
OpenHaptic() opens SDL_OpenHapticFromJoystick and selects the best strategy:
- LeftRight — best for dual-motor
- Sine — periodic fallback
- Constant — last resort
Devices with both simple rumble and LeftRight haptic prefer simple rumble (more reliable for gamepads). Gain set to 100 if SDL_HAPTIC_GAIN is supported.
File: PadForge.Engine/Common/SdlDeviceWrapper.cs
Namespace: PadForge.Engine
public enum HapticEffectStrategy
{
None, // No haptic support
LeftRight, // Best: SDL_HAPTIC_LEFTRIGHT (dual-motor)
Sine, // Periodic effect (period varies by motor)
Constant // Fallback: constant level from dominant motor
}File: PadForge.Engine/Common/SdlKeyboardWrapper.cs
Namespace: PadForge.Engine
Wraps a keyboard device for unified input via ISdlInputDevice. State read from Raw Input (per-device) via RawInputListener.
| Property | Type | Value/Description |
|---|---|---|
NumAxes |
int |
0 |
NumButtons |
int |
Up to 256 (min of 256 and MaxButtons) |
RawButtonCount |
int |
0 |
NumHats |
int |
0 |
HasRumble |
bool |
false |
HasHaptic |
bool |
false |
HasGyro |
bool |
false |
HasAccel |
bool |
false |
RawInputHandle |
IntPtr |
The Raw Input device handle for per-device state reading |
| Method | Signature | Description |
|---|---|---|
Open |
bool Open(RawInputListener.DeviceInfo deviceInfo) |
Opens from Raw Input enumeration. Builds GUID from device path; path hash as pseudo SDL instance ID. |
GetCurrentState |
CustomInputState GetCurrentState(bool forceRaw) |
Reads from RawInputListener.GetKeyboardState, merges hooked state via InputHookManager.MergeHookedKeyState (suppressed keys bypass Raw Input). |
GetDeviceObjects |
DeviceObjectItem[] |
256 button items with ObjectGuid.Key GUIDs. Names from SDL.VirtualKeyName. |
GetInputDeviceType |
int |
InputDeviceType.Keyboard (19). |
SetRumble / StopRumble
|
Always false. |
File: PadForge.Engine/Common/SdlMouseWrapper.cs
Namespace: PadForge.Engine
Wraps a mouse device for unified input via ISdlInputDevice. State read from Raw Input (per-device) via RawInputListener.
| Constant | Value | Description |
|---|---|---|
MouseButtons |
5 | Left, Middle, Right, X1, X2 |
MouseAxes |
3 | X Motion, Y Motion, Scroll |
AxisCenter |
32767 | Center value for mouse axis output |
MotionScale |
2048f | Multiplier for mouse delta to axis value |
ScrollScale |
128f | Multiplier for scroll delta to axis value |
| Property | Type | Value/Description |
|---|---|---|
NumAxes |
int |
3 (X Motion, Y Motion, Scroll) |
NumButtons |
int |
5 (Left, Middle, Right, X1, X2) |
RawButtonCount |
int |
0 |
NumHats |
int |
0 |
HasRumble |
bool |
false |
RawInputHandle |
IntPtr |
The Raw Input device handle |
| Method | Signature | Description |
|---|---|---|
Open |
bool Open(RawInputListener.DeviceInfo deviceInfo) |
Opens from Raw Input enumeration. |
GetCurrentState |
CustomInputState GetCurrentState(bool forceRaw) |
Reads deltas via ConsumeMouseDelta, scroll via ConsumeMouseScroll, buttons via GetMouseButtons + MergeHookedMouseState. Axes = AxisCenter + (delta * Scale) clamped to 0–65535. |
GetDeviceObjects |
DeviceObjectItem[] |
3 RelativeAxis (X, Y, Scroll) + 5 PushButton (L, M, R, X1, X2). |
GetInputDeviceType |
int |
InputDeviceType.Mouse (18). |
File: PadForge.Engine/Common/WebControllerDevice.cs
Namespace: PadForge.Engine
Virtual input device for a browser-connected gamepad. Implements ISdlInputDevice for standard pipeline integration. State written by WebSocket thread, read by polling thread via volatile reference swaps.
| Constant | Value | Description |
|---|---|---|
WebVendorId |
0xBEEF |
Distinctive VID to avoid ViGEm filter false positives |
WebProductId |
0xCA7E |
Distinctive PID |
WebProductGuid |
{BEBC0000-...} |
Fixed ProductGuid for all web controller instances |
| Property | Value |
|---|---|
| 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) |
| HasHaptic | false |
| HasGyro | false |
| HasAccel | false |
public WebControllerDevice(string clientId, string displayName)Creates a web controller. clientId is a unique browser localStorage identifier. InstanceGuid derived from client ID via MD5. SdlInstanceId is the client ID hash code. Stick axes init to center (32767), trigger axes to 0.
| Event | Signature | Description |
|---|---|---|
RumbleRequested |
Action<ushort, ushort> |
Fired on SetRumble. Parameters: (lowFreq, highFreq), 0–65535. |
| Method | Signature | Description |
|---|---|---|
UpdateAxis |
void UpdateAxis(int code, int value) |
Sets axis (0=LX, 1=LY, 2=LT, 3=RX, 4=RY, 5=RT). Thread-safe. |
UpdateButton |
void UpdateButton(int code, bool pressed) |
Sets button (0=A through 10=Guide). Thread-safe. |
UpdatePov |
void UpdatePov(int value) |
Sets POV hat (centidegrees or −1). Thread-safe. |
SetConnected |
void SetConnected(bool connected) |
Sets connection state (volatile write). |
File: PadForge.Engine/Common/DeviceObjectItem.cs
Namespace: PadForge.Engine
Describes a single input object (axis, button, hat, slider) on a device. Used by mapping UI and pipeline.
public class DeviceObjectItem
{
// Identity
public string Name { get; set; } // Default: ""
public Guid ObjectTypeGuid { get; set; } // Default: Guid.Empty
public DeviceObjectTypeFlags ObjectType { get; set; } // Default: All
// Position
public int InputIndex { get; set; } // Default: 0
public int Offset { get; set; } // Default: 0
// Aspect
public ObjectAspect Aspect { get; set; } // Default: Position
// Computed helpers (read-only)
public bool IsForceActuator { get; }
public bool IsAxis { get; }
public bool IsButton { get; }
public bool IsPov { get; }
public bool IsSlider { get; }
public override string ToString(); // "{Name} ({TypeLabel}, Index {InputIndex})"
}| Property | Type | Default | Description |
|---|---|---|---|
Name |
string |
"" |
Display 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 (synthetic for SDL, mapping compatibility) |
Aspect |
ObjectAspect |
Position |
Object aspect |
| Property | Logic |
|---|---|
IsForceActuator |
(ObjectType & ForceFeedbackActuator) != 0 |
IsAxis |
(ObjectType & Axis) != 0 |
IsButton |
(ObjectType & Button) != 0 |
IsPov |
(ObjectType & PointOfViewController) != 0 |
IsSlider |
ObjectTypeGuid == ObjectGuid.Slider |
File: PadForge.Engine/Common/DeviceEffectItem.cs
Namespace: PadForge.Engine
Describes a force feedback effect supported by a device. Under SDL3, rumble is the primary type. Kept for UI display and settings compatibility.
| Field | GUID | Description |
|---|---|---|
ConstantForce |
{13541C20-8E33-11D0-9AD0-00A0C9A06E35} |
GUID_ConstantForce (DirectInput) |
Square |
{13541C22-...} |
GUID_Square |
Sine |
{13541C23-...} |
GUID_Sine |
Triangle |
{13541C24-...} |
GUID_Triangle |
Spring |
{13541C27-...} |
GUID_Spring |
Damper |
{13541C28-...} |
GUID_Damper |
SdlRumble |
{53444C52-554D-424C-...} |
Synthetic GUID for SDL rumble ("SDLRUMBL") |
| Property | Type | Default | Description |
|---|---|---|---|
EffectGuid |
Guid |
Guid.Empty |
GUID identifying the effect type |
Name |
string |
"" |
Human-readable name (e.g., "Constant Force", "Rumble") |
Parameters |
EffectParameterFlags |
None |
Which parameters the effect supports |
| Method | Signature | Description |
|---|---|---|
CreateRumbleEffect |
static DeviceEffectItem CreateRumbleEffect() |
Creates an SDL rumble item (SdlRumble GUID, name "Rumble"). |
File: PadForge.Engine/Common/InputTypes.cs
Namespace: PadForge.Engine
[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
}Well-known GUIDs for device object types, matching DirectInput GUID constants.
| Field | GUID | Description |
|---|---|---|
XAxis |
{A36D02E0-C9F3-11CF-BFC7-444553540000} |
GUID_XAxis |
YAxis |
{A36D02E1-C9F3-11CF-BFC7-444553540000} |
GUID_YAxis |
ZAxis |
{A36D02E2-C9F3-11CF-BFC7-444553540000} |
GUID_ZAxis |
RxAxis |
{A36D02F4-C9F3-11CF-BFC7-444553540000} |
GUID_RxAxis |
RyAxis |
{A36D02F5-C9F3-11CF-BFC7-444553540000} |
GUID_RyAxis |
RzAxis |
{A36D02E3-C9F3-11CF-BFC7-444553540000} |
GUID_RzAxis |
Slider |
{A36D02E4-C9F3-11CF-BFC7-444553540000} |
GUID_Slider |
Button |
{A36D02F0-C9F3-11CF-BFC7-444553540000} |
GUID_Button |
Key |
{55728220-D33C-11CF-BFC7-444553540000} |
GUID_Key |
PovController |
{A36D02F2-C9F3-11CF-BFC7-444553540000} |
GUID_POV |
Unknown |
Guid.Empty |
GUID_Unknown |
Integer constants matching DirectInput device type values. Used in UserDevice.CapType.
| Constant | Value | Description |
|---|---|---|
Device |
17 | Generic device |
Mouse |
18 | Mouse |
Keyboard |
19 | Keyboard |
Joystick |
20 | Joystick |
Gamepad |
21 | Gamepad |
Driving |
22 | Steering wheel |
Flight |
23 | Flight stick |
FirstPerson |
24 | First-person device |
Supplemental |
25 | Supplemental device (guitar, drum, dance pad) |
public enum MapType : int
{
None = 0,
Axis = 1,
Button = 2,
Slider = 3,
POV = 4
}File: PadForge.Engine/Common/ForceFeedbackState.cs
Namespace: PadForge.Engine
Per-device force feedback (rumble) state with change detection. Only sends to hardware when motor values differ. Uses uint.MaxValue duration (~49 days) to mimic XInput's "set and forget" model.
| Property | Type | Description |
|---|---|---|
LeftMotorSpeed |
ushort |
Last sent left (low-freq) motor speed, 0–65535. Read-only. |
RightMotorSpeed |
ushort |
Last sent right (high-freq) motor speed, 0–65535. Read-only. |
IsActive |
bool |
Whether FFB is active on the device. Read-only. |
| Field | Type | Description |
|---|---|---|
_cachedLeftMotorSpeed |
ushort |
Last sent left motor speed |
_cachedRightMotorSpeed |
ushort |
Last sent right motor speed |
_hapticEffectId |
int |
SDL haptic effect ID (-1 = none) |
_hapticEffectCreated |
bool |
Whether a haptic effect has been created |
_cachedEffectType |
uint |
Last sent FFB effect type |
_cachedSignedMag |
short |
Last sent signed magnitude |
_cachedDirection |
ushort |
Last sent polar direction |
_cachedPeriod |
uint |
Last sent period |
_cachedHasCondition |
bool |
Last sent condition data flag |
_cachedHasDirectional |
bool |
Last sent directional data flag |
| Method | Signature | Description |
|---|---|---|
SetDeviceForces |
void SetDeviceForces(UserDevice ud, ISdlInputDevice device, PadSetting ps, Vibration v) |
Main entry. Reads gain from PadSetting. Routes to directional haptic when HasDirectionalData or HasConditionData and device supports haptic, or scalar rumble otherwise. Only sends when values change. |
StopDeviceForces |
void StopDeviceForces(ISdlInputDevice device) |
Stops all rumble/haptic and resets cached state. |
| Method | Description |
|---|---|
SetDirectionalHapticForces(device, v, overallGain) |
Directional constant/periodic force. Single-axis (wheels): projects via sin(angle). Multi-axis: full 2D polar. Falls back to scalar if unsupported. |
SetConditionHapticForces(device, v, overallGain) |
Condition effects (spring/damper/friction/inertia) with per-axis coefficients. Scales HID (−10000..+10000) to SDL (−32767..+32767). |
SetHapticForces(device, left, right) |
Scalar haptic fallback. Translates dual-motor to SDL effect per HapticEffectStrategy. |
ApplyHapticEffect(device, ref effect) |
Creates on first call, updates in-place after. Avoids create/destroy churn. |
StopAndDestroyHapticEffect(device) |
Stops and destroys active haptic effect. Resets effect state. |
| 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 |
File: PadForge.Engine/Common/ForceFeedbackState.cs
Namespace: PadForge.Engine
FFB effect type constants matching vJoy FFBEType enum. Defined in Engine so both Engine and App can reference them.
| Constant | Value | Description |
|---|---|---|
None |
0 | No effect |
Const |
1 | Constant force |
Ramp |
2 | Ramp force |
Square |
3 | Square wave periodic |
Sine |
4 | Sine wave periodic |
Triangle |
5 | Triangle wave periodic |
SawUp |
6 | Sawtooth up periodic |
SawDown |
7 | Sawtooth down periodic |
Spring |
8 | Spring condition |
Damper |
9 | Damper condition |
Inertia |
10 | Inertia condition |
Friction |
11 | Friction condition |
File: PadForge.Engine/Common/ForceFeedbackState.cs
Namespace: PadForge.Engine
Vibration/FFB state for a virtual controller slot. Carries scalar motor speeds (rumble) and directional FFB data (haptic joysticks/wheels).
public class Vibration
{
// Scalar fields (ViGEm Xbox/DS4 callbacks and rumble path)
public ushort LeftMotorSpeed { get; set; } // 0-65535, low-frequency heavy rumble
public ushort RightMotorSpeed { get; set; } // 0-65535, high-frequency light buzz
// Directional FFB fields (vJoy FFB callback for haptic devices)
public bool HasDirectionalData { get; set; }
public uint EffectType { get; set; } // FfbEffectTypes constant
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, device-level gain
// Condition effect fields (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
// Constructors
public Vibration();
public Vibration(ushort leftMotor, ushort rightMotor);
}| Field | Type | Default | Description |
|---|---|---|---|
LeftMotorSpeed |
ushort |
0 | Left (low-freq) motor speed. Set by ViGEm callbacks. |
RightMotorSpeed |
ushort |
0 | Right (high-freq) motor speed. Set by ViGEm callbacks. |
HasDirectionalData |
bool |
false |
Directional FFB data available (vJoy path) |
EffectType |
uint |
0 |
FfbEffectTypes constant |
SignedMagnitude |
short |
0 | −10000 to +10000. Negative = opposite direction. |
Direction |
ushort |
0 | Polar HID units 0–32767 (0=N, ~8192=E, ~16384=S, ~24576=W) |
Period |
uint |
0 | Period in ms (periodic effects) |
DeviceGain |
byte |
255 | Device-level gain 0–255, on top of per-effect gain |
HasConditionData |
bool |
false |
Per-axis condition data available |
ConditionAxes |
ConditionAxisData[] |
null |
Per-axis coefficients (0=X, 1=Y) |
ConditionAxisCount |
int |
0 | Valid entries (1 = wheel, 2 = joystick) |
File: PadForge.Engine/Common/ForceFeedbackState.cs
Namespace: PadForge.Engine
Per-axis condition parameters for spring/damper/friction/inertia effects.
public struct ConditionAxisData
{
public short PositiveCoefficient; // 0–10000, force when displacement > center
public short NegativeCoefficient; // 0–10000, force when displacement < center
public short Offset; // -10000 to +10000, center offset
public uint DeadBand; // 0–10000, dead band around center
public uint PositiveSaturation; // 0–10000
public uint NegativeSaturation; // 0–10000
}File: PadForge.Engine/Common/RumbleLogger.cs
Namespace: PadForge.Engine
Diagnostic logger for FFB debugging. Disabled by default. Thread-safe.
public static class RumbleLogger
{
public static bool Enabled { get; set; } // Default: false
public static void Log(string message);
public static void Close();
}| Member | Description |
|---|---|
Enabled |
Set true in InputService.Start() to activate. |
Log(string) |
Writes timestamped message to rumble_log.txt beside the executable. Stopwatch timing, lock for thread safety. Creates file on first call. |
Close() |
Closes the log StreamWriter. Call on shutdown. |
File: PadForge.Engine/Common/InputHookManager.cs
Namespace: PadForge.Engine.Common
Manages WH_KEYBOARD_LL and WH_MOUSE_LL low-level hooks to suppress mapped keyboard/mouse inputs. Only suppresses inputs in the active suppression sets.
public class InputHookManager : IDisposable
{
void Start();
void Stop();
void SetSuppressedKeys(HashSet<int> vkCodes);
void SetSuppressedMouseButtons(HashSet<int> buttons);
bool HasAnySuppression { get; }
static void MergeHookedKeyState(bool[] dest, int count);
static void MergeHookedMouseState(bool[] dest, int count);
}| Method | Signature | Description |
|---|---|---|
Start |
void Start() |
Creates background thread with GetMessage loop, installs both hooks. Blocks until installed (5s timeout). |
Stop |
void Stop() |
Posts WM_QUIT to hook thread, joins (2s timeout), clears state. |
SetSuppressedKeys |
void SetSuppressedKeys(HashSet<int> vkCodes) |
Updates VK codes to suppress. Clears state for removed keys. Volatile reference swap. |
SetSuppressedMouseButtons |
void SetSuppressedMouseButtons(HashSet<int> buttons) |
Updates mouse button IDs to suppress (0=L, 1=R, 2=M, 3=X1, 4=X2). Volatile reference swap. |
HasAnySuppression |
bool (property) |
true if any keys or mouse buttons suppressed. |
MergeHookedKeyState |
static void MergeHookedKeyState(bool[] dest, int count) |
Merges suppressed-key state into dest (hook state is authoritative). Called by SdlKeyboardWrapper. |
MergeHookedMouseState |
static void MergeHookedMouseState(bool[] dest, int count) |
Same for mouse buttons. Called by SdlMouseWrapper. |
-
Keyboard: Intercepts
WM_KEYDOWN/UP,WM_SYSKEYDOWN/UP. Returns(IntPtr)1to suppress,CallNextHookExto pass through. Captures state into_hookedKeyState[]before suppressing (LL hook runs beforeWM_INPUT). -
Mouse: Intercepts button messages (
WM_[LR/M/X]BUTTONDOWN/UP). Converts viaMouseMessageToButtonId(). Captures into_hookedMouseState[].
| 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
Namespace: PadForge.Engine
Receives keyboard and mouse input via Windows Raw Input API, even when unfocused (RIDEV_INPUTSINK). Creates a hidden message-only window (HWND_MESSAGE) on a background thread. State tracked per-device via RAWINPUT.header.hDevice for multi-device isolation.
public struct DeviceInfo
{
public IntPtr Handle; // Raw Input device handle
public string Name; // Device display name
public string DevicePath; // Device interface path
public ushort VendorId; // USB VID
public ushort ProductId; // USB PID
}| Field | Type | Description |
|---|---|---|
AggregateKeyboardHandle |
IntPtr |
Sentinel new IntPtr(-99). Aggregates all keyboards. |
AggregateMouseHandle |
IntPtr |
Sentinel new IntPtr(-98). Aggregates all mice. |
| Method | Signature | Description |
|---|---|---|
Start |
static void Start() |
Creates message-pump thread, registers Raw Input. Blocks until window created. |
Stop |
static void Stop() |
Posts WM_QUIT, joins thread. |
EnumerateKeyboards |
static DeviceInfo[] EnumerateKeyboards() |
All connected keyboards via GetRawInputDeviceList. |
EnumerateMice |
static DeviceInfo[] EnumerateMice() |
All connected mice. |
GetKeyboardState |
static void GetKeyboardState(IntPtr hDevice, bool[] dest, int count) |
Copies per-device key states. Aggregate handle for combined output. |
ConsumeMouseDelta |
static void ConsumeMouseDelta(IntPtr hDevice, out int dx, out int dy) |
Returns and resets accumulated mouse delta. |
ConsumeMouseScroll |
static int ConsumeMouseScroll(IntPtr hDevice) |
Returns and resets scroll delta. |
GetMouseButtons |
static void GetMouseButtons(IntPtr hDevice, bool[] dest) |
Copies per-device button states (5: L, M, R, X1, X2). |
-
Keyboard (
RIM_TYPEKEYBOARD): ReadsRAWKEYBOARD.VKey, handlesRI_KEY_E0extended keys (right Ctrl/Alt/Shift, NumLock, Insert, Home, etc.). Per-device state inConcurrentDictionary<IntPtr, bool[]>. -
Mouse (
RIM_TYPEMOUSE): AccumulateslLastX/lLastYdeltas. Tracks buttons viausButtonFlags. Scroll viaRI_MOUSE_WHEEL. -
Scroll:
usButtonDatais a signedshort. Accumulated per-device, consumed byConsumeMouseScroll.
File: PadForge.Engine/Data/PadSetting.cs
Namespace: PadForge.Engine.Data
Complete mapping configuration for a device-to-slot assignment. All mapping properties are string descriptors: "Button N", "Axis N", "IHAxis N", "POV N Dir", "Slider N", or "" (unmapped). Declared partial.
Stored separately from UserSettings, linked via PadSettingChecksum. Multiple UserSettings can share one PadSetting. Numeric settings stored as strings for XML consistency.
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
PadSettingChecksum |
string |
[XmlElement] |
"" |
Checksum from all mapping/setting properties. Links to UserSettings. |
| Property | Type | Serialization | Default |
|---|---|---|---|
ButtonA |
string |
[XmlElement] |
"" |
ButtonB |
string |
[XmlElement] |
"" |
ButtonX |
string |
[XmlElement] |
"" |
ButtonY |
string |
[XmlElement] |
"" |
LeftShoulder |
string |
[XmlElement] |
"" |
RightShoulder |
string |
[XmlElement] |
"" |
ButtonBack |
string |
[XmlElement] |
"" |
ButtonStart |
string |
[XmlElement] |
"" |
ButtonGuide |
string |
[XmlElement] |
"" |
LeftThumbButton |
string |
[XmlElement] |
"" |
RightThumbButton |
string |
[XmlElement] |
"" |
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
DPad |
string |
[XmlElement] |
"" |
Combined D-Pad mapping. POV descriptor auto-extracts all 4 directions. Individual overrides take priority. |
DPadUp |
string |
[XmlElement] |
"" |
|
DPadDown |
string |
[XmlElement] |
"" |
|
DPadLeft |
string |
[XmlElement] |
"" |
|
DPadRight |
string |
[XmlElement] |
"" |
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
LeftTrigger |
string |
[XmlElement] |
"" |
Mapping descriptor |
RightTrigger |
string |
[XmlElement] |
"" |
Mapping descriptor |
LeftTriggerDeadZone |
string |
[XmlElement] |
"0" |
0–100% |
RightTriggerDeadZone |
string |
[XmlElement] |
"0" |
0–100% |
LeftTriggerAntiDeadZone |
string |
[XmlElement] |
"0" |
0–100% |
RightTriggerAntiDeadZone |
string |
[XmlElement] |
"0" |
0–100% |
LeftTriggerMaxRange |
string |
[XmlElement] |
"100" |
1–100% |
RightTriggerMaxRange |
string |
[XmlElement] |
"100" |
1–100% |
LeftTriggerSensitivityCurve |
string |
[XmlElement] |
"0" |
−100 to 100 (0=linear, +100=exp, −100=log) |
RightTriggerSensitivityCurve |
string |
[XmlElement] |
"0" |
−100 to 100 |
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
LeftThumbAxisX |
string |
[XmlElement] |
"" |
|
LeftThumbAxisY |
string |
[XmlElement] |
"" |
|
RightThumbAxisX |
string |
[XmlElement] |
"" |
|
RightThumbAxisY |
string |
[XmlElement] |
"" |
|
LeftThumbAxisXNeg |
string |
[XmlElement] |
"" |
Negative direction (buttons mapped to bidirectional axes) |
LeftThumbAxisYNeg |
string |
[XmlElement] |
"" |
|
RightThumbAxisXNeg |
string |
[XmlElement] |
"" |
|
RightThumbAxisYNeg |
string |
[XmlElement] |
"" |
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
LeftThumbDeadZoneX |
string |
[XmlElement] |
"0" |
Left stick dead zone X (0–100%) |
LeftThumbDeadZoneY |
string |
[XmlElement] |
"0" |
Left stick dead zone Y |
RightThumbDeadZoneX |
string |
[XmlElement] |
"0" |
Right stick dead zone X |
RightThumbDeadZoneY |
string |
[XmlElement] |
"0" |
Right stick dead zone Y |
LeftThumbDeadZoneShape |
string |
[XmlElement] |
"2" |
DeadZoneShape enum value. 2 = ScaledRadial. |
RightThumbDeadZoneShape |
string |
[XmlElement] |
"2" |
DeadZoneShape enum value |
LeftThumbAntiDeadZone |
string |
[XmlElement] |
"0" |
Legacy unified (0–100%). Prefer per-axis X/Y. |
RightThumbAntiDeadZone |
string |
[XmlElement] |
"0" |
Legacy unified |
LeftThumbAntiDeadZoneX |
string |
[XmlElement] |
"0" |
Left stick anti-dead zone X (0–100%) |
LeftThumbAntiDeadZoneY |
string |
[XmlElement] |
"0" |
Left stick anti-dead zone Y |
RightThumbAntiDeadZoneX |
string |
[XmlElement] |
"0" |
Right stick anti-dead zone X |
RightThumbAntiDeadZoneY |
string |
[XmlElement] |
"0" |
Right stick anti-dead zone Y |
LeftThumbLinear |
string |
[XmlElement] |
"0" |
Response curve (0–100%). 0=default, 100=fully linear. |
RightThumbLinear |
string |
[XmlElement] |
"0" |
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
LeftThumbSensitivityCurveX |
string |
[XmlElement] |
"0" |
−100 to 100 (0=linear, +100=exp, −100=log) |
LeftThumbSensitivityCurveY |
string |
[XmlElement] |
"0" |
|
RightThumbSensitivityCurveX |
string |
[XmlElement] |
"0" |
|
RightThumbSensitivityCurveY |
string |
[XmlElement] |
"0" |
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
LeftThumbMaxRangeX |
string |
[XmlElement] |
"100" |
Left stick X max range (1–100%). Symmetric/positive direction. |
LeftThumbMaxRangeY |
string |
[XmlElement] |
"100" |
|
RightThumbMaxRangeX |
string |
[XmlElement] |
"100" |
|
RightThumbMaxRangeY |
string |
[XmlElement] |
"100" |
|
LeftThumbMaxRangeXNeg |
string |
[XmlElement] |
null |
Left stick X negative (left). Null = inherit symmetric. |
LeftThumbMaxRangeYNeg |
string |
[XmlElement] |
null |
Left stick Y negative (down) direction |
RightThumbMaxRangeXNeg |
string |
[XmlElement] |
null |
|
RightThumbMaxRangeYNeg |
string |
[XmlElement] |
null |
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
LeftThumbCenterOffsetX |
string |
[XmlElement] |
"0" |
−100 to 100%. Corrects stick drift before dead zone. |
LeftThumbCenterOffsetY |
string |
[XmlElement] |
"0" |
|
RightThumbCenterOffsetX |
string |
[XmlElement] |
"0" |
|
RightThumbCenterOffsetY |
string |
[XmlElement] |
"0" |
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
ForceType |
string |
[XmlElement] |
"1" |
0=Off, 1=SDL Rumble |
ForceOverall |
string |
[XmlElement] |
"100" |
Overall strength 0–100%. Multiplier for both motors. |
ForceSwapMotor |
string |
[XmlElement] |
"0" |
"0"=no swap, "1"=swap left/right motors |
LeftMotorStrength |
string |
[XmlElement] |
"100" |
Left (low-freq) motor strength 0–100% |
RightMotorStrength |
string |
[XmlElement] |
"100" |
Right (high-freq) motor strength 0–100% |
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
AudioRumbleEnabled |
string |
[XmlElement] |
"0" |
Enable audio bass rumble. "0"=off, "1"=on. |
AudioRumbleSensitivity |
string |
[XmlElement] |
"4" |
Bass detection sensitivity (1–20) |
AudioRumbleCutoffHz |
string |
[XmlElement] |
"80" |
Low-pass cutoff Hz (40–200) |
AudioRumbleLeftMotor |
string |
[XmlElement] |
"100" |
Left motor strength for audio rumble (0–100%) |
AudioRumbleRightMotor |
string |
[XmlElement] |
"100" |
Right motor strength for audio rumble (0–100%) |
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
AxisToButtonThreshold |
string |
[XmlElement] |
"50" |
Threshold 0–100% for axis-as-button |
MappingDeadZoneEntries |
VJoyMappingEntry[] |
[XmlArray("MappingDeadZones")] [XmlArrayItem("Map")] |
null |
Per-mapping axis-to-button thresholds. Keys = target names, values = 0–100%. |
LeftThumbAxisXInvert |
string |
[XmlElement] |
"0" |
Invert left stick X. "0" or "1". |
LeftThumbAxisYInvert |
string |
[XmlElement] |
"0" |
|
RightThumbAxisXInvert |
string |
[XmlElement] |
"0" |
|
RightThumbAxisYInvert |
string |
[XmlElement] |
"0" |
For custom vJoy with arbitrary axis/button/POV counts. Keys: "VJoyAxis0", "VJoyAxis0Neg", "VJoyBtn0", "VJoyPov0Up". Values: mapping descriptors.
| Property | Type | Serialization | Description |
|---|---|---|---|
VJoyMappingEntries |
VJoyMappingEntry[] |
[XmlArray("VJoyMappings")] [XmlArrayItem("Map")] |
Serializable array for XML persistence |
| Method | Signature | Description |
|---|---|---|
GetVJoyMapping |
string GetVJoyMapping(string key) |
Gets a vJoy mapping value by key. Returns "" if not found. |
SetVJoyMapping |
void SetVJoyMapping(string key, string value) |
Sets a vJoy mapping value. Empty/null removes the key. |
FlushVJoyMappings |
void FlushVJoyMappings() |
Flushes in-memory dictionary back to serializable array. |
Same pattern as vJoy. Keys: "MidiCC0", "MidiCC0Neg", "MidiNote0", etc.
| Property | Type | Serialization | Description |
|---|---|---|---|
MidiMappingEntries |
VJoyMappingEntry[] |
[XmlArray("MidiMappings")] [XmlArrayItem("Map")] |
Serializable array |
| Method | Signature | Description |
|---|---|---|
GetMidiMapping |
string GetMidiMapping(string key) |
Gets a MIDI mapping value. |
SetMidiMapping |
void SetMidiMapping(string key, string value) |
Sets a MIDI mapping value. |
FlushMidiMappings |
void FlushMidiMappings() |
Flushes dictionary to array. |
Keys: "KbmKey41" (VK_A), "KbmMouseX", "KbmMouseXNeg", "KbmMBtn0", "KbmScroll", etc.
| Property | Type | Serialization | Description |
|---|---|---|---|
KbmMappingEntries |
VJoyMappingEntry[] |
[XmlArray("KbmMappings")] [XmlArrayItem("Map")] |
Serializable array |
| Method | Signature | Description |
|---|---|---|
GetKbmMapping |
string GetKbmMapping(string key) |
Gets a KBM mapping value. |
SetKbmMapping |
void SetKbmMapping(string key, string value) |
Sets a KBM mapping value. |
FlushKbmMappings |
void FlushKbmMappings() |
Flushes dictionary to array. |
Same pattern as vJoy/MIDI/KBM mappings. Keys = target mapping names (e.g. "LeftThumbAxisX"), values = 0–100% threshold for axis-to-button activation. Default removal values: "0" or "50".
| Method | Signature | Description |
|---|---|---|
GetMappingDeadZone |
string GetMappingDeadZone(string key) |
Gets dead zone for a target. Returns "" if not found. |
SetMappingDeadZone |
void SetMappingDeadZone(string key, string value) |
Sets or removes a dead zone entry. Removes at "0" or "50". |
FlushMappingDeadZones |
void FlushMappingDeadZones() |
Syncs in-memory dictionary to MappingDeadZoneEntries array for serialization. |
| Property | Type | Serialization | Description |
|---|---|---|---|
HasAnyMapping |
bool |
[XmlIgnore] |
true if any mapping property has a non-empty descriptor. |
| Method | Signature | Description |
|---|---|---|
MigrateAntiDeadZones |
void MigrateAntiDeadZones() |
Migrates legacy unified anti-dead zone to per-axis X/Y. Call after deserialization. |
MigrateMaxRangeDirections |
void MigrateMaxRangeDirections() |
Copies symmetric max range to null/empty negative-direction properties. |
ComputeChecksum |
string ComputeChecksum() |
8-char hex checksum (first 4 bytes of MD5) from all properties. Keys sorted for determinism. |
UpdateChecksum |
void UpdateChecksum() |
Computes and stores checksum in PadSettingChecksum. |
ClearMappingDescriptors |
void ClearMappingDescriptors() |
Clears all mapping descriptors. Preserves dead zone and FFB settings. |
GetAllMappingDescriptors |
List<string> GetAllMappingDescriptors() |
All non-empty mapping descriptor strings. |
ToJson |
string ToJson(VirtualControllerType outputType, bool isCustomVJoy) |
JSON for clipboard. Embeds __OutputType, __IsCustomVJoy metadata and mapping arrays. |
FromJson |
static PadSetting FromJson(string json) |
Deserializes JSON. Returns null on invalid. |
FromJson |
static PadSetting FromJson(string json, out VirtualControllerType, out bool) |
Same, also extracts source layout metadata. |
CopyFrom |
void CopyFrom(PadSetting source) |
Copies all properties. Deep-copies mapping arrays. |
CopyFromTranslated |
void CopyFromTranslated(PadSetting source, VirtualControllerType srcType, bool srcCustom, VirtualControllerType tgtType, bool tgtCustom) |
Cross-layout copy via MappingTranslation. Translates mapping properties by canonical position. |
CloneDeep |
PadSetting CloneDeep() |
Deep copy including checksum. |
File: PadForge.Engine/Data/PadSetting.cs
Namespace: PadForge.Engine.Data
Key-value entry for vJoy/MIDI/KBM mapping XML persistence. Shared by all three dictionary-based systems.
public class VJoyMappingEntry
{
[XmlAttribute] public string Key { get; set; } = "";
[XmlAttribute] public string Value { get; set; } = "";
}File: PadForge.Engine/Data/UserSetting.cs
Namespace: PadForge.Engine.Data
Links a physical device to a virtual controller slot and mapping. One per device-to-slot assignment. Implements INotifyPropertyChanged.
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
InstanceGuid |
Guid |
[XmlElement] |
Physical device instance GUID | |
InstanceName |
string |
[XmlElement] |
"" |
Instance name (for offline display) |
ProductGuid |
Guid |
[XmlElement] |
Product GUID for matching across sessions | |
ProductName |
string |
[XmlElement] |
"" |
Product name |
MapTo |
int |
[XmlElement] |
-1 |
VC slot index (0–15). −1 = unmapped. Raises PropertyChanged. |
PadSettingChecksum |
string |
[XmlElement] |
"" |
Links to a PadSetting
|
IsEnabled |
bool |
[XmlElement] |
true |
Whether this mapping is enabled. Disabled = skipped in pipeline. |
DateCreated |
DateTime |
[XmlElement] |
DateTime.Now |
Creation timestamp |
DateUpdated |
DateTime |
[XmlElement] |
DateTime.Now |
Last modification timestamp |
| Property | Type | Serialization | Description |
|---|---|---|---|
OutputState |
Gamepad |
[XmlIgnore] |
Mapped output from Step 3. Written by background thread. |
RawMappedState |
Gamepad |
[XmlIgnore] |
Pre-processing state (axis-selected, Y-negated, before DZ/ADZ/linear/range). For UI preview. |
VJoyRawOutputState |
VJoyRawState |
[XmlIgnore] |
Mapped vJoy raw output for custom vJoy slots. |
MidiRawOutputState |
MidiRawState |
[XmlIgnore] |
Mapped MIDI raw output for MIDI slots. |
KbmRawOutputState |
KbmRawState |
[XmlIgnore] |
Mapped KBM raw output for KeyboardMouse slots. |
_cachedPadSetting |
PadSetting |
[XmlIgnore] (internal) |
Cached PadSetting reference set by SettingsManager. |
| Method | Signature | Description |
|---|---|---|
GetPadSetting |
PadSetting GetPadSetting() |
Returns cached PadSetting. |
SetPadSetting |
void SetPadSetting(PadSetting ps) |
Sets cached PadSetting. Called by SettingsManager on load/sync. |
File: PadForge.Engine/Data/UserDevice.cs
Namespace: PadForge.Engine.Data
Data model for a physical input device. Serializable properties (settings-persisted) and runtime-only fields (pipeline). Partial class. Implements INotifyPropertyChanged.
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
InstanceGuid |
Guid |
[XmlElement] |
Deterministic GUID from device path | |
InstanceName |
string |
[XmlElement] |
"" |
Instance name (e.g., "Xbox Controller") |
ProductGuid |
Guid |
[XmlElement] |
Product GUID (PIDVID format) | |
ProductName |
string |
[XmlElement] |
"" |
Product name |
VendorId |
ushort |
[XmlElement] |
0 | USB Vendor ID |
ProdId |
ushort |
[XmlElement] |
0 | USB Product ID |
DevRevision |
ushort |
[XmlElement] |
0 | USB Product Version / Revision |
DevicePath |
string |
[XmlElement] |
"" |
Device file system path |
SerialNumber |
string |
[XmlElement] |
"" |
Device serial number (e.g., Bluetooth MAC) |
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
CapAxeCount |
int |
[XmlElement] |
0 | Number of axes |
CapButtonCount |
int |
[XmlElement] |
0 | Button count (gamepad-mapped for gamepads) |
RawButtonCount |
int |
[XmlElement] |
0 | Raw button count before gamepad remapping |
CapPovCount |
int |
[XmlElement] |
0 | Number of POV hat switches |
CapType |
int |
[XmlElement] |
0 |
InputDeviceType constant |
HasGyro |
bool |
[XmlElement] |
false |
Gyroscope support |
HasAccel |
bool |
[XmlElement] |
false |
Accelerometer support |
| Property | Type | Serialization | Default | Description |
|---|---|---|---|---|
DateCreated |
DateTime |
[XmlElement] |
DateTime.Now |
First creation timestamp |
DateUpdated |
DateTime |
[XmlElement] |
DateTime.Now |
Last update timestamp |
IsEnabled |
bool |
[XmlElement] |
true |
Whether device is enabled for mapping |
IsHidden |
bool |
[XmlElement] |
false |
Whether device is hidden from UI |
DisplayName |
string |
[XmlElement] |
"" |
User-assigned name (overrides InstanceName) |
HidHideEnabled |
bool |
[XmlElement] |
false |
Hide device from games via HidHide when assigned |
ConsumeInputEnabled |
bool |
[XmlElement] |
false |
Suppress mapped KB/mouse inputs via hooks |
ForceRawJoystickMode |
bool |
[XmlElement] |
false |
Bypass SDL gamepad remapping |
HidHideInstanceIds |
List<string> |
[XmlArray] [XmlArrayItem("Id")] |
new() |
Cached HID instance IDs for HidHide (persisted for offline devices) |
| Property | Type | Serialization | Description |
|---|---|---|---|
Device |
ISdlInputDevice |
[XmlIgnore] |
Live device handle. Set in Step 1. |
IsOnline |
bool |
[XmlIgnore] |
Connected and opened. |
InputState |
CustomInputState |
[XmlIgnore] |
Current state snapshot (Step 2, atomic ref). |
InputUpdates |
CustomInputUpdate[] |
[XmlIgnore] |
Buffered changes since last poll. |
InputStateTime |
DateTime |
[XmlIgnore] |
Timestamp of InputState. |
OldInputState |
CustomInputState |
[XmlIgnore] |
Previous state for change detection. |
OldInputUpdates |
CustomInputUpdate[] |
[XmlIgnore] |
Previous buffered updates. |
OldInputStateTime |
DateTime |
[XmlIgnore] |
Timestamp of OldInputState. |
ActuatorCount |
int |
[XmlIgnore] |
FFB actuator axis count. |
DeviceObjects |
DeviceObjectItem[] |
serialized | Object metadata (Step 1). |
ForceFeedbackState |
ForceFeedbackState |
[XmlIgnore] |
Per-device FFB state. |
| Property | Type | Serialization | Description |
|---|---|---|---|
IsMouse |
bool |
[XmlIgnore] |
CapType == InputDeviceType.Mouse |
IsKeyboard |
bool |
[XmlIgnore] |
CapType == InputDeviceType.Keyboard |
HasForceFeedback |
bool |
[XmlIgnore] |
`ActuatorCount > 0 |
ResolvedName |
string |
[XmlIgnore] |
DisplayName if set, then InstanceName, then ProductName, then "(Unknown Device)" |
StatusText |
string |
[XmlIgnore] |
"Disabled", "Online", or "Offline" |
| Method | Signature | Description |
|---|---|---|
LoadInstance |
void LoadInstance(...) |
Sets identity properties. |
LoadCapabilities |
void LoadCapabilities(...) |
Sets capability properties. |
LoadFromSdlDevice |
void LoadFromSdlDevice(SdlDeviceWrapper) |
Loads from SDL wrapper + DevRevision. |
LoadFromKeyboardDevice |
void LoadFromKeyboardDevice(SdlKeyboardWrapper) |
Loads from keyboard wrapper. |
LoadFromMouseDevice |
void LoadFromMouseDevice(SdlMouseWrapper) |
Loads from mouse wrapper. |
LoadFromWebDevice |
void LoadFromWebDevice(WebControllerDevice) |
Loads from web controller. |
ClearRuntimeState |
void ClearRuntimeState() |
Clears runtime fields. Preserves serialized properties. |
NotifyStateChanged |
void NotifyStateChanged() |
Raises PropertyChanged for IsOnline, StatusText, InputState. |
ToString |
string |
Returns "{ResolvedName} [{InstanceGuid:N}]". |
File: PadForge.Engine/Data/DeadZoneShape.cs
Namespace: PadForge.Engine.Data
Dead zone algorithm for thumbstick axes.
public enum DeadZoneShape
{
Axial = 0, // Independent per-axis (square/cross shape). Legacy behavior.
Radial = 1, // Circular/elliptical magnitude check, no output rescaling.
ScaledRadial = 2, // Circular/elliptical with output rescaling (industry standard). DEFAULT.
SlopedAxial = 3, // Axis-dependent thresholds: DZ grows as other axis increases.
SlopedScaledAxial = 4, // Sloped axis-dependent with output rescaling.
Hybrid = 5, // Scaled Radial followed by Sloped Scaled Axial (best hybrid).
}File: PadForge.Engine/Data/MappingTranslation.cs
Namespace: PadForge.Engine.Data
Translates mapping property names between virtual controller layouts using positional equivalence.
public enum ControlCategory { Button, Axis, AxisNeg, DPad }
public record MappingSlot(ControlCategory Category, int Position);MappingSlot represents a canonical position (e.g., "3rd button", "1st axis negative"). Translation converts source property name to MappingSlot, then to the target layout's property name.
| Method | Signature | Description |
|---|---|---|
GetPosition |
static MappingSlot GetPosition(string propertyName, VirtualControllerType type, bool isCustomVJoy) |
Property name to canonical MappingSlot
|
GetPropertyName |
static string GetPropertyName(MappingSlot slot, VirtualControllerType type, bool isCustomVJoy) |
Canonical MappingSlot to property name |
IsSameLayout |
static bool IsSameLayout(...) |
true if source and target share property names |
GetLayoutLabel |
static string GetLayoutLabel(VirtualControllerType type, bool isCustomVJoy) |
Display label (e.g., "Xbox 360", "vJoy", "MIDI", "KB+M") |
| Layout | Property Name Examples | Notes |
|---|---|---|
| Gamepad (Xbox 360 / DS4 / vJoy preset) |
ButtonA, LeftThumbAxisX, DPadUp
|
Xbox 360 and DS4 share property names. Buttons: A=0..Guide=10. Axes: LX=0..RT=5. |
| vJoy Custom |
VJoyBtn0, VJoyAxis2, VJoyAxis2Neg, VJoyPov0Up
|
Indexed by position. POV 0 only maps to D-Pad. |
| MIDI |
MidiNote0, MidiCC3, MidiCC3Neg
|
No D-Pad support (returns null). |
| KB+M |
KbmMBtn0, KbmMouseX, KbmMouseXNeg, KbmKey20, KbmScroll
|
Mouse buttons 0–4, VK codes, 3 mouse axes. D-Pad mapped to arrow keys. |
private enum LayoutKind { Gamepad, VJoyCustom, Midi, Kbm }- Xbox360, DS4, and vJoy gamepad preset all resolve to
LayoutKind.Gamepad. - vJoy with
isCustomVJoy=trueresolves toLayoutKind.VJoyCustom. -
IsSameLayoutcompares resolvedLayoutKindvalues.
File: PadForge.Engine/Common/SDL3Minimal.cs
Namespace: SDL3
Minimal SDL3 P/Invoke declarations for joystick, gamepad, keyboard, mouse, and haptic. Only functions used by PadForge are declared. Native library: "SDL3".
| Constant | Value | Description |
|---|---|---|
SDL_INIT_VIDEO |
0x00000020 |
Required for keyboard/mouse |
SDL_INIT_JOYSTICK |
0x00000200 |
Joystick subsystem |
SDL_INIT_HAPTIC |
0x00001000 |
Haptic subsystem |
SDL_INIT_GAMEPAD |
0x00002000 |
Gamepad subsystem (was SDL_INIT_GAMECONTROLLER) |
| Constant | Value |
|---|---|
SDL_HAT_CENTERED |
0x00 |
SDL_HAT_UP |
0x01 |
SDL_HAT_RIGHT |
0x02 |
SDL_HAT_DOWN |
0x04 |
SDL_HAT_LEFT |
0x08 |
SDL_HAT_RIGHTUP |
0x03 |
SDL_HAT_RIGHTDOWN |
0x06 |
SDL_HAT_LEFTUP |
0x09 |
SDL_HAT_LEFTDOWN |
0x0C |
| Constant | Value | Description |
|---|---|---|
SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS |
"SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS" |
Allow events when app not focused |
SDL_HINT_JOYSTICK_RAWINPUT |
"SDL_JOYSTICK_RAWINPUT" |
Do NOT set (conflicts with XInput enumeration) |
SDL_HINT_JOYSTICK_XINPUT |
"SDL_JOYSTICK_XINPUT" |
Enables Xbox controller enumeration |
SDL_HINT_JOYSTICK_HIDAPI_SWITCH2 |
"SDL_JOYSTICK_HIDAPI_SWITCH2" |
Switch 2 controller support |
SDL_HINT_VIDEO_ALLOW_SCREENSAVER |
"SDL_VIDEO_ALLOW_SCREENSAVER" |
Allow screensaver |
SDL_JoystickType:
| Value | Name |
|---|---|
| 0 | SDL_JOYSTICK_TYPE_UNKNOWN |
| 1 | SDL_JOYSTICK_TYPE_GAMEPAD |
| 2 | SDL_JOYSTICK_TYPE_WHEEL |
| 3 | SDL_JOYSTICK_TYPE_ARCADE_STICK |
| 4 | SDL_JOYSTICK_TYPE_FLIGHT_STICK |
| 5 | SDL_JOYSTICK_TYPE_DANCE_PAD |
| 6 | SDL_JOYSTICK_TYPE_GUITAR |
| 7 | SDL_JOYSTICK_TYPE_DRUM_KIT |
| 8 | SDL_JOYSTICK_TYPE_ARCADE_PAD |
| 9 | SDL_JOYSTICK_TYPE_THROTTLE |
| 10 | SDL_JOYSTICK_TYPE_COUNT |
SDL_PowerState:
| Value | Name |
|---|---|
| -1 | SDL_POWERSTATE_ERROR |
| 0 | SDL_POWERSTATE_UNKNOWN |
| 1 | SDL_POWERSTATE_ON_BATTERY |
| 2 | SDL_POWERSTATE_NO_BATTERY |
| 3 | SDL_POWERSTATE_CHARGING |
| 4 | SDL_POWERSTATE_CHARGED |
SDL_GUID (16 bytes): data0 through data15. Methods: ToGuid() (converts to .NET Guid), ToByteArray().
SDL_HapticDirection (16 bytes): type (byte), dir0, dir1, dir2 (int).
SDL_HapticLeftRight (12 bytes): type, length, large_magnitude, small_magnitude.
SDL_HapticConstant (40 bytes): type, direction, length, delay, button, interval, level, attack_length, attack_level, fade_length, fade_level.
SDL_HapticPeriodic (44 bytes): type, direction, length, delay, button, interval, period, magnitude, offset, phase, attack_length, attack_level, fade_length, fade_level.
SDL_HapticCondition (68 bytes): type, direction, length, delay, button, interval, per-axis arrays (3 axes): right_sat[0-2], left_sat[0-2], right_coeff[0-2], left_coeff[0-2], deadband[0-2], center[0-2].
SDL_HapticRamp (44 bytes): type, direction, length, delay, button, interval, start, end, attack_length, attack_level, fade_length, fade_level.
SDL_HapticEffect (72 bytes, explicit layout): Union overlaying type, leftright, constant, periodic, condition, ramp all at FieldOffset(0).
| Constant | Value | Description |
|---|---|---|
SDL_HAPTIC_CONSTANT |
1 << 0 |
Constant force |
SDL_HAPTIC_SINE |
1 << 1 |
Sine wave |
SDL_HAPTIC_SQUARE |
1 << 2 |
Square wave |
SDL_HAPTIC_TRIANGLE |
1 << 3 |
Triangle wave |
SDL_HAPTIC_SAWTOOTHUP |
1 << 4 |
Sawtooth up |
SDL_HAPTIC_SAWTOOTHDOWN |
1 << 5 |
Sawtooth down |
SDL_HAPTIC_RAMP |
1 << 6 |
Ramp |
SDL_HAPTIC_SPRING |
1 << 7 |
Spring condition |
SDL_HAPTIC_DAMPER |
1 << 8 |
Damper condition |
SDL_HAPTIC_INERTIA |
1 << 9 |
Inertia condition |
SDL_HAPTIC_FRICTION |
1 << 10 |
Friction condition |
SDL_HAPTIC_LEFTRIGHT |
1 << 11 |
Left/right dual-motor |
SDL_HAPTIC_CUSTOM |
1 << 15 |
Custom effect |
SDL_HAPTIC_GAIN |
1 << 16 |
Gain control supported |
SDL_HAPTIC_AUTOCENTER |
1 << 17 |
Auto-center supported |
SDL_HAPTIC_INFINITY |
0xFFFFFFFF |
Infinite duration |
SDL_HAPTIC_POLAR |
0 (byte) | Polar direction type |
SDL_HAPTIC_CARTESIAN |
1 (byte) | Cartesian direction type |
SDL_HAPTIC_SPHERICAL |
2 (byte) | Spherical direction type |
SDL_HAPTIC_STEERING_AXIS |
3 (byte) | Steering axis direction type |
| Constant | Value | Description |
|---|---|---|
SDL_GAMEPAD_AXIS_LEFTX |
0 | Left stick X |
SDL_GAMEPAD_AXIS_LEFTY |
1 | Left stick Y |
SDL_GAMEPAD_AXIS_RIGHTX |
2 | Right stick X |
SDL_GAMEPAD_AXIS_RIGHTY |
3 | Right stick Y |
SDL_GAMEPAD_AXIS_LEFT_TRIGGER |
4 | Left trigger |
SDL_GAMEPAD_AXIS_RIGHT_TRIGGER |
5 | Right trigger |
SDL_GAMEPAD_AXIS_COUNT |
6 | Total axis count |
| Constant | Value | Description |
|---|---|---|
SDL_GAMEPAD_BUTTON_SOUTH |
0 | A |
SDL_GAMEPAD_BUTTON_EAST |
1 | B |
SDL_GAMEPAD_BUTTON_WEST |
2 | X |
SDL_GAMEPAD_BUTTON_NORTH |
3 | Y |
SDL_GAMEPAD_BUTTON_BACK |
4 | Back/Select |
SDL_GAMEPAD_BUTTON_GUIDE |
5 | Guide/Home |
SDL_GAMEPAD_BUTTON_START |
6 | Start |
SDL_GAMEPAD_BUTTON_LEFT_STICK |
7 | Left stick click |
SDL_GAMEPAD_BUTTON_RIGHT_STICK |
8 | Right stick click |
SDL_GAMEPAD_BUTTON_LEFT_SHOULDER |
9 | Left bumper |
SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER |
10 | Right bumper |
SDL_GAMEPAD_BUTTON_DPAD_UP |
11 | D-pad up |
SDL_GAMEPAD_BUTTON_DPAD_DOWN |
12 | D-pad down |
SDL_GAMEPAD_BUTTON_DPAD_LEFT |
13 | D-pad left |
SDL_GAMEPAD_BUTTON_DPAD_RIGHT |
14 | D-pad right |
SDL_GAMEPAD_BUTTON_COUNT |
21 | Total button count |
| Constant | Value | Description |
|---|---|---|
SDL_SENSOR_ACCEL |
1 | Accelerometer |
SDL_SENSOR_GYRO |
2 | Gyroscope |
SDL_SENSOR_ACCEL_L |
3 | Left accelerometer |
SDL_SENSOR_GYRO_L |
4 | Left gyroscope |
SDL_SENSOR_ACCEL_R |
5 | Right accelerometer |
SDL_SENSOR_GYRO_R |
6 | Right gyroscope |
| Constant | Value | Description |
|---|---|---|
SDL_BUTTON_LMASK |
1 << 0 |
Left button |
SDL_BUTTON_MMASK |
1 << 1 |
Middle button |
SDL_BUTTON_RMASK |
1 << 2 |
Right button |
SDL_BUTTON_X1MASK |
1 << 3 |
X1 button |
SDL_BUTTON_X2MASK |
1 << 4 |
X2 button |
string[256] array of human-readable Windows VK code names. Built by BuildVirtualKeyNames(). Covers standard keys, modifiers, F1–F24, numpad, OEM keys. Used by SdlKeyboardWrapper.GetDeviceObjects() for button naming.
Lifecycle: SDL_Init, SDL_Quit, SDL_EnableScreenSaver, SDL_GetError, SDL_SetHint, SDL_free
Joystick Enumeration: SDL_GetJoysticks, SDL_GetJoystickGUIDForID, SDL_GetJoystickVendorForID, SDL_GetJoystickProductForID, SDL_GetJoystickProductVersionForID, SDL_GetJoystickTypeForID, SDL_GetJoystickNameForID, SDL_GetJoystickPathForID, SDL_IsGamepad
Gamepad Mappings: SDL_AddGamepadMappingsFromFile, SDL_AddGamepadMapping, GetGamepadMapping
Joystick Instance: SDL_OpenJoystick, SDL_CloseJoystick, SDL_GetJoystickID, SDL_JoystickConnected
Gamepad Instance: SDL_OpenGamepad, SDL_CloseGamepad, SDL_GetGamepadJoystick
Gamepad State: SDL_GetGamepadAxis, SDL_GetGamepadButton
Joystick State: SDL_UpdateJoysticks, SDL_PumpEvents, SDL_GetJoystickAxis, SDL_GetJoystickButton, SDL_GetJoystickHat, SDL_GetNumJoystickAxes, SDL_GetNumJoystickButtons, SDL_GetNumJoystickHats
Joystick Properties: SDL_GetJoystickName, SDL_GetJoystickVendor, SDL_GetJoystickProduct, SDL_GetJoystickProductVersion, SDL_GetJoystickType, SDL_GetJoystickPath, SDL_GetJoystickSerial, SDL_GetJoystickGUID, SDL_GetJoystickProperties, SDL_GetBooleanProperty, SDL_GetJoystickPowerInfo
Sensors: SDL_GamepadHasSensor, SDL_SetGamepadSensorEnabled, SDL_GetGamepadSensorData
Rumble: SDL_RumbleJoystick
Haptic: SDL_OpenHapticFromJoystick, SDL_CloseHaptic, SDL_GetHapticFeatures, SDL_CreateHapticEffect, SDL_UpdateHapticEffect, SDL_RunHapticEffect, SDL_StopHapticEffect, SDL_DestroyHapticEffect, SDL_SetHapticGain, SDL_GetNumHapticAxes
Keyboard: SDL_GetKeyboards, SDL_GetKeyboardNameForID, SDL_GetKeyboardState
Mouse: SDL_GetMice, SDL_GetMouseNameForID, SDL_GetMouseState, SDL_GetRelativeMouseState
Version: SDL_GetVersion, SDL_Linked_Version (returns (major, minor, patch) tuple)
- Architecture Overview — Solution structure, how Engine and App assemblies relate
-
Input Pipeline — 6-step pipeline consuming
CustomInputState,Gamepad,PadSetting -
SDL3 Integration — SDL3 P/Invoke details,
SdlDeviceWrapperusage, haptic strategies -
Virtual Controllers —
IVirtualControllerimplementations consumingGamepad,VJoyRawState,KbmRawState,MidiRawState -
Settings and Serialization —
PadSettingXML persistence,UserDevice/UserSettingserialization -
vJoy Deep Dive —
VJoyVirtualControllerFFB usingVibration,FfbEffectTypes