udev规则可在插入USB键盘时自动加载键盘布局


24

我在尝试插入USB键盘时尝试加载新的键盘布局,但我的udev规则不起作用。

SUBSYSTEM ==“ input”,ATTR {idVendor} ==“ 062a”,ATTR {idProduct} ==“ 0201”,GOTO =“ usb_xmodmap_auto”

LABEL =“ usb_xmodmap_auto”
ACTION ==“ add”,RUN + =“ / usr / bin / xmodmap〜/ .usbXmodmap”
ACTION ==“ remove”,RUN + =“ / usr / bin / xmodmap〜/ .pndXmodmap”

我使用以下方法重新加载了规则:

> sudo udevadm控制-重新加载规则

并通过重新启动系统,但是当我插入USB键盘时,原始xmodmap仍然加载,因此键盘布局错误,但是如果我在终端中运行命令

> / usr / bin / xmodmap〜/ .usbXmodmap
要么
> / usr / bin / xmodmap〜/ .pndXmodmap

他们工作得很好。

希望索能能有所帮助。

编辑:

为了提供更多帮助,我运行了一些udevadm测试:

> udevadm test --action = add /devices/platform/ehci-omap.0/usb1/1-2/1-2.3/1-2.3:1.1/input/input10

输出:

run_command:调用:测试
udevadm_test:151版
该程序仅用于调试,不运行任何程序,
由RUN键指定。它可能显示错误的结果,因为
一些值可能不同,或者在模拟运行中不可用。

[...]
parse_file:将“ /etc/udev/rules.d/usb-keyboard.rules”读取为规则文件
udev_rules_new:规则使用100572个字节的令牌(8381 * 12个字节),21523个字节的缓冲区
udev_rules_new:使用的临时索引为35380字节(1769 * 20字节)
udev_device_new_from_syspath:设备0x3b4d8具有devpath'/devices/platform/ehci-omap.0/usb1/1-2/1-2.3/1-2.3:1.1/input/input10'
udev_rules_apply_to_event:运行'/ sbin / modprobe -b $ env {MODALIAS}'/etc/udev/rules.d/80-drivers.rules:5
udev_rules_apply_to_event:运行'socket:@ / org / freedesktop / hal / udev_event'/etc/udev/rules.d/90-hal.rules:2
udev_rules_apply_to_event:运行'/ sbin / modprobe $ env {MODALIAS}'/etc/udev/rules.d/local.rules:31
udev_rules_apply_to_event:运行'socket:/ org / kernel / udev / monitor'/etc/udev/rules.d/run.rules:2
udev_rules_apply_to_event:运行'/ usr / bin / xmodmap〜/ .usbXmodmap'/etc/udev/rules.d/usb-keyboard.rules:4
udevadm_test:UDEV_LOG = 6
udevadm_test:DEVPATH = / devices / platform / ehci-omap.0 / usb1 / 1-2 / 1-2.3 / 1-2.3:1.1 / input / input10
udevadm_test:PRODUCT = 3 / 62a / 201/110
udevadm_test:NAME =“符合USB的键盘”
udevadm_test:PHYS =“ usb-ehci-omap.0-2.3 / input1”
udevadm_test:UNIQ =“”
udevadm_test:EV == 1f
udevadm_test:KEY == 837fff 2c3027 bf004444 0 0 1fe3 c04 a27c000 267bfa d941dfed 9e0000 0 0 0
udevadm_test:REL == 143
udevadm_test:ABS == 1 0
udevadm_test:MSC == 10
udevadm_test:MODALIAS = input:b0003v062Ap0201e0110-e0,1,2,3,4,k71,72,73,74,77,80,82,83,85,86,87,88,89,8A,8B,8C, 8E,8F,90,96,98,9B,9C,9E,9F,A1,A3,A4,A5,A6,A7,A8,A9,AB,AC,AD,AE,B1,B2,B5,CE, CF,D0,D1,D2,D5,D9,DB,E2,EA,EB,100,101,105,106,107,108,109,10A,10B,10C,162,166,16A,16E,178,179,17A,17B,17C,17D,17F,180,181,182,185,18C, 18D,192,193,195,1A0,1A1,1A2,1A3,1A4,1A5,1A6,1A7,1A8,1A9,1AA,1AB,1AC,1AD,1AE,1B0,1B1,1B7,r0,1,6,8,a20, m4,lsfw
udevadm_test:ACTION =添加
udevadm_test:SUBSYSTEM =输入
udevadm_test:运行:'/ sbin / modprobe -b输入:b0003v062Ap0201e0110-e0,1,2,3,4,k71,72,73,74,77,80,82,83,85,86,87,88,89 ,8A,8B,8C,8E,8F,90,96,98,9B,9C,9E,9F,A1,A3,A4,A5,A6,A7,A8,A9,AB,AC,AD,AE,B1 ,B2,B5,CE,CF,D0,D1,D2,D5,D9,DB,E2,EA,EB,100,101,105,106,107,108,109,10A,10B,10C,162,166,16A,16E,178,179,17A,17B,17C,17D ,17F,180,181,182,185,18C,18D,192,193,195,1A0,1A1,1A2,1A3,1A4,1A5,1A6,1A7,1A8,1A9,1AA,1AB,1AC,1AD,1AE,1B0,1B1,1B7,r0,1 ,6,8,a20,m4,lsfw'
udevadm_test:运行:'socket:@ / org / freedesktop / hal / udev_event'
udevadm_test:运行:'/ sbin / modprobe输入:b0003v062Ap0201e0110-e0,1,2,3,4,k71,72,73,74,77,80,82,83,85,86,87,88,89,8A ,8B,8C,8E,8F,90,96,98,9B,9C,9E,9F,A1,A3,A4,A5,A6,A7,A8,A9,AB,AC,AD,AE,B1,B2 ,B5,CE,CF,D0,D1,D2,D5,D9,DB,E2,EA,EB,100,101,105,106,107,108,109,10A,10B,10C,162,166,16A,16E,178,179,17A,17B,17C,17D,17F ,180,181,182,185,18C,18D,192,193,195,1A0,1A1,1A2,1A3,1A4,1A5,1A6,1A7,1A8,1A9,1AA9,1AB,1AC,1AD,1AE,1B0,1B1,1B7,r0,1,6 ,8,a20,m4,lsfw'
udevadm_test:运行:'socket:/ org / kernel / udev / monitor'
udevadm_test:运行:'/ usr / bin / xmodmap〜/ .usbXmodmap'

> udevadm test --action =删除/devices/platform/ehci-omap.0/usb1/1-2/1-2.3/1-2.3:1.1/input/input10

输出:

run_command:调用:测试
udevadm_test:151版
该程序仅用于调试,不运行任何程序,
由RUN键指定。它可能显示错误的结果,因为
一些值可能不同,或者在模拟运行中不可用。

[...]
parse_file:将“ /etc/udev/rules.d/usb-keyboard.rules”读取为规则文件
udev_rules_new:规则使用100572个字节的令牌(8381 * 12个字节),21523个字节的缓冲区
udev_rules_new:使用的临时索引为35380字节(1769 * 20字节)
udev_device_new_from_syspath:设备0x3b4d8具有devpath'/devices/platform/ehci-omap.0/usb1/1-2/1-2.3/1-2.3:1.1/input/input10'
udev_rules_apply_to_event:运行'socket:@ / org / freedesktop / hal / udev_event'/etc/udev/rules.d/90-hal.rules:2
udev_rules_apply_to_event:运行'socket:/ org / kernel / udev / monitor'/etc/udev/rules.d/run.rules:2
udev_rules_apply_to_event:运行'/ usr / bin / xmodmap〜/ .pndXmodmap'/etc/udev/rules.d/usb-keyboard.rules:5
udevadm_test:UDEV_LOG = 6
udevadm_test:DEVPATH = / devices / platform / ehci-omap.0 / usb1 / 1-2 / 1-2.3 / 1-2.3:1.1 / input / input10
udevadm_test:PRODUCT = 3 / 62a / 201/110
udevadm_test:NAME =“符合USB的键盘”
udevadm_test:PHYS =“ usb-ehci-omap.0-2.3 / input1”
udevadm_test:UNIQ =“”
udevadm_test:EV == 1f
udevadm_test:KEY == 837fff 2c3027 bf004444 0 0 1fe3 c04 a27c000 267bfa d941dfed 9e0000 0 0 0
udevadm_test:REL == 143
udevadm_test:ABS == 1 0
udevadm_test:MSC == 10
udevadm_test:MODALIAS = input:b0003v062Ap0201e0110-e0,1,2,3,4,k71,72,73,74,77,80,82,83,85,86,87,88,89,8A,8B,8C, 8E,8F,90,96,98,9B,9C,9E,9F,A1,A3,A4,A5,A6,A7,A8,A9,AB,AC,AD,AE,B1,B2,B5,CE, CF,D0,D1,D2,D5,D9,DB,E2,EA,EB,100,101,105,106,107,108,109,10A,10B,10C,162,166,16A,16E,178,179,17A,17B,17C,17D,17F,180,181,182,185,18C, 18D,192,193,195,1A0,1A1,1A2,1A3,1A4,1A5,1A6,1A7,1A8,1A9,1AA,1AB,1AC,1AD,1AE,1B0,1B1,1B7,r0,1,6,8,a20, m4,lsfw
udevadm_test:ACTION =删除
udevadm_test:SUBSYSTEM =输入
udevadm_test:运行:'socket:@ / org / freedesktop / hal / udev_event'
udevadm_test:运行:'socket:/ org / kernel / udev / monitor'
udevadm_test:运行:'/ usr / bin / xmodmap〜/ .pndXmodmap'

