Use your Elite SQUARE cycling controller with indoor cycling apps that don't support it natively: Rouvy, Zwift, MyWhoosh, and any other app that takes keyboard input.
squarectl runs in the background, listens to the SQUARE over Bluetooth, and translates each button press into a keystroke for the app currently in focus. You ride normally; the SQUARE buttons just work.
The Elite SQUARE talks Bluetooth, but most indoor cycling apps don't pair with it directly. squarectl bridges the gap by impersonating a keyboard, so any app that responds to keys (which is essentially all of them) can be controlled from the handlebars.
- An Elite SQUARE controller
- Windows 10 or 11 (WebView2 runtime : preinstalled on Win11, auto-installed by the installer on Win10)
- Bluetooth
- A cycling app you already use
macOS and Linux are supported by the codebase but not packaged as releases yet. See Build from source.
Grab the latest .exe installer from the Releases page and run it.
Windows SmartScreen warning: the installer is not code-signed (signing certificates aren't free, and squarectl is a side project). On first launch you'll see a blue "Windows protected your PC" screen. Click More info → Run anyway. You only need to do this once.
- Power on the SQUARE.
- Launch squarectl. It stays open in the background.
- Pick the profile matching your cycling app from the dropdown (Rouvy, Zwift, MyWhoosh, or any custom profile).
- Launch your cycling app and bring its window to the front.
- Ride. The SQUARE buttons now drive the app via the keyboard mapping.
Zwift on Windows: Zwift ignores keystrokes from squarectl unless squarectl is launched with admin rights. Right-click squarectl → Run as administrator.
Each profile is a small TOML file mapping SQUARE buttons to keys. Three are bundled out of the box (Rouvy, Zwift, MyWhoosh) and you can drop in your own.
Where they live (Windows):
%APPDATA%\org.kochka.squarectl\profiles\
What a profile looks like:
[profile]
name = "Rouvy"
description = "Default mapping for Rouvy"
[buttons]
# D-pad
Up = "up"
Down = "down"
Left = "left"
Right = "right"
# Face buttons
A = "return"
B = "escape"
Triangle = "space"
Square = "h"
# Left shifter
LeftCampagnolo = "left"
LeftBrake = ["1", "6"] # toggle: alternates "1" and "6" each press
LeftShift1 = "" # unmappedMapping forms:
| Form | Effect |
|---|---|
Button = "key" |
A single key tap. |
Button = ["k1", "k2"] |
Toggle: alternates k1 and k2 on every press. Useful for things like switching between two gear groups. |
Button = "" |
Button is intentionally unmapped, no key sent. |
Available key names: up, down, left, right, return, escape, space, tab, backspace, single letters (a–z) and digits (0–9).
Mouse wheel: scroll_up, scroll_down, scroll_left, scroll_right (one press scrolls roughly one physical wheel notch).
SQUARE buttons: Up, Down, Left, Right, A, B, Triangle, Square, Circle, X, Y, Z, LeftCampagnolo, LeftBrake, LeftShift1, LeftShift2, RightCampagnolo, RightBrake, RightShift1, RightShift2.
- Copy an existing
.tomlin the profiles folder, or create a new one. The filename should be lowercase / snake_case (e.g.my_setup.toml); the user-facing profile name comes from thenamefield inside. - Edit the
[buttons]section. - Restart squarectl. The new profile appears in the dropdown.
Only needed if you're on macOS or Linux, or want to tweak the code. Requires Rust, Node.js and pnpm.
pnpm install
pnpm tauri buildThe bundled app lands in src-tauri/target/release/bundle/.
On macOS, squarectl needs Accessibility permission (to simulate keystrokes) and Bluetooth permission the first time it runs. Both are prompted by the OS.
MIT — do whatever you want with it.
squarectl is an independent project. It is not affiliated with or endorsed by Elite, Rouvy, Zwift, or MyWhoosh.
