Skip to content

ViewModels

hifihedgehog edited this page Mar 3, 2026 · 53 revisions

ViewModels Reference

All ViewModels live in PadForge.App/ViewModels/ under the PadForge.ViewModels namespace. They use CommunityToolkit.Mvvm (ObservableObject, RelayCommand).


ViewModelBase

File: ViewModelBase.cs

Abstract base class for all PadForge ViewModels. Extends ObservableObject (which provides INotifyPropertyChanged and SetProperty helpers).

public abstract class ViewModelBase : ObservableObject
{
    public string Title { get; set; }
}
Property Type Description
Title string Display title for the view. Used by navigation and page headers.

MainViewModel

File: MainViewModel.cs

Root ViewModel for the application. Serves as the DataContext for MainWindow. Manages navigation state, the collection of pad ViewModels, and app-wide status.

public partial class MainViewModel : ViewModelBase

Child ViewModels

Property Type Description
Pads ObservableCollection<PadViewModel> Virtual controller pad VMs (up to InputManager.MaxPads = 8).
NavControllerItems ObservableCollection<NavControllerItemViewModel> Sidebar navigation items for created controller slots.
Dashboard DashboardViewModel Dashboard overview VM.
Devices DevicesViewModel Devices list VM.
Settings SettingsViewModel Application settings VM.

Navigation

Property Type Description
SelectedNavTag string Currently selected nav tag: "Dashboard", "Pad1".."Pad16", "Devices", "Settings", "About", "Profiles".
IsPadPageSelected bool (computed) true if a Pad page (Pad1..Pad16) is currently selected.
SelectedPadIndex int (computed) Zero-based pad index for the selected Pad page, or -1.
SelectedPad PadViewModel (computed) PadViewModel for the selected Pad page, or null.

Status Properties

Property Type Description
StatusText string Status bar text (default: "Ready").
IsEngineRunning bool Whether the input engine polling loop is active. Also raises EngineStatusText.
EngineStatusText string (computed) "Running" or "Stopped".
PollingFrequency double Current input polling frequency in Hz.
ConnectedDeviceCount int Number of currently connected input devices.
IsViGEmInstalled bool Whether the ViGEmBus driver is available.

Commands

Command Type Execute CanExecute
StartEngineCommand RelayCommand Raises StartEngineRequested !IsEngineRunning
StopEngineCommand RelayCommand Raises StopEngineRequested IsEngineRunning

Events

Event Signature Description
StartEngineRequested EventHandler User requests engine start.
StopEngineRequested EventHandler User requests engine stop.
NavControllerItemsRefreshed EventHandler Raised after RefreshNavControllerItems() completes.

Methods

public void RefreshNavControllerItems()