这似乎表明它应该可以工作,但是它不希望这有助于得到答案。


Answers:


16

我发现了解决此问题的方法,尽管有点麻烦。

今天,我尝试使用udev,setxkbmap和xinput --list设置两个键盘,并使它们与USB热插拔配合使用,这也达到了相同的目的。我在交换密钥,而不更改布局,但是都一样,一旦您在热插拔上识别了键盘并可以连续调用setxkbmap,那么您应该只能设置指定键盘的语言。键盘布局列表可在此处找到ls -l /usr/share/kbd/keymaps/i386/,您可以找到要使用的设备名称xinput -list

  1. 您将要替换rizumu为您的用户名,因为我发现如果没有明确的话,这是不可能的。
  2. 确保您在your键盘名称上使用grep 。
  3. 使用lsusb发现硬件ID,你需要设置在udev规则。我的das键盘看起来像这样Bus 002 Device 009: ID 04d9:2013 Holtek Semiconductor, Inc.

我首先通过创建udev规则将udev规则设置为autodetct键盘:

在文件中/etc/udev/rules.d/00-usb-keyboards.rules

ACTION=="add", ATTRS{idVendor}=="04d9", ATTRS{idProduct}=="2013", RUN+="/home/rizumu/bin/kbd_udev", OWNER="rizumu"

我有两个文件〜/ bin / kbd和〜/ bin / kbd_udev。确保他们具有正确的权限chmod 755 ~/bin/kbd*

~/bin/kbd_udev脚本包含:

#!/bin/bash
/home/rizumu/bin/kbd &

您会注意到,它所做的只是~/bin/kbd在后台调用,因此udev可以完成其过程并激活键盘。在~/bin/kbd脚本内部,我们需要睡眠一秒钟,因为我们需要等到键盘被激活后才能使用xinput获取设备ID。为了实现这一目标,我将一些变量,并远销他们如此XINPUT setxkbmap可以做thier工作:DISPLAYXAUTHORITYHOME,和一个daskb_id为我daskeyboard的id:

#!/bin/bash
sleep 1
DISPLAY=":0.0"
HOME=/home/rizumu/
XAUTHORITY=$HOME/.Xauthority
export DISPLAY XAUTHORITY HOME
daskb_id=`xinput -list | grep -i 'daskeyboard' | grep -o id=[0-9]. | grep -o [0-9]. | head -1`

xset r rate 200 30
setxkbmap -layout colemak
setxkbmap -option ctrl:nocaps
if [ "${daskb_id}" ]; then
    setxkbmap -device "${daskb_id}" -option altwin:swap_lalt_lwin
fi

非常感谢您帮助我回答我自己的问题是AskUbuntu:askubuntu.com/questions/337411/…–
Sadi

