Wie kann man feststellen, mit welcher Tastatur eine Taste gedrückt wurde?

15

Ich arbeite häufig an Pairing-Stationen, auf denen mehrere Tastaturen installiert sind. Ich kann setxkbmapmit -device <ID>das Layout für eine bestimmte Tastatur festlegen (unter Verwendung einer ID vonxinput ), aber oft ist nicht klar, auf welcher Tastatur ich mich befinde. Es ist besser, das Hin und Her zu vermeiden, beide Tastaturen auszuprobieren. Daher möchte ich ein schnelles Tool schreiben, um diese Informationen zu erhalten setxkbmap. Ich würde einen typischen Anwendungsfall wie den folgenden erwarten:

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

Welche Schnittstelle bietet diese Informationen unter Linux? Idealerweise sollte es ohne X funktionieren, aber das ist keine Voraussetzung (es scheint nicht viele Tools zu geben, die dies ohne X unterstützen).


Bisherige Ergebnisse:

  • Linux muss wissen, auf welcher Tastatur ich tippe, um verschiedene Layouts für mehrere Tastaturen gleichzeitig zu unterstützen.
  • xinput→ list.c → list_xi2XIQueryDeviceliefert Geräte-IDs, die von verwendet werden können setxkbmap.
  • showkeyund xevdrucken Sie keine Tastatur-IDs.
  • xinput list-props $IDZeigt an, wohin Tastaturereignisse gesendet werden . Verwendung jedoch Code aus einer anderen Antwort scheint es , dieses Gerät nichts druckt die Tastatur zu identifizieren.
  • Eine fast mögliche Lösung besteht darin, xinput --test <ID> &für jede Tastatur-ID zu prüfen, welche zuerst etwas zurückgibt. Das Problem dabei ist, herauszufinden, welche "Tastaturen" tatsächlich Tastaturen sind:

    $ 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
quelle
1
Vielleicht suchen Sie nach MPX.
Ignacio Vazquez-Abrams
@ IgnacioVazquez-Abrams Ist das nicht eine massiv kompliziertere Lösung?
l0b0
Das hängt davon ab, wo das Problem liegt.
Ignacio Vazquez-Abrams
"Es scheint, dass dieses Gerät nichts druckt, um die Tastatur zu identifizieren": Was meinen Sie? Wenn Sie less -f /dev/input/eventXeine Taste auf der entsprechenden Tastatur drücken, sollte "Garbage" angezeigt werden, sodass Ihre Tastendrücke in der Tat in eine Dev-Datei und nicht in die anderen geleitet werden.
L. Levrel
Haben Sie versucht , diese (in einer anderen Antwort des anderen Frage , die Sie zitieren verwiesen)?
L. Levrel

Antworten:

4

Gerät deaktivieren

Hier ist eine Idee, um herauszufinden, welche Tastatur welche ist. Mit dem Befehl xinput können Sie Geräte aktivieren und deaktivieren.

Beispiel

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

Die obige Ausgabe zeigt die verschiedenen Geräte, die ich auf meinem Thinkpad-Laptop habe. Ich habe nur 1 Tastatur angeschlossen, diese:

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

Sehen Sie sich nun die Eigenschaften an, die über dieses Gerät verfügbar sind:

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

Anhand der obigen Abbildung können Sie sehen, dass es aktiviert ist. Deaktivieren Sie es also:

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

So aktivieren Sie es:

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

Die Idee?

Mit diesem Befehl können Sie eine der Tastaturen deaktivieren, um festzustellen, auf welcher Sie sich befinden.

Verweise

