.:: Jorge Pereira ::.

- getch() no Linux

Se você já precisou algum dia trabalhar diretamente com leituras de teclas a partir da STDIN sem a interação do <ENTER> conforme maioria das funções estilo gets(), fgets(). e estava a procura de algo no estilo getch() e percebeu que não existe implementação idêntica no Linux. pode ficar tranqüilo, abaixo segue uma implementação chamada getch.c que fiz para leitura de teclas pressionadas sem a interação do <ENTER>. Lembrando que está e um alternativa caso não queira utilizar a função getch() existente na biblioteca ncurses e sendo obrigado a ter tal dependência incluída no seu projeto para tão pouco uso!

/*
 * Autor: Jorge Pereira
 * Data:  Tue Jul 29 09:35:42 BRT 2008
 * Desc:  Implementacao da funcao getch() no Linux,
 * podendo ser feito leitura de um unico byte por vez.
 *
 */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>

#ifdef getch
#undef getch
#endif
typedef unsigned int keybd_t;

keybd_t getch (void)
{
	struct termio old_tty;	 /* current terminal settings */
	struct termio new_tty;	 /* new terminal settings     */
	keybd_t	key = 0;         /* character "buffer"	      */

	if (ioctl(STDIN_FILENO, TCGETA, &old_tty) < 0)
	{
		fprintf(stderr,"Port ioctl(TCGETA) it's failed, exiting...\n");
		exit(EXIT_FAILURE);
	}

	new_tty 	 = old_tty;		/* copy terminal settings    */
	new_tty.c_lflag &= ~(ICANON | ECHO);	/* set flags in teminal      */
	new_tty.c_cc[4]  = 01;			/* struct for raw mode	     */

	if (ioctl(STDIN_FILENO, TCSETA, &new_tty) < 0)
	{
		fprintf(stderr,"Port ioctl(TCSETA) it's failed, exiting...\n");
		exit(EXIT_FAILURE);
	}

	if(read(STDIN_FILENO, &key, sizeof(key)) < 0)
	{
		fprintf(stderr,"Problems in read()\n");
		exit(EXIT_FAILURE);
	}

	if (ioctl(STDIN_FILENO, TCSETA, &old_tty) < 0)
	{
		fprintf(stderr,"Port ioctl(TCSETA) it's failed, exiting...\n");
		exit(EXIT_FAILURE);
	}

	return key;
}

#if defined(RUN_MAIN)
int
main (void)
{
    keybd_t key;

    printf ("(*) Teste para funcao getch(), pressione  para sair!\n");

    while ((key = getch()) != 0x1b)
    {
        char ch = (key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z') || (key >= '0' && key <= '9') ? key: ' ';

        printf (" -> key char(%c) hex(0x%08x) dec(%d)\n", ch, key, key);
    }

    printf ("(*) Saindo...\n");

    return EXIT_SUCCESS;
}
#endif

Adicionei um bloco ifdef com um main(), para que seja possível executar e testar a função. Abaixo segue exemplo de compilação.

[jorge@jiraya codigos]$ gcc -W -Wall -DRUN_MAIN -o getch getch.c
[jorge@jiraya codigos]$ ./getch
(*) Teste para funcao getch(), pressione <ESC> para sair!
-> key char(a) hex(0×00000061) dec(97)
-> key char(b) hex(0×00000062) dec(98)
-> key char(c) hex(0×00000063) dec(99)
-> key char(d) hex(0×00000064) dec(100)
(*) Saindo…
[jorge@jiraya codigos]$

Caso queira adicionar o ao seu projeto, basta remover o bloco #ifdef e utilizar normalmente! ;)

4 Comments

  1. Eduardo Luna says:

    Muito legal a dica, estive procurando por algo parecido e este seu exemplo ficou ideal para minha necessidade!!!!

    Parabéns cara, seu blog e nota 10!!

  2. Ladislau says:

    Ops! :lol:

    Olá! Jorge,

    Muito boa essa função getch que você criou, mas pra mim, que uso kubuntu, ela só funcionou depois que googlei um pouco e descobri que devia acrescentar as bibliotecas a seguir:
    #include <sys/ioctl.h>
    #include <unistd.h>
    #include <termios.h>
    e, também, após substituir a expressão ‘&amp;’ por ‘&’. Em seguida, resolvi testar quais bibliotecas eram realmente necessárias, comentando uma a uma. Assim, verifiquei que as bibliotecas a seguir, podiam ser comentadas ou excluídas:
    //#include <string.h>
    //#include <errno.h>
    //#include <stdint.h>

    8)

  3. jpereira says:

    Olá Ladislau,

    Então, conforme você mesmo comentou o fato dos “&” ao invés de “&” foi causado pelo antigo plugin responsável pelo “Syntax Highlight” dos códigos!

    Obrigado pelo toque! ;)

  4. Junio says:

    Muito bom cara!
    Era oq eu procurava ;)

    Já publicou isso no viva o linux ?

    Abraço!

Leave a Reply