我想知道您是否还可以帮助我在此脚本的末尾添加一条通知消息(例如notify-send "USB Keyboard is plugged in and ready for use now." -i gtk-dialog-info -t 1000 -u normal)。由于我对脚本不太了解,因此我尝试在“ fi”之前或之后插入脚本,但是在两种情况下,通知消息都不断出现:-(
Sadi

为什么OWNER要为此设备设置?
Limbo Peng

1
这条xset r rate 200 30线是做什么的?xset在我的Ubuntu 17.04安装上不可用。
kleinfreund'7

1
我无法xmodmap $HOME/.Xmodmap使用类似于您的“ / home / rizumu / bin / kbd”的脚本来运行。为什么会这样呢?
Geremia

5

根据您的发行版,您可能已经在/lib/udev/rules.d/64-xorg-xkb.rules中有一个udev键盘规则。在Ubuntu上,这将导入/ etc / default / keyboard,其中的选项大致如下:

XKBMODEL="pc105"
XKBLAYOUT="us"
XKBVARIANT=""
XKBOPTIONS=""

对于我的设置,我发现此内置规则在我的自定义udev规则之后执行,并且覆盖了我的设置。相反,我将/ etc / default / keyboard中的XKBOPTIONS更改为:

XKBOPTIONS="-option ctrl:nocaps"

要获得“大写锁定就是控制”的行为,我希望在所有键盘上都可以。


2
好点子!我的作品与XBKOPTIONS="ctrl:nocaps"
RasmusWL

3

如果您正在运行GNOME,则需要禁用其键盘管理插件,以使其不会覆盖布局更改。

gconftool-2 --toggle /apps/gnome_settings_daemon/plugins/keyboard/active

再次运行相同的命令以根据需要启用它。


我正在运行埃。这会工作吗?
杰克·阿奇森

您在Ångström上使用GNOME吗?
伊格纳西奥·巴斯克斯

nope im using xfce 4.6.1
Jake Aitchison

1
在我的Ubuntu 13.04中,该文件位于dconf/org/gnome/settings-daemon/plugins/keyboard/active
nh2

1
Ubuntu 13.04的命令为:gsettings set org.gnome.settings-daemon.plugins.keyboard active false
Sadi 2013年

3

它不起作用,因为udev并且xmodmap没有访问X11显示器的权限。事实上,udev甚至不知道是否有活跃X11显示器。

  • 注意:显示,复数。它不能使用“ the” X11显示器,因为可以有多个显示器。例如,如果您使用“快速用户切换”。

所以我该如何做呢?
杰克·阿奇森

有人知道我该如何解决?
杰克·阿奇森

1
我已经得到udev来调用setxkbmap。udev规则调用一个脚本,该脚本在另一个脚本的背景下运行(以便udev可以完成)。第二个脚本暂停一秒钟,设置预期的X11变量,然后触发setxkbmap。有关更多详细信息,请参见我对主要问题的回答。
Thomas Schreiber

@rizumu:啊,祝您好运,但是可以与GDM一起使用。
grawity 2011年

3

我想我发现了一种更干净的配置方式,不需要特殊的X11 hack。

其背后的想法是,udev它将仅检测新的键盘输入并为每个布局创建一个符号链接,然后inotify将监视用户空间中的新布局。

udev规则

#/etc/udev/rules.d/61-usb-keyboard-layout.rules

# will match my Logitech keyboard with US layout 
SUBSYSTEM=="input", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c31c", GROUP="plugdev", MODE="0660", SYMLINK+="input/by-layout/us"

# will match my Lenovo integrated keyboard with IT layout
SUBSYSTEM=="input", ENV{ID_PATH}=="platform-i8042-serio-0", SYMLINK+="input/by-layout/it"

# force the directory to be recreated, just in case you unplug all input
SUBSYSTEM=="input", RUN="/bin/mkdir -p /dev/input/by-layout"

有了这个规则,我在dev(/dev/input/by-layout)下有一个目录来监视用户空间脚本中的更改。

KDE的用户空间脚本

例如,使用KDE时,我可以运行以下脚本(自动):

#!/bin/bash

# In case no link are found, switch to this layout
DEFAULT="it"

switch_layout () {
        [ ! -z "$1" ] || return 0
        /usr/bin/qdbus org.kde.keyboard /Layouts org.kde.KeyboardLayouts.setLayout $1
}

best_layout() {
        local LAYOUT=$(ls -1t /dev/input/by-layout/ | head -n 1)
        if [ -z "$LAYOUT" ] ; then
                LAYOUT=$DEFAULT
        fi
        echo $LAYOUT
}

switch_layout $(best_layout)

while true ; do
        EVENT=$(inotifywait -q -e create -e delete --exclude '.*tmp.*' /dev/input/by-layout/)

        if echo "$EVENT" | grep -qe CREATE ; then
                LAYOUT=${EVENT#?*CREATE }
        fi

        if echo "$EVENT" | grep -qe DELETE ; then
                LAYOUT=$(best_layout)
        fi

        switch_layout $LAYOUT
done

这对我来说就像一种魅力。要更改系统布局(我现在不需要),loadkeys可以使用系统初始化脚本来演示使用的类似脚本。


谢谢,这使我意识到,只要脚本本身是幂等的,我就可以使用它inotifywait来对任何更改进行运行安装脚本/dev/input
查理·戈里奇纳兹

3

X.Org配置如何?从Gentoo Wiki:X.Org/Input_drivers-udev

示例:如果您拥有瑞士法语区的Logitech Access键盘,则可以使用以下命令:

文件: /etc/X11/xorg.conf.d/10-keyboard.conf

Section "InputClass"
    Identifier             "evdev keyboard catchall"
    MatchIsKeyboard        "on"
    MatchDevicePath        "/dev/input/event*"
    Driver                 "evdev"
    Option                 "XkbModel" "logiaccess"
    Option                 "XkbLayout" "ch"
    Option                 "XkbVariant" "fr"
EndSection

有关详细说明,请阅读:

man xorg.conf

和:

man evdev

ArchWiki演示了在xorg.conf中使用相同的语法,但指出“如今,您应该创建一个单独的配置文件,例如/etc/X11/xorg.conf.d/90-keyboard-layouts.conf”。我使用Arch并在现有的/etc/X11/xorg.conf.d/vim 10-evdev.conf中配置了自己的USB键盘。

@rizumu:聪明的朋友,谢谢分享。


1
我没有x.org.conf.d目录上的Linux Mint的18.2
最大n

2

要回答有关访问正在运行的显示的问题,您可以在脚本中导出适当的DISPLAY变量,前提是已正确设置了显示权限。(man xset用于显示权限。)

在许多通常情况下,您只需export DISPLAY=:0输入命令即可,因为这是在单个用户系统上的第一次显示。直接运行脚本而不是直接运行xmodmap可能是最简单的方法,因为这将使您可以更好地控制环境变量和其他变量。(因此,将规则中的“ / usr / bin / xmodmap〜/ .usbXmodmap”替换为“ /usr/local/bin/keyboard_plug.sh”,并将相应的命令与DISPLAY变量一起放入该脚本中。)

但是,如上所述,如果您假设DISPLAY =:0,则如果您有多个用户或多个显示器,则稍后可能会遇到问题。您可以编写脚本来检测适当的显示,但是在这种情况下,您可以自己(就这个答案而言)。:)


1

由于无法获得使udev规则起作用的技巧,因此我编写了一个小的Python脚本pyudev来监视输入事件。

#! /usr/bin/env python3

import pyudev
import time
import subprocess

ctx = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(ctx)
monitor.filter_by("input")

def defer_xmodmap():
    time.sleep(1) # not sure if there's a race here, but it feels like there could be.
    subprocess.run("xmodmap ~/dotfiles/.xmodmap", shell=True)


for device in iter(monitor.poll, None):
    # there might be a way to add the action condition to the filter, but I couldn't find it
    if device.action != "add":
        continue

    # ensure the KB is initialized -- not sure if this is actually a needed check
    if not device.is_initialized:
        continue

    # my keyboard, from the output of `lsusb`
    if not "045E:07A5" in device.device_path:
        continue

    # it's the keyboard being added.
    defer_xmodmap()

然后,我使用这个systemd用户单元文件来保持其运行(systemctl --user enable name_of_service_file):

[Unit]
Description=udev xmodmap monitor

[Service]
ExecStart=/usr/bin/env python3 %h/local/bin/monitor_kb_udev
Restart=always
RestartSec=10

[Install]
WantedBy=default.target

inotifywait@ giosh94mhz 的解决方案更简单一些,并且避免了对的依赖pyudev。但是,由于某种原因,我发现在inotify连接键盘后10到20秒没有触发该事件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.