如何将不同的键盘布局永久分配给USB键盘?


16

我经常将USB键盘插入笔记本电脑(除了外部显示器和鼠标,它们实际上将笔记本电脑转换为台式计算机),然后我更喜欢使用其他键盘布局。

每次插入此USB键盘时,我都必须手动更改当前的键盘布局。

如果可能的话,我想使用自动化的方式。

拉杜的问题的答案在这里给出了一些线索,但似乎我需要一个启动脚本来完成这个任务对我的USB键盘的设备ID更改每次启动计算机时。

该启动脚本可能首先包含命令xinput -list | grep "USB Keyboard",以及另一个命令以获取显示的第一个USB键盘ID号,然后在最终命令中使用它来设置我为该USB键盘选择的布局,如下所示:

setxkbmap -device <NUMBER> -layout <LAYOUT>



1
@Sadi您是指在马丁·路德·金博士被暗杀之后将罗格斯和美国国旗颠倒吗?保罗·罗伯逊(Paul Robeson):《自由之路》的伟大先驱,第182页
guest271314 18-10-14

@ guest271314非常感谢!但是,我不知道您怎么会在这里对这个问题发表评论:history.stackexchange.com/questions/48704/… ;-)这也是另一种明智的抗议形式,但我认为这最终不会演变成我记得传闻故事。
萨迪

@Sadi您的问题在政治处被删除。
guest271314

Answers:


15

经过一番研究,我找到了解决方案,尽管我仍然愿意接受其他(可能更好)的答案。

这是一个启动脚本(可以将其添加到启动应用程序中),该脚本会将通常输入的usbkbd_layout变量设置为xinput -list中找到的usbkbd设备ID

#!/bin/bash
usbkbd=`xinput -list | grep -c "USB Keyboard"`
if [[ "$usbkbd" -gt 0 ]]
then
    usbkbd_ids=`xinput -list | grep "USB Keyboard" | awk -F'=' '{print $2}' | cut -c 1-2`
    usbkbd_layout="tr(f)"
    for ID in $usbkbd_ids
    do
      setxkbmap -device "${ID}" -layout "${usbkbd_layout}"
    done
fi
exit 0

对于用户开始在台式机设置上使用笔记本电脑(带有外部键盘,鼠标和显示器等)的情况,此脚本非常有用(并且更稳定),并且只要插入外部USB键盘,就可以手动运行该脚本。 ...

================================================== ========================

更好(几乎完美)的解决方案-感谢MinimusHeximus和他在下面的评论中提到的主题的各自贡献者:

现在,我可以插入USB键盘,并自动应用其不同的(TR-F)键盘布局,同时仍然在笔记本电脑上保留默认键盘布局(TR-Q)!

以下是使之成为可能的文件及其内容:

/etc/udev/rules.d/00-usb-keyboard.rules

ATTRS{idVendor}=="09da", ATTRS{idProduct}=="0260", OWNER="sadi"
ACTION=="add", RUN+="/home/sadi/.bin/usb-keyboard-in_udev"
ACTION=="remove", RUN+="/home/sadi/.bin/usb-keyboard-out_udev"

/home/sadi/.bin/usb-keyboard-in_udev

#!/bin/bash
/home/sadi/.bin/usb-keyboard-in &

/home/sadi/.bin/usb-keyboard-in

#!/bin/bash
sleep 1
DISPLAY=":0.0"
HOME=/home/sadi/
XAUTHORITY=$HOME/.Xauthority
export DISPLAY XAUTHORITY HOME
usbkbd_id=`xinput -list | grep "USB Keyboard" | awk -F'=' '{print $2}' | cut -c 1-2 | head -1`
usbkbd_layout="tr(f)"
if [ "${usbkbd_id}" ]; then
    gsettings set org.gnome.settings-daemon.plugins.keyboard active false
    sleep 2
    setxkbmap -device "${usbkbd_id}" -layout "${usbkbd_layout}"
fi

/home/sadi/.bin/usb-keyboard-out_udev

#!/bin/bash
/home/sadi/.bin/usb-keyboard-out &

/home/sadi/.bin/usb-keyboard-out

#!/bin/bash
sleep 1
DISPLAY=":0.0"
HOME=/home/sadi/
XAUTHORITY=$HOME/.Xauthority
export DISPLAY XAUTHORITY HOME
gsettings set org.gnome.settings-daemon.plugins.keyboard active true

