Java中的非阻塞输入通过JNI实现

时间:2013-02-27 10:47:00

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

我正在寻求使用Java设计命令shell。我必须立即实现的一个重要特性是“自动完成”,当按下“tab”键时由命令shell促成。为此,我估计我必须在非阻塞模式下逐个字符地读取输入命令。

不幸的是,正如我所理解的,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;
}

以及相应的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'(“标签”键)。因此,截至目前的指数值为1.

Probelm:

1&GT;该控件似乎没有阻止:

char variable = (char) read_character();

也就是说,它似乎不允许用户通过Java控制台在该行输入输入,这是为了做到这一点。而且,即使在getche()(非阻塞但回声)

的情况下,问题也是如此

相反,在每次迭代中,一些默认的垃圾值被用于“变量”,并且在执行以下语句时正在控制台上打印:

System.out.println(variable);

然而,当getch()被其阻塞对象(如getc(stdin),getchar()等)取代时,我的这段代码就像魅力一样。

我无法弄清楚通过JNI调用getch()究竟是什么问题。

2 - ;此外,如果有任何其他替代解决方案可以提出,我将不胜感激。

提前谢谢!

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

1 个答案:

答案 0 :(得分:1)

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

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

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

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