Como saber qual teclado foi usado para pressionar uma tecla?

16

Eu freqüentemente trabalho em estações de emparelhamento onde existem vários teclados instalados. Posso usar setxkbmapcom -device <ID>para definir o layout de um teclado específico (usando um ID dexinput ), mas geralmente não é óbvio em que teclado estou. Seria melhor evitar a tentativa e a tentativa de ambos os teclados, então eu gostaria de escrever uma ferramenta rápida para obter essas informações setxkbmap. Eu esperaria um caso de uso típico como o seguinte:

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

Qual interface fornece essas informações no Linux? Idealmente, ele deve funcionar sem o X, mas isso não é um requisito (não parece haver muitas ferramentas que suportem isso sem o X).


Resultados até agora:

  • O Linux deve saber em qual teclado estou digitando para oferecer suporte a diferentes layouts para vários teclados simultaneamente.
  • xinput→ list.c → list_xi2XIQueryDevicefornece IDs de dispositivos utilizáveis ​​por setxkbmap.
  • showkeye xevnão imprima os IDs do teclado.
  • xinput list-props $IDmostra para onde os eventos do teclado são enviados . No entanto, usando o código de outra resposta , parece que este dispositivo não imprime nada para identificar o teclado.
  • Uma solução quase possível é executar xinput --test <ID> &cada ID de teclado e ver qual retorna algo primeiro. O problema disso é descobrir quais "teclados" são realmente 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
fonte
1
Talvez você esteja procurando por MPX.
Ignacio Vazquez-Abrams
@ IgnacioVazquez-Abrams Não é uma solução massivamente mais complicada?
L0b0
Isso depende de qual é o problema.
Ignacio Vazquez-Abrams
"parece que este dispositivo não imprime nada para identificar o teclado": o que você quer dizer? Se você less -f /dev/input/eventXpressionar uma tecla no teclado correspondente, deverá ver "lixo" aparecendo, para que as teclas sejam realmente direcionadas para um arquivo dev e não para os outros.
L. Levrel
Você já tentou isso (referenciado em outra resposta dessa outra pergunta que você cita)?
L. Levrel

Respostas:

4

Desativar dispositivo

Aqui está uma idéia para identificar qual teclado é qual. Você pode usar o comando xinput para ativar e desativar dispositivos.

Exemplo

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

A saída acima mostra os vários dispositivos que tenho no meu laptop Thinkpad. Eu só tenho 1 teclado conectado, este:

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

Agora dê uma olhada nas propriedades disponíveis neste 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.

Do exposto acima, você pode ver que ele está ativado, então vamos desativá-lo:

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

Para habilitá-lo:

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

A ideia?

Você pode ativar a desativação de um dos teclados usando este comando para determinar em qual deles está.

Referências

slm
fonte
Isso não é ainda mais trabalho? Minha abordagem envolve no mínimo um comando, no máximo três. Essa abordagem sempre envolve três comandos - desabilitar, habilitar e definir o layout (além de possivelmente uma opção de teclado).
L0b0
@ l0b0 - sim, também não estou empolgado com essa abordagem. Eu continuo procurando, mas estava colocando esse método aqui como "unidirecional". Não é o ideal, eu concordo.
slm
@lobo - Esta resposta não vai receber a recompensa, então não se preocupe, ela teve os votos antes de começar a recompensa. stackoverflow.com/help/bounty . Além disso, qual é a sua raiva em relação a mim tentando ajudá-lo aqui? Dei a você não uma solução ideal, mas uma maneira de realizar sua tarefa. Eu forneci isso há mais de 2 anos e este Q ficou aqui com 0 alternativas. Eu acho que você precisa se perguntar se talvez seja a questão / abordagem que seja o problema. Obviamente, apenas meus US $ 0,02, mas já é o suficiente.
Slm
Meu péssimo x 2: eu não notei nada sobre "criado depois que a recompensa começou" e aprecio que você tenha escrito uma resposta muito bem formulada. Mas não posso aprovar uma solução mais complicada do que a original e não entendo por que outras pessoas o fazem.
L0b0
1
@ l0b0 Meu motivo para a votação: É um único comando que posso usar para confirmar rápida e facilmente minha suspeita de que teclado era, em vez de precisar ler um script inteiro para garantir que ele não limpe meu disco rígido, depois salve e execute. Ou, no caso da resposta mais votada até o momento, compile o código C. Além disso, idéias criativas como essa merecem votos positivos.
Fabian Röling 24/10/19
4

A pergunta parece um pouco contraditória, pois você está citando as ferramentas do X, mas pede uma solução que "idealmente funcione sem o X".

Sobre sua descoberta: xinputvocê receberá a correspondência

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

pelo menos com a seguinte versão

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


Primeiro passo: detectando o dispositivo de evento do teclado em 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;
}

Muito obrigado a esta página . Retirei a maioria das verificações de segurança do código emprestado lá, para fins de clareza, no código real você provavelmente as deseja.

Observe que as teclas pressionadas são repetidas, portanto, você pode realmente pedir ao usuário que pressione uma tecla modificadora (Shift, Control ...) em vez de qualquer tecla.

Segundo passo: use xinput para obter o X ID do nome do dispositivo

Compile a fonte C acima e use desta maneira:

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

L. Levrel
fonte
Há também/dev/input/by-id
jthill
Obrigado pela dica. Eu citei as ferramentas do X apenas porque a maioria das ferramentas parece exigir o X. Não sei como trabalhar /dev/input/event*- tentei tailting, mas sem sucesso.
L0b0
by-id dá nome dispositivo de mapeamento links simbólicos para fila de eventos, sem a necessidade de X.
jthill
@jthill Na máquina em que estou atualmente, esse diretório possui apenas links para o mouse.
L. Levrel
Hunh. Ok, viva e aprenda, o meu tem meu teclado listado muito bonito.
jthill
1

Mais pesquisas revelaram outra solução usando o Bash comum e uma conta de usuário 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
fonte