gswitch

gswitch fixes text typed in the wrong keyboard layout — system-wide, in any application, on X11 and Wayland.
You typed a word, but the wrong layout was active:
| You got |
You meant |
Layout pair |
ghbdtn |
привет |
English ↔ Russian |
yeit |
zeit |
English ↔ German (QWERTZ) |
;qdq;e |
madame |
English ↔ French (AZERTY) |
ma;ana |
mañana |
English ↔ Spanish |
By default, double-tap Shift: gswitch erases the word, switches the
layout, and retypes it correctly. You can replace double-Shift with another key
in the tray application's Settings window. No mouse, no retyping, no per-app
plugins.
It works at the Linux kernel input level: keystrokes are read from /dev/input (evdev) and corrections are replayed through a virtual keyboard (uinput). Because of this, correction is completely independent of the display server, toolkit, or application — it works in terminals, browsers, IDEs, Electron apps, and games alike.
Features
- Three correction modes
- Last word — double-tap Shift by default
- Whole phrase (everything since the last Enter) — hold one Shift, double-tap the other
- Selected text — select text anywhere, press Ctrl + double-Shift
- System-wide — operates below the display server; any app, X11 or Wayland
- Any layout pair — 1600+ keysym mappings (Latin, Cyrillic, Greek, Arabic, Hebrew, Thai, …); tested with Russian, Ukrainian, German (QWERTZ), French (AZERTY), and Spanish
- Zero-config by default — auto-detects your keyboards, your layouts, and your layout-switch hotkey from system settings (GNOME, KDE, fcitx5, ibus, XKB)
- Multi-keyboard aware — handles several keyboards at once, with hotplug support
- Tray application — status indicator, settings GUI, and service control
- Configurable trigger — use a custom key (e.g. Caps Lock or Pause) instead of double-Shift
- Runs as a systemd user service — starts with your graphical session
How It Works
flowchart LR
KB[Keyboards<br>/dev/input] --> R[evdev reader<br>+ hotplug watcher]
R --> C[Key buffer<br>+ trigger detection]
C --> V[Virtual keyboard<br>uinput]
V --> A[Backspaces + layout switch<br>+ corrected keystrokes]
- gswitch silently buffers your keystrokes (buffer is reset on focus-changing keys: Tab, arrows, mouse clicks, …).
- When it sees a trigger, it emits backspaces to erase the mistyped text, presses your layout-switch hotkey, and replays the buffered keys — now in the correct layout.
- For selected text, it reads the selection, converts characters using your system's XKB layout tables, and pastes the result.
Security & Privacy
A tool that reads every keystroke deserves scrutiny — here is the full picture:
- No network code. gswitch never sends anything anywhere; there is not a single network call in the codebase.
- Keystrokes never touch the disk. The key buffer lives only in process memory and is cleared whenever focus can change (mouse click, Tab, arrows, Enter, …). Debug mode writes operational metadata to the terminal only; it does not log key names, buffer contents, or selected/converted text.
- The daemon does not run as root. udev/logind grants the active local
session access to keyboard event nodes and
/dev/uinput. Only installation
and writing the fixed system config use administrator authorization; service
control is systemctl --user. Details in
the security policy.
- Releases are built by CI from a git tag with GoReleaser and ship a
checksums.txt; the full source is here to audit.
Found a vulnerability? See the security policy for
private reporting.
Tested Environments
Every release is verified by an automated end-to-end suite (synthetic keyboard input, real desktop sessions) across:
| Environment |
Display server |
Package |
| Ubuntu 24.04 · GNOME 46 |
Wayland, X11 |
deb |
| Ubuntu 24.04 · KDE Plasma 5.27 |
Wayland, X11 |
deb |
| KDE Plasma 6 |
Wayland |
deb |
| Fedora 44 · GNOME 50 |
Wayland |
rpm (SELinux enforcing) |
| Fedora 44 · KDE Plasma 6.7 |
Wayland |
rpm (SELinux enforcing) |
The suite covers word/phrase/selection correction in both directions for all five tested layout pairs, plus the tray application.
Installation
Requirements: Linux with uinput, systemd/logind for packaged device ACLs and
service mode, and administrator access to install the package. The daemon runs
as the graphical user. Selection conversion on pure Wayland additionally needs
wl-clipboard (installed automatically where supported).
Prebuilt packages currently target 64-bit x86 Linux (amd64/x86_64).
From packages (recommended)
Download the latest .deb or .rpm from Releases:
sudo apt install ./gswitch_<version>_linux_amd64.deb # Debian/Ubuntu
sudo dnf install ./gswitch_<version>_linux_amd64.rpm # Fedora
sudo gswitch --configure
systemctl --user enable --now gswitch.service
The package installs the daemon, the tray application, a systemd unit, udev rules, icons, and a polkit policy. The tray starts automatically on next login.
With Go
go install github.com/arumata/gswitch/cmd/gswitch@latest
Installs the daemon binary only — no systemd unit, udev rules, or tray.
Clipboard-based selection conversion requires a CGO-enabled build.
From source
git clone https://github.com/arumata/gswitch.git
cd gswitch
go build -o builds/gswitch ./cmd/gswitch
Quick Start
# 1) Interactive setup (writes /etc/gswitch/default.conf)
sudo gswitch --configure
# 2) Try it in the foreground with verbose terminal diagnostics
gswitch --debug
# 3) Then run it as a service
systemctl --user enable --now gswitch.service
Type a word in the wrong layout and double-tap Shift. This is the
default trigger; use the tray application's Settings window to replace it with
another key.
Usage
| Action |
Default trigger |
With custom convert-key |
| Fix last word |
Double-Shift |
ConvertKey |
| Fix whole phrase |
Hold Shift + double-tap other Shift |
Shift+ConvertKey |
| Convert selection |
Ctrl + double-Shift |
Ctrl+ConvertKey |
CLI
gswitch --configure # interactive configuration (-c)
gswitch --run # run in foreground (-r)
gswitch --debug # verbose terminal diagnostics, no text content (-d)
gswitch --version # print version (-v)
gswitch --detect-layout-switch # detect layout-switch hotkey, JSON output
[--source=xkb|gnome|kde] # restrict detection to one provider
Tray application
gswitch-tray shows the service status in the system tray and provides a
settings window (trigger key capture, delays, service start/stop). It controls
the daemon through systemctl --user; polkit is used only when writing the
system config.
To disable its autostart, create ~/.config/autostart/gswitch-tray.desktop containing:
[Desktop Entry]
Hidden=true
Configuration
Config file: /etc/gswitch/default.conf
| Parameter |
Description |
Default |
layout-switch |
Layout-switch key scancode(s): auto, single (125), or combo (29+42) |
auto |
convert-key |
One evdev scancode for the correction trigger; 0 = double-Shift mode (combinations are rejected) |
0 |
delay |
Delay between synthetic key events, ms |
10 |
layout-switch-delay |
Extra delay after the layout switch, ms |
100 |
blacklist |
Comma-separated device UIDs to ignore |
— |
layout1, layout2 |
Explicit layout pair, e.g. us / ru or ua(unicode) |
auto-detected |
Minimal example:
layout-switch=auto
convert-key=0
delay=10
layout-switch-delay=100
Notes:
layout-switch=auto detects your hotkey from XKB options, GNOME keybindings, or KDE settings; run gswitch --detect-layout-switch to see what it finds.
- The tray converts GTK/XKB hardware keycodes to evdev scancodes when capturing keys. For manual configuration, use
sudo showkey to look up scancodes.
- With more than two layouts configured in the system, set
layout1/layout2 explicitly.
- Run
gswitch -d to see device UIDs for blacklist.
Layout detection order
Layouts for text conversion are detected from, in order: fcitx5 (~/.config/fcitx5/profile) → ibus (gsettings) → KDE (~/.config/kxkbrc) → GNOME (gsettings input-sources) → setxkbmap (X11 fallback).
Troubleshooting
Service fails to start — check logs:
journalctl --user -u gswitch.service -f.
Selection conversion does nothing on Wayland — the packages pull in wl-clipboard automatically as a recommended dependency; if it is missing (installed with dpkg -i / --no-install-recommends, or built from source), install it manually.
Only one layout detected — make sure at least two layouts are configured in your desktop settings; with more than two, set layout1/layout2 in the config.
Layout resets when clicking the tray or taskbar — that is your desktop's per-window layout mode, not gswitch. Switch to a global layout policy:
How to enable global layout mode per desktop
- KDE Plasma (XKB): System Settings → Keyboard → Layouts → Switching Policy → Global
- KDE Plasma (fcitx5): Input Method → Global Options → Share Input State → All
- GNOME:
gsettings set org.gnome.desktop.input-sources per-window false
- Cinnamon:
gsettings set org.cinnamon.desktop.input-sources per-window false
- MATE:
gsettings set org.mate.peripherals-keyboard-xkb.general group-per-window false
- Xfce: Keyboard → Layout → Layout switching → Global
- LXQt: Keyboard and Mouse → Keyboard Layout → uncheck Per window
Known limitations
- More than two simultaneous layouts require explicit
layout1/layout2.
- Non-systemd distros: run the binary from the graphical session and arrange
equivalent device ACLs manually.
- Fast user switching does not revoke input file descriptors already opened by
another logged-in user; log out inactive users when strict isolation matters.
- Device ACLs are granted to a user ID, so every unsandboxed process running as
that user can use the same device permissions while the ACL is active.
License
MIT