Jak stwierdzić, której klawiatury użyto do naciśnięcia klawisza?

16

Często pracuję na parujących stacjach, na których jest zainstalowanych wiele klawiatur. Mogę użyć za setxkbmappomocą, -device <ID>aby ustawić układ dla określonej klawiatury (używając identyfikatora zxinput ), ale często nie jest oczywiste, na której klawiaturze jestem. Lepiej byłoby uniknąć próbowania obu klawiatur, więc chciałbym napisać szybkie narzędzie do uzyskania tych informacji setxkbmap. Oczekiwałbym typowego przypadku użycia takiego jak ten:

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

Który interfejs udostępnia te informacje w systemie Linux? Idealnie powinno działać bez X, ale nie jest to wymagane (wydaje się, że nie ma wielu narzędzi, które obsługują to bez X).


Dotychczasowe ustalenia:

  • Linux musi wiedzieć, na której klawiaturze piszę, aby obsługiwać różne układy wielu klawiatur jednocześnie.
  • xinput→ lista. C → list_xi2XIQueryDevicezapewnia identyfikatory urządzeń, których można używać setxkbmap.
  • showkeyi xevnie drukuj identyfikatorów klawiatury.
  • xinput list-props $IDpokazuje, gdzie wysyłane są zdarzenia z klawiatury . Jednak przy użyciu kodu z innej odpowiedzi wydaje się, że to urządzenie nie drukuje niczego, aby zidentyfikować klawiaturę.
  • Jednym prawie możliwym rozwiązaniem jest uruchomienie xinput --test <ID> &dla każdego identyfikatora klawiatury i sprawdzenie, który z nich coś zwraca jako pierwszy. Problem polega na tym, aby dowiedzieć się, które „klawiatury” są tak naprawdę klawiaturami:

    $ 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
źródło
1
Być może szukasz MPX.
Ignacio Vazquez-Abrams,
@ IgnacioVazquez-Abrams Czy to nie jest znacznie bardziej skomplikowane rozwiązanie?
l0b0,
To zależy od problemu.
Ignacio Vazquez-Abrams,
„wygląda na to, że to urządzenie nie drukuje niczego, by zidentyfikować klawiaturę”: co masz na myśli? Jeśli naciśniesz less -f /dev/input/eventXklawisz na odpowiedniej klawiaturze, powinieneś zobaczyć „śmieci”, więc twoje naciśnięcia klawiszy są rzeczywiście skierowane do jednego pliku programisty, a nie do innych.
L. Levrel,
Czy próbowałeś tego (o którym mowa w innej odpowiedzi na inne cytowane przez ciebie pytanie)?
L. Levrel,

Odpowiedzi:

4

Wyłącz urządzenie

Oto jeden pomysł na określenie, która klawiatura jest która. Możesz użyć polecenia xinput, aby włączyć lub wyłączyć urządzenia.

Przykład

$ 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)]

Powyższe dane wyjściowe pokazują różne urządzenia, które mam na moim laptopie Thinkpad. Mam tylko 1 klawiaturę, w tym:

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

Teraz spójrz na właściwości dostępne za pośrednictwem tego urządzenia:

$ 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.

Z powyższego widać, że jest włączony, więc wyłączmy go:

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

Aby to włączyć:

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

Pomysł?

Możesz włączyć wyłączenie jednej z klawiatur za pomocą tego polecenia, aby określić, na której jesteś.

Bibliografia

slm
źródło
Czy to jeszcze nie praca? Moje podejście obejmuje co najmniej jedno polecenie, maksymalnie trzy. To podejście zawsze obejmuje trzy polecenia - wyłącz, włącz, a następnie ustaw układ (oraz ewentualnie przełącznik klawiatury).
l0b0
@ l0b0 - tak, nie podoba mi się to podejście. Nadal szukam, ale umieściłem tę metodę tutaj jako „1 sposób”. Zgadzam się, że nie jest idealny.
slm
@lobo - Ta odpowiedź nie dostanie nagrody, więc nie przejmuj się, miała głosy przed rozpoczęciem nagrody. stackoverflow.com/help/bounty . Jaki jest twój gniew na mnie, który próbuje ci tutaj pomóc? Dałem ci nie idealne rozwiązanie, ale 1 sposób na wykonanie zadania. Dostarczyłem to ponad 2 lata temu i to Q siedziało tutaj z / 0 alternatywami. Myślę, że musisz zadać sobie pytanie, czy to może pytanie / podejście jest problemem. Oczywiście tylko moje 0,02 $, ale już wystarczy.
slm
Mój zły x 2: Nie zauważyłem trochę o „stworzonym po rozpoczęciu nagrody” i doceniam, że napisałeś bardzo dobrze sformułowaną odpowiedź. Ale nie mogę głosować za rozwiązaniem, które jest bardziej skomplikowane niż oryginalne, i nie rozumiem, dlaczego inni to robią.
l0b0
1
@ l0b0 Mój powód upvotingu: To jedno polecenie, którego mogę użyć, aby szybko i łatwo potwierdzić moje podejrzenie, którą to była klawiatura, zamiast czytać cały skrypt, aby upewnić się, że nie wyczyści mojego dysku twardego, a następnie zapisz i wykonaj to. Lub, w przypadku jak dotąd najlepiej głosowanej odpowiedzi, skompiluj kod C. Również kreatywne pomysły, takie jak ten, zasługują na aprobatę.
Fabian Röling
4

Pytanie brzmi trochę sprzecznie, ponieważ cytujesz narzędzia X, ale pytasz o rozwiązanie, które „idealnie powinno działać bez X”.

O swojej 4 -tego stwierdzenia: xinputdaje korespondencji

$ 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"

przynajmniej z następującą wersją

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


Pierwszy krok: wykrycie klawiaturowego urządzenia zdarzeń w 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;
}

Wielkie dzięki za tę stronę . Usunąłem większość kontroli bezpieczeństwa z kodu, który tam pożyczyłem, dla jasności, w prawdziwym kodzie prawdopodobnie ich potrzebujesz.

Zauważ, że naciśnięcia klawiszy są powtarzane, więc możesz chcieć uprzejmie poprosić użytkownika o naciśnięcie klawisza modyfikującego (Shift, Control ...) zamiast jakiegokolwiek klawisza.

Drugi krok: użyj xinput, aby uzyskać identyfikator X z nazwy urządzenia

Skompiluj powyższe źródło C i użyj tego:

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

L. Levrel
źródło
Jest też/dev/input/by-id
jthill
Dzięki za wskazówkę. Mam cytowane narzędzi x Tylko dlatego, że większość narzędzi wydają się wymagać X. ja nie wiem, jak pracować z /dev/input/event*- Próbowałem tailting ale bezskutecznie.
l0b0
by-id podaje nazwę urządzenia mapującego dowiązania symboliczne do kolejki zdarzeń, bez wymagania X.
jthill
@ jthill Na komputerze, na którym aktualnie pracuję, ten katalog zawiera tylko linki do myszy.
L. Levrel,
Hun Dobra, żyj i ucz się, moja klawiatura jest wymieniona.
jthill
1

Dalsze kopanie ujawniło inne rozwiązanie przy użyciu zwykłego Bash i zwykłego konta użytkownika. Skrypt :

#!/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
źródło