Как определить, какая клавиатура использовалась для нажатия клавиши?

16

Я часто работаю на сопряженных станциях, где установлено несколько клавиатур. Я могу использовать setxkbmapс, -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предоставляет идентификаторы устройств, используемые setxkbmap.
  • showkeyи xevне печатать идентификаторы клавиатуры.
  • xinput list-props $IDпоказывает, куда отправляются события клавиатуры . Однако, используя код из другого ответа, кажется, что это устройство не печатает ничего, чтобы идентифицировать клавиатуру.
  • Одно из почти возможных решений - запустить xinput --test <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)]
    
l0b0
источник
1
Возможно, вы ищете MPX.
Игнасио Васкес-Абрамс
@ IgnacioVazquez-Abrams Разве это не намного более сложное решение?
10
Это зависит от того, в чем проблема.
Игнасио Васкес-Абрамс
«кажется, что это устройство не печатает ничего, чтобы идентифицировать клавиатуру»: что вы имеете в виду? Если вы less -f /dev/input/eventXнажмете клавишу на соответствующей клавиатуре, вы должны увидеть «мусор», поэтому ваши нажатия клавиш действительно направлены в один файл разработчика, а не в другие.
Л. Леврел
Вы пробовали это (упоминается в другом ответе на тот другой вопрос, который вы цитируете)?
Л. Леврел

Ответы:

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

Идея?

Вы можете включить отключение одной из клавиатур, используя эту команду, чтобы определить, на какой вы находитесь.

Ссылки

SLM
источник
Разве это не больше работы? Мой подход включает как минимум одну команду, максимум три. Этот подход всегда включает три команды - отключить, включить, затем установить макет (плюс, возможно, переключатель клавиатуры).
10
@ l0b0 - да, я тоже не в восторге от такого подхода. Я продолжаю искать, но выкладываю этот метод здесь как "1 way". Хотя я не идеальный, я согласен.
СЛМ
@lobo - этот ответ не получит награду, так что не беспокойтесь об этом, у него были голоса до того, как вы начали награду. stackoverflow.com/help/bounty . Кроме того, что твой гнев на меня пытается помочь вам здесь? Я дал вам не идеальное решение, но 1 способ выполнить вашу задачу. Я предоставил это более двух с лишним лет назад, и этот вопрос находился здесь без альтернатив. Я думаю, вам нужно спросить себя, возможно, проблема в подходе. Очевидно, только мои 0,02 доллара, но этого уже достаточно.
СЛМ
Мой плохой х 2: Я не заметил ничего о «созданном после начала награды», и я ценю, что вы написали очень хорошо сформулированный ответ. Но я не могу высказать решение, которое является более сложным, чем оригинальное, и я не понимаю, почему другие делают.
10
1
@ l0b0 Моя причина для голосования: это единственная команда, которую я могу использовать, чтобы быстро и легко подтвердить свое подозрение, какой клавиатурой она была, вместо того, чтобы читать весь скрипт, чтобы убедиться, что он не стирает мой жесткий диск, затем сохранить и выполнить его. Или, в случае ответа с наибольшим количеством голосов, скомпилируйте C-код. Кроме того, такие креативные идеи заслуживают одобрения.
Фабиан Röling
4

Вопрос звучит несколько противоречиво, поскольку вы цитируете инструменты X, но спрашиваете решение, которое «в идеале должно работать без X».

О вашей 4- й находке: 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*- я пробовал, tailно безрезультатно.
августа
by-id дает имя устройства сопоставления символических ссылок в очередь событий, не требуя X.
jthill
@jthill На машине, на которой я сейчас работаю, этот каталог содержит только ссылки для мыши.
Л. Леврел
Hunh. Ладно, живи и учись, у меня есть моя красивая клавиатура.
до
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
l0b0
источник