笔记:

  1. 当然,您的“ .bin”文件夹中的所有四个文件都应具有必要的权限(可读和可执行),例如可以使用诸如Terminal的命令来实现 chmod - 755 /home/sadi/.bin/usb-keyboard-*
  2. 有时,插入USB键盘后,它仍然使用相同(默认)的键盘布局,并在第二次尝试时切换到指定的布局(也许在某处需要更多的睡眠时间?)
  3. USB键盘的特定布局在登录屏幕中(退出时)无效。
  4. 如果将单独的分区用于/ home,那么最好将四个脚本放在根分区中的某个位置,例如/ usr / local / bin,并相应地修改所有各自文件的内容,因为有时udev可能会寻找在挂载/ home分区之前,这些文件会引起问题。

为了使此设置适应不同的要求:

  1. USB键盘供应商和产品ID应改为按照该命令的输出lsusb(例如,我的lsusb输出都为我的USB键盘:Bus 001 Device 006: ID 09da:0260 A4 Tech Co., Ltd
  2. OWNER和所有用户目录名称应从“ sadi”更改为另一个名称
  3. usbkbd_id可能需要稍作调整以获取正确的设备ID(例如,命令的输出xinput -list | grep "USB Keyboard"给了我两行;↳ USB Keyboard id=14 [slave keyboard (3)]↳ USB Keyboard id=16 [slave keyboard (3)];然后通过awk使用“ =”作为字段定界符并捕获第二部分来进行过滤;然后仅剪切掉前两位数字,然后仅使用第一行中的值)
  4. usbkbd_layout的值可以是任何其他有效选择

最好在插入USB键盘后自动运行另一个类似脚本,如此处要求(尚未回答):askubuntu.com/questions/284224/…
萨迪

2
它可以是有益的,如果你能发布另一种答案了这个混乱的线程:superuser.com/questions/249064/...
纳米-合并我

1
@MinimusHeximus谢谢一百万!!!经过您指出的线程并进行了反复试验后,我终于对其进行了整理,并将在上面添加这个新的(几乎)完美的热插拔解决方案!
萨迪

1
我由于某种原因,键盘有两个ID,所以不是用IF我不得不使用FOR。现在对我有用,谢谢!gist.github.com/zvictor/193b567c14b5b6a679fe
zVictor 2014年

1
@Sadi我本人只是普通用户。我将在这里发布我的解决方案。也许您可以摆脱一些想法。
kleinfreund '17

9

您可以在udev规则中指定X11驱动程序选项,不需要自定义脚本。例如,这是我的/etc/udev/rules.d/99-usb-kbd.rules的内容

ACTION=="add", ATTRS{idVendor}=="04d9", ATTRS{idProduct}=="2323", ENV{XKBMODEL}="pc104", ENV{XKBLAYOUT}="us", ENV{XKBVARIANT}="euro", ENV{XKBOPTIONS}="compose:caps"

此规则可确保特定的USB键盘在Xorg中使用美国布局(我的笔记本电脑的内部键盘为德语,这也是我的主要布局)。重要事项:

  1. 你可以找出来 idVendoridProduct使用lsusb或在设备中和evtest
  2. 您可以使用中的任何布局/usr/share/X11/xkb/symbols。请注意同时指定有效的布局和有效的变体。
  3. 文件名必须以数字> 64开头,以便设置覆盖在中指定的系统范围设置。 /lib/udev/rules.d/64-xorg-xkb.rules
  4. 确保Gnome / KDE布局管理不会覆盖您的设置。

拔下并重新插入键盘,然后检查/var/log/Xorg.0.log是否存在问题。您也可以udevadm info用来检查设置是否正确应用。
pavel

尤里卡!仅当我输入以下命令(一次即可)以覆盖当前的gconf设置后,您的智能解决方案才开始工作gsettings set org.gnome.settings-daemon.plugins.keyboard active false。如果您还添加了这样的注释,我会尝试将您答案标记为答案(而不是那条笨拙,漫长而曲折的道路;-)
Sadi

这是例外。在Ubuntu 14.04上,可能的模型/布局/选项/等。在/usr/share/X11/xkb/rules/evdev.lst
Jon 2016年

2
不幸的是,在升级到Ubuntu Gnome 17.04之后,这个很好的简单解决方案对我来说不再起作用:-(
Sadi

尝试过Linux Mint 18.2,它基于Ubuntu 16.04 LTS,具有udev版本229-4ubuntu19,再次无效:-( 关于这种奇怪的udev行为的任何想法?
Sadi

2

我刚刚针对bépoTypematrix键盘(优化的优秀dvorak的法语版本)并在广泛的系统环境(假设您具有对计算机的root访问权)方面改进了该解决方案。它只需要3个文件即可工作。如果失败,您可以查阅日志文件以找出失败的原因。

/etc/udev/96-usb-keyboard.rules

ATTRS{idVendor}=="1e54", ATTRS{idProduct}=="2030", SUBSYSTEMS=="usb", ACTION=="add", RUN+="/etc/udev/bepo-typematrix-kbd.sh in"
ATTRS{idVendor}=="1e54", ATTRS{idProduct}=="2030", SUBSYSTEMS=="usb", ACTION=="remove", RUN+="/etc/udev/bepo-typematrix-kbd.sh out"

/etc/udev/bepo-typematrix-kbd.sh(使用中间背景脚本绝对必要)

#!/bin/bash

dir=$(dirname $0)
command=$(basename $0)
command=$dir/${command%\.sh}
arg=$1 # must be "in" or "out"
LOG=/var/log/bepo-typematrix-kbd.log

[ -x "$command" ] && $command $arg >$LOG 2>&1 &

/ etc / udev / bepo-typematrix-kbd

#!/bin/bash
# jp dot ayanides at free.fr

MODEL="tm2030USB-102" # keyboard model
DISPLAY=':0.0'
GSETTING=/usr/bin/gsettings
XSET=/usr/bin/xset
SETXKBMAP=/usr/bin/setxkbmap
XINPUT=/usr/bin/xinput

USER=$(/usr/bin/who | /usr/bin/awk -v DIS=':0' '{if ($2==DIS) print $1}')
eval HOME=~$USER
XAUTHORITY=$HOME/.Xauthority
export DISPLAY XAUTHORITY HOME

case $1 in
        'in')
                BEPO=$($XINPUT list --short | grep "TypeMatrix.com USB Keyboard" | grep keyboard | sed -e 's/^.*id=\([0-9]\+\).*/\1/g')
                if [ -n "$BEPO" ]; then
                        [ -x $GSETTING ] && $GSETTING set org.gnome.settings-daemon.plugins.keyboard active false
                        # apparently nothing to do with TDE (trinity KDE)
                        for ID in $BEPO; do # case of multiple bepo keyboard is taken into account
                                [ -x $SETXKBMAP ] && $SETXKBMAP -device $ID -model $MODEL -layout fr -variant bepo
                        done
                fi
                echo "bépo keyboard id(s) is (are) $BEPO"
                [ -x $XSET ] && $XSET -display $DISPLAY r rate 250 40
        ;;
        'out')
                # apparently nothing to do with TDE (trinity KDE)
                [ -x $GSETTING ] && $GSETTING set org.gnome.settings-daemon.plugins.keyboard active true
        ;;
        *)
                printf "wrong parameter: $1\n"
                exit 1
        ;;
