2015年1月30日金曜日

Perl でキーボードからリアルタイムに文字入力

Perl で入力した文字をリアルタイムに読みたいことがあるが、普通に

$char = <STDIN>;

と書くと
  • ENTER キーを押すまでは入力されない
  • 入力した文字がそのまま画面に表示される(エコーバック)
という問題がある。

◇ (方法1) Term::ReadKey を使う (Windows, UNIX)


Windows で使える方法はないかと思って調べたら、実は PerlFAQ に書いてあった方法。知らなかったが通常はこちらで OK だろう。

use Term::ReadKey;
ReadMode('cbreak');
while(1) {
  if (defined ($char = ReadKey(-1)) ) {
    # 文字が入力された場合
      print STDERR $char, "\n";
  } else {
    # 文字が入力されていない場合
  }
}
# ReadMode('normal');


こう書けば押したキーの文字がリアルタイムで $char に代入される。
何も押さなかった場合は「# 文字が入力されていない場合」のほうが実行される。

"Term::ReadKey" モジュールのインストールが必要。
便利なことに Windows のプロンプトでも利用できる。ActivePerl5.20.1 ではTerm::ReadKey モジュールは最初からインストールされていた。

◇ (方法2) stty コマンドを使う (UNIX)

$|=0;

system("stty cbreak");
system("stty -echo");

while(1) {
  sysread(STDIN,$char,1);
  print STDERR $char, "\n"

}

UNIX 限定だが、system() 関数で stty コマンドを実行することでも似たことが実現できる。
"Term::ReadKey" モジュールがインストールできない場合はこちらで。 ただ、この書き方では何か文字が入力されるまで sysread(STDIN,$char,1); のところで動作が停止(ブロック) してしまうので、リアルタイムな処理はできない。リアルタイムに処理するためには工夫が必要になる。