slm
quelle
Ist das nicht noch mehr Arbeit? Mein Ansatz umfasst mindestens einen Befehl, höchstens drei. Dieser Ansatz umfasst immer drei Befehle: Deaktivieren, Aktivieren und Festlegen des Layouts (sowie möglicherweise einen Tastaturschalter).
l0b0
@ l0b0 - Ja, ich bin auch nicht begeistert von diesem Ansatz. Ich schaue weiter, habe diese Methode aber hier als "Einbahnstraße" angegeben. Ich stimme jedoch zu, dass es nicht das ideale ist.
slm
@lobo - Diese Antwort wird kein Kopfgeld bekommen, also mach dir keine Sorgen, sie hatte die Stimmen, bevor du mit dem Kopfgeld angefangen hast. stackoverflow.com/help/bounty . Und was ärgert dich daran, dass ich versuche, dir hier zu helfen? Ich gab Ihnen keine ideale Lösung, aber einen Weg, um Ihre Aufgabe zu erfüllen. Ich habe dies vor über 2 Jahren zur Verfügung gestellt und dieses Q hat hier mit 0 Alternativen gesessen. Ich denke, Sie müssen sich fragen, ob es vielleicht die Frage / Herangehensweise ist, die das Problem ist. Offensichtlich nur meine 0,02 $, aber es ist schon genug.
slm
Mein schlechtes x 2: Ich habe das bisschen "Erstellt nach dem Start des Kopfgeldes" nicht bemerkt, und ich schätze, dass Sie eine sehr gut formulierte Antwort geschrieben haben. Aber ich kann eine Lösung nicht gutheißen, die komplizierter ist als die ursprüngliche, und ich verstehe nicht, warum andere das tun.
l0b0
1
@ l0b0 Mein Grund für das Upvoting: Es ist ein einziger Befehl, mit dem ich schnell und einfach feststellen kann, um welche Tastatur es sich handelt, anstatt ein ganzes Skript lesen zu müssen, um sicherzustellen, dass meine Festplatte nicht gelöscht wird. Dann speichern und speichern Führ es aus. Oder kompilieren Sie im Fall der bisher am höchsten bewerteten Antwort C-Code. Auch kreative Ideen wie diese verdienen positive Stimmen.
Fabian Röling
4

Die Frage klingt etwas widersprüchlich, da Sie X-Tools zitieren, aber nach einer Lösung fragen, die "idealerweise ohne X funktionieren sollte".

Über Ihre 4 th Befund: xinputgibt Ihnen die Korrespondenz

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

Zumindest mit der folgenden Version

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


Erster Schritt: Erkennen des Tastaturereignisgeräts in 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;
}

Vielen Dank an diese Seite . Ich habe die meisten Sicherheitsüberprüfungen aus dem Code entfernt, den ich dort aus Gründen der Klarheit ausgeliehen habe. In echtem Code möchten Sie sie wahrscheinlich haben.

Beachten Sie, dass die Tastendrücke wiederholt werden. Sie können den Benutzer also auffordern, eine Modifikatortaste (Umschalttaste, Steuerungstaste ...) anstelle einer beliebigen Taste zu drücken.

Zweiter Schritt: Verwenden Sie xinput, um die X-ID aus dem Gerätenamen abzurufen

Kompilieren Sie die obige C-Quelle und verwenden Sie diese Methode:

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

L. Levrel
quelle
Es gibt auch/dev/input/by-id
bis
Danke für den Tipp. Ich habe X-Tools nur zitiert, weil die meisten Tools anscheinend X erfordern. Ich weiß nicht , wie ich damit arbeiten soll /dev/input/event*- ich habe es versucht, tailaber ohne Erfolg.
10.
by-id gibt Symlinks an, die den Gerätenamen der Ereigniswarteschlange
zuordnen
@jthill Auf dem Computer, auf dem ich mich gerade befinde, enthält dieses Verzeichnis nur Links für die Maus.
L. Levrel
Hunh. Okay, lebe und lerne, meine Tastatur ist alle hübsch aufgelistet.
bis
0

Mehr Graben ergab eine andere Lösung mit einfachen Bash und einem normalen Benutzerkonto. Skript :

#!/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
quelle