x20ctl 1.0.1
1.0.1 — 2026-08-16
First stable release. Verified on two EasySMX X20 controllers.
Download x20ctl.exe and run it. No install, no Python needed.
Added
- Standalone Windows executable
- Controller roster: up to four controllers, one per player slot
- Per-controller save files, keyed by Bluetooth address
- Button remapping page
- Macro editor: piano-roll grid, all four slots, per-step timing, repeat
- Macro recording from live play
- Stick direction dial for macro steps, snapping to eight headings
- Saved macros page: whole-controller setups, open in editor or send to pad
- Trigger travel zones and response curves
- Idle shutdown timer, 1–30 minutes or never
- Sensor calibration
- Factory reset, behind a confirmation
- Battery level in the header
- Live connection state per controller, with a prompt when one goes quiet
- Vibration preview: the pad buzzes at the strength being set
- Update check against GitHub releases
- Simple and Advanced modes
- CLI:
sleep,remap,macro --read,calibrate,factory-reset,
curve --gear,curve --preset
Changed
- App opens on the controller roster instead of the macro editor
- Sidebar navigation replaces the tab strip
- Every page that edits the controller has a Save button
- Vibration saves itself; no Apply needed
- Discovery returns every controller found, not just the first
- Higher-contrast text throughout
- Window opens at 1280×820
Fixed
- Macros capped at 47 steps, where the chunk index runs out, instead of failing
inside the packet builder - Macro recording captures the left stick, not only buttons
- Key lists stop at their declared count instead of overrunning a repeated
record - Recording nothing no longer crashes
- Select and Start refused as remap sources; the controller accepts and ignores
them
Protocol
Decoded and verified on hardware:
- Idle shutdown timer lives inside the motor record, as 5 ms ticks
- Trigger zones are deadzone pairs; response curves are Hermite control points
- Sensor calibration is
SET_MODE 03 DF AB 10 - Factory reset is
RECOVER 03 DF A9 02; the wrong generation byte is ignored
silently - Macros read back via
HOST_MACRO, notREAD_MACRO
(found by chriss80) - Select and Start are key codes 93 and 94, not 9 and 10
Known limitations
- Output mode (XInput / DirectInput) changes only by button combination on the
controller - Sensor calibration sends correctly; its effect is unverified
- Lighting and turbo are not configurable over this protocol
- Trigger settings are chosen by name, not drawn
- The executable is unsigned, so Windows warns that the publisher is unknown