Yet another keyboard remapping tool for X environment
xkeysnailis yet another keyboard remapping tool for X environment written in Python. It's like
xmodmapbut allows more flexible remappings.
Ctrl+x Ctrl+cto
Ctrl+q
evdevand
uinput), making remapping work in almost all the places
sudo)
The key remapping mechanism of
xkeysnailis based on
pykeymacs(https://github.com/DreaminginCodeZH/pykeymacs).
Requires root privilege and Python 3.
sudo apt install python3-pip sudo pip3 install xkeysnailIf you plan to compile from source
sudo apt install python3-dev
sudo dnf install python3-pip sudo pip3 install xkeysnail # Add your user to input group if you don't want to run xkeysnail # with sudo (log out and log in again to apply group change) sudo usermod -a -G input $USERIf you plan to compile from source
sudo dnf install python3-devel
# Some distros will need to compile evdev components # and may fail to do so if gcc is not installed. sudo pacman -Syy sudo pacman -S gcc
# Some distros will need to compile evdev components # and may fail to do so if gcc is not installed. sudo eopkg install gcc sudo eopkg install -c system.devel
git clone --depth 1 https://github.com/mooz/xkeysnail.git cd xkeysnail sudo pip3 install --upgrade .
sudo xkeysnail config.py
When you encounter the errors like
Xlib.error.DisplayConnectionError: Can't connect to display ":0.0": b'No protocol specified\n', try
xhost +SI:localuser:root sudo xkeysnail config.py
If you want to specify keyboard devices, use
--devicesoption:
sudo xkeysnail config.py --devices /dev/input/event3 'Topre Corporation HHKB Professional'
If you have hot-plugging keyboards, use
--watchoption.
If you want to suppress output of key events, use
-q/
--quietoption especially when running as a daemon.
config.py?
(If you just need Emacs-like keybindings, consider to use
example/config.py, which contains Emacs-like keybindings).
Configuration file is a Python script that consists of several keymaps defined by
define_keymap(condition, mappings, name)
define_keymap(condition, mappings, name)
Defines a keymap consists of
mappings, which is activated when the
conditionis satisfied.
Argument
conditionspecifies the condition of activating the
mappingson an application and takes one of the following forms: - Regular expression (e.g.,
re.compile("YYY")) - Activates the
mappingsif the pattern
YYYmatches the
WM_CLASSof the application. - Case Insensitivity matching against
WM_CLASSvia
re.IGNORECASE(e.g.
re.compile('Gnome-terminal', re.IGNORECASE)) -
lambda wm_class: some_condition(wm_class)- Activates the
mappingsif the
WM_CLASSof the application satisfies the condition specified by the
lambdafunction. - Case Insensitivity matching via
casefold()or
lambda wm_class: wm_class.casefold()(see example below to see how to compare to a list of names) -
None: Refers to no condition.
None-specified keymap will be a global keymap and is always enabled.
Argument
mappingsis a dictionary in the form of
{key: command, key2: command2, ...}where
keyand
commandtake following forms: -
key: Key to override specified by
K("YYY")- For the syntax of key specification, please refer to the key specification section. -
command: one of the followings -
K("YYY"): Dispatch custom key to the application. -
[command1, command2, ...]: Execute commands sequentially. -
{ ... }: Sub-keymap. Used to define multiple stroke keybindings. See multiple stroke keys for details. -
pass_through_key: Pass through
keyto the application. Useful to override the global mappings behavior on certain applications. -
escape_next_key: Escape next key. - Arbitrary function: The function is executed and the returned value is used as a command. - Can be used to invoke UNIX commands.
Argument
namespecifies the keymap name. This is an optional argument.
Key specification in a keymap is in a form of
K("(-)*")where is one of the followings -
Cor
Ctrl-> Control key -
Mor
Alt-> Alt key -
Shift-> Shift key -
Superor
Win-> Super/Windows key
You can specify left/right modifiers by adding any one of prefixes
L/
R.
And
is a key whose name is defined inkey.py.
Here is a list of key specification examples:
K("C-M-j"):
Ctrl+
Alt+
j
K("Ctrl-m"):
Ctrl+
m
K("Win-o"):
Super/Windows+
o
K("M-Shift-comma"):
Alt+
Shift+
comma(=
Alt+
>)
When you needs multiple stroke keys, define nested keymap. For example, the following example remaps
C-x C-cto
C-q.
define_keymap(None, { K("C-x"): { K("C-c"): K("C-q"), K("C-f"): K("C-q"), } })
WM_CLASSwith
xprop
To check
WM_CLASSof the application you want to have custom keymap, use
xpropcommand:
xprop WM_CLASS
and then click the application.
xproptells
WM_CLASSof the application as follows.
WM_CLASS(STRING) = "Navigator", "Firefox"
Use the second value (in this case
Firefox) as the
WM_CLASSvalue in your
config.py.
config.py
example/config.py.
Here is an excerpt of
example/config.py.
from xkeysnail.transform import *define_keymap(re.compile("Firefox|Google-chrome"), { # Ctrl+Alt+j/k to switch next/previous tab K("C-M-j"): K("C-TAB"), K("C-M-k"): K("C-Shift-TAB"), }, "Firefox and Chrome")
define_keymap(re.compile("Zeal"), { # Ctrl+s to focus search area K("C-s"): K("C-k"), }, "Zeal")
define_keymap(lambda wm_class: wm_class not in ("Emacs", "URxvt"), { # Cancel K("C-g"): [K("esc"), set_mark(False)], # Escape K("C-q"): escape_next_key, # C-x YYY K("C-x"): { # C-x h (select all) K("h"): [K("C-home"), K("C-a"), set_mark(True)], # C-x C-f (open) K("C-f"): K("C-o"), # C-x C-s (save) K("C-s"): K("C-s"), # C-x k (kill tab) K("k"): K("C-f4"), # C-x C-c (exit) K("C-c"): K("M-f4"), # cancel K("C-g"): pass_through_key, # C-x u (undo) K("u"): [K("C-z"), set_mark(False)], } }, "Emacs-like keys")
terminals = ["gnome-terminal","konsole","io.elementary.terminal","sakura"] terminals = [term.casefold() for term in terminals] termStr = "|".join(str(x) for x in terminals)[Conditional modmap] Change modifier keys in certain applications
define_conditional_modmap(lambda wm_class: wm_class.casefold() not in terminals,{ # Default Mac/Win Key.LEFT_ALT: Key.RIGHT_CTRL, # WinMac Key.LEFT_META: Key.LEFT_ALT, # WinMac Key.LEFT_CTRL: Key.LEFT_META, # WinMac Key.RIGHT_ALT: Key.RIGHT_CTRL, # WinMac Key.RIGHT_META: Key.RIGHT_ALT, # WinMac Key.RIGHT_CTRL: Key.RIGHT_META, # WinMac })
[Conditional modmap] Change modifier keys in certain applications
define_conditional_modmap(re.compile(termStr, re.IGNORECASE), {
# Default Mac/Win Key.LEFT_ALT: Key.RIGHT_CTRL, # WinMac Key.LEFT_META: Key.LEFT_ALT, # WinMac Key.LEFT_CTRL: Key.LEFT_CTRL, # WinMac Key.RIGHT_ALT: Key.RIGHT_CTRL, # WinMac Key.RIGHT_META: Key.RIGHT_ALT, # WinMac Key.RIGHT_CTRL: Key.LEFT_CTRL, # WinMac
})
In the Firefox location bar, go to
about:config, search for
ui.key.menuAccessKeyFocuses, and set the Value to
false.
xkeysnailis distributed under GPL.
xkeysnail Copyright (C) 2018 Masafumi OyamadaThis program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see http:.
xkeysnailis based on
pykeymacs(https://github.com/DreaminginCodeZH/pykeymacs), which is distributed under GPL.
pykeymacs Copyright (C) 2015 Zhang HaiThis program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see http:.