Linux keyboard scancode issues: For example, UP ARROW gives ^[[A
Asked Answered
H

1

6

We've been struggling for a while now to understand the keyboard scancode behavior in Linux.

When we open a normal bash shell, the arrow keys works as expected: UP shows the previous item in the history etc. However when you spawn a process, arrows does not work as expected anymore. For example, UP prints ^[[A instead of the previous command.

To demonstrate this, do something like:

bash$ ping www.google.com

Now, press UP or DOWN etc. and you will see the wrongly mapped key codes while the process is running. However, when you terminate the process the arrow keys will work again.

We've tested it on CentOs, Ubuntu, Mac and even in different shells (bash, sh, zsh) and the same happens everywhere. I've also tried different keyboard modes using kbd_mode where we tested with RAW and XLATE modes.

The closest thing I could see while searching for answers were IPython users have experienced the same behavior when IPython was not build against readline. However, this is not related to our case as far as I can see.

We are developing a C++ Tcl based console application which uses cin and cout to communicate with, and get input from the user. We are having issues with the arrow keys when we try to access the history of previously entered commands. This is a major issue for us as 99% of people expects the arrow characters to just work.

Any ideas on how we could overcome this would be much appreciated.

Herdic answered 16/10, 2013 at 9:50 Comment(0)
P
1

You must set the terminal into raw mode to get the scan codes and handle them (that is: disable ICANON, you want the non-canonical mode). You probably also want to disable ECHO (so that it doesn't print your input on the terminal).

That is what readline or linenoise are doing. See here for some code. Esp. see the function linenoiseEnableRawMode. Some other simple sample Python code is here where I have written a simple console media player which checks for the keypresses left ("\x1b[D") and right ("\x1b[C").

The relevant calls are to tcgetattr (to get the current terminal state and modify that state struct to get into raw mode and enable some other useful behavior stuff) and tcsetattr (to set the state).

readline, libedit or linenoise are some libraries which do all that work for you and provide you with history, autocompletion, etc.

At the end, you must restore back the old state, otherwise you get the behavior you are describing in your shell.

Ponderous answered 16/10, 2013 at 10:44 Comment(5)
Thanks. Funny, I thought I was in raw mode. When typing kbd_mode in my console it does return RAW. I even spawned a kbd_mode process from within the application itself which also returned RAW on its stdout. Maybe I'm interpreting it wrong or something. In any case, I'm going to give linenoise a try and see how that works out.Herdic
If you don't want to see the input printed, you must disable ECHO, as in the examples.Ponderous
linenoise works perfectly! Thanks. In our app the input is passed on to a tcl interpreter so in the end it looks a lot different from the example, but it was a good starting point.Herdic
By the way, since we are using C++, I had to patch it using github.com/ioddly/linenoise/commit/…. I did notice that TABBING (autocomplete) is not working anymore after the patch, but will need to investigate further.Herdic
I also patched linenoise to be C++ valid code and extended it a little bit. That was the file I linked, i.e. header and cpp source.Ponderous

© 2022 - 2024 — McMap. All rights reserved.