Rebuilds sidebar controller entries from SettingsManager.SlotCreated[]. Computes per-type instance numbering (Xbox #1, DS4 #1, etc.) and updates NavControllerItems, SlotLabel, TypeInstanceLabel, icon keys, and enabled states.

public void ForceNavControllerItemsRefreshed()

Forces a NavControllerItemsRefreshed event even when slot count hasn't changed. Used after slot reorder/swap.

public void RefreshCommands()

Calls NotifyCanExecuteChanged() on start/stop commands.

NavControllerItemViewModel (nested class)

public class NavControllerItemViewModel : ObservableObject
{
    public NavControllerItemViewModel(int padIndex);
    public int PadIndex { get; }
    public string Tag { get; }                   // "Pad1".."Pad8"
    public int SlotNumber { get; set; }          // 1-based global number
    public string InstanceLabel { get; set; }    // Per-type instance number
    public string IconKey { get; set; }          // "XboxControllerIcon"/"DS4ControllerIcon"/"VJoyControllerIcon"
    public bool IsEnabled { get; set; }
    public int ConnectedDeviceCount { get; set; }
}

DashboardViewModel

File: DashboardViewModel.cs

ViewModel for the Dashboard page. At-a-glance overview of all controller slots, engine status, device counts, driver status, and DSU settings.

public partial class DashboardViewModel : ViewModelBase

Slot Summaries

Property Type Description
SlotSummaries ObservableCollection<SlotSummary> Summary cards for active virtual controller slots.
ShowAddController bool Whether the "Add Controller" card is visible (any type has capacity).

Engine Status

Property Type Description
EngineStatus string Current engine status text. Default: "Stopped".
PollingFrequency double Polling frequency in Hz.
PollingFrequencyText string (computed) Formatted: "987.3 Hz" or "---".

Device Counts

Property Type Description
TotalDevices int Total detected input devices.
OnlineDevices int Currently connected devices.
MappedDevices int Devices with active slot mappings.

Driver Status

Property Type Description
IsViGEmInstalled bool ViGEmBus installed. Also raises ViGEmStatusText.
ViGEmStatusText string (computed) "Installed" or "Not Installed".
ViGEmVersion string ViGEmBus driver version.
IsHidHideInstalled bool HidHide installed. Also raises HidHideStatusText.
HidHideStatusText string (computed) "Installed" or "Not Installed".
IsVJoyInstalled bool vJoy driver installed. Also raises VJoyStatusText.
VJoyStatusText string (computed) "Installed" or "Not Installed".

DSU Motion Server

Property Type Description
EnableDsuMotionServer bool Whether DSU server is enabled.
DsuMotionServerPort int UDP port (clamped 1024-65535, default 26760).
DsuServerStatus string Server status for UI display.

Methods

public void RefreshActiveSlots(IList<int> activeSlots, bool canAddMore)

Rebuilds SlotSummaries to match active slots. Updates sequential global numbering. Sets ShowAddController.

SlotSummary (nested class)

public class SlotSummary : ObservableObject
{
    public SlotSummary(int padIndex);
    public int PadIndex { get; }
    public string SlotLabel { get; set; }
    public string DeviceName { get; set; }                // Default: "No device"
    public bool IsActive { get; set; }
    public bool IsVirtualControllerConnected { get; set; }
    public int MappedDeviceCount { get; set; }
    public int ConnectedDeviceCount { get; set; }
    public string StatusText { get; set; }                // "Active"/"Idle"/"No mapping"/"Disabled"
    public bool IsEnabled { get; set; }
    public int SlotNumber { get; set; }                   // 1-based global number
    public string TypeInstanceLabel { get; set; }         // Per-type instance
    public VirtualControllerType OutputType { get; set; }
}

PadViewModel

File: PadViewModel.cs

The most complex VM. Represents a single virtual controller slot (one of 8 pads).

public partial class PadViewModel : ViewModelBase
{
    public PadViewModel(int padIndex);
}

Identity

Property Type Description
PadIndex int Zero-based pad slot index (0-7).
SlotNumber int (computed) One-based slot number.
SlotLabel string Display label (e.g., "Virtual Controller 1").
TypeInstanceLabel string Per-type instance number label.

Output Type

Property Type Description
OutputType VirtualControllerType Virtual controller output type. Setting triggers ResetDeadZoneSettings(), RebuildMappings(), RebuildStickConfigs(), RebuildTriggerConfigs(), SyncMacroButtonStyle().
OutputTypeIndex int Int binding for ComboBox (0=Xbox, 1=DS4, 2=VJoy).

vJoy Configuration

Property Type Description
VJoyConfig VJoySlotConfig Per-slot vJoy configuration. Subscribes to PropertyChanged for dynamic rebuilds.

Multi-Device Selection

Property Type Description
MappedDevices ObservableCollection<MappedDeviceInfo> Physical devices mapped to this slot.
SelectedMappedDevice MappedDeviceInfo Currently selected device for configuration.
HasSelectedDevice bool (computed) Whether a device is selected.
MappedDeviceName string Primary mapped device name.
MappedDeviceGuid Guid Primary device GUID.
IsDeviceOnline bool Whether the primary device is connected.

MappedDeviceInfo (nested class)

public class MappedDeviceInfo : ObservableObject
{
    public string Name { get; set; }
    public Guid InstanceGuid { get; set; }
    public bool IsOnline { get; set; }
}

XInput Output State (15 buttons, 6 analog)

Property Type Description
ButtonA bool A button state
ButtonB bool B button state
ButtonX bool X button state
ButtonY bool Y button state
LeftShoulder bool Left bumper
RightShoulder bool Right bumper
ButtonBack bool Back/Select
ButtonStart bool Start
LeftThumbButton bool Left stick click
RightThumbButton bool Right stick click
ButtonGuide bool Guide/Home
DPadUp bool D-Pad Up
DPadDown bool D-Pad Down
DPadLeft bool D-Pad Left
DPadRight bool D-Pad Right
LeftTrigger double Left trigger (0.0-1.0)
RightTrigger double Right trigger (0.0-1.0)
ThumbLX double Left stick X normalized (0.0-1.0, 0.5=center)
ThumbLY double Left stick Y normalized
ThumbRX double Right stick X normalized
ThumbRY double Right stick Y normalized
RawThumbLX short Raw left stick X (-32768..32767)
RawThumbLY short Raw left stick Y
RawThumbRX short Raw right stick X
RawThumbRY short Raw right stick Y
RawLeftTrigger byte Raw left trigger (0-255)
RawRightTrigger byte Raw right trigger

Per-device preview values (shown on Sticks/Triggers tabs for selected device only):

DeviceThumbLX, DeviceThumbLY, DeviceThumbRX, DeviceThumbRY (double), DeviceRawThumbLX..DeviceRawThumbRY (short), DeviceLeftTrigger, DeviceRightTrigger (double), DeviceRawLeftTrigger, DeviceRawRightTrigger (byte).

Dead Zones (per-axis X/Y)

Left Stick: LeftDeadZoneX, LeftDeadZoneY, LeftAntiDeadZoneX, LeftAntiDeadZoneY, LeftLinear (all int, clamped 0-100).

Right Stick: RightDeadZoneX, RightDeadZoneY, RightAntiDeadZoneX, RightAntiDeadZoneY, RightLinear (all int, clamped 0-100).

Triggers: LeftTriggerDeadZone, RightTriggerDeadZone, LeftTriggerAntiDeadZone, RightTriggerAntiDeadZone (int, 0-100), LeftTriggerMaxRange, RightTriggerMaxRange (int, 1-100).

Backward compat shims: LeftDeadZone { set => LeftDeadZoneX = LeftDeadZoneY = value; }, RightDeadZone same pattern.

Force Feedback

Property Type Description
ForceOverallGain int Overall FF gain (0-100, default 100).
LeftMotorStrength int Left motor strength (0-100).
RightMotorStrength int Right motor strength (0-100).
SwapMotors bool Swap L/R motors.
LeftMotorDisplay double Live left motor value for visualizer.
RightMotorDisplay double Live right motor value for visualizer.

Mappings

Property Type Description
Mappings ObservableCollection<MappingItem> Mapping rows for this slot.
public void RebuildMappings()

Clears and rebuilds Mappings based on OutputType and VJoyConfig. For gamepad presets: 21 standard items (11 buttons + 4 D-Pad + 2 triggers + 4 stick axes). For custom vJoy: dynamic numbered items. Raises MappingsRebuilt.

Dynamic Stick/Trigger Config

Property Type Description
StickConfigs ObservableCollection<StickConfigItem> Dynamic stick config items.
TriggerConfigs ObservableCollection<TriggerConfigItem> Dynamic trigger config items.
public void RebuildStickConfigs()
public void RebuildTriggerConfigs()
public void SyncStickItemFromVm(StickConfigItem item)
public void SyncTriggerItemFromVm(TriggerConfigItem item)
public void SyncAllConfigItemsFromVm()

Macros

Property Type Description
Macros ObservableCollection<MacroItem> Configured macros.
SelectedMacro MacroItem Selected macro.
HasSelectedMacro bool (computed) Whether a macro is selected.
AddMacroCommand RelayCommand Creates new macro with derived button style.
RemoveMacroCommand RelayCommand Removes selected macro.

Map All / Recording

Property Type Description
CurrentRecordingTarget string TargetSettingName of the mapping being recorded. null when idle. Drives controller-tab flash animation.
SelectedConfigTab int Active tab index (0=Controller, 1=Macros, 2=Mappings, 3=Sticks, 4=Triggers, 5=Force Feedback).
VJoyOutputSnapshot VJoyRawState Latest vJoy raw output state for schematic view.

Events

Event Signature
SelectedDeviceChanged EventHandler<MappedDeviceInfo>
MappingsRebuilt EventHandler
TestRumbleRequested EventHandler
TestLeftMotorRequested EventHandler
TestRightMotorRequested EventHandler

DevicesViewModel

File: DevicesViewModel.cs

ViewModel for the Devices page. Shows all detected input devices and raw input state for the selected device.

public partial class DevicesViewModel : ViewModelBase

Device List

Property Type Description
Devices ObservableCollection<DeviceRowViewModel> All known devices.
SelectedDevice DeviceRowViewModel Currently selected device.
HasSelectedDevice bool (computed) Whether a device is selected.
TotalCount int Total detected devices.
OnlineCount int Connected devices.

Raw State Display

Property Type Description
RawAxes ObservableCollection<AxisDisplayItem> Axis values for progress bars.
RawButtons ObservableCollection<ButtonDisplayItem> Button states for circles.
RawPovs ObservableCollection<PovDisplayItem> POV hat values for compass.
KeyboardKeys ObservableCollection<KeyboardKeyItem> Keyboard key layout items.
IsKeyboardDevice bool Whether selected device is a keyboard.
SelectedButtonTotal int Total buttons on selected device.
HasRawData bool Whether raw data is available.
HasGyroData / HasAccelData bool Whether gyro/accel data available.
GyroX / GyroY / GyroZ double Gyroscope values.
AccelX / AccelY / AccelZ double Accelerometer values.
LastRawStateDeviceGuid Guid (internal) Tracks which device's collections are populated.

Slot Toggle Buttons

Property Type Description
ActiveSlotItems ObservableCollection<SlotButtonItem> Dynamic slot assignment buttons.
ToggleSlotCommand RelayCommand<int> Toggle device assignment to slot.

Commands

Command Type Execute
RefreshCommand RelayCommand Raises RefreshRequested.
AssignToSlotCommand RelayCommand<int> Raises AssignToSlotRequested.
HideDeviceCommand RelayCommand Marks device hidden, raises HideDeviceRequested.
RemoveDeviceCommand RelayCommand Removes device row and raises RemoveDeviceRequested.

Events

Event Signature
RefreshRequested EventHandler
AssignToSlotRequested EventHandler<int>
HideDeviceRequested EventHandler<Guid>
RemoveDeviceRequested EventHandler<Guid>
ToggleSlotRequested EventHandler<int>

Methods

internal void RebuildRawStateCollections(int axisCount, int buttonCount, int povCount, bool isKeyboard = false)
internal void ClearRawState()
public void RefreshSlotButtons()
public DeviceRowViewModel FindByGuid(Guid instanceGuid)
public void RefreshCounts()

Display Item Classes

AxisDisplayItem

public class AxisDisplayItem : ObservableObject
{
    public int Index { get; set; }
    public string Name { get; set; }
    public double NormalizedValue { get; set; }  // 0.0-1.0
    public int RawValue { get; set; }            // 0-65535
}

ButtonDisplayItem

public class ButtonDisplayItem : ObservableObject
{
    public int Index { get; set; }
    public bool IsPressed { get; set; }
}

KeyboardKeyItem

public class KeyboardKeyItem : ObservableObject
{
    public int VKeyIndex { get; set; }
    public string Label { get; set; }
    public double X { get; set; }
    public double Y { get; set; }
    public double KeyWidth { get; set; }
    public double KeyHeight { get; set; }
    public bool IsPressed { get; set; }
    public const double LayoutWidth = 556;
    public const double LayoutHeight = 136;
    public static ObservableCollection<KeyboardKeyItem> BuildLayout()
    public static bool IsVKeyPressed(bool[] buttons, int vk)
}

BuildLayout() generates a full ANSI QWERTY keyboard with numpad. Constants: u=24 (key width unit), g=2 (gap), kh=20 (key height), rh=22 (row height). Wrapped in a Viewbox for auto-scaling.

PovDisplayItem

public class PovDisplayItem : ObservableObject
{
    public int Index { get; set; }
    public int Centidegrees { get; set; }  // 0-35900, or -1 for centered
    public bool IsCentered { get; }        // computed
    public double AngleDegrees { get; }    // computed (0-359)
}

SlotButtonItem

public class SlotButtonItem : ObservableObject
{
    public int PadIndex { get; set; }      // 0-based slot index
    public int SlotNumber { get; set; }    // 1-based display number
    public bool IsAssigned { get; set; }
}

DeviceRowViewModel

public class DeviceRowViewModel : ObservableObject
{
    // Identity
    public Guid InstanceGuid { get; set; }
    public string DeviceName { get; set; }
    public string ProductName { get; set; }
    public Guid ProductGuid { get; set; }
    public ushort VendorId { get; set; }
    public ushort ProductId { get; set; }
    public string VendorIdHex { get; }     // computed "045E"
    public string ProductIdHex { get; }    // computed "028E"
    // Status
    public bool IsOnline { get; set; }
    public bool IsEnabled { get; set; }
    public bool IsHidden { get; set; }
    public string StatusText { get; }      // computed "Online"/"Offline"/"Disabled"
    // Capabilities
    public int AxisCount { get; set; }
    public int ButtonCount { get; set; }
    public int PovCount { get; set; }
    public string DeviceType { get; set; }
    public bool HasRumble { get; set; }
    public bool HasGyro { get; set; }
    public bool HasAccel { get; set; }
    // Slot assignment
    public List<int> AssignedSlots { get; }
    public ObservableCollection<SlotBadge> SlotBadges { get; }
    public bool IsUnassigned { get; }
    public void SetAssignedSlots(List<int> slots);
    // Misc
    public string DevicePath { get; set; }
    public string CapabilitiesSummary { get; }
    public void NotifyDisplayChanged();
}

SettingsViewModel

File: SettingsViewModel.cs

ViewModel for the Settings page.

public partial class SettingsViewModel : ViewModelBase

Theme

Property Type Description
SelectedThemeIndex int 0=System, 1=Light, 2=Dark. Raises ThemeChanged.

Driver Status (3 sections)

ViGEmBus:

Property Type Description
IsViGEmInstalled bool Installed flag.
ViGEmStatusText string (computed) "Installed" / "Not Installed".
ViGEmVersion string Version string.
InstallViGEmCommand RelayCommand CanExecute: !IsViGEmInstalled.
UninstallViGEmCommand RelayCommand CanExecute: IsViGEmInstalled && !HasAnyViGEmSlots().

HidHide:

Property Type Description
IsHidHideInstalled bool Installed flag.
HidHideStatusText string (computed) "Installed" / "Not Installed".
HidHideVersion string Version string.
InstallHidHideCommand RelayCommand CanExecute: !IsHidHideInstalled.
UninstallHidHideCommand RelayCommand CanExecute: IsHidHideInstalled.

vJoy:

Property Type Description
IsVJoyInstalled bool Installed flag.
VJoyStatusText string (computed) "Installed" / "Not Installed".
VJoyVersion string Version string.
InstallVJoyCommand RelayCommand CanExecute: !IsVJoyInstalled.
UninstallVJoyCommand RelayCommand CanExecute: IsVJoyInstalled && !HasAnyVJoySlots().

Uninstall guards:

internal Func<bool> HasAnyViGEmSlots { get; set; }  // set by MainWindow
internal Func<bool> HasAnyVJoySlots { get; set; }   // set by MainWindow
public void RefreshDriverGuards()

Engine Settings

Property Type Description
AutoStartEngine bool Auto-start on launch (default true).
MinimizeToTray bool Minimize to system tray.
StartMinimized bool Start minimized.
StartAtLogin bool Auto-start on login.
EnablePollingOnFocusLoss bool Continue polling on focus loss (default true).
PollingRateMs int Target polling interval (clamped 1-16).
Use2DControllerView bool Show 2D view instead of 3D.

Settings File

Property Type Description
SettingsFilePath string Path to current settings file.
HasUnsavedChanges bool Unsaved changes flag.
SaveCommand RelayCommand Raises SaveRequested.
ReloadCommand RelayCommand Raises ReloadRequested.
ResetCommand RelayCommand Raises ResetRequested.
OpenSettingsFolderCommand RelayCommand Raises OpenSettingsFolderRequested.

Diagnostics

Property Type Description
SdlVersion string SDL3 library version.
ApplicationVersion string App version.
RuntimeVersion string .NET runtime version.

Profiles

Property Type Description
EnableAutoProfileSwitching bool Auto-profile switching enabled.
ProfileItems ObservableCollection<ProfileListItem> Profile list.
SelectedProfile ProfileListItem Selected profile.
ActiveProfileInfo string Active profile display text.

Profile commands: NewProfileCommand, SaveAsProfileCommand, DeleteProfileCommand, EditProfileCommand, LoadProfileCommand.

ProfileListItem

public class ProfileListItem : ObservableObject
{
    public const string DefaultProfileId = "__default__";
    public bool IsDefault { get; }
    public string Id { get; set; }
    public string Name { get; set; }
    public string Executables { get; set; }
    public string TopologyLabel { get; set; }
    public int XboxCount { get; set; }
    public int DS4Count { get; set; }
    public int VJoyCount { get; set; }
}

MappingItem

File: MappingItem.cs

Represents a single mapping row linking a physical input source to an output target.

public class MappingItem : ObservableObject
{
    public MappingItem(string targetLabel, string targetSettingName, MappingCategory category, string negSettingName = null);
}
Property Type Description
TargetLabel string Human-readable output label (e.g., "A", "Left Stick X").
TargetSettingName string PadSetting property name (e.g., "ButtonA", "LeftThumbAxisX").
Category MappingCategory Grouping category.
NegSettingName string Negative direction property (e.g., "LeftThumbAxisXNeg"). Null for non-axis.
HasNegDirection bool (computed) Whether negative direction is supported.
SourceDescriptor string Mapping descriptor: "Button 0", "Axis 1", "IHAxis 2", "POV 0 Up". Empty=unmapped.
NegSourceDescriptor string Negative-direction descriptor.
SourceDisplayText string (computed) Human-readable source text. For bidirectional: "neg / pos".
IsMapped bool (computed) Whether source is assigned.
IsRecording bool Recording mode active.
RecordButtonText string (computed) "Record" or "Recording...".
CurrentValueText string Live raw value (updated at 30Hz).
IsInverted bool Axis inversion. Setting calls RebuildDescriptor().
IsHalfAxis bool Half-axis mode. Setting calls RebuildDescriptor().

Methods

public void LoadDescriptor(string descriptor)      // Parses I/H prefixes, sets flags + descriptor
public void LoadNegDescriptor(string descriptor)   // Sets NegSourceDescriptor
public void SetResolvedSourceText(string text)     // Human-readable override
public void SetResolvedNegText(string text)

Commands

Command Description
ToggleRecordCommand Toggles recording; raises StartRecordingRequested / StopRecordingRequested.
ClearCommand Clears source, neg source, inversion, half-axis.

MappingCategory (enum)

public enum MappingCategory { Buttons, DPad, Triggers, LeftStick, RightStick }

MacroItem

File: MacroItem.cs

Represents a single macro with trigger condition and action sequence.

public class MacroItem : ObservableObject

Identity

Property Type Description
Name string Macro name (default "New Macro").
IsEnabled bool Active flag.

Trigger Condition

Property Type Description
TriggerButtons ushort Xbox bitmask flags (all must be pressed simultaneously).
TriggerCustomButtonWords uint[4] vJoy 128-bit button bitmask. [XmlIgnore].
TriggerCustomButtons string Serializable hex form of TriggerCustomButtonWords.
UsesCustomTrigger bool (computed) Any custom trigger button set.
TriggerSource MacroTriggerSource InputDevice or OutputController.
TriggerDisplayText string (computed) Human-readable trigger combo.
TriggerDeviceGuid Guid Raw device trigger source. Guid.Empty = use bitmask.
TriggerRawButtons int[] Raw button indices.
UsesRawTrigger bool (computed) Uses raw device button trigger path.
IsRecordingTrigger bool Recording trigger combo.
RecordingLiveText string Live display during recording. [XmlIgnore].
ButtonStyle MacroButtonStyle Display names style. [XmlIgnore].
CustomButtonCount int vJoy button count. [XmlIgnore].

Trigger Options

Property Type Description
TriggerMode MacroTriggerMode OnPress, OnRelease, WhileHeld.
ConsumeTriggerButtons bool Remove trigger buttons from output (default true).

Actions

Property Type Description
Actions ObservableCollection<MacroAction> Ordered action sequence.
SelectedAction MacroAction Selected action.

Repeat Settings

Property Type Description
RepeatMode MacroRepeatMode Once, FixedCount, UntilRelease.
RepeatCount int Repeat count (min 1).
RepeatDelayMs int Delay between repeats (min 0).

Runtime State (not serialized)

Property Type Description
IsExecuting bool Currently executing.
CurrentActionIndex int Position in sequence.
RemainingRepeats int Remaining repeats.
ActionStartTime DateTime When current action started.
WasTriggerActive bool Trigger active on previous frame.

MacroAction (nested class)

public class MacroAction : ObservableObject
{
    public MacroActionType Type { get; set; }
    public bool IsButtonType { get; }        // ButtonPress or ButtonRelease
    public bool IsKeyType { get; }           // KeyPress or KeyRelease
    public bool IsDurationType { get; }      // ButtonPress, KeyPress, or Delay
    public bool IsAxisType { get; }          // AxisSet
    public MacroButtonStyle ButtonStyle { get; set; }
    public int CustomButtonCount { get; set; }
    public ushort ButtonFlags { get; set; }
    public uint[] CustomButtonWords { get; set; }       // 4 x uint = 128 buttons
    public string CustomButtons { get; set; }           // Serializable hex
    public void SetCustomButton(int index, bool pressed);
    public bool IsCustomButtonPressed(int index);
    public bool HasCustomButtons { get; }
    public IReadOnlyList<GamepadButtonOption> ButtonOptions { get; }
    public int KeyCode { get; set; }
    public VirtualKey SelectedVirtualKey { get; set; }
    public string KeyString { get; set; }               // "{Control}{Alt}{Delete}" format
    public int[] ParsedKeyCodes { get; }
    public static int[] ParseKeyString(string keyString);
    public static string FormatKeyString(int[] keyCodes);
    public VirtualKey SelectedKeyToAdd { get; set; }    // Auto-appends to KeyString
    public RelayCommand ClearKeyStringCommand { get; }
    public int DurationMs { get; set; }                 // Hold/delay duration
    public short AxisValue { get; set; }                // -32768..32767
    public MacroAxisTarget AxisTarget { get; set; }
    public string DisplayText { get; }                  // Computed summary
}

GamepadButtonOption

public class GamepadButtonOption : ObservableObject
{
    public GamepadButtonOption(MacroAction parent, string label, ushort flag);       // Xbox/DS4 bitmask mode
    public GamepadButtonOption(MacroAction parent, string label, int customIndex);   // vJoy custom mode
    public string Label { get; internal set; }
    public ushort Flag { get; }
    public int CustomIndex { get; }     // -1 = use Flag
    public bool IsChecked { get; set; }
    public void Refresh();
}

Enums

public enum MacroTriggerMode { OnPress, OnRelease, WhileHeld }
public enum MacroTriggerSource { InputDevice, OutputController }
public enum MacroRepeatMode { Once, FixedCount, UntilRelease }
public enum MacroActionType { ButtonPress, ButtonRelease, KeyPress, KeyRelease, Delay, AxisSet }
public enum MacroAxisTarget { None, LeftStickX, LeftStickY, RightStickX, RightStickY, LeftTrigger, RightTrigger }
public enum MacroButtonStyle { Xbox360, DualShock4, Numbered }

MacroButtonNames (static helper)

public static class MacroButtonNames
{
    public static (string Label, ushort Flag)[] GetButtonDefs(MacroButtonStyle style);
    public static string FormatButtons(ushort flags, MacroButtonStyle style);
    public static string FormatCustomButtons(uint[] words);
    public static MacroButtonStyle DeriveStyle(VirtualControllerType outputType, VJoyPreset vJoyPreset = VJoyPreset.Xbox360);
}

StickConfigItem

File: StickConfigItem.cs

Represents one thumbstick section in the dynamic Sticks tab.

public class StickConfigItem : ObservableObject
{
    public StickConfigItem(int index, string title, int axisXIndex = -1, int axisYIndex = -1);
    public string Title { get; }
    public int Index { get; }
    public int DeadZoneX { get; set; }        // clamped 0-100
    public int DeadZoneY { get; set; }
    public int AntiDeadZoneX { get; set; }
    public int AntiDeadZoneY { get; set; }
    public int Linear { get; set; }
    public double LiveX { get; set; }         // 0.0-1.0 normalized
    public double LiveY { get; set; }
    public short RawX { get; set; }
    public short RawY { get; set; }
    public int AxisXIndex { get; }            // VJoyRawState axis index (-1 for gamepad)
    public int AxisYIndex { get; }
}

TriggerConfigItem

File: TriggerConfigItem.cs

Represents one trigger section in the dynamic Triggers tab.

public class TriggerConfigItem : ObservableObject
{
    public TriggerConfigItem(int index, string title, int axisIndex = -1);
    public string Title { get; }
    public int Index { get; }
    public int DeadZone { get; set; }        // clamped 0-100
    public int MaxRange { get; set; }        // clamped 1-100
    public int AntiDeadZone { get; set; }    // clamped 0-100
    public double LiveValue { get; set; }    // 0.0-1.0 normalized
    public byte RawValue { get; set; }
    public int AxisIndex { get; }            // VJoyRawState axis index (-1 for gamepad)
}

VJoySlotConfig

File: VJoySlotConfig.cs

Per-slot vJoy configuration. Drives HID descriptor generation, stick/trigger/POV/button counts, and mapping generation.

public enum VJoyPreset { Xbox360, DualShock4, Custom }

public class VJoySlotConfig : ObservableObject
{
    public const int MaxAxes = 8;
    public VJoyPreset Preset { get; set; }           // Setting calls ApplyPresetDefaults()
    public int ThumbstickCount { get; set; }         // Clamped: sticks*2 + triggers <= MaxAxes
    public int TriggerCount { get; set; }            // Clamped: sticks*2 + triggers <= MaxAxes
    public int PovCount { get; set; }                // Clamped 0-4
    public int ButtonCount { get; set; }             // Clamped 0-128
    public int TotalAxes { get; }                    // Min(ThumbstickCount*2 + TriggerCount, MaxAxes)
    public int MaxThumbsticks { get; }               // (MaxAxes - TriggerCount) / 2
    public int MaxTriggers { get; }                  // MaxAxes - ThumbstickCount * 2
    public bool IsGamepadPreset { get; }             // Preset != Custom
    public void ComputeAxisLayout(out int[] stickAxisX, out int[] stickAxisY, out int[] triggerAxis);
    public void ApplyPresetDefaults();
}

ComputeAxisLayout() Algorithm

Interleaves sticks and triggers: [StickX, StickY, Trigger] per group.

For min(sticks, triggers) groups:
  stickAxisX[g] = g * 3
  stickAxisY[g] = g * 3 + 1
  triggerAxis[g] = g * 3 + 2

Remaining sticks get consecutive pairs: offset, offset+1
Remaining triggers get consecutive singles: offset++

Example with 3 sticks, 2 triggers:

Axis 0: Stick 1 X   Axis 1: Stick 1 Y   Axis 2: Trigger 1
Axis 3: Stick 2 X   Axis 4: Stick 2 Y   Axis 5: Trigger 2
Axis 6: Stick 3 X   Axis 7: Stick 3 Y

Preset Defaults

Preset Sticks Triggers POVs Buttons
Xbox360 2 2 1 11
DualShock4 2 2 1 14
Custom (keep current)

VJoySlotConfigData (serialization DTO)

public class VJoySlotConfigData
{
    [XmlAttribute] public int SlotIndex { get; set; }
    [XmlAttribute] public VJoyPreset Preset { get; set; }
    [XmlAttribute] public int ThumbstickCount { get; set; }
    [XmlAttribute] public int TriggerCount { get; set; }
    [XmlAttribute] public int PovCount { get; set; }
    [XmlAttribute] public int ButtonCount { get; set; }
}

Clone this wiki locally