简体   繁体   English

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

[英]Non-Blocking Input in Java realized through JNI

I am in the pursuit of designing a command-shell using Java . 我一直在追求使用Java设计命令外壳。 One important feature which I had to immediately implement was "auto complete" , as facilitated by the command-shell when "tab" key is being pressed . 我必须立即实现的一项重要功能是“自动完成”,这是在按下“ tab”键时通过命令外壳实现的。 For this , I reckoned I had to read the input-command, character-by-character in the non-blocking mode . 为此,我认为我必须在非阻塞模式下逐字符读取输入命令。

Unfortunately , as I have understood , none of the Java API's support non-blocking input . 不幸的是,据我所知,Java API均不支持非阻塞输入。 That is , Java API's that are meant to read the input waits (blocks) until the user hits the "Enter" key , which is highly undesirable in my case .Also ,I have made up my mind not to use any third party Java libraries ( Such as JLine ). 也就是说,用于读取输入的Java API会等待(块),直到用户按下“ Enter”键,这在我的情况下是非常不希望的。此外,我已经下定决心不使用任何第三方Java库(例如JLine)。

So , I had to resort for JNI . 因此,我不得不求助于JNI。 The native .C file appears to be this - 本机.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;
}

And the corresponding Java method in which the afore-mentioned native method is invoked : 以及相应的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;
}

Also I can assure you that there are no hassles with respect to linking the native .dll . 我也可以向您保证,链接本机.dll不会有麻烦。 And , the "InterruptableCharacterArray" , as of now contains only '\\t'( The "tab" key ). 并且,“ InterruptableCharacterArray”截至目前仅包含'\\ t'(“ tab”键)。 Hence , value of index as of now is 1 . 因此,截至目前的index值为1。

Probelm: 探针:

1> The control doesn't seem to block at : 1>控件似乎没有在处阻塞:

char variable = (char) read_character();

That is , it doesn't seem to allow the user to enter the input through the Java Console at that line , which is intended to do that . 也就是说,它似乎不允许用户在该行通过Java控制台输入输入,而这样做是为了做到这一点。 And , same is the problem even in the case of getche() ( Non-blocking but echoes ) 并且,即使在getche()的情况下(无阻塞但回声),问题也同样存在

Instead , in each iteration some default garbage value is being taken for "variable" and that is being printed on the console when the following statement is executed : 相反,在每次迭代中,都会为“变量”获取一些默认的垃圾值,并在执行以下语句时在控制台上将其打印出来:

System.out.println(variable);

However , this code of mine works like a charm when getch() is replaced by its blocking counterparts like getc(stdin),getchar() etc . 但是,当getch()被其阻塞的对应对象(如getc(stdin),getchar()等)代替时,我的这段代码就像一个魅力。

I am not able to figure-out as to what exactly is the problem in invoking getch() through JNI . 我无法弄清楚通过JNI调用getch()到底是什么问题。

2> Also , I would be grateful , if any other alternateive solutions to achieve the same are suggested . 2>另外,如果有人提出其他实现此目标的替代解决方案,我将不胜感激。

Thank you in advance ! 先感谢您 !

Edit : The command-shell is to be implemented both on Windows and Unix based O/S. 编辑:命令外壳将在Windows和基于Unix的O / S上实现。

Before you can have non-blocking IO from a terminal, you need to put it into "raw" mode: Terminals usually collect one line of input (that way, you can edit the current line with the cursor keys, etc) and just send it to the stdin of the application when it's "finished" (= when the user presses enter). 在从终端获得非阻塞IO之前,您需要将其置于“原始”模式:终端通常会收集一行输入(这样,您可以使用光标键编辑当前行,等等)并只发送它在应用程序“完成”时返回标准输入(=当用户按下Enter键时)。

In "raw" mode, any keypress is sent to the app immediately and editing isn't possible (unless the app implements it itself). 在“原始”模式下,任何按键都会立即发送到应用程序,并且无法进行编辑(除非应用程序自行实现)。

To enable this, see the manual for stty(1) . 要启用此功能,请参见stty(1)的手册。 To modify the mode, you will need the C function tcsetattr(3) . 要修改模式,您将需要C函数tcsetattr(3)

I suggest to look into the source for JLine2 even when you don't want to use it, specifically into UnixTerminal.java and TerminalLineSettings 我建议即使您不想使用它, 也要研究JLine2源代码,尤其UnixTerminal.javaTerminalLineSettings

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM