Javaでコンソールから単一の文字を読み取る方法(ユーザーが入力するとおり)?


110

ユーザーがJavaで入力しているときに、コンソールから単一の文字を読み取る簡単な方法はありますか?出来ますか?私はこれらの方法を試しましたが、すべてユーザーがEnterキーを押すのを待ちます:

char tmp = (char) System.in.read();
char tmp = (char) new InputStreamReader(System.in).read ();
char tmp = (char) System.console().reader().read();           // Java 6

Enterが押されるまで、System.inはユーザー入力を認識しないと思い始めています。

回答:


57

コンソールを「生」モード(行編集がバイパスされ、Enterキーが不要)にするのではなく、「クック」モード(Enterキーが必要な行編集)にします。UNIXシステムでは、 'stty'コマンドでモードを変更します。

さて、Javaに関して... PythonとJavaでのノンブロッキングコンソール入力を参照してください。抜粋:

プログラムをコンソールベースにする必要がある場合は、端末を行モードから文字モードに切り替え、プログラムが終了する前に必ず復元する必要があります。オペレーティングシステム間でこれを行うためのポータブルな方法はありません。

提案の1つは、JNIを使​​用することです。繰り返しますが、これはあまり移植性がありません。スレッドの最後に、上記の投稿と同様に、jCursesの使用を検討することもできます。


4
JCursesもあまり移植性がありません。JCursesのREADMEから:「JCursesは、プラットフォームの独立した部分と、プラットフォームの最初の部分で使用できるプリミティブ入力および出力操作を行うネイティブ共有ライブラリで構成されるプラットフォーム依存の部分から構成されます。 」
ライアンフェルナンデス

6
@RyanFernandesは私にとっては非常に移植性が高いように思えます-複数のシステムで実行できる単一のツール(異なる依存関係を使用)
Antoniossss

25

コンソールをrawモードにする必要があります。そこに到達するための、プラットフォームに依存しない組み込みの方法はありません。ただし、jCursesは興味深いかもしれません。

Unixシステムでは、これはうまくいくかもしれません:

String[] cmd = {"/bin/sh", "-c", "stty raw </dev/tty"};
Runtime.getRuntime().exec(cmd).waitFor();

たとえば、キーストローク間の時間を考慮したい場合は、そこに到達するためのサンプルコードを次に示します。


Linuxで
うまくいった

4
Macでも動作しました。おそらくstty cooked </dev/tty、プログラムがバッファモードに戻る必要があるときに、プログラムが終了する前に実行する必要があることをお伝えしたいと思います。
ケルビン

15

Javaコンソールから生の文字を読み取るポータブルな方法はありません。

いくつかのプラットフォームに依存する回避策は、上記に提示されています。ただし、実際に移植するには、コンソールモードを破棄し、AWTやSwingなどのウィンドウモードを使用する必要があります。


22
たとえば、Mono(またはCLR)がSystem.Console.ReadKeyすべてのプラットフォームで機能するものを持っている理由がよくわかりません。Javaは、プラットフォームに依存するライブラリと実装を備えたすべてのプラットフォームにJVMとJREも配布しているので、それは言い訳にはなりません。
Martin Macak、2015年

13

JNAを使用してWindowsおよびUnix / Linuxのオペレーティングシステム関数を呼び出すJavaクラスRawConsoleInputを作成しました。

  • Windowsでは_kbhit()_getwch()msvcrt.dllを使用します。
  • Unixではtcsetattr()、コンソールを非標準モードに切り替え、System.in.available()データが使用可能かどうかを確認System.in.read()し、コンソールからバイトを読み取るために使用します。A CharsetDecoderは、バイトを文字に変換するために使用されます。

それは非ブロッキング入力と混合rawモードと通常のラインモード入力をサポートします。


これはどのくらい厳しくテスト/ストレステストされていますか?
ファンドモニカの訴訟

2
@QPaysTaxesストレステストは、コンソール入力では困難です。この場合、さまざまな環境(異なるWindows / Linuxバージョン、64/32ビット、SSH経由のLinux、Telnet、シリアルポートまたはデスクトップコンソールなど)でテストすることがより重要になると思います。これまでのところ、私は自分のプライベートテストツールでのみ使用します。しかし、他のソリューション(Jansiを使用するJLine2など)と比較すると、ソースコードは比較的小さいです。したがって、問題が発生する可能性はあまりありません。JLine2はブロックせずに単一の文字入力をサポートしていないため、私はそれを書きました。
クリスチャンデュルーズ、

それは私がストレステストで意味したことです-それはおそらく間違った言葉です。私の悪い。とにかく、いいね!私は盗んだ^ H ^ H ^ H ^ H ^ H ^学校の私のプロジェクトでそれを使用し、それはたくさんを助けました。
モニカの訴訟に資金を提供する

ねえ-このクラスは素晴らしく見えます。ただし、動作させることはできません。どのように使用すればよいですか。CTRL + D(Linux)を押すまでSystem.inブロッキングに遭遇し、コンソールモードなどについて読みました。私はあなたのRawConsoleInputが私が探しているものだと思います-それをどうやって使うのですか?
Igor

@Igorキーボード文字を読み取るには、RawConsoleInput.read(boolean)を呼び出すだけです。ソースコード(RawConsoleInput.java)に記載されています。
クリスチャンドゥルーズ

8

jline3を使用

例:

Terminal terminal = TerminalBuilder.builder()
    .jna(true)
    .system(true)
    .build();

// raw mode means we get keypresses rather than line buffered input
terminal.enterRawMode();
reader = terminal .reader();
...
int read = reader.read();
....
reader.close();
terminal.close();

RawConsoleInputベースのソリューションはMacOS High Sierraでは機能しないことがわかりました。ただし、これは完全に機能します。
RawToast

jlineには、インタラクティブなコンソール/ターミナルシステムを作成するために必要なすべてのものが揃っています。Linuxでうまく動作します。より完全な例については、github.com / jline / jline3 / blob / master / builtins / src / test / java / org / …をご覧ください。これは、オートコンプリート、歴史、パスワードのマスクなどを持っている
レペ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.