Como ler diretamente a entrada do teclado em tempo real?

1

Não tenho certeza se esse é o lugar correto para fazer isso, mas estou desenvolvendo um programa que requer entrada em tempo real do usuário. Isso é; ele precisa ser capaz de ler as teclas sendo pressionadas (e, opcionalmente, pressionadas e soltas) em tempo real. O que torna esse problema um pouco problemático é que eu absolutamente não posso usar nenhum tipo de biblioteca para isso; nem mesmo a biblioteca C padrão. Então, isso precisa ser tratado com o syscalls do kernel e int 0x80 .

Eu pensei em definir o stdin para o modo sem bloqueio com fcntl e O_NONBLOCK e, em seguida, ler os dados de entrada de stdin. No entanto, para minha surpresa, meu código parece não estar funcionando corretamente. Agora parece que a entrada começa a ser lida de stdin depois que a tecla Enter estiver sendo pressionada. A parte complicada é que estou achando incômodo descobrir se é culpa de:

  • Meu código não está se comportando corretamente (o mais provável)
  • Meu terminal / usuário / processo (o que quer que o manipule?) não tendo acesso de gravação sem bloqueio a stdin (não provável).
  • Supondo erroneamente que posso ler a entrada direta do teclado do stdin.

Então, minha pergunta é: qual é a melhor / usual maneira de ler a interação direta com o teclado se não configurando o modo stdin para não bloquear e lendo os dados de entrada do teclado a partir daí? Ou eu estou correto e devo apenas consertar meu código? :)

(E para os curiosos, não, não é um keylogger. É para um produto demoscene muito limitado (tamanho de executável < = 256 bytes) que requer que o usuário seja capaz de sair da introdução.)

    
por zxcdw 24.01.2012 / 01:08

2 respostas

2

Se você estiver lendo em stdin , leia a manpage de tcsetattr e, especificamente, a seção sobre "Modo canônico e não canônico" ( ICANON ). A menos que você desative ICANON on stdin , a entrada é orientada por linha (você não obtém nada até que Enter seja pressionado). Esse é o caso mesmo para O_NONBLOCK .

Em caso de dúvida, strace -v stty raw >&log; stty sane; grep TCSETSW log e veja o que acontece com stdin . Você pode usar a mesma chamada de sistema com parâmetros idênticos para desbloquear o terminal. Tenha cuidado, a menos que você restaure as configurações na saída, o terminal será inútil após o término do seu programa. (é por isso que eu fiz stty sane após stty raw )

O uso de hardware bruto de E / S é provavelmente uma idéia muito muito ruim, a menos que você esteja absolutamente certo sobre o hardware de destino e / ou deseje antecipar cada tipo de teclado existe.

Ah, apesar de ser "cru", você ainda está lendo alguma informação do teclado: você não obterá scancodes, você obterá ASCII (ou UTF-8, provavelmente). Então Escape é decimal 27, não 1 (como no teclado IBM PC original).

Sugestão alternativa que requer acesso de superusuário: leia os dispositivos de evento, abra o caminho certo e leia as estruturas de evento do Linux a partir dele. Este método retorna eventos e press raw key / key (eles são os códigos de chave internos do kernel, não scancodes de hardware). Confira /usr/include/linux/input.h para os detalhes. Encontrar o dispositivo eventX correto para abrir em 256 bytes de código é outra coisa, claro.

    
por 24.01.2012 / 03:01
0

Você precisa definir o tty para o modo raw, consulte man stty .

    
por 24.01.2012 / 03:01

Tags