C言語ではキー入力を受け取るときに最後に[Enter]キーを押す必要があります。[Enter]キーを押さなくてもキー入力を受け取るプログラムのサンプルです。同じことはncurses ライブラリでもできますが、キー入力のみでよい場合は、このプログラムを組み込むだけでOKです。プログラムの作成はRaspberry Pi4で行っています。
#include <stdio.h> #include <stdlib.h> #include <termios.h> #include <unistd.h> #include <signal.h> #include <fcntl.h> /* * 押されたキーの値を返す * ブロックしない。キーが押されていない場合は戻り値は0となる。 */ int getkeyNB(void) { struct termios oldt, newt; int ch0,ch1,ch2,ch3,ch4; int ret,oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_iflag = ~( BRKINT | ISTRIP | IXON ); newt.c_lflag = ~( ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHONL ); newt.c_cc[VTIME] = 0; /* キャラクタ間タイマを使わない */ newt.c_cc[VMIN] = 1; /* 1文字来るまで,読み込みをブロックする */ //newt.c_cc[VINTR] = 0; /* Ctrl-c */ //newt.c_cc[VQUIT] = 0; /* Ctrl-\ */ //newt.c_cc[VERASE] = 0; /* del */ //newt.c_cc[VKILL] = 0; /* @ */ //newt.c_cc[VEOF] = 4; /* Ctrl-d */ //newt.c_cc[VSWTC] = 0; /* '\0' */ //newt.c_cc[VSTART] = 0; /* Ctrl-q */ //newt.c_cc[VSTOP] = 0; /* Ctrl-s */ //newt.c_cc[VSUSP] = 0; /* Ctrl-z */ //newt.c_cc[VEOL] = 0; /* '\0' */ //newt.c_cc[VREPRINT] = 0; /* Ctrl-r */ //newt.c_cc[VDISCARD] = 0; /* Ctrl-u */ //newt.c_cc[VWERASE] = 0; /* Ctrl-w */ //newt.c_cc[VLNEXT] = 0; /* Ctrl-v */ //newt.c_cc[VEOL2] = 0; /* '\0' */ if(tcsetattr(STDIN_FILENO, TCSANOW, &newt)==-1) { fprintf(stderr,"error tcsetattr\n"); exit(EXIT_FAILURE); } /* ノンブロックモードに設定 */ oldf = fcntl(STDIN_FILENO, F_GETFL, 0); if(oldf<0) { fprintf(stderr,"error fcntl\n"); exit(EXIT_FAILURE); } if(fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK)<0) { fprintf(stderr,"error fcntl\n"); exit(EXIT_FAILURE); } ch0 = getchar(); if(ch0==0x1B) { //矢印キー Fnキーなどの取得 取得できないキーもある ch1 = getchar(); ch2 = getchar(); if(ch2==0x32) { ch3 = getchar(); if(ch3==0x7e) { ret = (ch0<<24) | (ch1<<16) | (ch2<<8) | ch3; } else { ch4 = getchar(); ret = (ch1<<24) | (ch2<<16) | (ch3<<8) | ch4; } } else if(ch2==0x31) { ch3 = getchar(); ch4 = getchar(); ret = (ch1<<24) | (ch2<<16) | (ch3<<8) | ch4; } else if((ch2==0x33)||(ch2==0x35)||(ch2==0x36)) { ch3 = getchar(); ret = (ch0<<24) | (ch1<<16) | (ch2<<8) | ch3; } else { ret = (ch0<<16) | (ch1<<8) | ch2; } } else if(ch0 != EOF) { ret = ch0; } else { ret = 0; } if(tcsetattr(STDIN_FILENO, TCSANOW, &oldt)==-1) { fprintf(stderr,"error tcsetattr\n"); exit(EXIT_FAILURE); } if(fcntl(STDIN_FILENO, F_SETFL, oldf)<0) { fprintf(stderr,"error fcntl\n"); exit(EXIT_FAILURE); } if(ret == 0x03) { //[Ctrl]+[C] で割り込み発生 pid_t pid = getpid(); kill(pid, SIGINT); } /*if(ret == 0x1a) { //[Ctrl]+[Z] で割り込み発生 pid_t pid = getpid(); kill(pid, SIGTSTP); }*/ return ret; } /* * 押されたキーの値を返す * ブロックする。キーが押されるまで戻らない。 */ int getkey(void) { struct termios oldt, newt; int ch0,ch1,ch2,ch3,ch4; int ret; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_iflag = ~( BRKINT | ISTRIP | IXON ); newt.c_lflag = ~( ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHONL ); newt.c_cc[VTIME] = 0; /* キャラクタ間タイマを使わない */ newt.c_cc[VMIN] = 1; /* 1文字来るまで,読み込みをブロックする */ if(tcsetattr(STDIN_FILENO, TCSANOW, &newt)==-1) { fprintf(stderr,"error tcsetattr\n"); exit(EXIT_FAILURE); } ch0 = getchar(); if(ch0==0x1B) { //矢印キー Fnキーなどの取得 取得できないキーもある ch1 = getchar(); ch2 = getchar(); if(ch2==0x32) { ch3 = getchar(); if(ch3==0x7e) { ret = (ch0<<24) | (ch1<<16) | (ch2<<8) | ch3; } else { ch4 = getchar(); ret = (ch1<<24) | (ch2<<16) | (ch3<<8) | ch4; } } else if(ch2==0x31) { ch3 = getchar(); ch4 = getchar(); ret = (ch1<<24) | (ch2<<16) | (ch3<<8) | ch4; } else if((ch2==0x33)||(ch2==0x35)||(ch2==0x36)) { ch3 = getchar(); ret = (ch0<<24) | (ch1<<16) | (ch2<<8) | ch3; } else { ret = (ch0<<16) | (ch1<<8) | ch2; } } else if(ch0 != EOF) { ret = ch0; } else { ret = 0; } if(tcsetattr(STDIN_FILENO, TCSANOW, &oldt)==-1) { fprintf(stderr,"error tcsetattr\n"); exit(EXIT_FAILURE); } if(ret == 0x03) { //[Ctrl]+[C] で割り込み発生 pid_t pid = getpid(); kill(pid, SIGINT); } return ret; } int main(int argc,char *argv[]) { int key; while (1) { //key = getkeyNB(); key = getkey(); if (key!=0) { printf("key code %4x\n",key); }else{ printf("wait\n"); usleep(100000); } } return 0; }
参考