-
Notifications
You must be signed in to change notification settings - Fork 6
ViewModels
All ViewModels live in PadForge.App/ViewModels/ under the PadForge.ViewModels namespace. They use CommunityToolkit.Mvvm (ObservableObject, RelayCommand).
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. |
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| 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. |
| 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. |
| 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. |
| Command | Type | Execute | CanExecute |
|---|---|---|---|
StartEngineCommand |
RelayCommand |
Raises StartEngineRequested
|
!IsEngineRunning |
StopEngineCommand |
RelayCommand |
Raises StopEngineRequested
|
IsEngineRunning |
| Event | Signature | Description |
|---|---|---|
StartEngineRequested |
EventHandler |
User requests engine start. |
StopEngineRequested |
EventHandler |
User requests engine stop. |
NavControllerItemsRefreshed |
EventHandler |
Raised after RefreshNavControllerItems() completes. |
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.
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; }
}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| 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). |
| 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 "---". |
| Property | Type | Description |
|---|---|---|
TotalDevices |
int |
Total detected input devices. |
OnlineDevices |
int |
Currently connected devices. |
MappedDevices |
int |
Devices with active slot mappings. |
| 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". |
| 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. |
public void RefreshActiveSlots(IList<int> activeSlots, bool canAddMore)Rebuilds SlotSummaries to match active slots. Updates sequential global numbering. Sets ShowAddController.
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; }
}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);
}| 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. |
| 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). |
| Property | Type | Description |
|---|---|---|
VJoyConfig |
VJoySlotConfig |
Per-slot vJoy configuration. Subscribes to PropertyChanged for dynamic rebuilds. |
| 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. |
public class MappedDeviceInfo : ObservableObject
{
public string Name { get; set; }
public Guid InstanceGuid { get; set; }
public bool IsOnline { get; set; }
}| 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).
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.
| 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. |
| 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.
| 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()| 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. |
| 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. |
| Event | Signature |
|---|---|
SelectedDeviceChanged |
EventHandler<MappedDeviceInfo> |
MappingsRebuilt |
EventHandler |
TestRumbleRequested |
EventHandler |
TestLeftMotorRequested |
EventHandler |
TestRightMotorRequested |
EventHandler |
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| 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. |
| 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. |
| Property | Type | Description |
|---|---|---|
ActiveSlotItems |
ObservableCollection<SlotButtonItem> |
Dynamic slot assignment buttons. |
ToggleSlotCommand |
RelayCommand<int> |
Toggle device assignment to slot. |
| 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. |
| Event | Signature |
|---|---|
RefreshRequested |
EventHandler |
AssignToSlotRequested |
EventHandler<int> |
HideDeviceRequested |
EventHandler<Guid> |
RemoveDeviceRequested |
EventHandler<Guid> |
ToggleSlotRequested |
EventHandler<int> |
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()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
}public class ButtonDisplayItem : ObservableObject
{
public int Index { get; set; }
public bool IsPressed { get; set; }
}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.
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)
}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; }
}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();
}File: SettingsViewModel.cs
ViewModel for the Settings page.
public partial class SettingsViewModel : ViewModelBase| Property | Type | Description |
|---|---|---|
SelectedThemeIndex |
int |
0=System, 1=Light, 2=Dark. Raises ThemeChanged. |
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()| 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. |
| 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. |
| Property | Type | Description |
|---|---|---|
SdlVersion |
string |
SDL3 library version. |
ApplicationVersion |
string |
App version. |
RuntimeVersion |
string |
.NET runtime version. |
| 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.
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; }
}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(). |
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)| Command | Description |
|---|---|
ToggleRecordCommand |
Toggles recording; raises StartRecordingRequested / StopRecordingRequested. |
ClearCommand |
Clears source, neg source, inversion, half-axis. |
public enum MappingCategory { Buttons, DPad, Triggers, LeftStick, RightStick }File: MacroItem.cs
Represents a single macro with trigger condition and action sequence.
public class MacroItem : ObservableObject| Property | Type | Description |
|---|---|---|
Name |
string |
Macro name (default "New Macro"). |
IsEnabled |
bool |
Active flag. |
| 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]. |
| Property | Type | Description |
|---|---|---|
TriggerMode |
MacroTriggerMode |
OnPress, OnRelease, WhileHeld. |
ConsumeTriggerButtons |
bool |
Remove trigger buttons from output (default true). |
| Property | Type | Description |
|---|---|---|
Actions |
ObservableCollection<MacroAction> |
Ordered action sequence. |
SelectedAction |
MacroAction |
Selected action. |
| Property | Type | Description |
|---|---|---|
RepeatMode |
MacroRepeatMode |
Once, FixedCount, UntilRelease. |
RepeatCount |
int |
Repeat count (min 1). |
RepeatDelayMs |
int |
Delay between repeats (min 0). |
| 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. |
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
}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();
}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 }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);
}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; }
}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)
}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();
}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 | Sticks | Triggers | POVs | Buttons |
|---|---|---|---|---|
| Xbox360 | 2 | 2 | 1 | 11 |
| DualShock4 | 2 | 2 | 1 | 14 |
| Custom | (keep current) |
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; }
}