¿Cómo saber qué teclado se usó para presionar una tecla?

16

Con frecuencia trabajo en estaciones de emparejamiento donde hay varios teclados instalados. Puedo usar setxkbmapcon -device <ID>para configurar el diseño de un teclado específico (usando una ID dexinput ), pero a menudo no es obvio en qué teclado estoy. Sería mejor evitar el ir y venir de probar ambos teclados, por lo que me gustaría escribir una herramienta rápida para obtener esta información setxkbmap. Esperaría un caso de uso típico como el siguiente:

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

¿Qué interfaz proporciona esta información en Linux? Idealmente, debería funcionar sin X, pero eso no es un requisito (no parece haber muchas herramientas que lo admitan sin X).


Hallazgos hasta el momento:

  • Linux debe saber en qué teclado estoy escribiendo para admitir diferentes diseños para varios teclados simultáneamente.
  • xinput→ list.c → list_xi2XIQueryDeviceproporciona ID de dispositivo utilizables por setxkbmap.
  • showkeyy xevno imprima ID de teclado.
  • xinput list-props $IDmuestra dónde se envían los eventos del teclado . Sin embargo, usando el código de otra respuesta parece que este dispositivo no imprime nada para identificar el teclado.
  • Una solución casi posible es ejecutar xinput --test <ID> &cada ID de teclado y ver cuál devuelve algo primero. El problema con eso es descubrir qué "teclados" son en realidad teclados:

    $ 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
fuente
1
Quizás estés buscando MPX.
Ignacio Vazquez-Abrams
@ IgnacioVazquez-Abrams ¿No es esa una solución masivamente más complicada?
l0b0
Eso depende de cuál sea el problema.
Ignacio Vazquez-Abrams
"Parece que este dispositivo no imprime nada para identificar el teclado": ¿qué quieres decir? Si less -f /dev/input/eventXpresionas una tecla en el teclado correspondiente, deberías ver aparecer "basura", por lo que tus pulsaciones de teclas se dirigen a un archivo de desarrollo y no a los demás.
L. Levrel
¿Has probado esto (mencionado en otra respuesta de esa otra pregunta que citas)?
L. Levrel

Respuestas:

4

Deshabilitar dispositivo

Aquí hay una idea para identificar qué teclado es cuál. Puede usar el comando xinput para habilitar y deshabilitar dispositivos.

Ejemplo

$ 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 salida anterior muestra los diversos dispositivos que tengo en mi computadora portátil Thinkpad. Solo tengo 1 teclado conectado, este:

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

Ahora eche un vistazo a las propiedades disponibles a través de este dispositivo:

$ 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 lo anterior puede ver que está habilitado, así que deshabilítelo:

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

Para habilitarlo:

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

¿La idea?

Puede habilitar deshabilitar uno de los teclados con este comando para determinar en cuál está.

Referencias

slm
fuente
¿No es eso aún más trabajo? Mi enfoque implica como mínimo un comando, como máximo tres. Este enfoque siempre involucra tres comandos: deshabilitar, habilitar y luego configurar el diseño (más posiblemente un interruptor de teclado).
l0b0
@ l0b0: sí, tampoco estoy entusiasmado con este enfoque. Sigo buscando pero ponía este método aquí como "1 vía". Sin embargo, no es el ideal, estoy de acuerdo.
slm
@lobo: esta respuesta no obtendrá la recompensa, así que no te preocupes por eso, tenía los votos antes de que comenzaras la recompensa. stackoverflow.com/help/bounty . Además, ¿cuál es tu ira hacia mí tratando de ayudarte aquí? No te di una solución ideal, sino una forma de cumplir tu tarea. Proporcioné esto hace más de 2 años y este Q se ha sentado aquí con 0 alternativas. Creo que debe preguntarse si tal vez la pregunta / enfoque es el problema. Obviamente solo mis $ 0.02 pero ya es suficiente.
slm
Mi mala x 2: no me di cuenta del bit sobre "creado después de que comenzó la recompensa", y aprecio que hayas escrito una respuesta muy bien formulada. Pero no puedo votar una solución que sea más complicada que la original, y no entiendo por qué lo hacen otros.
l0b0
1
@ l0b0 Mi razón para votar: es un solo comando que puedo usar para confirmar rápida y fácilmente mi sospecha de qué teclado era, en lugar de tener que leer un script completo para asegurarme de que no borre mi disco duro, luego guardar y ejecutalo. O, en el caso de la respuesta más votada hasta ahora, compile el código C. Además, las ideas creativas como esta merecen votos positivos.
Fabian Röling
4

La pregunta suena un poco contradictoria ya que estás citando herramientas X pero pides una solución que "idealmente debería funcionar sin X".

Sobre su hallazgo: xinputle dará la correspondencia

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

al menos con la siguiente versión

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


Primer paso: detectar el dispositivo de evento de teclado 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;
}

Muchas gracias a esta pagina . Eliminé la mayoría de las comprobaciones de seguridad del código que pedí prestado allí, para mayor claridad, en el código real probablemente las desee.

Tenga en cuenta que las pulsaciones de teclas se repiten, por lo que es posible que desee pedir amablemente al usuario que presione una tecla modificadora (Shift, Control ...) en lugar de cualquier tecla.

Segundo paso: use xinput para obtener la X ID del nombre del dispositivo

Compile la fuente C anterior y úsela de esta manera:

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

L. Levrel
fuente
También hay/dev/input/by-id
jthill
Gracias por el consejo. He citado herramientas X sólo porque la mayoría de las herramientas parecen requerir X. Yo no sé cómo trabajar con /dev/input/event*- Probé tailting, pero en vano.
2016
by-id proporciona el nombre del dispositivo de mapeo de enlaces simbólicos a la cola de eventos, sin requerir X.
jthill
@jthill En la máquina en la que estoy actualmente, este directorio solo tiene enlaces para el mouse.
L. Levrel
Hunh Bien, vive y aprende, el mío tiene mi teclado en una lista muy bonita.
Jill
1

Más excavaciones revelaron otra solución usando Bash simple y una cuenta de usuario normal. Guión :

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