esac

1

经过很多次摆弄后,这就是我现在正在运行的东西。如果有兴趣的话,也许我会写一篇完整的文章,然后将代码发布在存储库中。


为udev设置新的规则集,如下所示:

 sudo gedit /etc/udev/rules.d/80-external-keyboard.rules

每当具有给定供应商和产品ID组合的设备触发某些操作时,该规则应调用Shell脚本。

ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="4042", RUN+="/home/phil/.bin/switch-kb-layout-wrapper.sh"

添加新规则集后,重新启动udev服务:

sudo service udev restart

注意:通过在该文件中提供更具体的匹配规则,我无法获得可靠的结果。最重要的是,添加一个ACTION匹配规则无效。据我所知,脚本还是被触发了。添加时ACTION=="add",删除设备后仍会调用脚本。非常奇怪和令人困惑。

但是,触发udev规则的操作将可用于被调用的脚本,如下所示。


接下来,脚本本身。好吧,不完全是。请注意wrapper文件名中的后缀。这表明这不是实际的脚本,而是包装器,该包装器调用脚本并在后台执行该脚本,以便udev可以完成其过程。

~/.bin/switch-kb-layout-wrapper.sh

#!/bin/sh
/home/phil/.bin/switch-kb-layout.sh "${ACTION}" &

该变量ACTION包含设备触发的udev操作。它产生的值类似于add(已插入设备)和remove(已删除设备)。我们稍后将使用它们。

~/.bin/switch-kb-layout.sh

#!/bin/sh

sleep 1

# Some environment variables that need to be set in order to run `setxkbmap`
DISPLAY=":0.0"
HOME=/home/phil
XAUTHORITY=$HOME/.Xauthority
export DISPLAY XAUTHORITY HOME

udev_action=$1
log_file="$HOME/switch-kb-layout.log"

