The desktop app
Connect over USB, tweak your buttons, axes, and rules, watch your inputs live, and flash firmware updates. All from one window, no drivers needed.
The desktop app is optional. A box works as a joystick without it. You want it when you need to change what the box does, when you want to see what it is actually sending, or when there is a firmware update.
Download
Grab the latest build from the releases page and pick the file for your operating system. It is a single file, no installation required.
On Windows, download siminput-updater-windows.exe and double-click to run. On Linux, download siminput-updater-linux, then make it executable and run it:
chmod +x siminput-updater-linux
./siminput-updater-linuxLinux notes
Serial access needs your user in the dialout group:
sudo usermod -aG dialout $USER # log out and back in afterwardsIf you hit a tkinter error, install it for your distro:
sudo dnf install python3-tkinter # Fedora
sudo apt install python3-tk # Ubuntu / DebianTiny text on a HiDPI screen means the scale detection missed. Start it with --scale 1.5, or set SIMINPUT_SCALE, and adjust the number to taste.
One window, three pages
There is no connect button anywhere. The app scans for SIMINPUT boards by USB vendor ID, connects to the first one it finds, and shows a green dot with the box name in the top right once it has one. With more than one box plugged in, that name is a menu to switch between them. The sidebar switches between the three pages and shows the connected box's name, port, and firmware version. The window follows your system's light or dark mode, with a toggle in the header.
Device
Shows what the box is: name, firmware version, board revision, CircuitPython version, USB product ID, and NVM size. Below that sits the live monitor, a grid of all 128 buttons and bars for the eight axes, updating live as you press things. Under the axes it lists the raw reading of every analog pin the saved config claims, and a Pins line naming the physical pins currently pressed. The box scans its inputs 200 times a second, so what you see is what the sim gets. That makes the monitor the fastest way to find a bad solder joint or work out which pin a control is wired to: press it and read the pin off the Pins line. If the I/O expander was missing at boot, the page shows the fault the firmware reports instead of a silent half-working box.
Configure
Four tabs. Device holds the USB name, product ID, debounce time, and keep-alive. Variables are named on/off states for latches, each with a Remember checkbox to persist across power cycles. Axes map a name to one of the eight HID axes, with a default value, a Remember checkbox, and a Backlight checkbox that drives the backlight from that same axis. Pick Backlight Only as the output instead and the axis drives the backlight without reporting anything to the sim. Rules is the main event: every rule is a card with its fields inline and a plain English summary of what it does, reordered by dragging the handle on the left, or with Alt+↑ and Alt+↓. Order matters, because rules can read the outputs of earlier rules in the same cycle.
There are nine rule types to pick from: Direct Map, All-Off Detector, Toggle Switch, Timed Pulse, Rotary Encoder, Increase Axis, Decrease Axis, Analog Axis, and Analog Threshold. The two analog types need firmware 2.7 or newer, and the picker only offers them when the connected box has it. Every pin field has a Learn button: click it, press the switch on the box, and the pin fills itself in. An Analog Axis card has a Calibrate button that opens a window with the raw reading live, records the travel as you move the sensor, and captures the rest position with a suggested deadzone. One catch for both: the box only samples the analog pins the saved config claims, so a freshly assigned analog pin needs a Save to device before Learn or Calibrate can see it. The app says so in a hint when nothing moves. What the firmware does with those numbers is on the firmware page.
The editor works on a copy. Read from device pulls the box's current configuration in, Save to device validates everything, writes it back, and reboots the box; a save with an unknown pin or button in it is refused before anything is written. Changing the USB name or product ID also needs an unplug and replug before the PC sees it. Import and export move the same configuration through JSON files, which doubles as backup and as the way to share a setup. The hands-on walkthrough, module by module, is in setting up the modules.
Update
Flashes firmware from a .zip package, with a Find the latest firmware button in the header that opens the firmware releases page. The app verifies every file in the package against its checksums before sending anything and backs your configuration up to a SIMINPUT Backupsfolder in your home directory first (a checkbox, on by default; the app's log lives in the same folder, which is the file to attach when reporting a problem). On firmware 2.6 or newer it stages the whole update on the box before committing it, so a failed transfer leaves the device unchanged. Older firmware gets the files written directly, and a failure there can leave the box half updated: re-run the update before unplugging. Packages deliberately do not contain a configuration file, so updating the firmware never touches your rules. Uploads go lib files first, then boot.py, then code.py last, since code.py is what runs.
--mock (or SIMINPUT_MOCK=1 in the environment) to explore the whole app against a simulated device. Useful if you are writing a config before your hardware arrives.Building it yourself
It is built with customtkinter and uv, on Python 3.12 or newer. Clone the repository, run uv sync, then uv run siminput-updater. It is MIT licensed, same as the firmware.