【问题标题】:Non-Blocking Input in Java realized through JNIJava中通过JNI实现的非阻塞输入
【发布时间】:2013-02-27 10:46:59
【问题描述】:

我正在追求使用 Java 设计一个命令外壳。我必须立即实现的一项重要功能是“自动完成”,当按下“tab”键时,命令外壳会促进这一点。为此,我认为我必须在非阻塞模式下逐个字符地读取输入命令。

不幸的是,据我所知,Java API 都不支持非阻塞输入。也就是说,用于读取输入的 Java API 会等待(阻塞)直到用户点击“Enter”键,这在我的情况下是非常不可取的。另外,我已经下定决心不使用任何第三方 Java 库(如JLine)。

所以,我不得不求助于 JNI。本机 .C 文件似乎是这样的 -

 JNIEXPORT jint JNICALL Java_autoComplete_IOUtils_read_1character(JNIEnv *env, jobject obj)
{

int ch = getch(); // getch() - non-blocking input and doesn't echo the characters
return (jint)ch;
}

以及调用上述native方法的对应Java方法:

 public static String GetLine()
{

    int i = 0;
    do
    {
        char variable = (char) read_character(); // Native method is invoked here 

        System.out.println(variable); // Just printing it for my reference 

        cmdLine = new StringBuffer(cmdLine).insert(i, variable).toString(); // cmdLine is of type String
        i++;

    } while ((search(cmdLine.charAt(i - 1), interruptableCharacterArray)) == false);

    return (new String(cmdLine));

}

 //Checks if the entered character is any one of those keys in the interruptableCharacterArray . As of now , interruptableCharacterArray contains only '\t' (The tab key )


  private static boolean search(char charAt,char[] interruptableCharacterArray2)
{
    for (int i = 0; i < index; i++)
    {
        if (interruptableCharacterArray2[i] == charAt)
            return true;
    }
    return false;
}

我还可以向您保证,在链接本机 .dll 方面没有任何麻烦。而且,截至目前,“InterruptableCharacterArray”仅包含“\t”(“tab”键)。因此,截至目前的索引值为 1。

问题:

1> 控件似乎没有阻塞:

char variable = (char) read_character();

也就是说,它似乎不允许用户在该行通过 Java 控制台输入输入,而这是打算这样做的。而且,即使在 getche() (非阻塞但回显)的情况下也是同样的问题

相反,在每次迭代中,“变量”都会采用一些默认垃圾值,并在执行以下语句时将其打印在控制台上:

System.out.println(variable);

但是,当 getch() 被 getc(stdin)、getchar() 等阻塞对应物替换时,我的这段代码就像一个魅力。

我无法弄清楚通过 JNI 调用 getch() 到底有什么问题。

2> 另外,如果提出任何其他替代解决方案来实现相同的效果,我将不胜感激。

提前谢谢你!

编辑:command-shell 将在基于 Windows 和 Unix 的操作系统上实现。

【问题讨论】:

  • 你想要的不是“非阻塞”IO,而是“原始”终端IO。我建议你看看 stty 之类的东西
  • @Ingo:非常感谢! Windows 操作系统呢?
  • 请注意 Aaron 发布的链接。 JLine2 显然也处理 windows 终端,所以你可以在那里得到想法。顺便说一句,要成为 stack-overflow 的好公民,您应该投票赞成有用的答案并接受最好的答案。我认为 Aarons 的帖子值得这样做。

标签: java c dll java-native-interface getch


【解决方案1】:

在您可以从终端获得非阻塞 IO 之前,您需要将其置于“原始”模式:终端通常收集一行输入(这样,您可以使用光标键等编辑当前行)并在“完成”时(=当用户按下回车键时)将其发送到应用程序的标准输入。

在“原始”模式下,任何按键都会立即发送到应用,并且无法进行编辑(除非应用自己实现)。

要启用此功能,请参阅stty(1) 的手册。要修改模式,您需要 C 函数 tcsetattr(3)

即使您不想使用它,我也建议查看source for JLine2,特别是查看UnixTerminal.javaTerminalLineSettings

【讨论】:

  • 非常好,但是你弄错了一件事:在熟模式下,你不能用光标键编辑命令行,只能用 DEL 或 Backspace 键。它是原始的 noecho 模式,使程序可以使用光标键实现编辑。
  • @Ingo:是的,你对 Unix 来说是对的。 shell 通过在 Unix 上将终端置于 raw/noecho 模式来实现编辑。在 Amiga 上,终端拥有自己的编辑功能。为了在那里移植 unix shell,我们必须用 stdin.readline() 替换这段代码 :-)
  • @AaronDigulla - 非常感谢!我会朝那个方向努力。另外,能否请您告诉我如何在 Windows O/S 中进行操作?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-26
  • 2011-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-03
相关资源
最近更新 更多