I'm writing a C program that requires to hide the characters a user types from the screen during the program execution. For example, when running the following loop
while (1)
{
//do some work
}
the console displays the blinking cursor (that's good). BUT, when the user types keys on the keyboard, these keys are being echoed out to the console. To visualize it better:
Step 1: Starting the program
root#debian:/home/root# ./program
_
Step 2: User types some characters (even though he shouldn't)
root#debian:/home/root# ./program
AdajfsaSJ_
The characters get echoed on the console. How can I stop this? I know it's theoretically possible, but I can't find out how to implement it.
If you need a better example for what I want to achieve, use the screen command on an empty serial port. screen /dev/tty30 for example. This empties the console and runs the program, HOWEVER, the user is not able to enter any characters (there's a blinking white cursor block and no keyboard characters are being echoed to the console). That's what I need.
Any insight would help, thanks!
Use termios() to turn off the ECHO flag of the terminal.
To turn off the text cursor, use the termcap library to control the cursor visibility.
Related
I am trying to code a little console chat-program in C on linux.
So far I coded it in a way that both chatting partners are only able to alternately send/recv, because these function calls are blocking by default.
Now I would like to modify that program, so that both are able to send and receive simultaneously.
The problem that I find is, that once you typed some input to the terminal, I don't know how to output received messages, without messing up the current input line of the terminal.
If there was a way to delete that current input line, you could temporarily save that line, print the new message and put the input line right back.
However, I was not able to find a solution for this problem on the internet.
Is it possible to delete the current input line, and if not, how else could I achieve what I want?
I think you should look into ncurses as Edd said in his comment.
It would allow you to easily manage contents in your terminal window, which sounds like a good idea for your chat program.
All you'd need to do is store your messages in 2 character arrays:
char incoming[MSG_MAX]
and
char outgoing[MSG_MAX]
Then you can output those messages wherever you want in your terminal window, since ncurses allows you to specify x,y coordinates on where to put your text.
Then a simple wrapper for one of ncurses erase() family functions would allow you to delete characters from specify x,y coordinates in your terminal window.
Edit: MSG_MAX is not an actual ncurses macro.
i am writing a terminal chat and would like to reprint the content the user has typed in, if a new message from another user has arrived asynchronously.
if a new message arrives i print "\x1B[2K" to stdout (ANSI ESCAPE CODE for erasing the current line) to clear the current line, then i print "\r" to move the cursor to the leftmost position, then i print the received message with a newline
now i would like to reprint the characters the user has typed - i found out that there is a special character VREPRINT (http://www.gnu.org/software/libc/manual/html_node/Editing-Characters.html) that can be used and if a hit CTRL-R it actually works... but if print the character to stdout using the character placed in c_cc[VREPRINT] of a struct termios, it does not work - is it even possible to do it that way?
I do not want to use any other libraries like readline or ncurses, since this would be plain overkill... i just would like to make my solution work using ICANON terminal mode if possible
Thanks in advance!
While it is possible to write to the same tty device that you are reading from, this doesn't mean that the characters that appear will be processed as input characters.
You can test this yourself, using two separate shell sessions (using screen, tmux, or, if you are on MacOSX, iTERM.app sessions).
in Session 1, get the current tty name:
tty
Let's assume the tty name of Session 1 is /dev/ttys000.
Then enter the following, without a return or newline -- just leave it pending:
echo abc def-
In Session 2 (using the tty name from Session 1), enter the following command:
echo foo >/dev/ttys000
The string foo should appear on the pending line in Session 1, like this:
echo abc def-foo
Now, go back to Session 1, and hit an "enter" (or return), causing the input buffer to be completed and sent to the shell, which will parse the first word as the echo command, with the subsequent arguments as text to be printed.
You should see the string "abc def-" echoed -- but not the foo.
This test makes it clear that the string foo was never placed into the input buffer, even though it was sent to the same tty being used for input (and output).
You can try to see if special control characters are recognized and processed; but they won't be. These characters are only being output to the terminal, but not processed.
In order for the special characters to be processed, they have to be received via the socket connected to the input device.
To accomplish what you are trying to do, you'll have to go non-canonical (stty -icanon) and process every character in your code, in order to collect the pending input and also be able to produce asynchronous output.
Alternatively, using nurses is not hard at all, and if you are writing a terminal-based chat program, I would suggest creating at least two panels: a "chat" panel for all output, and an "input" panel for user input. This allows output from other users, as well as the completed commands from the "input" panel, to be received and written to the "chat" panel asynchronously without disturbing the current command in progress by the user in the "input" panel.
I'm trying to build my own console and I'm using the below statement to get RAW access so I can implement some advanced features such as implementing the auto suggest feature that's implemented in a BASH shell by pressing the TAB key.
system("/bin/stty raw")
When using this, the enter key (and others) doesn't behave normally and when I press enter, it displays ^M and doesn't go to the next line.
How do I set the RAW console to go to the next line when it receives ^M
Also can I set the Shell to NOT display the keys pressed so I can send the char back to the console with putchar() (so ^M doesn't display when pressed).
Thanks
How do I set the RAW console to go to the next line when it receives ^M
You write an appropriate control code to the console when you read an ^M. The whole point of raw mode is that the console does not do things like recognize line ends, backspaces, etc., etc., because you want to handle them yourself. Once you do that, you need to handle all those things.
can I set the Shell to NOT display the keys pressed
Sure. Turn off echo. With the stty command, you would use stty raw -echo but if you're doing this from a C program, you'd be much better off using the terminal API. See man tcsetattr
My embedded system has one background program which generates some output message to console.
When it's not finished, the login program starts and prompt login string to same console as well.
My question is, when the login prompt string comes out, the output message generated by the background program is not aligned like this:
Embedded System login: msg_line1...
msg_line2...
msg_line3...
The expected output should be:
Embedded System login: msg_line1...
msg_line2...
msg_line3...
msg_line4...
Have no idea how to resolve the problem...
Could anyone help?
THX!!
Configure your terminal program to autolinefeed, so that it generates the \r internally whenever it receives a \n.
use a redirection for your background program
YourBackStuff.sh >/tmp/back_out.1 2>/tmp/Back_out.2 &
or refresh the screen.
Notice that only the appearance is modified, the real output ou current application/shell (so not the background one) is correct, only the terminal show your all the info received. So
YourFrontApp.sh | tee /tmp/front_out.1
cat /tmp/front_out.1
will produce a correct display (when background process stop)
Looks to me like your messages are sent with a new-line character (represented by \n in C) at the end of each line. This requests a new line from the terminal, which it duly provides. It does not request a carriage return (i.e. "go back to the left hand edge"). This would be represented in C as a \r.
To fix it, you need to set your terminal application to interpret \n as \n\r - it will have a setting for "treat newlines as newline+CR" or some such.
I have this program in C that reads the input like this:
cod1 = getch ();
if (kbhit())
cod2 = getch ();
I can read every Ctrl+Char possible sequences, except for Ctrl+C, that closes the program - that is OK, and Ctrl+S, that simple is not catch. But I wanted to make Ctrl+S to be the save function in my program; how could I do that? Furthermore, is it possible to read Alt+Char characters? Because it reads it as a regular character, e.g., Alt+A is read with the same codes as A.
Your problem is that input probably gets eaten by terminal emulator.
For example Alt+<Whatever> is often reserved for menu shortcuts (e.g. Alt+F opens File menu). Matching characters are often hilighted once you hold Alt (F get's underscored in File).
Ctrl+S is reserved for Stops all output on screen (XOFF) (again your terminal emulator does that).
As for using Alt+<...> as shortcuts in your command line application. As far as I'm concerned holding Alt doesn't affect character received, it just sets flags which are hard to access in console. Even in GUI application (in Windows) it's quite tricky and you have to use function like GetAsyncState() to check whether alt was pressed.