if [ "${udev_action}" != "add" ] && [ "${udev_action}" != "remove" ]; then
    echo "Other action. Aborting." >> $log_file
    exit 1
fi

internal_kb_layout="de"
internal_kb_variant=""

external_kb_layout="us"
external_kb_variant="altgr-intl"

kb_layout=""
kb_variant=""

if [ "${udev_action}" = "add" ]; then
    kb_layout=$external_kb_layout
    kb_variant=$external_kb_variant
elif [ "${udev_action}" = "remove" ]; then
    kb_layout=$internal_kb_layout
    kb_variant=$internal_kb_variant
fi

setxkbmap -layout "${kb_layout}"
echo "set layout:" "$kb_layout" >> $log_file
if [ ! -z "${kb_variant}" ]; then
    setxkbmap -variant "${kb_variant}"
    echo "set variant:" "$kb_variant" >> $log_file
fi

设置HOME变量时,请用您的用户名替换我的用户名($(whoami)此处将无法使用,因为用户名不会被用户调用root)。

sed -i "s/phil/YOUR_USERNAME/g" ~/.bin/switch-kb-layout.sh

为了进行测试,我添加了一些行,将某些事件记录到主目录中的文件中,以查看一切是否正常。您可以保存删除这些。


最后,这些脚本需要具有执行权限。同样重要的是要注意,这些脚本将由root用户调用,因此请注意在其中执行的操作。

chmod +x ~/.bin/switch-kb-layout-wrapper.sh ~/.bin/switch-kb-layout.sh 

1
谢谢,辛苦了!我也能正常工作。但是,为什么在插入外部命令时看到14次“添加动作”和3次“其他动作”是一个谜,我将在以后尝试解决。但是我发现最好在setxkbmap命令中添加设备ID,以便内部键盘和外部键盘仍然可以使用,就像我最新的自动启动脚本一样。我将尝试几天,然后返回,看看是否可以将您的答案视为答案,也许在这里和那里稍加修改;-)
Sadi

还会多次获得相同的记录行。命令上的设备ID很好。
kleinfreund '17

@Sadi另外,我认为该行gsettings set org.gnome.settings-daemon.plugins.keyboard active false无法按预期运行,因为脚本由运行root。在我的测试中,该行对该设置没有影响。
kleinfreund

我认为在这种情况下,最好是gsettings set org.gnome.settings-daemon.plugins.keyboard active false一劳永逸地以用户身份执行命令,然后在不使用gsettings set命令的情况下使用此脚本……
Sadi

到目前为止,我已经看到我们仍然无法使此事情顺利进行;udev有时不实现键盘布局,因此您必须重新插入电源。我想我将在答案的顶部再次回到我的(更新的)启动脚本一段时间,这可以使我更加顺畅-仅在启动后插入外部键盘时才需要手动运行它。udev似乎有点bug,在很多动作重复中也可以看到(它多次运行包装脚本,并且以奇怪的方式运行)...
Sadi

1

我对udev执行的脚本有一些权限问题。我用sudo解决了如下问题:

# Estract id of MX3 keyboard devices that present themself as "123 COM Smart Control"
    IDLIST=$(sudo -u max /usr/bin/xinput -list | grep "123 COM Smart Control" | grep keyboard | sed -e 's/^.*id=\([0-9]\+\).*/\1/g')

设置每个设备的键盘映射

    for ID in $IDLIST; do
            sudo -u max /usr/bin/setxkbmap -device $ID -layout "${kb_layout}" -display :0
    done

我认为,如果您可以完整编写它,它可能会更有用。例如,您将这些行放在哪里?
萨迪

0

您也可以在Xorg配置文件中定义它。

它在以下stackexchange答案中列出:https : //superuser.com/a/946575/437492


如果我能使它工作的话,那就太好了。但是使用最新的LTS版本Ubuntu 18.04,我只能看到/usr/share/X11/xorg.conf.d/目录,其中包含名为40-libinput.conf的文件。因此,我只是在该文件中为外部键盘添加了一个部分。使用驱动程序libinputevdev以及一个越来越短的供应商名称,我没有得到任何结果。有任何想法吗?
Sadi

@Sadi:如果您对Xorg的配置有所了解,就会发现您可以简单地向其中添加新文件/etc/X11/xorg.conf.d/
Golar Ramblar

谢谢。我一定会读很多书,并首先尝试使用“ /etc/X11/xorg.conf.d/30-keyboard.conf”。我将在上面提到的stackexchange答案下尝试自己的运气。;-)
萨迪(Sadi)
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.