리눅스 계열 프로그램을 만들때, gcc로 개발하다보면 키보드 입력을 받아야 하는 경우가 있다.

(보통 키입력으로 메뉴 선택하는 경우가 더 많겠지만..)

그런데 키 입력은 보통 getchar 나 scanf 를 사용하는데, 키보드가 눌러질때까지 대기를 해서

"프로그램 구동 중 키가 눌러지면 종료" 같은 프로세스를 짜기가 귀찮아진다.

스레드를 쓴다던가 해서 해결할 방안은 있지만 간단하게(?) 구현된 예를 찾아서 공유 할 겸, 포스팅을 한다.

 

How can I use input without waiting user to give something (using C) ? - CodeProject

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/select.h>

int kbhit(void)
{
  struct timeval tv;
  fd_set read_fd;

  /* Do not wait at all, not even a microsecond */
  tv.tv_sec=0;
  tv.tv_usec=0;

  /* Must be done first to initialize read_fd */
  FD_ZERO(&read_fd);

  /* Makes select() ask if input is ready:
   * 0 is the file descriptor for stdin    */
  FD_SET(0,&read_fd);

  /* The first parameter is the number of the
   * largest file descriptor to check + 1. */
  if(select(1, &read_fd,NULL, /*No writes*/NULL, /*No exceptions*/&tv) == -1)
    return 0;  /* An error occured */

  /*  read_fd now holds a bit map of files that are
   * readable. We test the entry for the standard
   * input (file 0). */
  
    if(FD_ISSET(0,&read_fd))
    /* Character pending on stdin */
    return 1;

  /* no characters were pending */
  return 0;
}

int main()
{
  do{
    if(kbhit())
    {
      printf("키 입력 감지!!\n");
      break;      
    }
  }while(1);

  printf("눌러진 키 : %c\n",getchar());  
  return 0;
}

kbhit() 함수는 select 함수와 표준입력(STDIN) 0을 사용하여 타임아웃을 체크하는 방식을 사용했다.

생각보다 리눅스에서는 select함수가 유용하다.


  • 표준입력(STDIN): 표준 입력 장치의 ID 는 숫자로는 0 이며 일반적으로는 키보드가 됩니다.
  • 표준출력(STDOUT): 출력을 위한 스트림으로 표준 출력 장치의 ID 는 1이며 일반적으로는 현재 쉘을 실행한 콘솔(console)이나 터미널(terminal)이 됩니다.
  • 표준에러(STDERR): 에러를 위한 스트림으로 표준 에러 장치의 ID 는 2이며 일반적으로는 표준 출력과 동일합니다.

     <출처 : 표준 입력(STDIN), 표준 출력(STDOUT), 표준 에러(STDERR)란 (lesstif.com)>


실행결과