Installation
Download the latest VGhostSetup.exe from the
Download page and run it.
The installer will place V-Ghost in %LocalAppData%\Programs\V-Ghost
and create a Start Menu shortcut.
V-Ghost requires the .NET 9 Desktop Runtime. If it is not already installed, the setup wizard will offer to download it automatically.
First Launch
On first launch V-Ghost will ask you to:
- Grant microphone permission � Windows will show a permission prompt, click Allow.
- Choose your default language (English is pre-selected).
- Choose your recognition engine � Vosk (recommended, offline) or Windows SAPI.
If you chose Vosk, the app will download the language model (~50�150 MB depending on language) on first use. An internet connection is only required for this initial download; afterwards everything runs offline.
Create a Profile
Profiles group voice commands together. You can have as many profiles as you like � for example one for a game, one for your code editor, one for general Windows control.
- Open the Profiles tab (second icon in the bottom bar).
- Tap the + button to create a new profile.
- Give it a name, e.g.
Visual Studio Code. - Optionally set a Confidence Threshold (0�1). The default of
0.75is a good starting point � lower it if commands aren't triggering. - Press Save.
Add Voice Commands
Inside a profile, each command maps a spoken phrase to one or more actions.
- With a profile open, tap Add Command.
- In the Phrase field, type the spoken trigger � e.g.
save. - Choose an Action Type:
- Key Press � simulate a key or modifier combo
- Mouse Click � left, right, or middle click at a target
- Process Launch � start an application or script
- Delay � pause for N milliseconds (useful in sequences)
- Configure the action. For Key Press, select the key and any modifier (
Ctrl,Shift,Alt,Win). - Press Save.
Example: "save" ? Ctrl+S
Phrase: save
Action: Key Press
Key: S
Modifiers: Ctrl
Say "save" while the profile is active and V-Ghost sends Ctrl+S.
Macro sequences
You can chain multiple actions into a single command using a Macro Sequence. Add multiple steps (key presses, delays, etc.) in order � they execute in sequence when the phrase is heard.
Vosk vs Windows SAPI
V-Ghost supports two recognition backends. Both work fully � choose based on your preference:
| Vosk | Windows SAPI | |
|---|---|---|
| Internet required | Only for model download | Never |
| Accuracy | Excellent | Good |
| Languages | 29 (downloadable models) | Whatever Windows supports |
| Extra download | ~50�150 MB per language | None |
| Custom vocabulary | No | Yes (Windows Speech Training) |
Auto-Activate Profiles
A profile can be set to automatically activate when a specific application is in the foreground. This means your gaming profile switches on the moment you alt-tab into your game and switches back when you leave it.
- Open a profile and scroll to Auto-Activate.
- Enter the process name of the target app � e.g.
Codefor VS Code orEliteDangerous64for Elite Dangerous. - Save the profile. It will now activate and deactivate automatically.
Ctrl+Shift+Esc) ? Details tab to find the exact executable name.
Settings Reference
Recognition Engine
Switch between Vosk and Windows SAPI globally, or override per profile.
Push-to-Talk
When enabled, recognition only runs while you hold down the configured hotkey. Useful if you don't want accidental triggers during normal conversation.
Overlay
A small on-screen indicator that shows the last recognized phrase and the active profile. Can be positioned in any corner of the screen (Top-Left, Top-Right, Bottom-Left, Bottom-Right) or disabled entirely.
Command Timeout
How long (in seconds) V-Ghost waits after a phrase is heard before discarding the match. Default: 30 seconds.
New in v1.3.0
Variables & State Management
Variables let you store named values that persist across command executions within a profile session. Three action types manage them:
- Set Variable � store any string value; the
Valuefield supports{OtherVar}interpolation so one variable can be derived from another. - Toggle Variable � flips a boolean between
"true"and"false". An unset variable is treated as"false", so the first toggle sets it to"true". - Increment Variable � adds an integer amount (positive or negative) to a numeric variable. Unset variables are treated as
0.
Reference any variable with {VarName} in Say Text, Set Variable
values, and other text fields. Variables are case-insensitive and scoped to the active
profile � they reset when you switch profiles.
Command: "Flight assist on"
Set Variable: flightAssist = "true"
Say Text: "Flight assist enabled"
Command: "Flight assist off"
Set Variable: flightAssist = "false"
Say Text: "Flight assist disabled"
Command: "Toggle flight assist"
Toggle Variable: flightAssist
If flightAssist IsTrue
Then ? Say Text: "Flight assist on"
Else ? Say Text: "Flight assist off"
If�Then�Else Conditionals
The If Condition action evaluates a variable and branches into a Then or Else action list. Branches can be nested.
Operators
| Operator | Passes when� |
|---|---|
IsTrue | variable equals "true" (case-insensitive) |
IsFalse | variable does not equal "true" |
IsSet | variable exists (any value) |
IsNotSet | variable has never been set |
Equals | case-insensitive string match |
NotEquals | string mismatch |
GreaterThan | numeric comparison (both sides parsed as integers) |
LessThan | numeric comparison |
Command: "Emergency boost"
If fuel GreaterThan "20"
Then ?
Key Press: BoostKey
Increment Variable: fuel (Amount: -20)
Else ?
Say Text: "Insufficient fuel"
Call Command
Call Command looks up another command in the active profile by its exact phrase (case-insensitive) and executes its actions, sharing the same variable context. This lets you build reusable subroutines.
- Recursion protection � V-Ghost tracks call depth and throws an error if it exceeds 10, preventing infinite loops.
- Global profile support � a command in a global profile can be called from any game profile.
Command: "Battle stations"
Call Command: "Raise shields"
Call Command: "Weapons hot"
Play Sound: alert.wav
Say Text: "Battle stations"
Command: "Raise shields" ? reusable subroutine
Key Press: ShieldKey
Delay: 100 ms
Key Press: MaxShield
_raise shields so they are easy to distinguish from spoken commands.
Text-to-Speech (Say Text)
Speak text aloud using Windows SAPI 5.1 (built-in on Windows 10 and later).
| Parameter | Range / Default | Notes |
|---|---|---|
| Text | Any string | Supports {variable} interpolation |
| Rate | -10 to +10 / 0 | Negative = slower, positive = faster |
| Volume | 0�100 / 100 | Percentage of system volume |
| Voice | Installed SAPI voices | Leave blank for Windows default |
Command: "Status report"
Set Variable: shields = "75"
Say Text: "Shields at {shields} percent" (Rate: 0, Volume: 90)
Audio Playback (Play Sound)
Trigger an audio file. Playback is synchronous � the next action waits until the sound finishes.
| Parameter | Details |
|---|---|
| File Path | Full or relative path to audio file. Supported formats: WAV, MP3, FLAC, OGG, WMA. |
| Volume | 0.0 (silent) � 1.0 (full). Default 1.0. |
Command: "Enemy detected"
Play Sound: sounds/alert.wav (Volume: 1.0)
Say Text: "Enemy contact" (Rate: -2)
Mouse Move
Move the cursor to an exact position or shift it by a pixel offset.
| Parameter | Details |
|---|---|
| X | Horizontal coordinate (absolute pixels from left, or relative offset) |
| Y | Vertical coordinate (absolute pixels from top, or relative offset) |
| Relative | OFF (default) = absolute screen coordinates. ON = offset from current position. |
Command: "Fine aim right"
Mouse Move: X=15, Y=0, Relative=ON
Command: "Centre cursor"
Mouse Move: X=960, Y=540, Relative=OFF
Mouse Scroll
Spin the scroll wheel by a set number of clicks.
| Parameter | Details |
|---|---|
| Clicks | Positive = up or right; negative = down or left. Any integer. |
| Horizontal | OFF (default) = vertical scroll. ON = horizontal scroll. |
Command: "Scroll inventory up"
Mouse Scroll: Clicks=5, Horizontal=OFF
Command: "Scroll tabs right"
Mouse Scroll: Clicks=3, Horizontal=ON
Command Groups
Assign a Group name to any command. In the profile editor, commands with the same group name are collected under a collapsible section, making large profiles easier to navigate. Groups have no effect on recognition or execution.
Elite Dangerous profile
? Weapons � Fire primary, Fire secondary, Arm/Disarm
? Shields � Raise shields, Reboot shields
? Navigation � Cruise control, Full stop, Jump
Global Profiles
A profile marked as Global is always active alongside whichever game-specific profile is running. Commands in the global profile are checked as a fallback after the active game profile.
- Ideal for system-level controls: mute mic, volume up/down, toggle overlay.
- Global variables are scoped to the global profile and survive game profile switches.
- Game-profile commands take precedence � the global version runs only if no match is found in the active profile.
Profile: "Global" (Is Global: ?)
"mute microphone" ? Key Press: F1
"unmute" ? Key Press: F1
"volume up" ? Key Press: Vol+
"toggle overlay" ? Toggle overlay action
First-Run Onboarding
New installations launch a guided setup wizard instead of dropping the user directly into an empty app. The wizard covers:
- Microphone selection � choose and test your input device.
- Recognition engine � Vosk (offline, recommended) or Windows SAPI.
- Language & model � download a Vosk model or confirm the SAPI language.
- First profile � create a blank profile or import a built-in template.
- Tutorial � optional walkthrough showing how to create and fire a command.
You can re-run the wizard at any time from Settings ? Run Setup Wizard.
New in v1.4.0
Dictation (Free-Form Text Capture)
Capture any spoken text without a predefined phrase list � perfect for note-taking, search input, chat messages, or any scenario where the user speaks exactly what they want to type.
| Parameter | Details |
|---|---|
| Target | type (default) = type into focused window; any other value = variable name to store result |
| Timeout | How long to wait for speech (milliseconds). Default 10 000 (10 seconds). |
Command: "Take a note"
Dictation: (Target: "type", Timeout: 10000)
Command: "Save to clipboard"
Dictation: (Target: "clipboard_text", Timeout: 5000)
Call Command: "copy that" ? copies {clipboard_text} to clipboard
HTTP Request (REST Integration)
Trigger HTTP GET or POST requests from a voice command. URLs and request bodies support
{variable} interpolation, and response bodies can be captured into variables for further processing.
| Parameter | Details |
|---|---|
| URL | Endpoint to call. Supports {variable} interpolation. |
| Method | GET (default) or POST |
| Body | JSON or form data (POST only). Supports {variable} interpolation. |
| Content-Type | Header sent with POST. Default: application/json |
| Response Variable | Optional: if set, response body is stored in this variable |
| Timeout | Request timeout in milliseconds. Default 10 000. |
Command: "check weather"
HTTP Request:
URL: "https://api.weather.example/current?city=Seattle"
Method: GET
Response Variable: weather_data
Say Text: "Current conditions: {weather_data}"
Command: "log to server"
HTTP Request:
URL: "https://example.com/logs"
Method: POST
Body: {"event": "command_fired", "timestamp": "{timestamp}"}
Content-Type: application/json
Repeat (Fixed Iteration Loop)
Execute a list of sub-actions a fixed number of times with optional delay between each iteration. Hard cap of 1 000 iterations prevents accidental infinite loops.
| Parameter | Details |
|---|---|
| Count | Number of times to execute the body (1�1 000). Default 3. |
| Delay Between | Milliseconds to wait between each iteration. 0 = no delay (runs as fast as possible). |
Command: "spam test"
Repeat: (Count: 10, Delay: 100ms)
Body:
Key Press: Space
Command: "multi-select"
Repeat: (Count: 5, Delay: 0)
Body:
Left Click
Key Press: Down
Key Press: Ctrl+Space
Repeat While (Conditional Loop)
Loop a sub-action list as long as a variable condition remains true. Uses the same 8 operators as If�Then�Else. Iteration limit (default 100) prevents hangs.
| Parameter | Details |
|---|---|
| Variable | Name of the variable to check |
| Operator | IsTrue, IsFalse, Equals, NotEquals, GreaterThan, LessThan, IsSet, IsNotSet |
| Compare Value | For Equals / NotEquals / GreaterThan / LessThan (optional for IsTrue/IsFalse/IsSet/IsNotSet) |
| Max Iterations | Safety guard (default 100). If exceeded, loop terminates. |
| Delay Between | Milliseconds to wait between iterations. 0 = no delay. |
Command: "drain mana"
Set Variable: action_count = 0
Repeat While: (Variable: "action_count" GreaterThan "0", Max Iterations: 100, Delay: 50ms)
Body:
Key Press: CastSpell
Increment Variable: action_count (Amount: -1)
Command: "wait for ready"
Set Variable: game_ready = false
Repeat While: (Variable: "game_ready" IsFalse, Max Iterations: 60, Delay: 1000ms)
Body:
(loop runs up to 60 times, 1 second apart, waiting for some external trigger to set game_ready=true)
Persistent Variables (Saved State)
Variables now survive app restart. Each profile has its own persistent variable file on disk (stored as JSON), shared across all commands in that profile.
Use cases
- Game state tracking � remember which loadout is active, even after closing V-Ghost
- Configuration persistence � save user preferences (difficulty, volume, UI theme) without UI dialogs
- Session history � log gameplay events or command usage across multiple sessions for analytics
- Long-running automation � track progress on multi-day or multi-session tasks
Example: Game Profile Persistent Variables
Initial state (first run):
last_loadout = "not_set"
session_kills = 0
playtime_minutes = 0
Command: "load combat loadout"
Set Variable: last_loadout = "combat" (persisted on cmd execution)
(game loads combat gear)
User closes V-Ghost, plays, comes back in 3 days
Command: "resume last loadout"
If last_loadout Equals "combat"
Load saved loadout automatically
Command: "tally kills"
Increment Variable: session_kills
If session_kills GreaterThan "50"
Say Text: "50 kill milestone!"
Set Variable: last_milestone = "50"
Persistent variable files are edited alongside your command JSON; they are human-readable and fully portable. You can back them up, sync them to cloud, or restore them manually.
New in v1.5.6
Key Hold
Hold a keyboard key or modifier combination for a specified number of milliseconds, then release it. The game or app sees a sustained key-down event � useful for any input that behaves differently when held vs. tapped (boost, charge, thrust, etc.).
| Parameter | Details |
|---|---|
| Key | Key name or combo, e.g. Space, Ctrl+S, Shift+F5 |
| Duration (ms) | How long to hold before releasing. Default: 500 ms. |
Command: "boost"
Key Hold: Space (Duration: 2000 ms)
Command: "charge attack"
Key Hold: LeftMouseButton (Duration: 1000 ms)
Key Repeat
Press a key (or key combo) a fixed number of times with an optional delay between each press. Replaces a Repeat + Key Press pair with a single compact action.
| Parameter | Details |
|---|---|
| Key | Key name or combo, e.g. Down, Ctrl+Z |
| Count | Number of presses (1�1 000). Default: 3. |
| Delay Between (ms) | Pause between each press. 0 = fire as fast as possible. Default: 50 ms. |
Command: "undo five"
Key Repeat: Ctrl+Z (Count: 5, Delay: 30 ms)
Command: "scroll down fast"
Key Repeat: Down (Count: 20, Delay: 0)
Type Text
Simulate character-by-character keyboard typing into the currently focused window.
Supports {variable} interpolation � compose a value across commands and
then type it anywhere without copy-paste.
| Parameter | Details |
|---|---|
| Text | String to type. Supports {VarName} interpolation. |
| Delay Per Character (ms) | Time between each character. 0 = instant. Default: 20 ms. |
Command: "type my email"
Type Text: "[email protected]" (Delay: 20 ms)
Command: "paste player name"
Type Text: "{playerName}" (Player name previously stored via Set Variable)
SendInput for high-fidelity character simulation.
Most applications (browsers, editors, chat boxes) respond correctly. Games that bypass
the Windows input stack may not receive typed input � use Key Press for those instead.
Gamepad Macros
V-Ghost emulates a virtual Xbox 360 controller via the ViGEm Bus driver, which is bundled with the installer. No extra software is required. Games and applications that accept XInput input will respond to all four gamepad macro types below.
Gamepad Button Press
Press and immediately release a single virtual controller button.
| Parameter | Details |
|---|---|
| Button | A, B, X, Y, LB, RB, LT, RT, Start, Back, DUp, DDown, DLeft, DRight |
| Press Delay (ms) | How long to hold before releasing. Default: 100 ms. Shorter values may not register in some games. |
Command: "jump"
Gamepad Button Press: A (Press Delay: 100 ms)
Command: "reload"
Gamepad Button Press: X (Press Delay: 120 ms)
Gamepad Button Hold
Hold a button for a configurable duration, then release it. Release is guaranteed even if the command is cancelled mid-execution.
| Parameter | Details |
|---|---|
| Button | Same options as Button Press above |
| Duration (ms) | How long to hold the button. Default: 500 ms. |
Command: "sprint"
Gamepad Button Hold: LS (Duration: 3000 ms)
Command: "charge shot"
Gamepad Button Hold: RT (Duration: 2000 ms)
Gamepad Button Chord
Hold a modifier button, then press a second button while the modifier is held � like LB+A or RB+X. Configurable timing for each phase.
| Parameter | Details |
|---|---|
| Hold (modifier) | Button to hold throughout |
| Press (button) | Button pressed while the modifier is held |
| Pre-Hold (ms) | How long to hold the modifier before pressing. Default: 100 ms. |
| Press Delay (ms) | How long to hold the pressed button. Default: 100 ms. |
| Post-Hold (ms) | How long to keep holding the modifier after releasing. Default: 100 ms. |
Command: "special move"
Gamepad Button Chord: Hold=LB, Press=A
Command: "ultimate"
Gamepad Button Chord: Hold=RB, Press=Y (Pre-Hold: 200 ms, Press Delay: 150 ms)
Gamepad Axis
Set an analog stick or trigger to a precise position for a specified duration. Useful for throttle, steering, or camera deflection. The axis returns to centre after the duration expires.
| Parameter | Details |
|---|---|
| Axis | LeftX, LeftY, RightX, RightY, LeftTrigger, RightTrigger |
| Value | -100 to +100 for sticks; 0�100 for triggers. 0 = centre / not pressed. |
| Duration (ms) | How long to hold the axis at the value before releasing. Default: 500 ms. |
Command: "full throttle"
Gamepad Axis: RightTrigger, Value=100 (Duration: 2000 ms)
Command: "steer left"
Gamepad Axis: LeftX, Value=-80 (Duration: 500 ms)
Your Data & File Format
V-Ghost stores all configuration as plain JSON files on your local machine. There is no database, no cloud sync, and no proprietary binary encoding. You own the files outright � V-Ghost is simply a reader and writer for them.
Where files are stored
%AppData%\V-Ghost\
Profiles\
EliteDangerous.json
Coding.json
Global.json
Settings.json
Open this folder at any time from Settings ? Open Profiles Folder in the app.
Profile file structure
Each profile is a single self-contained .json file. Below is an annotated
example showing the key fields:
{
"Name": "Elite Dangerous",
"IsGlobal": false,
"AutoActivateProcess": "EliteDangerous64.exe",
"Commands": [
{
"Phrase": "battle stations",
"Group": "Combat",
"Actions": [
{ "Type": "KeyPress", "Key": "F1" },
{ "Type": "PlaySound", "FilePath": "sounds/alert.wav", "Volume": 1.0 },
{ "Type": "SayText", "Text": "Battle stations", "Rate": 0, "Volume": 90 }
]
},
{
"Phrase": "check fuel",
"Group": "Navigation",
"Actions": [
{
"Type": "IfCondition",
"Variable": "fuel",
"Operator": "GreaterThan",
"Value": "20",
"SubActions": {
"Then": [ { "Type": "SayText", "Text": "Fuel at {fuel} percent" } ],
"Else": [ { "Type": "SayText", "Text": "Warning: fuel critical" } ]
}
}
]
}
]
}
What this means for you
- Edit by hand � fix a phrase typo, reorganise groups, or add a command directly in any text editor. No UI required.
- Version control � drop your Profiles folder into a Git repository to track every change and roll back mistakes.
- Bulk generation � write a script to produce hundreds of commands from a spreadsheet or data source and drop the resulting JSON straight into the folder.
- Sharing � send a
.jsonfile to another V-Ghost user; they place it in their Profiles folder and it works immediately. No account linking, no import wizard. - Zero lock-in � if you ever move to a different voice-macro tool, your data is already in a universally readable format. Copy the folder. You're done.