如何在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

我开始认为System.in在按下Enter之前不知道用户输入。

Answers:


57

您想要做的就是将控制台置于“原始”模式(绕过行编辑并且不需要输入键),而不是“经烹煮”模式(需要输入键进行行编辑)。在UNIX系统上,'stty'命令可以更改模式。

现在,关于Java ...参见Python和Java中的非阻塞控制台输入。摘抄:

如果您的程序必须基于控制台,则必须将终端从行模式切换到字符模式,并记住在程序退出之前将其还原。没有跨操作系统的可移植方法。

建议之一是使用JNI。同样,这不是很容易移植。线程结尾处的另一个建议与上述文章一样,是使用jCurses


4
JCurses也不是很可移植。...从JCurses README:“ JCurses包括两个部分:平台无关的部分和平台相关的部分,其包括本机共享库,使原始输入和输出操作可用于第一部分。”
Ryan Fernandes

6
@RyanFernandes对我来说很便携-可以在多个系统上运行的单个工具(使用不同的依赖项)
Antoniossss

25

您需要将控制台打成原始模式。没有内置的独立于平台的方法。jCurses可能很有趣。

在Unix系统上,这可能起作用:

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

例如,如果您要考虑两次击键之间的时间,请使用此处的示例代码。


在Linux下对我来说效果很好
MrSmith42

4
在Mac上也可以使用。您可能想提到stty cooked </dev/tty应该在程序需要恢复到缓冲模式时运行,并且一定要在程序退出之前运行。
开尔文(Kelvin)

15

没有从Java控制台读取原始字符的便携式方法。

上面已经介绍了一些依赖于平台的解决方法。但是要真正具有便携性,您必须放弃控制台模式并使用窗口模式,例如AWT或Swing。


22
我不太了解为什么Mono(或CLR)具有System.Console.ReadKey在所有平台上都适用的功能。Java还通过依赖于平台的库和实现为每个平台分发JVM和JRE,所以这不是借口。
马丁·麦卡

13

我写了一个Java类RawConsoleInput,它使用JNA调用Windows和Unix / Linux的操作系统功能。

  • 在Windows上它采用_kbhit()_getwch()从MSVCRT.DLL。
  • 在Unix上,它用于tcsetattr()将控制台切换到非规范模式,System.in.available()以检查数据是否可用以及System.in.read()从控制台读取字节。A CharsetDecoder用于将字节转换为字符。

它支持无阻塞输入以及混合原始模式和法线模式输入。


已对此进行了多大程度的测试/压力测试?
基金莫妮卡的诉讼

2
@QPaysTaxes控制台输入很难进行压力测试。我认为,在这种情况下,在各种环境(不同的Windows / Linux版本,64/32位,通过SSH的Linux,Telnet,串行端口或桌面控制台等)中进行测试将更为重要。到目前为止,我仅在专用测试工具中使用它。但是与其他解决方案(例如使用Jansi的JLine2)相比,源代码相对较小。因此,没有什么地方会出错。我写了它,因为JLine2不支持无阻塞的单字符输入。
Christian d'Heureuse '16

这就是我经过压力测试的意思-这可能是错误的词;我的错。无论如何,很好!我在我的一个学校项目中偷了^ H ^ H ^ H ^ H ^ H ^偷了它,它帮了很多忙。
基金莫妮卡的诉讼

嘿-这堂课很棒。但是:我无法使它工作..我应该如何使用它?我遇到了System.in阻塞,直到我按CTRL + D(在Linux上),现在我才了解控制台模式等。我认为您的RawConsoleInput是我想要的-但是我该如何使用它?
伊戈尔(Igor)

@Igor只需调用RawConsoleInput.read(boolean)即可读取键盘字符。它记录在源代码(RawConsoleInput.java)中。
Christian d'Heureuse,2016年

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/…。它具有自动完成功能,历史记录,密码掩码等
。– lepe
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.