{"id":51321553,"url":"https://github.com/jagbhandal/keyzer","last_synced_at":"2026-07-01T14:01:41.785Z","repository":{"id":365944040,"uuid":"1272474977","full_name":"jagbhandal/keyzer","owner":"jagbhandal","description":"Visual key-remapper for Razer Tartarus Pro \u0026 Naga Pro on Linux — a Razer Synapse-style UI on top of input-remapper.","archived":false,"fork":false,"pushed_at":"2026-06-19T14:08:01.000Z","size":6941,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-19T16:16:41.183Z","etag":null,"topics":["chroma","input-remapper","key-remapping","keybind","keybinding","keypad","linux-app","naga-pro","openrazer","razer","razer-peripherals","razer-synapse","synapse","tartarus-pro"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jagbhandal.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-17T16:36:40.000Z","updated_at":"2026-06-19T14:08:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jagbhandal/keyzer","commit_stats":null,"previous_names":["jagbhandal/keyzer"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/jagbhandal/keyzer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagbhandal%2Fkeyzer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagbhandal%2Fkeyzer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagbhandal%2Fkeyzer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagbhandal%2Fkeyzer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jagbhandal","download_url":"https://codeload.github.com/jagbhandal/keyzer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagbhandal%2Fkeyzer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35009272,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-01T02:00:05.325Z","response_time":130,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chroma","input-remapper","key-remapping","keybind","keybinding","keypad","linux-app","naga-pro","openrazer","razer","razer-peripherals","razer-synapse","synapse","tartarus-pro"],"created_at":"2026-07-01T14:01:39.838Z","updated_at":"2026-07-01T14:01:41.768Z","avatar_url":"https://github.com/jagbhandal.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/keyzer-wordmark.png\" alt=\"KEYZER\" width=\"300\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/platform-Linux-44d62c\" alt=\"Linux\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/license-MIT-44d62c\" alt=\"MIT licensed\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/engine-input--remapper-2f9a1f\" alt=\"Built on input-remapper\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Wayland-ready-2f9a1f\" alt=\"Wayland ready\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/telemetry-none-2f9a1f\" alt=\"No telemetry\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\u003cb\u003eThe Razer Synapse experience Linux never had — click your device, set a key.\u003c/b\u003e\u003c/p\u003e\n\n![KEYZER — click a key on a picture of your device and bind it](docs/screenshots/keyzer.png)\n\n\u003e Razer Synapse doesn't run on Linux, and [input-remapper](https://github.com/sezanzeb/input-remapper)'s stock editor makes you map raw event codes by hand. **KEYZER gives you the workflow you actually want: see your real device, click a key, pick a binding — and it's live instantly, no Apply step.** Free, open source, no account, no telemetry.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/screenshots/tour.gif\" alt=\"KEYZER in action — keypad, calibration, 4-way thumb mode, profile compare, Chroma lighting\" width=\"760\"\u003e\n\u003c/p\u003e\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"50%\"\u003e\u003cimg src=\"docs/screenshots/calibrate.png\" alt=\"In-app calibration\"\u003e\u003cbr\u003e\u003csub\u003e\u003cb\u003eCalibrate in the app\u003c/b\u003e — click a key, press it, done. No terminal.\u003c/sub\u003e\u003c/td\u003e\n    \u003ctd width=\"50%\"\u003e\u003cimg src=\"docs/screenshots/compare.png\" alt=\"Compare two profiles\"\u003e\u003cbr\u003e\u003csub\u003e\u003cb\u003eCompare profiles\u003c/b\u003e — green = same, amber = changed, at a glance\u003c/sub\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"50%\"\u003e\u003cimg src=\"docs/screenshots/naga.png\" alt=\"Naga Pro side view\"\u003e\u003cbr\u003e\u003csub\u003e\u003cb\u003eNaga Pro\u003c/b\u003e — the 12-button thumb grid, face-on\u003c/sub\u003e\u003c/td\u003e\n    \u003ctd width=\"50%\"\u003e\u003cimg src=\"docs/screenshots/lighting.png\" alt=\"Per-zone Chroma lighting\"\u003e\u003cbr\u003e\u003csub\u003e\u003cb\u003eLighting\u003c/b\u003e — per-zone Chroma effects + a full colour wheel\u003c/sub\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"50%\"\u003e\u003cimg src=\"docs/screenshots/thumb-4way.png\" alt=\"Tartarus thumb pad in 4-way movement mode\"\u003e\u003cbr\u003e\u003csub\u003e\u003cb\u003e4-way thumb (movement)\u003c/b\u003e — diagonals auto-blend from the cardinals: buttery WASD strafing, zero stutter\u003c/sub\u003e\u003c/td\u003e\n    \u003ctd width=\"50%\"\u003e\u003cimg src=\"docs/screenshots/thumb.png\" alt=\"Tartarus thumb pad in 8-way mode\"\u003e\u003cbr\u003e\u003csub\u003e\u003cb\u003e8-way thumb (discrete)\u003c/b\u003e — bind all eight directions independently for abilities\u003c/sub\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Supported devices\n\n| Device | USB ID | Views |\n|---|---|---|\n| Razer Tartarus Pro (keypad) | `1532:0244` | keypad |\n| Razer Naga Pro (mouse) | `1532:008f` | top (L/R click · wheel + tilt · sensitivity) · side (12-button thumb grid) |\n\nAdding a device is just an entry in [`layouts.json`](layouts.json) — no code change. PRs welcome for more Razer gear.\n\n## KEYZER vs Razer Synapse\n\nKEYZER isn't trying to out-feature Synapse — it fills the gap Synapse leaves on\nLinux, where Synapse simply doesn't run. Here's the honest picture, including where\nSynapse is more capable:\n\n| | KEYZER | Razer Synapse |\n|---|---|---|\n| **Runs on Linux** | ✅ Yes (Wayland + X11) | ❌ Windows / macOS only |\n| **Price \u0026 account** | ✅ Free, open source, no account | Free, but requires a Razer account |\n| **Telemetry** | ✅ None | ❌ Collects usage data |\n| **Click-the-device remapping** | ✅ Yes | ✅ Yes |\n| **Key / combo / mouse-button bindings** | ✅ Yes | ✅ Yes |\n| **Macros** | ⚠️ Basic chords (full macros via input-remapper presets) | ✅ Full recorder with timing |\n| **Profiles** | ✅ Yes — plain JSON, import/export, version-control friendly | ✅ Yes — with cloud sync |\n| **Per-app / per-game auto-switch** | ❌ Not yet ([roadmap](#roadmap)) | ✅ Yes |\n| **RGB / Chroma lighting** | ⚠️ Per-zone colour, brightness \u0026 effects (needs OpenRazer) | ✅ Full Chroma Studio (per-key, animations, app sync) |\n| **DPI / sensitivity stages** | ❌ No (a hardware function) | ✅ Yes |\n| **Hypershift / second layer** | ✅ Yes — hold a key for a whole second layer | ✅ Yes |\n| **8-way thumb-pad modes (4-way / 8-way)** | ✅ Yes — per device, per profile | ✅ Yes |\n| **Visual calibration** | ✅ In-app (click a key, press it) | ✅ N/A (knows its own devices) |\n| **Profile compare / diff** | ✅ Yes — see what changed between profiles | ❌ No |\n| **On-board memory (profile saved on the device)** | ❌ No — applies live through the OS, so it works system-wide | ✅ Yes — travels with the device |\n| **Supported devices** | ⚠️ Tartarus Pro + Naga Pro (more via a JSON entry) | ✅ The full Razer lineup |\n| **Support** | Community / unofficial | Official (Razer) |\n\n**The takeaway:** if you're on Windows, use Synapse. If you're on Linux and want\nyour Razer keypad or mouse to actually be remappable — with a UI instead of raw\nevent codes — that's what KEYZER is for.\n\n## Install\n\nKEYZER needs two things, both packaged on Ubuntu/Debian: the **input-remapper** engine and **PySide6** (the Qt6 UI). OpenRazer is **optional** (lighting only).\n\n**TL;DR** (Ubuntu/Debian) — clone, run the installer, launch:\n\n```bash\ngit clone https://github.com/jagbhandal/keyzer.git \u0026\u0026 cd keyzer \u0026\u0026 ./install.sh \u0026\u0026 python3 app/main.py\n```\n\n**Just want to look first?** `python3 app/main.py --demo` runs the whole UI with sample devices — no Razer hardware, input-remapper, or OpenRazer needed.\n\n### Ubuntu / Debian (recommended)\n\n```bash\n# required: engine + UI\nsudo apt install input-remapper \\\n  python3-pyside6.qtquick python3-pyside6.qtquickcontrols2 \\\n  python3-pyside6.qtsvg python3-pyside6.qtdbus\n\n# get KEYZER\ngit clone https://github.com/jagbhandal/keyzer.git\ncd keyzer\npython3 app/main.py\n```\n\nOr just run the helper — it installs anything missing **and adds KEYZER to your\napplication menu** (icon + launcher), so you can open it from your app grid like\nany other app instead of the terminal:\n\n```bash\n./install.sh\n```\n\nThen search **KEYZER** in your activities/app grid (right-click → pin to favourites\nfor one-click launch).\n\n### Optional — Chroma lighting (OpenRazer)\n\nLighting control needs [OpenRazer](https://openrazer.github.io/). Without it, KEYZER works fully for remapping; the Lighting toggle simply stays disabled.\n\n```bash\nsudo add-apt-repository ppa:openrazer/stable\nsudo apt install openrazer-meta python3-openrazer\n# then add yourself to the 'plugdev' group and re-log\n```\n\n### Other distros (pip)\n\n```bash\npip install --user PySide6        # if your distro lacks a PySide6 package\n# install input-remapper from https://github.com/sezanzeb/input-remapper\npython3 app/main.py\n```\n\n## Dependencies at a glance\n\n| | Package | Purpose |\n|---|---|---|\n| **Required** | `input-remapper` (≥ 2.0) | does the actual remapping (evdev → uinput) |\n| **Required** | PySide6 (`python3-pyside6.*` or `pip install PySide6`) | the UI |\n| Optional | `openrazer-meta`, `python3-openrazer` | per-key Chroma lighting |\n\nKEYZER detects what's present at startup and adapts (the footer shows engine status; the Lighting toggle disables itself without OpenRazer).\n\n## Setting up keybinds\n\nYou don't need to know anything about input-remapper. The flow:\n\n**Once per machine — calibrate.** Click **Calibrate** in the toolbar, then click a key on the device and press it; repeat for each highlighted key. This teaches KEYZER the real code each physical key sends. (Prefer the terminal? `python3 app/capture.py` does the same. A default map ships so you can click around before calibrating.)\n\n**To bind a key:**\n1. Pick your device, then click the key on the picture.\n2. Set what it should do — three ways:\n   - **Listen** — click it, then press a key or shortcut (e.g. `F5`, `Ctrl+1`).\n   - **Quick pick** — tap a common key from the row.\n   - **Type it** — type the output in the binding box. This is the most powerful — it's how you set held combos like `W+A`.\n3. Hit **Bind** — it's live on the device instantly. **Clear** removes it.\n\n**What you can bind** — type any of these in the box (or use Listen / Quick pick):\n\n| You want… | Type | Result |\n|---|---|---|\n| A single key | `W` · `Space` · `F5` · `Esc` · `5` | that key |\n| **Diagonal movement** (two keys held together) | `W+A` | holds **W and A** while you hold the key — strafe / diagonal |\n| Sprint or crouch held down | `Shift` · `Ctrl` | holds the modifier while pressed |\n| A shortcut | `Ctrl+C` · `Alt+F4` · `Ctrl+Shift+1` | the combo, tapped |\n| A named action | `Copy` · `Paste` · `Undo` · `Save` | the matching shortcut |\n| A mouse button | `LMB` · `RMB` · `MMB` | mouse click |\n| Volume / media | `Vol+` · `Vol-` · `Mute` · `Play` | media key |\n| Punctuation | `-` · `=` · `/` · `Ctrl+-` | that symbol |\n| Disable the key | `Disable` | the key does nothing |\n\n**The one gamers want:** bind a thumb key to `W+A` (or `W+D`, `S+A`, `S+D`) and that single key walks you diagonally — it holds both directions for as long as you hold it.\n\n\u003e **Held, not tapped:** anything joined with `+` is *held down together* for as long as you hold the trigger key, then released — perfect for movement (`W+A`) and modifiers (`Shift`). The same syntax covers shortcuts like `Ctrl+C` — just tap the key and the combo fires once.\n\n**Tartarus thumb pad — 4-way vs 8-way.** The Tartarus Pro's directional thumb pad has a mode toggle in the thumb view. **4-way** binds the four cardinals and lets diagonals happen *automatically* by holding two neighbours at once — so WASD movement stays buttery smooth, with no stutter when you roll between a strafe and straight. It's the one to use for games. **8-way** instead lets you bind all eight directions independently — ideal for mapping eight distinct abilities, at the cost of blended movement. The choice is saved per device, per profile.\n\nProfiles (e.g. **Gaming** vs **Work**) live in the header menu — switching one applies it live instantly (there's no separate Apply step). **Compare** shows what differs between two profiles at a glance, and **Hypershift** gives each device a hold-key second layer: hold one key and every other key does something else. Export/import to share a setup. Timed/recorded macro sequences aren't in the UI yet; for those you can edit the input-remapper preset directly.\n\n## How it works\n\nKEYZER is a friendly front-end; the remapping is done by a proven engine.\n\n```\n┌─ KEYZER (this app) ───────────────────────────────────┐\n│ device image + clickable hotspots (from layouts.json) │\n│ assign panel · profiles · views · lighting            │\n│            │ writes preset JSON / drives the daemon    │\n└────────────▼──────────────────────────────────────────┘\n┌─ input-remapper (engine) ─────────────────────────────┐\n│ evdev → uinput remapping, runs as a system service     │\n└────────────────────────────────────────────────────────┘\n```\n\nKEYZER talks to input-remapper only through its CLI / preset files / DBus — never its internals — so an engine update can't break the UI. See [ARCHITECTURE.md](ARCHITECTURE.md).\n\n## Roadmap\n\n- [x] Visual UI: device images + clickable hotspots, assign panel, profiles, views, theme\n- [x] Dependency-aware startup (engine + OpenRazer detection)\n- [x] In-app click-to-calibrate (capture evdev codes from the UI; `capture.py` CLI still available)\n- [x] Generate input-remapper presets from a profile and reload the daemon (`engine.py`)\n- [x] Bindings persist across reboot \u0026 device reconnect (input-remapper autoload), applied automatically — no Apply button\n- [x] OpenRazer lighting control (per-zone Chroma effects + brightness)\n- [x] Hypershift second layer (hold-key combinations)\n- [x] Per-device 4-way/8-way thumb-pad mode (smooth movement vs eight discrete binds)\n- [x] Profile compare/diff + honest apply-health readout\n- [x] Demo mode (`--demo`) — try KEYZER with no hardware\n- [ ] App-aware profile switching (GNOME/Wayland active-window)\n- [ ] Timed/recorded macros in the UI\n- [ ] `.deb` package (`Depends: input-remapper, python3-pyside6.*`, `Recommends: openrazer-meta`)\n\n## Disclaimer\n\nKEYZER is an independent, unofficial project — **not affiliated with Razer Inc.**\n\"Razer\", \"Tartarus\", \"Naga\", \"Chroma\" and related marks are trademarks of Razer Inc.,\nused here only to identify compatible hardware. See [NOTICE](NOTICE) for details on\ntrademarks and the bundled device images.\n\n## License\n\nSee [LICENSE](LICENSE). (KEYZER's own code; bundled device images are © Razer Inc. — see NOTICE.)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjagbhandal%2Fkeyzer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjagbhandal%2Fkeyzer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjagbhandal%2Fkeyzer/lists"}