Comment savoir quel clavier a été utilisé pour appuyer sur une touche?

16

Je travaille fréquemment sur des stations d'appairage où plusieurs claviers sont installés. Je peux utiliser setxkbmapavec -device <ID>pour définir la disposition d'un clavier spécifique (en utilisant un ID dexinput ), mais souvent, il n'est pas évident de savoir quel clavier je suis. Il serait préférable d'éviter les allers-retours d'essayer les deux claviers, donc j'aimerais écrire un outil rapide pour obtenir ces informations setxkbmap. Je m'attendrais à un cas d'utilisation typique comme le suivant:

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

Quelle interface fournit ces informations sur Linux? Idéalement, cela devrait fonctionner sans X, mais ce n'est pas une exigence (il ne semble pas y avoir beaucoup d'outils qui prennent en charge cela sans X).


Résultats à ce jour:

  • Linux doit savoir sur quel clavier je tape pour prendre en charge différentes dispositions pour plusieurs claviers simultanément.
  • xinput→ list.c → list_xi2XIQueryDevicefournit des ID de périphérique utilisables par setxkbmap.
  • showkeyet xevn'imprimez pas les ID de clavier.
  • xinput list-props $IDindique où les événements clavier sont envoyés . Cependant, en utilisant le code d'une autre réponse, il semble que cet appareil n'imprime rien pour identifier le clavier.
  • Une solution presque possible consiste à exécuter xinput --test <ID> &pour chaque ID de clavier et à voir lequel renvoie quelque chose en premier. Le problème avec cela est de savoir quels "claviers" sont en fait des claviers:

    $ 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
la source
1
Peut-être que vous recherchez MPX.
Ignacio Vazquez-Abrams
@ IgnacioVazquez-Abrams N'est-ce pas une solution massivement plus compliquée?
l0b0
Cela dépend du problème.
Ignacio Vazquez-Abrams
"il semble que cet appareil n'imprime rien pour identifier le clavier": que voulez-vous dire? Si vous less -f /dev/input/eventXet appuyez sur une touche du clavier correspondant, vous devriez voir "ordures" apparaître, de sorte que vos touches sont en effet dirigées dans un fichier de développement et non dans les autres.
L. Levrel
Avez-vous essayé ceci (référencé dans une autre réponse à cette autre question que vous citez)?
L. Levrel

Réponses:

4

Désactiver l'appareil

Voici une idée pour identifier quel clavier est lequel. Vous pouvez utiliser la commande xinput pour activer et désactiver des périphériques.

Exemple

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

La sortie ci-dessus montre les différents appareils que j'ai sur mon ordinateur portable Thinkpad. Je n'ai qu'un seul clavier connecté, celui-ci:

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

Jetez maintenant un œil aux propriétés disponibles via cet appareil:

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

De ce qui précède, vous pouvez voir qu'il est activé, alors désactivons-le:

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

Pour l'activer:

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

L'idée?

Vous pouvez activer la désactivation de l'un des claviers à l'aide de cette commande pour déterminer celui sur lequel vous vous trouvez.

Les références

slm
la source
N'est-ce pas encore plus de travail? Mon approche implique au moins une commande, au maximum trois. Cette approche implique toujours trois commandes - désactiver, activer, puis définir la disposition (plus éventuellement un commutateur de clavier).
l0b0
@ l0b0 - ouais je ne suis pas non plus ravi de cette approche. Je continue à regarder mais je mettais cette méthode ici comme "1 voie". Pas l'idéal cependant, je suis d'accord.
slm
@lobo - Cette réponse n'obtiendra pas la prime, alors ne vous inquiétez pas, elle avait les votes avant de commencer la prime. stackoverflow.com/help/bounty . Quelle est votre colère envers moi qui essaie de vous aider ici? Je ne vous ai pas donné une solution idéale, mais une façon d'accomplir votre tâche. Je l'ai fourni il y a plus de 2 ans et ce Q s'est assis ici avec 0 alternatives. Je pense que vous devez vous demander si c'est peut-être la question / l'approche qui est le problème. Évidemment juste mon 0,02 $ mais c'est déjà suffisant.
slm
Mon mauvais x 2: je n'ai pas remarqué le peu de "créé après le début de la prime", et j'apprécie que vous ayez écrit une réponse très bien formulée. Mais je ne peux pas voter contre une solution qui est plus compliquée que l'original, et je ne comprends pas pourquoi d'autres le font.
l0b0
1
@ l0b0 Ma raison de voter: c'est une seule commande que je peux utiliser pour confirmer rapidement et facilement mon soupçon de quel clavier il s'agissait, au lieu d'avoir besoin de lire un script entier pour s'assurer qu'il n'efface pas mon disque dur, puis enregistrez et l'exécuter. Ou, dans le cas de la réponse la plus votée jusqu'à présent, compilez le code C. De plus, des idées créatives comme celle-ci méritent des votes positifs.
Fabian Röling
4

La question semble un peu contradictoire puisque vous citez des outils X mais demandez une solution qui "devrait idéalement fonctionner sans X".

A propos de votre 4 ème constatation: xinputvous donnera la correspondance

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

au moins avec la version suivante

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


Première étape: détecter le périphérique d'événements clavier en 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;
}

Un grand merci à cette page . J'ai supprimé la plupart des contrôles de sécurité du code que j'y ai emprunté, pour plus de clarté, dans le vrai code, vous en avez probablement besoin.

Notez que les pressions sur les touches sont répercutées, vous pouvez donc en effet vouloir demander à l'utilisateur d'appuyer sur une touche de modification (Maj, Contrôle ...) plutôt que sur n'importe quelle touche.

Deuxième étape: utilisez xinput pour obtenir l'ID X à partir du nom de l'appareil

Compilez la source C ci-dessus et utilisez cette méthode:

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

L. Levrel
la source
Il y a aussi/dev/input/by-id
jthill
Merci pour le conseil. J'ai cité les outils X uniquement parce que la plupart des outils semblent nécessiter X. Je ne sais pas comment travailler /dev/input/event*- j'ai essayé tailting mais en vain.
l0b0
by-id donne les liens symboliques mappant le nom du périphérique à la file d'attente des événements, sans nécessiter X.
jthill
@jthill Sur la machine sur laquelle je suis actuellement, ce répertoire n'a que des liens pour la souris.
L. Levrel
Hunh. D'accord, vivez et apprenez, le mien a mon clavier très joli.
jthill
1

Plus de fouilles ont révélé une autre solution utilisant Bash ordinaire et un compte d'utilisateur normal. Script :

#!/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
la source