如何判断哪个键盘按下了某个键?

如何判断哪个键盘按下了某个键?

我经常在安装了多个键盘的配对站上工作。我可以使用setxkbmapwith-device <ID>来设置特定键盘的布局(使用身份证件来自xinput),但通常我使用的键盘并不明显。最好避免来回尝试两种键盘,因此我想编写一个快速工具来获取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显示键盘事件发送到的位置。然而,使用另一个答案的代码看来该设备不会打印任何内容来识别键盘。
  • 一种几乎可能的解决方案是针对每个键盘 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

禁用设备

这是识别哪个键盘是哪个键盘的一个想法。您可以使用命令x输入启用和禁用设备。

例子

$ 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

这个想法?

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

参考

答案2

更多挖掘工作揭晓另一种解决方案使用普通 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

答案3

这个问题听起来有点矛盾,因为您引用了 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*)"

相关内容