如何分辨是哪个键盘按下了按键?


16

我经常在配对站中安装多个键盘。我可以使用setxkbmapwith -device <ID>来设置特定键盘的布局(使用中的IDxinput),但是通常我不清楚使用的是哪个键盘。最好避免反复尝试两个键盘,所以我想编写一个快速工具来获取有关此信息setxkbmap。我期望一个典型的用例如下:

$ setxkbmap -device "$(get-keyboard-id)" -layout gb
Press Enter to detect keyboard ID

哪个接口在Linux上提供此信息?理想情况下,它应该在没有X的情况下也可以工作,但这不是必须的(似乎没有很多工具可以在没有X的情况下支持此功能)。


到目前为止的发现:

  • Linux 必须知道我要键入哪个键盘才能同时支持多个键盘的不同布局。
  • xinput→list.c→ list_xi2XIQueryDevice提供设备ID可使用的通过setxkbmap
  • showkey并且xev不打印键盘ID。
  • xinput list-props $ID显示键盘事件的发送位置。但是,使用其他答案中的代码,似乎该设备无法打印任何内容来识别键盘。
  • 一种几乎可行的解决方案是xinput --test <ID> &为每个键盘ID 运行并查看哪个首先返回值。这样做的问题是弄清楚哪些“键盘” 实际上是键盘:

    $ xinput | grep keyboard
    ⎣ Virtual core keyboard                         id=3    [master keyboard (2)]
        ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
        ↳ Power Button                              id=6    [slave  keyboard (3)]
        ↳ Video Bus                                 id=7    [slave  keyboard (3)]
        ↳ Power Button                              id=8    [slave  keyboard (3)]
        ↳ Sleep Button                              id=9    [slave  keyboard (3)]
        ↳ WebCam SC-13HDL10931N                     id=10   [slave  keyboard (3)]
        ↳ AT Translated Set 2 keyboard              id=11   [slave  keyboard (3)]
    

1
也许您正在寻找MPX。
伊格纳西奥·巴斯克斯

@ IgnacioVazquez-Abrams这不是更复杂的解决方案吗?
l0b0

这取决于问题所在。
伊格纳西奥·巴斯克斯

“该设备似乎无法打印任何内容来识别键盘”:您是什么意思?如果您less -f /dev/input/eventX按下相应键盘上的一个键,您应该会看到“垃圾”出现,因此您的按键确实指向了一个开发文件,而不是其他文件。
L. Levrel's

您是否尝试过此方法(在您引用的另一个问题的另一个答案中进行了引用)?
L. Levrel '16

Answers:


4

禁用设备

这是确定哪个键盘是哪个键盘的一个想法。您可以使用命令xinput启用和禁用设备。

