Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

non-blocking console input #58

Open
chdh opened this issue Sep 27, 2012 · 8 comments · May be fixed by #69
Open

non-blocking console input #58

chdh opened this issue Sep 27, 2012 · 8 comments · May be fixed by #69

Comments

@chdh
Copy link

chdh commented Sep 27, 2012

Please implement non-blocking console input, e.g. ConsoleReader.readCharacterNoWait(). It would only require a minor change in NonBlockingInputStream and ConsoleReader.

I'm writing a console-mode communications tool, where I have to read from the console without blocking. I know that I could use a separate thread to do that.

I tried the following code:

ConsoleReader con = new ConsoleReader();
NonBlockingInputStream in = (NonBlockingInputStream)(con.getInput());
int key = in.read(1);

But: 1. i'ts not guaranteed that future versions of ConsoleReader.getInput() will return a NonBlockingInputStream and 2. it blocks 1ms if no keyboard input is ready.

@gnodet
Copy link
Member

gnodet commented Sep 27, 2012

Do you think you could propose a patch for this issue ?

@chdh
Copy link
Author

chdh commented Sep 27, 2012

Yes, I could propose a patch.

I'm not sure which is the best way to implement it. In NonBlockingInputStream.read(long timeout, boolean isPeek) the value 0 for the timeout parameter is already used to wait forever. We could use an additional boolean parameter e.g. noWait, or e.g. the special value Long.MIN_VALUE for zero timeout.

I have no experience with Git. What is the best way to propose a patch? Do I have to fork the jline2 repository, make the changes and send a pull request?

@scgray
Copy link

scgray commented Sep 28, 2012

Just so you know, the NonBlockInputStream does use a separate thread to do
the actual read, so it is somewhat costly to use to read a lot of input;
for example if you wanted to consume an entire input file with it, it could
involve many many back and forths between the thread is actually blocked
waiting for input and the thread that desires that input.

On Thu, Sep 27, 2012 at 6:00 PM, Christian d'Heureuse <
notifications@github.com> wrote:

Please implement non-blocking console input, e.g.
ConsoleReader.readCharacterNoWait(). It would only require a minor change
in NonBlockingInputStream and ConsoleReader.

I'm writing a console-mode communications tool, where I have to read from
the console without blocking. I know that I could use a separate thread to
do that.

The tried the following code:

ConsoleReader con = new ConsoleReader();NonBlockingInputStream in = (NonBlockingInputStream)(con.getInput());int key = in.read(1);

But: 1. i'ts not guaranteed that future versions of
ConsoleReader.getInput() will return a NonBlockingInputStream and 2. it
block 1ms if no keyboard input is ready.


Reply to this email directly or view it on GitHubhttps://github.com//issues/58.

@chdh
Copy link
Author

chdh commented Sep 28, 2012

NonBlockInputStream (with nonBlockingEnabled=true) is already used now within ConsoleReader, even if STDIN is redirected from a file (redirecting STDIN works on Linux, but has no effect on Windows).

But I found another problem. The data that passes through the NonBlockInputStream is a byte stream and the character set decoding (e.g. from UTF-8 to Java char Unicode) is done outside in the InputStreamReader. So to implement ConsoleReader.readCharacterNoWait() we need a NonBlockingReader, which would add another thread to the console input chain. The negative effect could be reduced if the NonBlockingReader is inserted only when readCharacterNoWait() is called for the first time.

@scgray
Copy link

scgray commented Sep 28, 2012

Yes, I'm sorry, what I meant to say was that if you actually request
non-blocking behavior (i.e. you put a wait period in), then the other
thread gets involved, when you ask for blocking behavior (wait time of 0),
then a regular read is performed, so there is very little cost. I
introduced that class to use in "vi" mode to time the time between hitting
an ESC and the next character, to see if the sequence was more likely to be
a terminal control sequence, or actual user input, so it was only used when
ESC was pressed,

Also, note that while NonBlockInputStream is always used, it isn't always
non-blocking, you have to ask it if it is configured as such. For example,
when reading from an input file, rather than a user, the feature will be
disabled. The reason for this was due to the above description -- the
character that follows an ESC will always flow at the same rate through an
input file, so there is no need to run the thread to do the nonblocking
request.

Because the NBInputStream is an InputStream, it has no concept of a
character and, as such, it wouldn't be wise to place character semantics
there. However, you can already add a non-blocking readChar() to the
ConsoleReader -- you just have to take care of accumulating the time spent
waiting for each part of a unicode sequence. You could also change
NonBockingInputStream to allow up to three bytes of pushback, so that if
you don't see a whole character you could push the ones you have read back
into the stream.

-scot

On Fri, Sep 28, 2012 at 6:16 AM, Christian d'Heureuse <
notifications@github.com> wrote:

NonBlockInputStream (with nonBlockingEnabled=true) is already used now
within ConsoleReader, even if STDIN is redirected from a file (redirecting
STDIN works on Linux, but has no effect on Windows).

But I found another problem. The data that passes through the
NonBlockInputStream is a byte stream and the character set decoding (e.g.
from UTF-8 to Java char Unicode) is done outside in the InputStreamReader.
So to implement ConsoleReader.readCharacterNoWait() we need a
NonBlockingReader, which would add another thread to the console input
chain. The negative effect could be reduced if the NonBlockingReader is
inserted only when readCharacterNoWait() is called for the first time.


Reply to this email directly or view it on GitHubhttps://github.com//issues/58#issuecomment-8969946.

@chdh
Copy link
Author

chdh commented Sep 28, 2012

Scott, thanks for your explanation. I now understand that the thread in NonBlockInputStream is bypassed when a blocking read() is used.

So there could be two possible implementations of ConsoleReader.readCharacterNoWait(), if it has to be really non-blocking and character set conversion is done right:

  1. Extend NonBockingInputStream for a 3 byte buffer and a push back method to put partial bytes of an incomplete UTF-8 sequence back into the stream. readCharacterNoWait() would have to try to get up to 3 bytes from the stream and use CharsetDecoder to check when a character is complete.
  2. Wrap a NonBlockingReader around the InputStreamReader. The internal thread could by bypassed on blocking reads, as it's done in NonBockingInputStream. The creation of the internal thread could be delayed until the first time a non-blocking read is used.

A problem with version 1 is that in the current implementation of ConsoleReader, the NonBockingInputStream is only set into non-blocking mode when escapeTimeout > 0 && terminal.isSupported(). This could be solved by adding a setNonBlockingEnabled() method to NonBockingInputStream. It would be used to enable non-blocking mode afterwards and start the internal thread when readCharacterNoWait() is called for the first time.

@chdh chdh linked a pull request Jan 3, 2013 that will close this issue
@chdh
Copy link
Author

chdh commented May 4, 2015

I have written a Java class for non-blocking console input:

RawConsoleInput

It's based on JNA. It uses a CharsetDecoder to decode UTF-8 and other encodings and reads only as much bytes from the console input stream at once as are necessary to decode a single character. No thread is necessary for non-blocking input. Maybe the same techniques could be used in JLine.

@charsima
Copy link

charsima commented Aug 8, 2017

Thank you for the RawConsoleInput script. Is it possible to modify it to enable echo as well as read the input without hitting enter?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants