Description
This is a guide for running [kanata | github.com/jtroo/kanata] on QubesOS. This might work for other keyboard remappers, but it wasn’t tested.
Note: This guide was written for kanata v1.9.0
Note: This guide assumes that you have a separate USB Qube and that it’s disposable
To prevent conflicts use
linux-dev-names-include
in your kanata configuration (see: [kanata v1.9.0 docs | github.com])
Overview
- Create a new template for kanata
- Configure kanata in the template
- Set the template to be the base of sys-usb
1. Installing kanata
- Create a new AppVM based on
fedora-41-xfce
and name itsys-usb-dvm
- Obtain a kanata binary (either build it yourself or download it from [their GitHub releases | github.com]) and copy it to
sys-usb-dvm
sys-usb-dvm
: Copy the received binary to~/kanata/
(create if needed)
2. Configuring kanata
sys-usb-dvm
: Copy your kanata config to~/kanata/kanata.cfg
sys-usb-dvm
: Create the following files:
File ~/kanata/kanata-exclusions.conf
[Service]
ExecStart=
ExecStart=/usr/local/bin/launch-input-sender.py qubes.InputKeyboard /dev/input/%i "$TARGET_DOMAIN"
File ~/kanata/kanata.service
[Unit]
Description=Improve keyboard comfort and usability with advanced customization
[Service]
Type=simple
ExecStart=/usr/local/bin/kanata -c /rw/home/user/kanata/kanata.cfg
Restart=on-failure
sys-usb-dvm
: Add this to the bottom of/rw/config/rc.local
:
rc.local
# === kanata configuration
# exclusion:
cp /rw/home/user/kanata/launch-input-sender.py /usr/local/bin/
chmod +x /usr/local/bin/launch-input-sender.py
mkdir /etc/systemd/system/qubes-input-sender-keyboard@.service.d/
cp /home/user/kanata/kanata-exclusions.conf /etc/systemd/system/qubes-input-sender-keyboard@.service.d/kanata-exclusions.conf
# kanata:
cp /rw/home/user/kanata/kanata /usr/local/bin/
chmod +x /usr/local/bin/kanata
cp /rw/home/user/kanata/kanata.service /etc/systemd/system/
systemctl daemon-reload
systemctl restart qubes-input-sender-keyboard@*
systemctl enable kanata
systemctl start kanata
# ===
- Go to sys-usb.
sys-usb
: Runcat /proc/bus/input/devices
. You should get something like this:
...
I: Bus=0003 Vendor=REDACTED Product=REDACTED Version=0110
N: Name="REDACTED Keyboard"
<more lines>
...
- Find all the keyboards you want to be remapped and save their
Vendor
andProduct
values (if the same keyboard is listed multiple times, save them all) - Go to sys-usb-dvm.
sys-usb-dvm
Create~/kanata/launch-input-sender.py
with the following contents (don’t forget to replace VENDOR and PRODUCT at the top):
File ~/kanata/launch-input-sender.py
#!/usr/bin/env python3
# Put your keyboard ids here
KEYBOARDS = [
"VENDOR:PRODUCT"
]
QUBES_INPUT_SENDER = "/usr/bin/qubes-input-sender"
import os
import subprocess
import sys
_, arg_rpc, arg_input, arg_domain = sys.argv
with open("/proc/bus/input/devices") as f:
deviceinfo = f.read()
devices = deviceinfo.split("\n\n")
inputs = []
keyboards_not_found = KEYBOARDS.copy()
def get_infoline(infolines, i):
for line in infolines:
if line.startswith(i+":"):
return line
for device in devices:
infolines = device.split("\n")
I_line = get_infoline(infolines, "I")
if not I_line: continue
vendor_pos = I_line.find("Vendor=")
product_pos = I_line.find("Product=")
vendor = I_line[vendor_pos+7:vendor_pos+11]
product = I_line[product_pos+8:product_pos+12]
if f"{vendor}:{product}" not in KEYBOARDS: continue
S_line = get_infoline(infolines, "S")
sysfs_pos = S_line.find("Sysfs=")
sysfs = S_line[sysfs_pos+6:]
sysfs_path = f"/sys{sysfs}"
sysfs_files = os.listdir(sysfs_path)
event_files = list(filter(lambda i: i.startswith("event"), sysfs_files))
inputs += event_files
if f"{vendor}:{product}" in keyboards_not_found:
keyboards_not_found.remove(f"{vendor}:{product}")
print(f"INFO: Found keyboard {vendor}:{product} with {len(event_files)} events: {' '.join(event_files)}")
input_paths = list(map(lambda i: f"/dev/input/{i}", inputs))
if arg_input in input_paths:
print("INFO: Not launching input-sender")
while True: pass
print(f"INFO: Launching {QUBES_INPUT_SENDER}")
os.execvp(QUBES_INPUT_SENDER, [QUBES_INPUT_SENDER, arg_rpc, arg_input, arg_domain])
3. Changing the template of sys-usb
- Shut down
sys-usb-dvm
dom0
: Makesys-usb-dvm
a disposable template (“Qube Manager” > “sys-usb-dvm” > “Settings” > “Advanced” > “Other” > “Disposable template”)- Change the template of
sys-usb
:This might lock you out of the system. Find a PS/2 keyboard to prevent that
dom0
:qvm-shutdown --wait sys-usb; qvm-prefs -s sys-usb template sys-usb-dvm; qvm-start sys-usb
Troubleshooting
- To launch a shell in
usb-sys-dvm
after it’s been made into a disposable template usedom0
:qvm-run sys-usb-dvm xfce4-terminal
- To revert sys-usb use
dom0
:qvm-shutdown --wait sys-usb; qvm-prefs -s sys-usb template default-dvm; qvm-start sys-usb