回答
このプログラムは、キーボード入力があるかどうかをチェックするための関数を実装しています。いくつかの関数や構造体が使用されていますので、必要なヘッダファイルと各行の動作を解説しますね。
必要なヘッダファイル:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>
それぞれの行の動作を解説します:
1. `struct termios old, new;`
- `struct termios`は、端末の属性を表す構造体です。`old`と`new`という名前の2つの変数を宣言しています。
2. `tcgetattr(STDIN_FILENO, &old);`
- 現在の端末属性を取得して、`old`構造体に格納しています。
3. `new = old;`
- 現在の端末属性をコピーして、`new`構造体にセットしています。
4. `new.c_lflag &= ~(ICANON | ECHO);`
- `new`構造体の `c_lflag` メンバーから `ICANON`(canonical モード)と `ECHO`(エコーバック)のビットをクリアしています。これにより、通常の入力モードやエコーバックが無効化されます。
5. `tcsetattr(STDIN_FILENO, TCSANOW, &new);`
- `tcsetattr()` 関数を使用して、変更した端末属性を適用します。
6. `int oldf = fcntl(STDIN_FILENO, F_GETFL, 0);`
- ファイルディスクリプタ `STDIN_FILENO`(標準入力)のフラグを取得して、`oldf` 変数に保存します。
7. `fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);`
- `O_NONBLOCK` フラグをセットすることで、入力がなくてもプログラムがブロックされないようにします。
8. `int byteswaiting = 0;`
- 待機しているバイト数を格納する変数を宣言しています。
9. `ioctl(STDIN_FILENO, FIONREAD, &byteswaiting);`
- `FIONREAD` オプションを使用して、待機しているバイト数を取得します。
10. `keyData = '\0';`
- キーデータを格納する変数 `keyData` を初期化しています。
11. `if ( byteswaiting > 0 ) { ... }`
- 待機しているバイト数が0より大きい場合、キー入力があると判断しています。
12. `keyData = getchar();`
- `getchar()` を使用してキー入力を取得し、`keyData` に格納します。
13. `fflush(stdout);`
- 標準出力をフラッシュしています。
14. `printf("\b");`
- バックスペース文字を出力しています。この行は、キーボード入力を読み込んだ後、カーソルを1つ戻しています。
15. `tcsetattr(STDIN_FILENO, TCSANOW, &old);`
- プログラムの最後で、元の端末属性に戻しています。
16. `fcntl(STDIN_FILENO, F_SETFL, oldf);`
- 元のファイルフラグに戻します。
17. `return keyData;`
- キー入力データを返します。
この関数は、非同期でキーボード入力を監視し、キー入力がある場合はそのキーを返します。しかし、この関数は1回の呼び出しで1文字しか処理しません。