OKWAVEのAI「あい」が美容・健康の悩みに最適な回答をご提案!
-PR-
締切り
済み

Linuxで入力待ちなしkeyread関数のようなものはありますか?

  • 困ってます
  • 質問No.160619
  • 閲覧数1989
  • ありがとう数4
  • 気になる数0
  • 回答数3
  • コメント数0

お礼率 11% (1/9)

いま練習として簡単な計測器の制御プログラムを作っていまして、
while文で計測させて、何かキーを押すと抜けだすような制御を
したいのです。
調べたところ、dos.hを用いたkeyread関数というものでできそう
だったのですが、Linux上ではできないようなのです。
ほかに、入力待ちなしでキーを読む方法を知っている方がいたら
すみませんがどうぞお教えください。よろしければ簡単なプログラム例など書いていただければ幸いです。
通報する
  • 回答数3
  • 気になる
    質問をブックマークします。
    マイページでまとめて確認できます。

回答 (全3件)

  • 回答No.1
レベル13

ベストアンサー率 34% (574/1662)

非同期モードにしてi/oすれば可能だろうと思います。 例えば, int f=open("/dev/tty", O_RDONLY|O_NONBLOCK); char c; if ( read(f,&c,1) == 1 ) { /* キー入力があった */ } else } /* キー入力がなかったか、エラー */ } みたいなので・・・。 コ ...続きを読む
非同期モードにしてi/oすれば可能だろうと思います。

例えば,

int f=open("/dev/tty", O_RDONLY|O_NONBLOCK);
char c;

if ( read(f,&c,1) == 1 ) {
/* キー入力があった */
} else }
/* キー入力がなかったか、エラー */
}

みたいなので・・・。
コンパイルもしていないので、あとはマニュアルで(^^;

dos.hはMS-DOS用のですね。

あとは、cursesにそういう関数かマクロがあったような記憶が。


  • 回答No.2
レベル8

ベストアンサー率 50% (2/4)

#「素人」からのコメントですが、ご了承ください。 #(cursesライブラリを使ったことがあります) cursesライブラリに、getch()という関数があります。 キーボードからの入力待ちなどに使います。 「while文で計測させて、何かキーを押すと抜けだすような制御」 とあるので、スレッドを作成して、そのスレッドで計測させては 駄目ですか? getch()が戻ってきて、入力された ...続きを読む
#「素人」からのコメントですが、ご了承ください。
#(cursesライブラリを使ったことがあります)

cursesライブラリに、getch()という関数があります。
キーボードからの入力待ちなどに使います。

「while文で計測させて、何かキーを押すと抜けだすような制御」
とあるので、スレッドを作成して、そのスレッドで計測させては
駄目ですか?
getch()が戻ってきて、入力されたキーをチェックして、
計測を終了させるためのキーだと判断したら、while()を
終了させてあげる条件(フラグなど)をセットするとか、、、

#「入力待ちなしでキーを読む」というのがちょっと理解できなかったので
#期待されている回答ではないかもしれませんね。
  • 回答No.3
レベル9

ベストアンサー率 71% (59/82)

入力待ちなしでキーを読むにはO_NONBLOCKフラッグを セットすればOKです。これにより、read()関数やscanf() 関数を呼び出しても、キー入力があるまでそこで 止まる(ブロックされる)ことが無くなります。 あるファイルにO_NONBLOCKをセットするには、 terra5さんが言うように、 open("/dev/tty", O_RDONLY|O_NON ...続きを読む
入力待ちなしでキーを読むにはO_NONBLOCKフラッグを
セットすればOKです。これにより、read()関数やscanf()
関数を呼び出しても、キー入力があるまでそこで
止まる(ブロックされる)ことが無くなります。

あるファイルにO_NONBLOCKをセットするには、
terra5さんが言うように、

open("/dev/tty", O_RDONLY|O_NONBLOCK);

でそのファイルをオープンします。

標準入力のように、既に開いてしまっているファイルに
対しては、

fcntl(0, F_SETFL, O_NONBLOCK);

です。

読み込みもterra5さんの通りです。

ただ、これだとリターンキーが押されるまで
入力なしとみなされます。

リターンキーを押さなくても1文字ずつ入力を
受けたい場合、もう一工夫要ります。

標準入力のターミナル属性を操作することでnon-canonical
モードにして、ターミナルのバッファリングを停止します。

詳しくは、tcgetattr(), tcsetattr(), termiosなどの
manページを見てください。

ただ、nabezo-さんの仰るようにスレッドにして、
そのスレッドを入力待ちの間ブロックしたほうが、
入力待ち以外の仕事が少ない場合は、
CPU負荷が減って良いことがあります。
(逆にそうしないとビジーウェイト状態になって、CPU
 負荷が異様に上がります)

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <signal.h>
#include <errno.h>

static void post_proc(int);

static struct termios SavedTermAttr;

int
main(int argc, char **argv)
{
 char c;
 signal(SIGINT, &post_proc);
 struct termios term_attr;

 /* Terminal control */
 /* ファイルディスクリプタ0(標準入力)
  のターミナル属性を取得 */
 if( tcgetattr(0, &term_attr) < 0 ){
  fprintf(stderr, "Can't get terminal attributes.\n");
  post_proc(-1);
 }
 /* 取得したターミナル属性を保存 */
 SavedTermAttr = term_attr;
 /* ICANON、ECHOフラッグをセット */
 term_attr.c_lflag &= ~(ICANON|ECHO);
 /* 入力文字列の最小読出バイト数を1に */
 term_attr.c_cc[VMIN] = 1;
 /* 入力待ち時間を0に */
 term_attr.c_cc[VTIME] = 0;

 /* 変更したターミナル属性をセット */
 if( tcsetattr(0, TCSANOW, &term_attr) < 0 ){
   fprintf(stderr, "Can't change terminal attributes.\n");
   post_proc(-1);
  }
 /* NONBLOCKフラグのセット */
 if( fcntl(0, F_SETFL, O_NONBLOCK) == -1 ){
  fprintf(stderr, "Can't fcntl().\n");
  post_proc(-1);
 }

 /* Main loop */
 while(1){
  while( read(0, &c, 1) != 1 )
   if( errno != EAGAIN ){
    fprintf(stderr, "EOF\n");
    post_proc(0);
   }
  printf("%c\n", c);
 }
}

void
post_proc(int sig)
{
 /* 保存されたターミナル属性を復元 */
 if( tcsetattr(0, TCSANOW, &SavedTermAttr) < 0 ){
  fprintf(stderr, "Can't change terminal attribute.\n");
  exit(-1);
 }
 if( sig < 0 )
  exit(-1);
 else
  exit(0);
}
このQ&Aで解決しましたか?
関連するQ&A
-PR-
-PR-
こんな書き方もあるよ!この情報は知ってる?あなたの知識を教えて!
このQ&Aにはまだコメントがありません。
あなたの思ったこと、知っていることをここにコメントしてみましょう。

その他の関連するQ&A、テーマをキーワードで探す

キーワードでQ&A、テーマを検索する
-PR-
-PR-
-PR-

特集


いま みんなが気になるQ&A

関連するQ&A

-PR-

ピックアップ

-PR-
ページ先頭へ