Como posso capturar as teclas digitadas de solteiro em um aplicativo de console unix sem bloquear?
Pergunta
Eu tenho um servidor TCP muito simples escrito em C. Ele é executado indefinidamente, aguardando conexões. No Windows, eu uso select
para verificar se há atividade no socket, e se não houver qualquer, eu tenho o seguinte código para permitir-me para sair por bater 'q' no teclado:
if( kbhit() ) {
char c = getch();
if( c == 'q' ) break;
}
Esta não funciona em Unix, desde kbhit
não existe e getch
funciona de forma diferente. Eu encontrei alguns código de exemplo que usos tcsetattr
para alterar as configurações do terminal e permitir a entrada caractere por caractere. Depois de chamar a função init, abro / dev / stdin (com O_NONBLOCK
) e ler um personagem, mas blocos read( f, &c, 1 )
até que um personagem é hit.
Acho que eu poderia gerar um segmento separado e têm it esperar indefinidamente e, em seguida, sinalizar o primeiro segmento se os acessos de usuários 'q', mas que parece um pouco pesada. Certamente há uma maneira mais fácil?
Solução
Adicionar stdin à sua lista de selecionados alças, e se ele tem dados, chamada de leitura para ler um caractere a partir dele.
Outras dicas
Em vez disso, adicionar "f" do seu
read( f, &c, 1 )
para selecionar chamada. Quando f está pronto para leitura, um personagem foi pressionado, e ler () não irá bloquear.
Em Unix, seja no console do sistema ou em uma janela do terminal X, teclado E / S passa por um terminal virtual. Dispositivo / dev / tty é a maneira usual, nos dias de hoje, de acesso a terminal de controle do processo. outros do que abrir / fechar / leitura / gravação manipulações do dispositivo são todos tratados pelo ioctl chamada de sistema (2) para esse dispositivo específico. A idéia geral do que você quer fazer é
Abrir o controlo de terminal (o qual pode ou não pode ser stdin)
Alterar o modo de operação em que o terminal para retornar sem esperar por uma linha completa de entrada (que é o padrão normal)
Continuar com o resto do seu programa, sabendo que lê a partir desse terminal (que pode ser stdin) pode retornar linhas parciais ou mesmo zero, personagens sem que seja uma condição de erro ou rescisão.
A resposta sobre como fazer o segundo passo é encontrado na faq C-programação detalhada . Eles também apontam que esta é uma questão OS, e não uma questão da língua. Eles fornecem nove possibilidades, mas os três principais são relevantes para esta questão são
- Use as maldições (3) biblioteca
- sistemas BSD velhos, uso sgttyb ao conjunto CBREAK ou RAW
- sistemas antigos estilo System V Posix ou, utilize TCGETAW / TCSETAW ao conjunto c_cc [VMIN] a 1 e c_cc [VTIME] a 0.
Após um par de referências no C FAQ poderia levar a desta página dos fragmentos de código kbhit .