Cross-platform gamepad tooling for anyone.
Ultimate multi-platform, multi-language controller tool for remapping and compability layering, Any input device in, any virtual controller out: Xbox, PlayStation or Nintendo. third-party gamepad, keyboard or/and mouse. Built on SDL3, HIDMaestro, VigemBus, and .NET 10 and Avalonia.
Autofire, remapping, stick shaping, freeze macros, keyboard/mouse-as-gamepad, and virtual controller output — all in one clean UI.
v1.0.0 Beta · Built with .NET 10 · Avalonia UI · SDL3 · HIDMaestro
No pressure — using and sharing the project already helps a lot. Thank you!
GameFlow is a desktop application that sits between your physical input (a gamepad, or your keyboard and mouse) and any game or application. It reads your physical input, transforms it according to a saved profile, and writes the result to one or more virtual controllers that the game sees.
This project started as a script to spare players from repetitive inputs that were damaging both their controllers and their hands — not a great solution, and it barely worked. It was later rebuilt in Python as Autofire, addressing gaps left by Joy2Key, DSX/DS4Windows, and Gamepad Viewer, but Python's dependency weight made it painful to maintain. That version served as the architecture prototype for the C#/.NET application you're looking at now, since renamed to GameFlow to avoid confusion between the product and autofire the individual feature.
Transformations include:
- Autofire / rapid fire — pulse any button or stick at a configurable rate
- Button remapping — re-route any button to any other button
- Stick shaping — deadzone, full-at threshold, and blend-mode control
- Freeze last direction — latch the stick vector at the moment a button is pressed
- Keyboard & mouse as gamepad (Windows) — map WASD, mouse look, and clicks straight into a virtual controller, no physical pad required
- Multiple virtual controllers — run several independent input → profile → output pipelines ("slots") at once, each with its own device assignment and output backend
- Profile system — create, duplicate, rename, import, and export JSON profiles
- Live dashboard — physical and virtual controllers rendered side by side, per slot, so you can see exactly what a profile changed
| Category | Details |
|---|---|
| Autofire | Button and stick autofire with configurable hold/release timing and jitter-resistant hysteresis |
| Remapping | Button-to-button remap with optional source suppression |
| Stick shaping | Per-stick deadzone and full-at threshold, applied directly to virtual output |
| Freeze macro | Captures the stick vector on the rising edge of an activation button; optional pulse-while-frozen mode |
| Keyboard & mouse input | Windows Raw Input, synthesized into a full gamepad snapshot (movement, look, clicks, scroll) — no physical controller needed |
| Multiple controllers | Each "slot" is an independent input → profile → output pipeline; run as many simultaneously as you have devices and outputs for |
| Profiles | JSON-based, per-profile polling rate, provider selection, controller style, and rename support |
| Input providers | SDL3 unified (all platforms, gamepads + joysticks), Windows Raw Input (keyboard/mouse), Demo preview, None |
| Output providers | HIDMaestro (Windows, no kernel driver), Preview (no virtual device, any platform) |
| Dashboard | Physical and virtual controllers shown side by side — both the primary pipeline and every active slot — with a shared background/theme picker and a clear "virtual" badge on emitted devices |
| UI | 8-language interface, switchable live from the header without restarting |
| Requirement | Version |
|---|---|
| .NET SDK | 10.0 or later |
| Git | Any recent version |
Input — gamepads and joysticks on every platform — goes through SDL3, so the native library must be available next to the app or on the system library path:
| Platform | File | Location |
|---|---|---|
| Windows | SDL3.dll |
Next to GameFlow.App.exe |
| Linux | libSDL3.so |
System library path, or the app directory |
| macOS | libSDL3.dylib |
System library path (e.g. /usr/local/lib), or the app directory |
Download from libsdl.org or build from source. An optional gamecontrollerdb.txt (SDL_GameControllerDB) can be placed in the application directory to extend the built-in gamepad mapping database.
GameFlow uses HIDMaestro exclusively to create a virtual controller: a user-mode platform with no kernel driver and no reboot. Drop HIDMaestro.Core.dll (plus its driver payload) next to GameFlow.App.exe and it activates automatically on next launch — no rebuild needed. The first run may prompt for elevation to install its (still driver-less, UMDF2) component.
If it isn't available, that slot simply has no output — GameFlow will not silently substitute a different provider, and the log and the slot's displayed name both say exactly why. The app still runs normally either way; any slot's output provider falls back to Preview (no virtual device — the transformed state is shown on the dashboard only).
SDL3 unified input works out of the box for reading physical gamepads once the native library above is in place. Native virtual-controller output (uinput on Linux, IOHIDUserDevice/CoreHID on macOS) is not implemented yet — Preview is the only output provider on these platforms today. Keyboard/mouse-as-gamepad input is currently Windows-only (it's built on Windows' Raw Input API).
For joystick/gamepad access on Linux without sudo, add your user to the input group:
sudo usermod -aG input $USER
# then log out and back ingit clone https://github.com/Prooxie/GameFlow.git
cd GameFlowdotnet build GameFlow.slndotnet run --project src/GameFlow.AppOn first launch the application creates a default profile under:
| Platform | Location |
|---|---|
| Windows | %LOCALAPPDATA%\AutofireNext\ |
| Linux | ~/.local/share/AutofireNext/ |
| macOS | ~/Library/Application Support/AutofireNext/ |
That folder is still named
AutofireNexton purpose — it predates the rename to GameFlow, and changing it would orphan existing installs' profiles and settings. It's an internal path nobody types or sees; the app itself, everywhere you actually interact with it, says GameFlow.
Open the Profiles tab and create a new profile, or start from the default. A profile bundles a polling rate, an input source, and every mapping rule (autofire, remap, thresholds, freeze) you define for it.
- Go to the Devices tab and confirm your physical gamepad, keyboard, or mouse is listed under Physical devices.
- Switch to the Virtual controllers panel and click Add controller to create a slot.
- Assign the slot's input: pick the physical device from the list.
- Open the slot's Template Editor and set:
- Output kind — the virtual controller shape (Xbox 360 / DualShock 4 / DualSense / Generic).
- Output provider — the backend that actually emits it (HIDMaestro or Preview). This is the setting that matters for whether a real device is created.
- Toggle Enabled on the slot.
The Dashboard shows a physical/virtual pair for the primary pipeline, plus one full-size physical/virtual pair per active slot — the virtual side carries a colored VIRTUAL badge so it's unmistakable which one is the emitted device. Move the physical controller (or type/click, for a keyboard/mouse slot) and confirm the virtual side mirrors it through whatever mapping you've applied.
Note that a slot's own virtual output is deliberately hidden from every input picker in the app — you can't accidentally (or deliberately) feed a virtual controller back in as input, direct or through another slot.
Back in Profiles, use + Add rule against any control to add autofire, remap, stick threshold, freeze-direction, or script rules. Rules apply in order, every polling tick, and take effect immediately — no separate "apply" step for rule changes.
The background picker (Dashboard tab) applies one background — a solid color or "follow the app theme" — across every physical/virtual pair at once, so comparisons stay visually consistent as you switch profiles, slots, or the app's own theme.
src/GameFlow.App/appsettings.json controls runtime behaviour:
{
"Runtime": {
"DashboardRefreshHz": 165,
"StartRuntimeOnLaunch": true,
"DefaultCulture": "en",
"Updates": {
"RepoOwner": "Prooxie",
"RepoName": "GameFlow",
"AssetNamePattern": "GameFlow-{tag}-{rid}.zip",
"UserAgent": "GameFlow-UpdateChecker"
}
}
}| Key | Default | Description |
|---|---|---|
DashboardRefreshHz |
165 |
UI refresh rate for the live dashboard and controller panels |
StartRuntimeOnLaunch |
true |
Whether the input/output runtime starts automatically on launch |
DefaultCulture |
en |
Fallback UI language before a user preference is saved |
Updates:RepoOwner / RepoName |
Prooxie / GameFlow |
GitHub-releases update checker — enabled by default, pointed at this repo |
Profiles are JSON files stored in the application data directory (see Quick Start). Each profile defines:
- Input provider selection and per-controller polling rate (30–1000 Hz)
- All mapping rules (autofire, remap, threshold, freeze, script)
- Controller surface display style and dashboard background
- Slot definitions: assigned input device(s), output kind, and output provider
Profiles can be created, duplicated, renamed, imported, and exported from the Profiles tab without touching JSON directly.
| ID | Platform | Notes |
|---|---|---|
sdl |
All | SDL3 unified — gamepads and joysticks on every platform, plus Raw Input keyboard/mouse synthesis on Windows. The default and recommended input provider. |
demo |
All | Animated preview source for UI testing. No hardware required. |
none |
All | Disables live input. Dashboard stays idle. |
Older profiles referencing retired providers (XInput, GameInput, x360ce, PS3, and similar) migrate to sdl automatically.
| ID | Platform | Notes |
|---|---|---|
hidmaestro |
Windows | Virtual controller via HIDMaestro — no kernel driver. Activates automatically when HIDMaestro.Core.dll is present. The sole real output backend; ViGEm was removed as a dependency. |
preview |
All | No virtual device. Shows the transformed state on the dashboard only. |
GameFlow/
├── src/
│ ├── GameFlow.App # Avalonia UI, ViewModels, Views, Localization
│ ├── GameFlow.Core # Domain models, pipeline, rule types, schedulers
│ └── GameFlow.Infrastructure # SDL3, HIDMaestro, profile persistence, runtime
├── tests/
│ └── GameFlow.Core.Tests # Unit tests for the mapping pipeline
└── .github/workflows/ # CI: build, test, and release packaging
Physical input Keyboard / mouse (Windows)
│ (SDL3 gamepad/joystick) │ (Raw Input)
▼ ▼
InputSource.ReadAsync() / ReadDevice() ────┘
│
▼
ControllerMappingPipeline (one per active slot, isolated)
├── StickThresholdRule (deadzone / full-at)
├── ButtonRemapRule (source → target)
├── ButtonAutofireRule (binary pulse scheduler)
├── StickAutofireRule (stick pulse scheduler + hysteresis)
└── FreezeLastDirectionRule (rising-edge capture + optional pulse)
│
▼
OutputSink.WriteAsync()
│ (HIDMaestro · Preview)
▼
Virtual controller seen by games — and hidden from GameFlow's
own input list, so it can never be selected back in as a source.
Every slot's rules are stored in its profile's JSON and applied in order on every polling tick. The dashboard reads from lock-free snapshot stores on a timer, independent of the mapping pipeline's own tick rate, so the UI never blocks live input processing.
The UI is fully translated into:
🇬🇧 English · 🇨🇿 Czech · 🇩🇪 German · 🇪🇸 Spanish · 🇫🇷 French · 🇮🇹 Italian · 🇵🇱 Polish · 🇷🇺 Russian
Language can be changed live from Settings without restarting the application.
Contributions are welcome.
- Fork the repository
- Create a branch:
git checkout -b feature/my-feature - Commit your changes
- Open a Pull Request
Please keep commits focused and include a short description of what changed and why.
This project is licensed under the MIT License.
- HIDMaestro by hifihedgehog — the driver-less, user-mode virtual controller platform.
- SDL_GameControllerDB — the community gamepad mapping database SDL3 input builds on.
- VSCView THEMEENGINE by Nielk1 — the controller theme format GameFlow's controller surfaces are compatible with.
- AL2009man's Gamepad Asset Pack & Prompt Asset Pack — controller and button-prompt art.
Check out my other projects on GitHub, YouTube, and Twitch.
Nazzareno96 — keeping me sane during development, beta testing twitch.tv/nazzareno96
NoobKillerRoof — voicing real hardware/software pain points that inspired this project, beta testing twitch.tv/noobkillerroof