MagShift - Advanced Keyboard Layout Switcher with Instant Correction Engine for Linux (Wayland & X11) and macOS. It fixes what you just typed without making you retype it.
Typed ghbdsn instead of привіт? Tap Shift twice: MagShift deletes the phrase, switches the layout and types
it again correctly. Tap twice again to undo.
Designed with NixOS Flakes in mind for reproducible and secure deployment. Also supports other Linux distros via a simple installer script, and macOS via a LaunchAgent:
- Features
- How it works
- NixOS Installation (Flake)
- Installation (Ubuntu / Fedora / Arch)
- Installation (macOS)
- Usage
- Autostart (Linux)
- Manual Usage (Development)
- Related
- ⚡ Double Shift: Tap either
Shifttwice to switch layout (e.g., English ↔ Ukrainian). Tap twice again to undo. - 🖋️ Auto-Correction: Corrects the last typed phrase when you switch, not just the last word.
- ⏸️ Pause key (optional): Punto Switcher style: a single
Pausepress corrects too. Off by default. - 🎛️ Works with your hotkey: On Linux it emulates the switch hotkey you already use: Meta+Space, Alt+Shift, Ctrl+Shift, CapsLock or the Menu key.
- 🔒 Secure: Runs with dynamic permissions (via Udev ACLs), no manual group configuration required.
- ❄️ Pure Nix: Zero global dependencies. Builds cleanly from the Nix Store.
- 🍎 macOS Native: Uses a Quartz event tap and the Text Input Source API - no hotkey emulation, no extra daemons.
MagShift listens to every connected keyboard, including ones plugged in later, and remembers the last phrase you
typed (up to 20 keystrokes, reset after 1 second of silence, on Enter/Tab/Esc, or when a shortcut like Ctrl+C
is pressed). On a double Shift it:
- sends
Backspacefor every remembered keystroke, - switches the layout (Linux: emulates your system hotkey; macOS: selects the input source directly),
- replays the phrase, keeping the shift state of every key.
Nothing is stored beyond those 20 keystrokes, the clipboard is never touched, and no data leaves your machine.
Since this project exports a NixOS module, installation is clean, but requires an overlay to make the package available to the system.
Add the input, import the module, and apply the overlay in your system configuration:
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
# Add MagShift input
magshift.url = "github:OleksandrCEO/MagShift";
# magshift.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, magshift, ... }: {
nixosConfigurations.myhostname = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
# 1. Import the module
magshift.nixosModules.default
# 2. Add Overlay (Required)
({ pkgs, ... }: {
nixpkgs.overlays = [
(final: prev: {
magshift = magshift.packages.${prev.stdenv.hostPlatform.system}.default;
})
];
})
];
};
};
}
{ config, pkgs, ... }:
{
services.magshift.enable = true;
# Optional, defaults shown:
# services.magshift.hotkey = "meta"; # meta | alt | ctrl | caps | menu (see Usage)
# services.magshift.pause = false; # also correct on a single Pause press
# services.magshift.autoNumlock = true; # force NumLock ON at start
}
The module installs the package, loads uinput, adds the udev rules and runs MagShift as a system service.
Note: With the udev-based approach, users do not need to be added to
inputoruinputgroups. Permissions are granted dynamically to the active graphical session user.
cd /etc/nixos
sudo nix flake update magshift
sudo nixos-rebuild switch
If you track your NixOS config in git, commit the updated flake.lock before rebuilding.
For non-NixOS systems, use the provided installer script:
# Download the latest release
wget https://github.com/OleksandrCEO/MagShift/archive/refs/heads/master.zip
unzip master.zip
cd MagShift-master
# Run installer (requires root)
sudo ./install.sh
The installer will:
- Print your system details (distro, session type, default keyboard layout) for troubleshooting
- Install
python3-evdevvia your package manager (apt/dnf/pacman) if it is missing. The exact command is shown, and package lists are not refreshed: if it fails, runsudo apt update(or your distro's equivalent) yourself - Copy
main.pyto/usr/local/bin/magshift - Create udev rules for dynamic device permissions and apply them
- Check that your user can access
/dev/uinputand every keyboard
Then start it with magshift (or set up autostart).
X11: on the first install the installer asks for a reboot instead of applying keyboard access live. X.Org re-creates every keyboard that gets a udev event, with the system default layout, so applying it live would reset a layout set via
setxkbmap. Wayland sessions get access immediately.
Download and run the installer again:
wget https://github.com/OleksandrCEO/MagShift/archive/refs/heads/master.zip
unzip -o master.zip
cd MagShift-master
sudo ./install.sh
macOS 12 or newer, Intel or Apple Silicon. No sudo needed - everything is installed under your home directory.
git clone https://github.com/OleksandrCEO/MagShift.git
cd MagShift
./install-macos.sh
The installer will:
- Create a private virtualenv in
~/.local/share/magshift/venvand installpyobjc-framework-Quartz - Copy
main.pynext to it and add amagshiftwrapper to~/.local/bin - Register a LaunchAgent (
com.magwer.magshift) that starts MagShift with your session, so no extra autostart setup is needed
macOS will not let any process read or inject keystrokes until you allow it. Open System Settings → Privacy & Security and add the Python binary the installer prints to both lists:
- Input Monitoring - lets MagShift see what you type
- Accessibility - lets MagShift type the correction back
With a standalone Python that is the venv binary:
~/.local/share/magshift/venv/bin/python3
With a framework Python (python.org or Homebrew) the venv binary re-launches Python.app, and that is what macOS
checks, e.g.:
/Library/Frameworks/Python.framework/Versions/3.x/Resources/Python.app
In that case the grant covers every script run by that Python.
In the file picker press
Cmd+Shift+Gand paste the path. The installer prints the exact absolute path at the end of its run.
Then restart the agent:
launchctl kickstart -k gui/$UID/com.magwer.magshift
tail -f ~/.local/share/magshift/magshift.log
Type a word in the wrong layout, tap Shift twice, and it should be retyped correctly.
git pull && ./install-macos.sh # update
./install-macos.sh --uninstall # remove agent, venv and wrapper
| Option | Behaviour on macOS |
|---|---|
-k / --hotkey |
Ignored. Layouts are switched directly through TISSelectInputSource, so no hotkey has to be configured or emulated. |
-p / --pause |
Has no effect: Mac keyboards have no Pause key. |
-d / --device |
Ignored. The Quartz event tap is system-wide; there is no per-device capture. |
-n / --numlock, --auto-numlock |
Ignored. Mac keyboards have no NumLock. |
--list |
Lists the enabled keyboard layouts instead of input devices. |
MagShift switches to the layout you used before the current one, so a second double-Shift undoes the correction.
When no previous layout is known yet it takes the next one in magshift --list order.
magshift # start with defaults (Linux: emulates Meta+Space to switch)
magshift -k alt # your desktop switches layouts with Alt+Shift
magshift -k menu -p # switch with the Menu key, and also correct on a single Pause press
magshift --list # Linux: input devices, macOS: keyboard layouts
magshift --verbose # show what is being corrected
| Option | Description | Platform |
|---|---|---|
-k, --hotkey STYLE |
Which hotkey your desktop uses to switch layouts, so MagShift can emulate it. meta (Meta+Space, default), alt (Alt+Shift), ctrl (Ctrl+Shift), caps (CapsLock), menu (Menu key) |
Linux |
-p, --pause |
Also correct on a single Pause press (Punto Switcher style). Double Shift keeps working. |
Linux |
-d, --device PATH |
Read only this /dev/input/event* device instead of every keyboard |
Linux |
--list |
List input devices (Linux) or enabled keyboard layouts (macOS) and exit | both |
-n, --numlock |
Force NumLock ON and exit | Linux |
--auto-numlock |
Force NumLock ON at start, then keep running (used by the NixOS service) | Linux |
-v, --verbose |
Log every correction | both |
The hotkey style must match your desktop settings. MagShift does not switch the layout itself on Linux: it presses the same hotkey you would. Check System Settings → Keyboard → Layouts if corrections do nothing.
X11: MagShift types through the XTEST extension of your X session, so start it from inside that session (desktop
autostart, i3 exec, .xinitrc). Started without access to the display, it falls back to a virtual uinput keyboard,
and X.Org gives new keyboards the system default layout (localectl status), not one set via setxkbmap.
On macOS the installer already registers a LaunchAgent. On NixOS the module runs a system service. For other Linux distros pick one of the two options below.
Since this tool relies on the graphical session (Wayland/X11), the most reliable way to start it is via KDE settings.
- Open System Settings (Системні параметри) -> Autostart (Автозапуск).
- Click + Add New (+ Додати нове) -> Application... (Програма...).
- Do not select "Login Script".
- Type
magshiftin the search bar and select it. - (Optional) To pass options, click on the added entry, then Properties, and change the command, e.g.
magshift -k altormagshift -k menu -p(see Usage). - Click Apply (Гаразд).
That's it! MagShift will now start automatically with your user session.
Works on any distro with systemd (Ubuntu, Fedora, Arch, ...).
-
Create the service file:
mkdir -p ~/.config/systemd/user nano ~/.config/systemd/user/magshift.servicePaste the following, adding your options after the executable path if needed (e.g.
magshift -k alt):[Unit] Description=MagShift Keyboard Layout Switcher After=graphical-session.target [Service] ExecStart=/usr/local/bin/magshift Restart=always RestartSec=5 [Install] WantedBy=default.target -
Enable and start it:
systemctl --user daemon-reload systemctl --user enable --now magshift.service -
Check status and logs:
systemctl --user status magshift.service journalctl --user -u magshift -f
# Linux with Nix: enter the development shell (Python + evdev + evtest)
nix develop
# macOS: use the interpreter the installer created
alias python3=~/.local/share/magshift/venv/bin/python3
# Run with verbose logging to see key events
python3 main.py --verbose
# Run the platform-neutral self-check (works on Linux and macOS, no hardware needed)
python3 test_magshift.py
main.py is a single file with three layers: platform-neutral key codes and the input buffer, a backend per platform
(LinuxBackend on evdev/uinput, MacBackend on Quartz + Carbon TIS), and the MagShift state machine that never
touches a platform API directly.
- Clipboard version: the old, less secure version with a clipboard dependency and extra features (like handling selected text) lives in a separate repo: SkySwitcher.
MIT License. Feel free to use and modify.