如何在 Linux 下为特定键盘重新映射键

FUZ*_*xxl 31 linux keyboard-layout

我最近买了一个 Unicomp 键盘,它带有交换的右 alt 和 Windows 键。键盘在 lsusb 上的标识是这样的:

Bus 003 Device 002: ID 17f6:0822 Unicomp, Inc 
Run Code Online (Sandbox Code Playgroud)

有没有办法让内核(即不是基于 xmodmap 的)交换 right-alt 和 windows 键,这样每个应用程序都会在交换的位置看到它们,即使它们获得原始键盘输入(用 xmodmap 交换东西不会那样做) ? 有没有办法只针对这个键盘?

小智 36

是的,可以使用 XKB。与 xmodmap 不同,XKB 可以为单个设备重新映射您的密钥。

注意:确保你有 xkbcomp > 1.2.0

首先列出您的设备:

xinput list

你会得到这样的东西:

? Virtual core pointer                      id=2    [master pointer  (3)]
?   ? Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
?   ? Wacom Bamboo Pen Pen stylus               id=11   [slave  pointer  (2)]
?   ? Wacom Bamboo Pen Finger touch             id=12   [slave  pointer  (2)]
?   ? Logitech USB-PS/2 Optical Mouse           id=13   [slave  pointer  (2)]
?   ? Wacom Bamboo Pen Pen eraser               id=14   [slave  pointer  (2)]
?   ? Wacom Bamboo Pen Finger pad               id=15   [slave  pointer  (2)]
?   ? GASIA USB KB V11                          id=17   [slave  pointer  (2)]
? Virtual core keyboard                     id=3    [master keyboard (2)]
    ? Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
    ? Power Button                              id=6    [slave  keyboard (3)]
    ? Power Button                              id=7    [slave  keyboard (3)]
    ? G19 Gaming Keyboard                       id=8    [slave  keyboard (3)]
    ? G19 Gaming Keyboard                       id=9    [slave  keyboard (3)]
    ? Logitech G19 Gaming Keyboard              id=10   [slave  keyboard (3)]
    ? GASIA USB KB V11                          id=16   [slave  keyboard (3)]
Run Code Online (Sandbox Code Playgroud)

确定设备的字符串并编辑以下 shell 脚本,将 sed 行更改为适合您设备名称的行。然后更改您需要重新映射的键。

示例:加载xev并按下要重新映射的键。假设您发现它是密钥代码 84。在https://gist.github.com/zoqaeski/3880640 中查找 84 。那里的关键名称是<KP5>. 然后查找您希望它替换的键(在同一个链接中,更远的下方)并复制括号内的内容。对所需的所有键重复此过程。

remote_id=$(
    xinput list |
    sed -n 's/.*GASIA.*id=\([0-9]*\).*keyboard.*/\1/p'
)
[ "$remote_id" ] || exit

# remap the following keys, only for my custom vintage atari joystick connected
# through an old USB keyboard:
#
# keypad 5 -> keypad 6
# . -> keypad 2
# [ -> keypad 8
# left shift -> left control

mkdir -p /tmp/xkb/symbols
# This is a name for the file, it could be anything you
# want. For us, we'll name it "custom". This is important
# later.
#
# The KP_* come from /usr/include/X11/keysymdef.h
# Also note the name, "remote" is there in the stanza
# definition.
cat >/tmp/xkb/symbols/custom <<\EOF

xkb_symbols "remote" {
    key <KP5>  { [ KP_Right, KP_6, U2192, U21D2 ]       };
    key <I129> { [ KP_Down, KP_2, U2193, U21D3 ]       };
    key <AD12> { [ KP_Up, KP_8, U2191, U21D1 ]  };
    key <LFSH> { [ Control_L ]        };
};
EOF

# (1) We list our current definition
# (2) Modify it to have a keyboard mapping using the name
#     we used above, in this case it's the "remote" definition
#     described in the file named "custom" which we specify in
#     this world as "custom(remote)".
# (3) Now we take that as input back into our definition of the
#     keyboard. This includes the file we just made, read in last,
#     so as to override any prior definitions.  Importantly we 
#     need to include the directory of the place we placed the file
#     to be considered when reading things in.
#
# Also notice that we aren't including exactly the 
# directory we specified above. In this case, it will be looking
# for a directory structure similar to /usr/share/X11/xkb
# 
# What we provided was a "symbols" file. That's why above we put
# the file into a "symbols" directory, which is not being included
# below.
setxkbmap -device $remote_id -print \
 | sed 's/\(xkb_symbols.*\)"/\1+custom(remote)"/' \
 | xkbcomp -I/tmp/xkb -i $remote_id -synch - $DISPLAY 2>/dev/null
Run Code Online (Sandbox Code Playgroud)

然后获取它(您可以将它添加到您的 .xinitrc 中)。全部完成!现在按下这些键应该会生成所需的输出,仅适用于您指定的设备。

编辑:最近,我注意到由于某种原因,新配置并未立即应用。您必须先按下另一个键盘上的一个键,然后在修改后的键盘上测试配置的键。我不知道为什么会发生这种情况,也许是某种缓存。


sso*_*low 13

对于从 Google 来到这里并希望得到更符合提问者最初希望的答案的任何其他人,我知道有两种方法可以在evdev级别重新映射事件,以便更改适用于所有应用程序:

  1. udev 提供了一个 API 来修改硬件数据库条目,这些条目控制扫描码和键码之间的映射。这个包含说明的ArchiWiki 页面明确表示它适用于 X11 和控制台输入。

    要点是您创建一个自定义条目,/etc/udev/hwdb.d/其中包含设备匹配模式和一些扫描码到键码的重新映射定义,然后运行systemd-hwdb update以重建数据库并udevadm trigger在不重新启动的情况下应用它。

  2. 鉴于 Wayland 不使用 X11 的键盘子系统,并且像 GNOME Shell 和 Weston 这样的主要 Wayland 合成器没有实现 UI 来配置 libinput 的相关方面,有人编写了一个名为evdevremapkeys的守护进程,它解决了类似于 Logitech 的 G15Daemon 用户空间驱动程序的问题G15 游戏键盘。

    (它吞下它打算重新映射的事件,因此在设备上侦听的任何其他东西都无法看到它们,然后通过uinputAPI发出更正的事件,以便从用户空间创建内核级输入设备。)

  • 这个答案比“选择的”要好得多。没有自定义的脏/黑客脚本。它直接引导我访问了 arch linux 的 wiki。按照说明,我创建了一个 hwdb 文件,其中包含干净的重新映射列表。在两台不同的机器上工作得非常顺利。谢谢!! (3认同)