본문 바로가기
개념정복💫/C 정복

C언어 멀티플랫폼 키 입력 처리: kbhit와 getch 함수 구현

by 옹쑥이 2025. 1. 12.

기존에 getchar를 사용했지만, 동적인 기능 작업을 위해 추가 구현하게 되었고

윈도우, 맥, 리눅스 환경에서 사용자의 키 입력을 감지해서 반영할 수 있도록 하였다.

 

 

1. 플랫폼별 키 입력 처리 분리

코드는 운영 체제에 따라 다른 라이브러리를 사용한다

#ifdef _WIN32
#include <conio.h>


#else
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
  • 윈도우 환경
    • conio.h 라이브러리의 _kbhit와 _getch를 사용.
    • 간단히 키 입력을 처리할 수 있는 함수 제공.
  • 맥/리눅스 환경
    • 키 입력 감지를 위해 termios, unistd.h, fcntl.h를 활용.
    • kbhit와 getch를 직접 구현하여 윈도우와 유사한 동작을 재현.

2. kbhit와 getch 함수 구현

2-1. kbhit 함수 구현 (맥/리눅스용)

  • kbhit()는 입력된 키가 있는지 여부를 확인하는 함수
  • 주요 동작:
    1. 터미널 속성을 읽어와 캐논 모드(Canonical Mode)를 비활성화.
      • 캐논 모드란 입력된 문자열이 Enter 키를 눌러야 처리되는 모드.
    2. 입력 버퍼를 비동기로 확인하도록 설정 (fcntl 함수 사용).
    3. 입력이 있으면 해당 문자를 ungetc로 버퍼에 다시 넣고 1 반환.
    4. 입력이 없으면 0 반환.
int kbhit() {
    struct termios oldt, newt;
    int ch;
    int oldf;

    tcgetattr(STDIN_FILENO, &oldt);  // 현재 터미널 속성 저장
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);  // 캐논 모드 및 에코 비활성화
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);  // 새 터미널 속성 적용
    oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
    fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

    ch = getchar();  // 키 입력 확인
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);  // 터미널 속성 복원
    fcntl(STDIN_FILENO, F_SETFL, oldf);

    if (ch != EOF) {
        ungetc(ch, stdin);  // 읽은 문자 반환
        return 1;
    }
    return 0;
}

2-2. getch 함수 구현 (맥/리눅스용)

  • getch()는 사용자가 입력한 단일 키를 읽어오는 함수
  • 주요 동작:
    1. 터미널 속성을 읽어와 캐논 모드 및 에코를 비활성화.
      • 에코(Echo)는 키 입력 시 화면에 출력되는 동작.
    2. 단일 키 입력을 getchar로 읽는다.
    3. 터미널 속성을 복원.
char getch() {
    struct termios oldt, newt;
    char ch;

    tcgetattr(STDIN_FILENO, &oldt);  // 현재 터미널 속성 저장
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);  // 캐논 모드 및 에코 비활성화
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);  // 새 터미널 속성 적용

    ch = getchar();  // 키 입력 읽기

    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);  // 터미널 속성 복원
    return ch;
}