$ xinput list
⎡ Virtual core pointer                      id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad                id=12   [slave  pointer  (2)]
⎜   ↳ TPPS/2 IBM TrackPoint                     id=13   [slave  pointer  (2)]
⎜   ↳ Logitech USB Receiver                     id=9    [slave  pointer  (2)]
⎜   ↳ Logitech USB Receiver                     id=10   [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)]
    ↳ Video Bus                                 id=7    [slave  keyboard (3)]
    ↳ Sleep Button                              id=8    [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard              id=11   [slave  keyboard (3)]
    ↳ ThinkPad Extra Buttons                    id=14   [slave  keyboard (3)]

上面的输出显示了Thinkpad笔记本电脑上的各种设备。我只连接了1个键盘,这一个是:

    ↳ AT Translated Set 2 keyboard              id=11   [slave  keyboard (3)]

现在看一下通过此设备可用的属性:

$ xinput list-props "AT Translated Set 2 keyboard"
Device 'AT Translated Set 2 keyboard':
    Device Enabled (124):   1
    Coordinate Transformation Matrix (126): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.

从上面可以看到它已启用,因此让我们禁用它:

$ xinput set-prop "AT Translated Set 2 keyboard" "Device Enabled" 0

要启用它:

$ xinput set-prop "AT Translated Set 2 keyboard" "Device Enabled" 1

这个主意?

您可以使用此命令启用禁用其中一个键盘来确定您使用的是哪个键盘。

参考文献


这不是更多的工作吗?我的方法涉及至少一个命令,最多三个。这种方法总是涉及三个命令-禁用,启用,然后设置布局(可能还有键盘开关)。
l0b0

@ l0b0-是的,我也不为这种方法感到兴奋。我一直在寻找,但在这里将此方法称为“ 1向”。我同意,这不是理想的选择。
slm

@lobo-这个答案不会得到赏金,所以不用担心,在您开始赏金之前,它已经获得了投票。stackoverflow.com/help/bounty。另外,您对我在这里帮助您的愤怒是什么?我给您的不是理想的解决方案,而是您完成任务的一种方法。我在2年前就提供了此功能,而此Q在这里有0种选择。我认为您需要问自己是否是问题/方法。显然只有我的0.02美元,但已经足够了。
slm

不好意思x 2:我没有注意到“赏金开始后创建的”问题,我感谢您写了一个很好的公式化答案。但是我无法提出比原始解决方案更复杂的解决方案,而且我不明白其他人为什么这样做。
l0b0

1
@ l0b0我赞成的理由:这是一个命令,我可以用来快速,轻松地确认自己是哪个键盘的怀疑,而无需阅读整个脚本以确保它不会擦拭硬盘,然后保存并执行它。或者,对于迄今为止获得最高投票的答案,请编译C代码。同样,像这样的创新想法也应该得到赞扬。
法比安·罗林(FabianRöling)

4

这个问题听起来有点矛盾,因为您引用的是X工具,但要求一个“理想情况下不使用X即可工作”的解决方案。

关于您的第四发现: xinput将给您信件

$ xinput list-props 11
Device 'AT Translated Set 2 keyboard':
    Device Enabled (145):   1
    Coordinate Transformation Matrix (147): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000
    Device Product ID (266):    1, 1
    Device Node (267):  "/dev/input/event0"

至少具有以下版本

$ xinput --version
xinput version 1.6.1
XI version on server: 2.3


第一步:在C中检测键盘事件设备

#include <stdio.h>
//#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>

// typical use : sudo ./a.out /dev/input/event*
int main (int argc, char *argv[])
{
  struct input_event ev[64];
  int fd[argc],rd,idev,value, size = sizeof (struct input_event);
  char name[256] = "Unknown";

  if(argc==1) return -1;

  int ndev=1;
  while(ndev<argc && (fd[ndev] = open (argv[ndev], O_RDONLY|O_NONBLOCK)) != -1){
    ndev++;
  }
  fprintf (stderr,"Found %i devices.\n", ndev);
  if(ndev==1) return -1;

  while (1){
    for(idev=1; idev<argc; idev++){
      if( (rd=read (fd[idev], ev, size * 64)) >= size){
      value = ev[0].value;
      if (value != ' ' && ev[1].value == 1 && ev[1].type == 1){
        ioctl (fd[idev], EVIOCGNAME (sizeof (name)), name);
        printf ("%s\n", name);
        return idev;
      }
      }
    }
//    sleep(1);
  }
  return -1;
}

非常感谢此页面。为了清楚起见,我已经从我那里借来的代码中剥离了大多数安全检查,在实际的代码中,您可能希望使用它们。

请注意,按键是回声,因此您可能确实想请用户敲击修饰键(Shift,Control ...)而不是任何键。

第二步:使用xinput从设备名称获取X ID

编译上面的C源代码并使用这种方式:

xinput list --id-only "keyboard:$(sudo ./a.out /dev/input/event*)"


还有/dev/input/by-id
jthill,

谢谢你的提示。我之所以引用X工具只是因为大多数工具似乎都需要X。我知道如何使用/dev/input/event*-我试过tailting但无济于事。
l0b0

通过-ID给符号链接映射设备名称事件队列,而不需要X.
jthill

@jthill在我当前所在的计算机上,此目录仅具有鼠标链接。
L. Levrel '16

Hunh。好吧,生活和学习,我的键盘全部列出来了。
jthill,2013年

1

进一步的挖掘揭示使用普通Bash和普通用户帐户的另一种解决方案剧本

#!/usr/bin/env bash

set -o errexit -o nounset -o noclobber -o pipefail

# Remove leftover files and processes on exit
trap 'rm --recursive -- "$dir"; kill -- -$$' EXIT
dir="$(mktemp --directory)"
cd "$dir"

# Log key presses to file
xinput --list --id-only | while read id
do
    # Only check devices linked to an event source
    if xinput --list-props "$id" | grep --quiet --extended-regexp '^\s+Device Node.*/dev/input/event'
    then
        xinput test "$id" > "$id" &
    fi
done

# Check for key presses
while sleep 0.1
do
    for file in *
    do
        if [[ -s "$file" ]]
        then
            echo "$file"
            exit
        fi
    done
done
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.