1. ホーム
  2. c

[解決済み] C ノンブロッキングキーボード入力

2023-03-22 05:04:23

質問

私は、ユーザーがキーを押すまでループする C 言語 (Linux) のプログラムを書こうとしていますが、各ループを継続するためにキーを押す必要はないはずです。

これを行うための簡単な方法はありますか?私は、おそらく select() でできるかもしれませんが、それは多くの仕事のように思われます。

別の方法として、以下のように ctrl - c ノンブロッキングのioの代わりに、プログラムが終了する前にクリーンアップを行うためのkeypress?

どのように解決するのですか?

すでに述べたように sigaction でctrl-cをトラップする、あるいは select で任意の標準入力をトラップします。

しかし、後者の方法では、TTY が line-at-a-time モードではなく character-at-a-time モードになるように設定する必要があることに注意してください。 後者がデフォルトで、テキストの行を入力しても、Enter を押すまで実行中のプログラムの標準入力に送信されません。

を使用する必要があります。 tcsetattr() 関数を使用して ICANON モードをオフにし、おそらく ECHO も無効にする必要があります。 記憶では、プログラムが終了したときに、ターミナルを ICANON モードに戻す必要があります。

念のため、Unix TTY をセットアップして DOS をエミュレートする、私が今作成したいくつかのコード (nb: エラーチェックなし!) を示します。 <conio.h> 関数 kbhit()getch() :

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

struct termios orig_termios;

void reset_terminal_mode()
{
    tcsetattr(0, TCSANOW, &orig_termios);
}

void set_conio_terminal_mode()
{
    struct termios new_termios;

    /* take two copies - one for now, one for later */
    tcgetattr(0, &orig_termios);
    memcpy(&new_termios, &orig_termios, sizeof(new_termios));

    /* register cleanup handler, and set the new terminal mode */
    atexit(reset_terminal_mode);
    cfmakeraw(&new_termios);
    tcsetattr(0, TCSANOW, &new_termios);
}

int kbhit()
{
    struct timeval tv = { 0L, 0L };
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(0, &fds);
    return select(1, &fds, NULL, NULL, &tv) > 0;
}

int getch()
{
    int r;
    unsigned char c;
    if ((r = read(0, &c, sizeof(c))) < 0) {
        return r;
    } else {
        return c;
    }
}

int main(int argc, char *argv[])
{
    set_conio_terminal_mode();

    while (!kbhit()) {
        /* do some work */
    }
    (void)getch(); /* consume the character */
}