A complete port of OpenRazer to Windows 10 and 11. The Linux kernel driver becomes user-space HID, D-Bus becomes a loopback daemon, and every per-device quirk is transpiled straight from the upstream C sources.
Python 3.9 or newer on Windows 10 / 11 (amd64). Nothing else.
pip install openrazer-win
# optional, for Bluetooth-only devices such as the Kraken Kitty V2 BT
pip install "openrazer-win[ble]"
The entire port runs on the standard library — no compiler, no hidapi wheel,
no driver signing, no reboot. Prefer a single file? Download
openrazer-win.exe from the
latest release; it
needs no Python at all.
openrazer-win doctor to check.
A command line, a Python API and a small graphical panel — pick whichever suits.
# start the background service, then look around
openrazer-win daemon start
openrazer-win list
openrazer-win info
# lighting
openrazer-win effect static red
openrazer-win effect spectrum
openrazer-win effect wave --direction 2
openrazer-win effect breath_dual "#ff0080" --colour2 cyan
openrazer-win effect ripple green # follows your typing
# one colour per zone -- on the Bluetooth headset, one per ear
openrazer-win zones
openrazer-win zones red blue
# named lighting profiles, kept on this PC
openrazer-win profile save night
openrazer-win profile load night
# settings
openrazer-win brightness 60
openrazer-win dpi 1800
openrazer-win poll-rate 1000
openrazer-win battery
# start the daemon with Windows (per-user, no admin rights)
openrazer-win autostart enable
Every command accepts --device (serial, product id or part of the name),
--zone and --json. Autostart writes a single
HKCU\…\Run entry, so it shows up in Task Manager's Startup tab too.
from openrazer_win.client import DeviceManager
for device in DeviceManager().devices:
print(device.name, device.serial, device.firmware_version)
device.fx.static(0, 255, 0)
device.brightness = 75
if device.has('dpi'):
device.dpi = (1800, 1800)
# per-key lighting, same shape as upstream's fx.advanced
keyboard = DeviceManager().by_name('BlackWidow')[0]
matrix = keyboard.fx.advanced
for row in range(matrix.rows):
for column in range(matrix.columns):
matrix[row, column] = (255, 0, 128)
matrix.draw()
# one colour per zone, sent as a single write where the device allows it
headset = DeviceManager().by_name('Kraken Kitty V2 BT')[0]
headset.colour_zones() # ['left', 'right']
headset.set_colour_zones([(255, 0, 0), (0, 0, 255)])
The API mirrors upstream's openrazer.client, so Linux scripts usually port by
changing the import. No daemon? DeviceManager(direct=True) opens the HID
handles in-process.
openrazer-win-gui
A small Tk window: device list, zone and effect pickers, colour swatches, brightness, DPI and polling rate. Tk ships with Python on Windows, so this needs no extra install either.
The Linux stack is a kernel module plus a D-Bus daemon. Neither exists on Windows, so each layer gets a direct replacement.
OpenRazer's drivers encode roughly 20 000 lines of per-device behaviour as
switch (device->usb_pid) statements — which report builder to call, which LED id,
which transaction id. Hand-porting that would guarantee drift from upstream.
Instead a transpiler parses the C, folds every switch against each known product id, and emits a tiny program per (attribute, device):
[{"op": "build", "fn": "razer_chroma_extended_matrix_effect_static",
"args": [{"k": "const", "value": 1}, {"k": "var", "name": "led_id"},
{"k": "rgb", "offset": 0}]},
{"op": "txid", "value": {"k": "const", "value": 63}},
{"op": "send"}]
565 distinct recipes cover all 267 devices, and a runtime interpreter executes them. Tracking a new upstream release means re-running the transpiler, not rewriting Python.
The kernel addresses a USB interface directly. Windows exposes each as its own HID
collection, so the port picks the one whose path carries the matching &mi_XX
and declares a 90-byte feature report.
Windows denies read/write on keyboard and mouse collections. Feature-report IOCTLs are
FILE_ANY_ACCESS, so the port falls back to a zero-access handle and still
talks to the device.
A built-in emulator validates CRCs and answers the protocol. 315 tests plus a fleet simulation exercise every capability of all 267 devices on every commit.
Upstream reads /dev/input to place ripples. Here a low-level keyboard hook
observes key presses — it never swallows or synthesises input — and the host renders the
frames.
Windows cuts USB power on suspend. The daemon records what was applied per serial and replays it when the device reappears.
Kraken headsets predate the control report: they expose the lighting controller's RAM.
Colours go to fixed addresses, then one byte says what to do with them — ported from
razerkraken_driver.c by hand, since it has no switch tables to transpile.
The Kraken Kitty V2 BT has no USB data mode, so upstream has no driver for it. Its
lighting was recovered here from a Bluetooth HCI capture: a vendor GATT service whose UUID
spells Amel-RazerBLE, taking c4 00 06 and one RGB triple per
ear. Each ear can be given its own colour, in a single write. It stores none of it, so
the colour is held for as long as the daemon runs, and named profiles keep as many of
those as you like.
The daemon binds loopback, generates a random bearer token in an owner-only file, and exposes a fixed allowlist of methods. It never touches the network.
Every product id OpenRazer knows about, generated from the upstream device classes. Search by name, or filter by category.
| Device | Type | Product id | Matrix | Max DPI | Battery |
|---|---|---|---|---|---|
| Loading… | |||||
Start here — it lists every Razer HID collection Windows can see and marks the control interface.
openrazer-win doctor
| Symptom | Cause |
|---|---|
no Razer control interface |
Synapse is running, or another program holds the device. Close it. |
Device shown as NOT IN DATABASE |
Newer than the bundled data. Open an issue with the product id. |
device replied not supported |
The firmware refused that command; the device genuinely lacks the feature. |
| Effects reset after sleep | Windows cuts USB power. The daemon replays stored state on reconnect. |
| A Bluetooth device is on, but not listed | Install the extra: pip install "openrazer-win[ble]".
doctor ends with a Bluetooth section saying whether support is
present and what the radio can hear. |
| Nothing listed at all | Only Razer devices (vendor 1532) are handled. |