改行が入力されるのを待つことなくタイプされたキーを受けとる方法
今までやりたくてもやれなかったけど、最近やり方を知ったのでここに書いておく。
日本語が不自由なのでこんなタイトルになってしまったけど、要するに「何かのキーがタイプされるまでブロックし、タイプされた瞬間にブロックを解く」ってカンジね。
Press any key to continue 的な。
答えは termios にあった。
#include <stdio.h> #include <string.h> #include <termios.h> #include <sys/select.h> int main(int argc, char *argv[]) { int c; struct termios old_tio, tio; fd_set fds; puts("Which is your sex?"); puts("[m] Male"); puts("[f] Female"); printf("Your answer: "); fflush(stdout); // これがないと、キータイプを待っているときに "Your answer: " が表示されない tcgetattr(0, &old_tio); memcpy(&tio, &old_tio, sizeof(struct termios)); tio.c_lflag &= ~ICANON; // これがミソ。c_lflag の ICANON を落としてやる tcsetattr(0, TCSANOW, &tio); FD_ZERO(&fds); FD_SET(0, &fds); select(1, &fds, NULL, NULL, NULL); c = fgetc(stdin); tcsetattr(0, TCSANOW, &old_tio); // 元の状態に戻す putchar('\n'); switch (c) { case 'M': case 'm': puts("OK, you're male"); break; case 'F': case 'f': puts("OK, you're female"); break; default: puts("???"); } return 0; }
インタラクティブに処理をするときに、選択肢から処理を選ばせる、という場面って意外とあると思う。
そんなときに、一文字入力した後にいちいちリターンキーを押すのって面倒だよね。*1
その面倒さを取り除く方法として、こういうやり方があるよ、という話でした。
参考
- man 4 termios
- man 3 tcsetattr
*1:そんなことを面倒くさがるのは俺だけ?rm -i とか cp -i とか mv -i とかで、y