-
Notifications
You must be signed in to change notification settings - Fork 183
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
Arrow keys all report as ASCII code 27 with readCharacter() #152
Comments
In my opinion, all that jline provide is line editing, and the only main API would be readline(). |
I am building a CLI with JLine with interactive commands that wait for a keystroke from the user to continue processing before control is returned back to the prompt. For example, a "more" command that can have data piped into it and the user can press "space" to output a line, or "enter" to output a page. The command calls readCharacter in a loop until its out of data and then returns to the prompt. Or it could be as simple as a "pause" command that says "press any key to continue" and then waits for the next keystroke. What library would you suggest using to capture keystrokes from the user that aren't specifically part of a "line" typed at a prompt? |
I think |
The point is that: there is no portable way to represent those control keys(arrow keys, etc.) with a single character. That is why we use ANSI escape sequences, key bindings, and why we have so many problems before on differents OS. |
I appreciate the internal difficulties in capturing complex keystrokes, and I think the fact that most of these issues have been solved with readLine() is promising that the same logic can be refactored to apply to a single character at a time. Perhaps abstract the keymap stuff to recognize one stroke at a time in a way that can be utilized by readLine() or stand alone for single character recognition. |
I'm still interested in seeing this issue solved, if for no other reason than to be able to use my keyboard's arrow keys to control my ASCII "snake" game I made in CommandBox :) On this note, I would be tempted to take a whack at this myself, but there is an absolute metric ton of cruft in the readLine() method that appears to have to do with making a VI editor or something. Is all that really necessary? It seems to me someone decided to make a Java version of VI and coded a bunch or VI-specific escape key support into JLine. Shouldn't that be abstracted out a bit so it's not part of the JLine core? If nothing else, can we subclass the reader with a VI version that does all that stuff to lighten up the class? |
As it has been stated, jline's main goal is the Anyway, to support arrow keys correctly, you need to use the KeyMap class to register the sequence/operations you want, then find a mapping operation from the sequence of chars you get. I've implemented a nearly complete less pager on top of jline: I'm sure there's room for improvements though... |
Holy cow, that's a lot of code! Here my implementation of a I'm not sure I follow what you're saying with the KeyMap stuff. I'm familiar with what that is, but there's no way for me to access more than one character at a time (an arrow key is a sequence of two characters) and I don't want the user to have to press "enter" and capture the entire line. The ability to read a single character sequence from the console seems like it would be a great feature and it would certainly make my live easier when using JLine for interactive CLIs like CommandBox. |
Yeah, less is quite complicated. Note that in the above code, the support for arrow keys is completely broken and does not work... Anyway, in the less code, I could make the readOperation() something available from the ConsoleReader: You would give a KeyMap as an argument, and it would return the Operation translated from the input stream. |
Well, you're also using Java. CommandBox is written in CFML which dispenses with a lot of the boilerplate :) Can you explain what the purpose would be to pass a keyMap into such a method? I'm just thinking about how readLine() works, and there's no need for the calling code to worry about the keymap-- that's taken care of internally. A method to read a single character from the input seems like it would deserve the same level of abstraction since it's right along the same lines from an API perspective:
Also, if we can get this figured out, I'll be able to actually play CommandBox snake with my array keys! |
Characters can't be easily used to represent arrow keys. There's no single representation on various systems. You can easily create a KeyMap
alternatively, you can use
The point of using KeyMap is that you can bind your Action.Up enum to different key combinations, such as the up arrow key or the E / e characters without having to care about the mapping. |
Thanks @gnodet for the explanation. How would I go about reading the next keystroke using the default keyMap that the ConsoleReader uses? Will getKeys() return that? Also, what will be returned from readBinding() if the sequence typed doesn't match anything in the keyMap? I'm just trying to think about how I can keep from duplicating any work already done in JLline and wrap all this up into a nice function that will read the next keystroke and basically account for anything without having to map every single key. |
The KeyMap used while reading a line is available using
However, the internal key map has all the VI / emacs line editing stuff, not sure you would really want that for a snake game... The readBinding method will block until a matching binding is found or EOF. If your keyMap is not full (i.e. not all characters map to something), characters that can't be mapped to anything will be silently discarded (see the junit example below where 'a' and 'd' are discarded). |
Well, it's much bigger than just that. CommandBox is basically a command framework for CFML developers that just uses Jline for the console interactions. Commands (like the "more" I linked to previously) are implemented as a component that extends a base class that provides them with helpers for ASNI formatting, asking the users for information, and a way for dynamic tab completion, etc. So, some of the built-in methods are https://github.com/Ortus-Solutions/commandbox/blob/master/src/cfml/system/Shell.cfc#L190-L206 This is a generic utility that command authors can use to collect a single keystroke from the user and it abstracts away the actual console reader. I don't have any idea what all the possible keystrokes are that will need to be mapped by every possible command. I just need to assume that a command author might want to listen for any possible keyboard input at runtime and have this method return the next thing the user presses. I understand that key presses that don't correspond to a unicode character will need to be mapped and I can try to do that for stuff like arrow keys, pg up/down,etc (though I'd prefer not to duplicate any logic JLine has already accomplished). However mapping every possible character that can be entered, especially once you take into account character like "©" seems a little impossible. Is there a way that we can capture a single keystroke, and if it has an unicode representation, return that, otherwise just have a map for the rest of the buttons on my keyboard (up, down, etc)? What I'm looking for here needs a bit more abstraction than what the |
We can't really be more generic than using KeyMap. First, jline can't support key pressed, key released, or any such event. The reason is that it's main goal is terminal interaction, and those are not available in virtual terminals such as ssh or telnet. For example the fact the user presses the SHIFT key and later release it will never go through such channels. They are not available from stdin either afaik. So we don't have access to keyboard events, just a stream of characters. What the That's why arrow keys are received as the sequence But again, the
With such code, you can return objects that can mimic awt keyboard events, but I think that should be part of your platform, not jline. |
Heh, well you can't be any more flexible, but I guess I was looking for a more "turn key" solution to this. This is a swiss army knife, but all I needed was a box cutter.
Sure. And to be clear, I didn't expect it to. The AWT reference was purely to show that other libraries abstract their users from the mundane details of the escape codes going on behind the scene of a single key press.
Well, let's be honest-- yes we do. This is a problem that has already solved as evidenced by the fact that the JLine library already allows me to interact with it using keys like up, left, and right. I can appreciate that some massaging and introspection of the character stream is necessary to divine this, but I guess that's been my point all along. The rest of the API of JLine that I'm familiar with has abstracted this nicely away from the developers using it so it just feels a little odd that we're pushing it off on the devs here to worry about something that feels like a lower-level intricacy. Sure, someone has to worry about what comprises an "up" key, and assuming you're a developer on JLine, I can appreciate that it's something you're used to having to account for. I'm just suggesting that there's value in a Jline method that that allows developers to interact with a terminal at a higher level of abstraction, on par with other languages/libraries. I'm glad to have JLine's abstraction in the rest of its API, especially when I see tickets like #100 that show the pitfalls of depending on specific escape codes that apparenlty can even be different based on locale settings. How do you feel about JLine including some constants somewhere that represent all the common escape codes for easy mapping, or at least some documentation you can point me to that lists them? I don't mind mashing all the keys on my keyboard to see what gets spit out, but that feels a little wrong. Thanks for the final code sample-- I'll see what I can do to mimic this. Am I correct that I'll need to use the bleeding edge or wait for the next release to do this since |
I've recently added support for
This would allow
I'm also open to make those values available as constants on the WindowsTerminal. And yes, |
This conversation is rather old, yet the jLine library still looks like the only available cross-platform option for detecting (synchronous) key presses in command-line environment. So here are my findings so far: Indeed, the best way to read complex (consisting of more than 1 character) key sequences is to use
So, the only viable option is the one also discussed here: call
Here This is not ideal, of course. But I can't think of any other way to perform the task needed. |
Note that JLine 3 has added
|
@ASemeniuk All my needs have been (mostly) met in JLine 3, where I can provide my users writing arbitrary interactive CLI task runners the ability to capture most of the possible keystrokes. You can see here that I simply dug through the code and mapped all the common key strokes and capture them, returning a bit of pre-defined text to represent the special multi-character bindings. I still wish I had a way in JLine to do this automatically, but this works for me. Here is my code (CFML, a dynamic JVM language) And here's the docs I provide my users: |
Thanks for the replies. |
@ASemeniuk I'm all for adding what's needed in JLine3, but I fail to understand the exact purpose. JLine3 provides access to the
|
@gnodet There is not much I need, actually. Just so when I bind "\u001b" to some operation and use |
When reading a key with ConsoleReader.readCharacter() all arrow keys return code 27. There is also extra text that shows up in the prompt such as [A [B [C and [D which seems to imply that the arrow keys are two bytes and only the first byte is being read. I think this might be related to https://github.com//issues/100
This is 64 bit Windows 7 with the bleeding edge of Jline.
The text was updated successfully, but these errors were encountered: