~jman/dotfiles

ref: refs/heads/master dotfiles/xkb/README.md -rw-r--r-- 10.4 KiB
eb3778b1jman Update Emacs/Doom config and build guide 5 days ago

This file contains key overrides to pilot the Keychron K2 on Sway

On X11 you would use xmodmap (man 1 xmodmap) to do something like:

$ xmodmap -pke | grep Delete
keycode  91 = KP_Delete KP_Decimal KP_Delete KP_Decimal KP_Delete KP_Separator
keycode 119 = Delete Insert Delete Insert Delete Insert
$ xmodmap -e "keycode 119 = Delete Insert Delete NoSymbol Delete"

This command will have no effect on Wayland.

Some troubleshooting for Linux: https://github.com/Kurgol/keychron

Have the F1-12 keys behave like function keys (not sure it persists after a reboot)

echo 0 | sudo tee /sys/module/hid_apple/parameters/fnmode

src: https://github.com/Kurgol/keychron/blob/master/k2.md#f-keys-on-ubuntu

On Sway we have to write a xkb file that overrides in part (or completely replace) the default X11 keybindings. This override file will be parsed and validated by Sway. When editing this file don't forget to reload Sway after any change.

General syntax is detailed here

Fully commented example:

# "partial" indicates that this map doesn't cover a complete keyboard
# "alphanumeric_keys" describes which section of the keyboard is being covered
default partial alphanumeric_keys
# "basic" declares symbol map name
xkb_symbols "basic" {
    # define a base layout to inherit
    include "us(altgr-intl)"
    include "level3(caps_switch)"
    # name of the layout
    name[Group1] = "Keychron";
    # map Del key to delete or insert, i.e.:
    # Press delete -> delete
    # Press shift+delete -> insert
    key <DELE> { [ Delete, Insert ] };
    # map left alt to left super (this mapping is always used)
    key <LWIN> { [ Alt_L ] };
    # map left super to left alt (this mapping is always used)
    key <LALT> { [ Super_L ] };
};
# define two options:
# - toggle keyboard layout (e.g. US,DE,IT,FR, ...) on Mod+Space combo press
# - turn Capslock into another Ctrl
xkb_options grp:win_space_toggle,caps:ctrl_modifier

A single key remapping in detail:

<DELE> is the physical key identifier. These identifiers can be found on the image map in the documentation page.

{ [ Delete, Insert ] } are symbols emitted on screen. The full list of symbols is mapped is found here. Symbols names are derived from this mapping (removing XL_). Number and ordering of parameters inside square brackets means:

  • 1st: no modifier (if only this value is present, it applies implicitely for any modifiers)
  • 2nd: shift
  • 3rd: ctrl
  • 4th: ctrl-shift
  • 5th...Nth : MOD1-MOD5

For available xkb_options options: see man 7 xkeyboard-config (jump to "OPTIONS")

When this file will be loaded in Sway, you can check its effect by using xev -event keyboard (to filter only the keyboard events).

Before:

KeyPress event, serial 42, synthetic NO, window 0x600001,
    root 0x2ac, subw 0x0, time 3805675, (264,614), root:(1229,650),
    state 0x0, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False

KeyRelease event, serial 42, synthetic NO, window 0x600001,
    root 0x2ac, subw 0x0, time 3805714, (264,614), root:(1229,650),
    state 0x8, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
    XLookupString gives 0 bytes:
    XFilterEvent returns: False

We have two events KeyPress and KeyRelease. Please notice the line with keycode 64 and the resulting key Alt_L key.

After:

KeyPress event, serial 42, synthetic NO, window 0x600001,
    root 0x2ac, subw 0x0, time 3841745, (27,367), root:(992,403),
    state 0x4000, keycode 64 (keysym 0xffeb, Super_L), same_screen YES,
    XKeysymToKeycode returns keycode: 133
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False

KeyRelease event, serial 42, synthetic NO, window 0x600001,
    root 0x2ac, subw 0x0, time 3841776, (27,367), root:(992,403),
    state 0x4008, keycode 64 (keysym 0xffeb, Super_L), same_screen YES,
    XKeysymToKeycode returns keycode: 133
    XLookupString gives 0 bytes:
    XFilterEvent returns: False

Please notice the new line XKeysymToKeycode with the remapped keycode 133 and the resulting key Super_L key.

#How Sway sees the Keychron K2

$ swaymsg -t get_inputs
Input device: Keychron K2 System Control
  Type: Keyboard
  Identifier: 1452:591:Keychron_K2_System_Control
  Product ID: 591
  Vendor ID: 1452
  Active Keyboard Layout: Keychron
  Libinput Send Events: enabled

Input device: Keychron K2 Consumer Control
  Type: Mouse
  Identifier: 1452:591:Keychron_K2_Consumer_Control
  Product ID: 591
  Vendor ID: 1452
  Libinput Send Events: enabled

Input device: Keychron K2 Consumer Control
  Type: Keyboard
  Identifier: 1452:591:Keychron_K2_Consumer_Control
  Product ID: 591
  Vendor ID: 1452
  Active Keyboard Layout: Keychron
  Libinput Send Events: enabled

Input device: Keychron K2 Keyboard
  Type: Keyboard
  Identifier: 1452:591:Keychron_K2_Keyboard
  Product ID: 591
  Vendor ID: 1452
  Active Keyboard Layout: Keychron
  Libinput Send Events: enabled

#Mapping mouse movements to keys

sudo apt install libinput-tools

sudo libinput debug-events

See this example:

https://github.com/mpsq/dotfiles/blob/master/.config/libinput-gestures.conf

Sway sees the following "mouse/touchpad" devices on my Thinkpad:

Input device: TPPS/2 IBM TrackPoint
  Type: Mouse
  Identifier: 2:10:TPPS/2_IBM_TrackPoint
  Product ID: 10
  Vendor ID: 2
  Libinput Send Events: enabled

Input device: Synaptics TM3276-022
  Type: Touchpad
  Identifier: 1739:0:Synaptics_TM3276-022
  Product ID: 0
  Vendor ID: 1739
  Libinput Send Events: enabled

I see some ways to accomplish this.

  1. Find a way to use the Keychron "mouse" device
Input device: Keychron K2 Consumer Control
  Type: Mouse
  Identifier: 1452:591:Keychron_K2_Consumer_Control
  Product ID: 591
  Vendor ID: 1452
  Libinput Send Events: enabled

$ libinput list-devices

Device:           Keychron Keychron K2
Kernel:           /dev/input/event16
Group:            5
Seat:             seat0, default
Capabilities:     keyboard
Tap-to-click:     n/a
Tap-and-drag:     n/a
Tap drag lock:    n/a
Left-handed:      n/a
Nat.scrolling:    n/a
Middle emulation: n/a
Calibration:      n/a
Scroll methods:   none
Click methods:    none
Disable-w-typing: n/a
Accel profiles:   n/a
Rotation:         n/a

Device:           Keychron Keychron K2
Kernel:           /dev/input/event17
Group:            5
Seat:             seat0, default
Capabilities:     keyboard pointer
Tap-to-click:     n/a
Tap-and-drag:     n/a
Tap drag lock:    n/a
Left-handed:      disabled
Nat.scrolling:    disabled
Middle emulation: disabled
Calibration:      n/a
Scroll methods:   button
Click methods:    none
Disable-w-typing: n/a
Accel profiles:   flat *adaptive
Rotation:         n/a
  1. Use the MouseKeys XKB extension to remap keys to mouse movements (this is an X11 feature, nothing to do with Wayland but in theory wlroots/sway support XKB key customizations so this XKB Option should work)

Problem: it is meant to use with the numeric keypad. By default mapped to Shift+Numlock modifier. Customizing these two things looks hard.

References:

https://www.x.org/releases/X11R7.6/doc/kbproto/xkbproto.html#the_mousekeys_control

The MouseKeys control lets a user control all the mouse functions from the keyboard. When MouseKeys are enabled, all keys with MouseKeys actions bound to them generate core pointer events instead of normal key press and release events.

https://www.x.org/releases/X11R7.6/doc/kbproto/xkbproto.html#keysyms_used_to_control_the_core_pointer

On X11 you enable it with: setxkbmap -option keypad:pointerkeys

and customize the parameters with: https://unix.stackexchange.com/questions/609367/setting-pointerkeys-numpad-as-mouse-keys-parameters-acceleration-delay-etc

KeySyms Used to Control The Core Pointer. To start with, I'm probably interested in: POINTER UP, POINTER DOWN, POINTER LEFT and POINTER RIGHT.

Controls for Using the Mouse from the Keyboard

What's the difference with Pointer_EnableKeys?

  1. Remap a key to a mouse movement from my custom XKB file

Reference: https://wiki.archlinux.org/index.php/X_KeyBoard_extension#Mouse_control

Problem: could not figure out how to implement the above suggestion

  1. Using libinput to remap a key to a POINTER_MOTION event

For a starting point, see the mousemapper.sh script (uses evemu-tools to simulate a device)

  • Debug libinput events for Thinkpad movements:
# libinput debug-events
 event5   POINTER_MOTION    +4.08s       -4.74/  0.00 ( -9.00/ +0.00)
 event5   POINTER_MOTION    +4.09s       -4.74/  0.00 ( -9.00/ +0.00)
 event5   POINTER_MOTION    +4.09s       -4.21/  0.53 ( -8.00/ +1.00)
 event5   POINTER_MOTION    +4.10s       -3.68/  1.05 ( -7.00/ +2.00)
  • Record keystrokes from Keychron

#libinput record --show-keycodes /dev/input/event16 --output-file=keychron.yml

  • Record mouse from Thinkpad touchpad (Synaptics TM3276-022)

#libinput record --show-keycodes /dev/input/event6 --output-file=touchpad.yml

  • Replay

#libinput replay touchpad.yml

evemu-event /dev/input/event16 --sync --type EV_KEY --code KEY_PAGEDOWN --value 1 &&
    evemu-event /dev/input/event16 --sync --type EV_KEY --code KEY_PAGEDOWN --value 0

evemu-event /dev/input/event6 --sync --type EV_ABS --code ABS_MT_POSITION_Y --value 600

evemu-event /dev/input/event6 --sync --type EV_REL --code REL_Y --value 10

I wrote a proof of concept script (filter.py) and talked with the libinput maintainer, this is a dead end.