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.
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.
Related
Certain control sequences have special effects in Linux, such as CTRL-C which sends SIGINT. I can handle signals easily enough, but it appears CTRL-S (XOFF) and CTRL-Q (XON) are special snowflakes. I know their effect (to pause input) can be disabled in the console with stty -ixon, and I could use some trickery to run that command, but that feels like a cheap workaround.
Is there a proper way to rid these sequences of their special effect and get their actual ASCII values (^S, ^Q) using system calls? I know it is doable because the text editor Nano does it, but for the life of me I can't find where it's being handled. I already tried searching the repo for "XOFF".
https://github.com/dtrebbien/nano/tree/master/src
Use the tcgetattr() and tcsetattr() system calls to turn off the IXON flag on standard input, as explained in this manual page.
I am trying to write up a C++ program for a class using XCode. One of the things I wish to do, is to simply clear the screen. I've looked into how to do this, however the catch is that the code needs to run on both a Windows and Macintosh computer. I've looked at some other similar questions, but none of the answers help me. I know there is no "screen" but I want the system to clear the output window. I know that the command system("clear"); does what I want it to, but when XCode tests the program, instead of clearing the screen it prints TERM Variable not set
I've tried opening up the terminal and typing clear and it does in fact respond the way I want it to, so why doesn't the 'terminal' inside of XCode do the same? I just want to get the output window in XCode to respond to clear the same way that the terminal already does.
Here is something I have already tried;
I went to the terminal and ran echo $TERM, to which the terminal responded xterm-256color. I then went over to XCode and opened the "Scheme" settings, and found an Environment Variables setting under "Arguments". I added a variable (to the blank list) called TERM and gave it value xterm-256color. Upon running the program again, the output displays ¿[H¿[2J in the output window, positioned where the TERM Variable not set used to be printed.
Last thing, as a reminder, I cannot change the source code from the way it is now, or it could cause errors when the program is run on a Windows machine.
It does not work because you are "lying": The terminal in Xcode is not a xterm-256color, but it is dumb terminal. More precise, the display represents a NSTextStorage that collects stdout and/or (depending on target switch) stderr.
A dumb terminal is not able to clean the display. If you want to change this, you can write a plug-in similar to Xcode-Colors what adds the ability to understand ansi color codes.
However, if your requirement that the code simply run at Windows and OSX, you may stick with your solution system("clear"), since it works prefectly in the "normal" OSX terminal.
When using vim in the terminal, it essentially blanks out the terminal's window and gives you a new one to start coding in, yet when you exit vim the terminal's previous output is still listed. How do you clear the terminal so that it only outputs your program's output, but returns to its normal state once the process has ended? (In linux, fedora)
At the low level, you send the terminal program a set of control characters that tell it what to do. This can be a bit too complex to to manage manually.
So instead, you might want to look at a console library like ncurses, which can manage all this complexity for you.
With respect specifically to the previous content magically appearing after the program exits, that's actually an xterm feature which vim is taking advantage of and which most modern terminals support. It's called "alternate screen" or simply "altscreen". Essentially you tell the terminal program "Ok, now switch to a completely new screen, we'll come back to the other one later".
The command to switch to the alternate screen is typically \E[?47h, while the command to switch back is \E[?47l For fun try this:
echo -e "\033[?47h"
and then to switch back:
echo -e "\033[?47l"
Or for a more more complete solution which relies a bit less on your shell to set things right (these are the sequences vim normally uses):
echo -e "\0337\033[?47h" # Save cursor position & switch to alternate screen
# do whatever
#Clear alternate screen, switch back to primary, restore cursor
echo -e "\033[2J\033[?47l\0338"
You can type "clear", or add a system command in your program to call "clear". Also, if you're not aware, you can run system commands from inside vim, so you dont have to exit and type clear. You can compile and run your programs from inside vim as well, for example ->
:!clear
:!make
:!./programName
Also, I never use this technique, but I believe you can have vim call a new terminal by using :set terminal
First, a bit of background: I'm running the latest stable build of Crunchbang Linux inside a VirtualBox VM. I'm designing a custom text-based user interface to run on top of bash. This is being done with a combination of C++ and bash scripts.
I need to, at times, completely and totally remove the ability for the user to provide the system with any sort of standard keyboard input. This is because, when I run a part of the system, the user is forced to wait for certain amounts of time.
Unfortunately, the user can still type while this is going on, and whatever they type is put on the screen. This happens when I'm running a C++ program as well as a bash script. The reason this is a problem is that there is text on the screen which the user is to read, and if they can type, it displaces the text. There will be other uses for this later, as well, like making the system seem like it has frozen up.
So, the question - How do I
disable the keyboard, or
prevent anything pressed on the keyboard from showing up on the screen?
Turn off echo mode with stty -echo or the equivalent C code (which would use tcgetattr and tcsetattr). When you are ready to accept input again, turn it back on. You may also wish to discard the input that arrived while you weren't expecting it. That would be done with tcflush but be aware that some users (like me) would consider that an annoyance. Typeahead is a feature, not a bug!
To see how user input to a certain process or tty can be intercepted, the man page and source code of interceptty may be enlightening. (have no experience with it)
However, you can hardly (totally) prevent user input. The user is probably always able to switch to a different virtual terminal (if any) or at least to reboot the system with Alt+Print+B (Magic SysRq_key) if not disabled. It is two different things to ignore input on a given tty and disabling keyboard input altogether.
I'm trying to make a C++ console application using Xcode 4.1, but I can't find the command for cleaning the screen while the program is executing...
Any ideas? Thanks!
OSX doesn't have "consoles" the way Windows does. It has pseudoterminals, which act like an old-fashioned glass terminal to the program running "inside" them, and like a bidirectional pipe to the program that set them up. That outer program can do whatever it likes with the inner program's input and output. Notable examples of such programs are Terminal.app, which emulates the venerable VT-100, and ssh, which forwards the I/O over a secure channel to its own controlling terminal (which is probably itself a pseudoterminal). This is all by way of saying that there isn't a method that's guaranteed to work, because maybe the program on the outside of the pseudoterminal doesn't have a "screen" that you can meaningfully "clear." (Expect is a good example of a program like that.)
Having said that, though, if there is a screen, these days you can pretty much count on it to respect the VT-100 control codes. So this should do what you want:
std::cout << "\033[2J" << std::flush;
If you find that you need even one more control code, though, it's time to hook your program up to ncurses, which presents a nice friendly API to all the tricks that modern terminal windows are capable of, and will also have your back in the increasingly unlikely event that your program is attached to a terminal (or a program emulating a terminal) that is not a VT-100 nor one of its descendants.