• Stars
    star
    366
  • Rank 116,547 (Top 3 %)
  • Language
    Rust
  • License
    MIT License
  • Created almost 5 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A keyboard input remapper for Linux/Wayland systems, written by @wez

evremap

A keyboard input remapper for Linux/Wayland systems, written by @wez

Why?

I couldn't find a good solution for the following:

  • Remap the CAPSLOCK key so that it produces CTRL when held, but ESC if tapped
  • Remap N keys to M keys. Eg: F3 -> CTRL+c, and ALT+LEFT to HOME

How?

evremap works by grabbing exclusive access to an input device and maintaining a model of the keys that are pressed. It then applies your remapping configuration to produce the effective set of pressed keys and emits appropriate changes to a virtual output device.

Because evremap targets the evdev layer of libinput, its remapping is effective system-wide: in Wayland, X11 and the linux console.

Configuration

Here's an example configuration that makes capslock useful:

# The name of the device to remap.
# Run `sudo evremap list-devices` to see the devices available
# on your system.
device_name = "AT Translated Set 2 keyboard"

# If you have multiple devices with the same name, you can optionally
# specify the `phys` value that is printed by the `list-devices` subcommand
# phys = "usb-0000:07:00.3-2.1.1/input0"

# Configure CAPSLOCK as a Dual Role key.
# Holding it produces LEFTCTRL, but tapping it
# will produce ESC.
# Both `tap` and `hold` can expand to multiple output keys.
[[dual_role]]
input = "KEY_CAPSLOCK"
hold = ["KEY_LEFTCTRL"]
tap = ["KEY_ESC"]

You can also express simple remapping entries:

# This config snippet is useful if your keyboard has an arrow
# cluster, but doesn't have page up, page down, home or end
# keys.  Here we're configuring ALT+arrow to map to those functions.
[[remap]]
input = ["KEY_LEFTALT", "KEY_UP"]
output = ["KEY_PAGEUP"]

[[remap]]
input = ["KEY_LEFTALT", "KEY_DOWN"]
output = ["KEY_PAGEDOWN"]

[[remap]]
input = ["KEY_LEFTALT", "KEY_LEFT"]
output = ["KEY_HOME"]

[[remap]]
input = ["KEY_LEFTALT", "KEY_RIGHT"]
output = ["KEY_END"]

When applying remapping configuration, ordering is important:

  • Dual Role entries are always processed first
  • Remap entries are applied in the order that they appear in your configuration file

Here's an example where ordering is important: on the PixelBook Go keyboard, the function key row has alternate functions on the keycaps. It is natural to want the mute button to mute by default, but to emit the F8 key when holding alt. We can express that with the following configuration:

[[remap]]
input = ["KEY_LEFTALT", "KEY_F8"]
# When our `input` is matched, our list of `output` is prevented from
# matching as the `input` of subsequent rules.
output = ["KEY_F8"]

[[remap]]
input = ["KEY_F8"]
output = ["KEY_MUTE"]
  • How do I list available input devices? sudo evremap list-devices

  • How do I list available key codes? evremap list-keys

Building it

$ sudo dnf install libevdev-devel # redhat/centos
## or
$ sudo apt install libevdev-dev # debian/ubuntu

$ cargo build --release

Running it

To run the remapper, invoke it as root (so that it can grab exclusive access to the input device):

$ sudo target/release/evremap remap my-config-file.toml

Or, grant an unprivileged user access to evdev and uinput. On Ubuntu, this can be configured by running the following commands and rebooting:

sudo gpasswd -a YOUR_USER input
echo 'KERNEL=="uinput", GROUP="input"' | sudo tee /etc/udev/rules.d/input.rules

For some platforms, you might need to create an input group first and run:

echo 'KERNEL=="event*", NAME="input/%k", MODE="660", GROUP="input"' | sudo tee /etc/udev/rules.d/input.rules

as well.

Systemd

A sample system service unit is included in the repo. You'll want to adjust the paths to match your system and then install and enable it:

$ sudo cp evremap.service /usr/lib/systemd/system/
$ sudo systemctl daemon-reload
$ sudo systemctl enable evremap.service
$ sudo systemctl start evremap.service

Runit

If you're using Runit instead of Systemd, follow these steps to create a service.

  • Create a directory called evremap and create a file called run under it
sudo mkdir /etc/sv/evremap
sudo touch /etc/sv/evremap/run
  • Copy these lines into the run file
#!/bin/sh
set -e 
exec <PATH_TO_EVREMAP> remap <CONFIG>

Replace <PATH_TO_EVREMAP> with the path to your evremap executable and <CONFIG> with the path to your configuration file.

  • Finally, symlink the evremap directory to /var/service
sudo ln -s /etc/sv/evremap /var/service

OpenRC

To make an OpenRC service, create the file /etc/init.d/evremap with the following contents...

#!/usr/bin/openrc-run

supervisor=supervise-daemon
command="<PATH_TO_EVREMAP>"
command_args="remap <CONFIG>"

Replace <PATH_TO_EVREMAP> with the path to your evremap executable and <CONFIG> with the path to your configuration file.

Make the file executable...

chmod +x /etc/init.d/evremap

Enable the service with...

rc-update add evremap

Start the service with...

rc-service evremap start

How do I make this execute a command when a key is pressed?

That feature is not implemented.

More Repositories

1

wezterm

A GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust
Rust
16,417
star
2

atomicparsley

AtomicParsley is a lightweight command line program for reading, parsing and setting metadata into MPEG-4 files, in particular, iTunes-style metadata.
C++
560
star
3

govee2mqtt

Govee2MQTT: Connect Govee lights and devices to Home Assistant
Rust
395
star
4

govee-lan-hass

Control Govee lights via the LAN API from Home Assistant
Python
199
star
5

wzsh

Wez's Shell
Rust
79
star
6

lemon-php

A PHP parser generator, based on the lemon parser generator tool. lemon-php requires a C compiler to build, and this will generate pure-PHP parsers.
C
72
star
7

EleDo

Increase or reduce the privilege level of the calling code on Windows systems
Rust
34
star
8

flutterby-rs

Keyboard firmware implemented in Rust
Rust
33
star
9

govee-py

Control Govee Lights from Python
Python
32
star
10

JLexPHP

A lexer generator for PHP. It is based on JLex and requires Java to generate the lexer. Once generated, the lexer only requires PHP to run.
Java
32
star
11

libssh-rs

Rust bindings for libssh https://www.libssh.org/
Rust
29
star
12

telnetjs

A Telnet protocol listener for Node.js
JavaScript
22
star
13

SpockKeyboard

Hardware and software for a split ergonomic keyboard
C
18
star
14

jlink_rtt

JLINK RTT debugger support for rust
Rust
18
star
15

halfdeck

An opensource keyboard hardware design
OpenSCAD
18
star
16

mdns

mDNS resolving crate for Rust
Rust
14
star
17

ecma48

The spec for "ANSI Escape sequences" in searchable, linkable form
12
star
18

mosquitto-rs

Rust
11
star
19

pview

PowerView to MQTT bridge for Home Assistant
Rust
11
star
20

evildesk

Wez's Evil Shell--A Windows Desktop Replacement. A replacement for the default WindowsยฎXP and Windows Server 2003 graphical shell (taskbar, start menu and "tray").
C
11
star
21

svn-to-git

A Subversion to Git migration tool for repositories with complex layouts
PHP
9
star
22

clacker

Keyboard firmware and hardware bits and bobs
Python
9
star
23

wez-sonos

Wez's Sonos Client API for Rust
Rust
7
star
24

circuits

Generate a kicad pcb from rust code
Rust
5
star
25

cancel-rs

Co-operative Cancellation Tokens in Rust
Rust
5
star
26

homebrew-wezterm

A Homebrew Tap for installing wezterm
Ruby
4
star
27

drv2605

Embedded HAL bindings for the DRV2605 Haptic Driver
Rust
4
star
28

KaleidoscopeKeyboards

Kaleidoscope-based firmware for my custom keyboard builds
C++
4
star
29

wez

2
star
30

homebrew-wezterm-linuxbrew

A Homebrew Tap for installing wezterm for linuxbrew users
Ruby
2
star
31

connect-riak

Riak Session Store for Connect
JavaScript
2
star
32

max32630

Rust Peripheral access API for max32630 microcontrollers
Rust
2
star
33

wez.github.io

code for my blog
HTML
2
star
34

varbincode

A binary encoder / decoder implementation using variable length integer encoding in Rust.
Rust
1
star
35

Kaleidoscope-Focus

Bidirectional communications plugin for Kaleidoscope
C++
1
star
36

gimli

Gimli is a crash tracing/analysis framework. It is available under a 3-clause BSD style license.
C
1
star
37

sx1509

Driver for the SX1509 targeting the Rust embedded-hal
Rust
1
star