ncurses- KEY_ENTER is fail - ncurses

I've been trying to teach myself ncurses and I'm loving it so far. However, I'm trying to write a small little text editor like pico or nano. I've got it set up fairly well so far. I created a function to map the keys. No matter what I do I can not get a response from KEY_ENTER. Whenever I press it it just goes to the beginning of the currently line that I'm on. I've tried using raw(); and using 13 instead of KEY_ENTER no luck. All the other keys respond as expected. I would appreciate any advice. I've been staring at this trying to make it work forever. Thanks!
#include <stdlib.h>
#include <ncurses.h>
// gcc keymaps.c -lncurses -o keymaps
int main(){
int ch;
initscr();
cbreak();
noecho();
keypad(stdscr,TRUE);
while (ch = getch()) {
switch(ch){
case KEY_UP:
addstr("Up\n");
break;
case KEY_LEFT:
addstr("Left\n");
break;
case KEY_RIGHT:
addstr("Right\n");
break;
case KEY_BACKSPACE:
addstr("Backspace\n");
break;
case KEY_ENTER:
addstr("You pressed Enter\n");
default:
printw ("%u\n", ch);
break;
}
}
}

The likely problem is user confusion between the Enter key on the regular keyboard versus the Enter key on the numeric keypad. Those could both send a control/M (13), but not necessarily. The terminal description and KEY_ENTER refer to the numeric keypad.
The ncurses manual page for getch explains the behavior in the NOTES:
Some keys may be the same as commonly used control keys,
e.g., KEY_ENTER versus control/M, KEY_BACKSPACE versus
control/H. Some curses implementations may differ according to whether they treat these control keys specially
(and ignore the terminfo), or use the terminfo definitions. Ncurses uses the terminfo definition. If it says
that KEY_ENTER is control/M, getch will return KEY_ENTER
when you press control/M.
Generally, KEY_ENTER denotes the character(s) sent by the
Enter key on the numeric keypad:
the terminal description lists the most useful keys,
the Enter key on the regular keyboard is already handled by the standard ASCII characters for carriage-return and line-feed,
depending on whether nl or nonl was called, pressing
"Enter" on the regular keyboard may return either a
carriage-return or line-feed, and finally
"Enter or send" is the standard description for this
key.
Line-feed, by the way, is a 10. But in C, it is usually shown as '\n' (and carriage return as '\r').

Try 10 as ASCII value ... worked for me on ncurses.Also please update the actual code because this code that you put is wrong by syntax.

From the PDCurses documentation:
#define KEY_ENTER 0x157 /* enter or send (unreliable) */
Try calling nonl() after raw().
The nl and nonl routines control whether the underlying display device translates the return key into newline on input, and whether it translates newline into return and line-feed on output (in either case, the call addch('\n') does the equivalent of return and line feed on the virtual screen). Initially, these translations do occur. If you disable them using nonl, curses will be able to make better use of the line-feed capability, resulting in faster cursor motion. Also, curses will then be able to detect the return key.

I got the same KEY_ENTER problem recently, and I fixed it by replacing KEY_ENTER with 10 or \n, which is ASCII new line.
#include <ncurses.h>
int main() {
initscr(); /* init ncurses */
keypad(stdscr, TRUE); /* get keyboard input */
addstr("Press enter to exit.\n");
while (10 != getch()) {} /* 10 == enter */
endwin(); /* end ncurses */
return 0;
}

Related

Eiffel: is there a way to print colorized characters into a terminal (console)

Trying to write some logger enhancements I'd like to deal with ANSI codes interpretation, and it seems that it's not working with the standard io.putstring method neither with print I wonder there is a way to do something such as
echo -e "\u001B[31mSome_red_txt" in bash
Seems other languages can do it but I can't in Eiffel.
Using ANSI codes interpretation, you can do
print ("%/27/[31mSome_red_txt%N")
print ("%/27/[1;31mbold red text%/27/[0m%N")
You may check for existing C libraries like ncurses.
Note it will not work on Windows console, as now it does not support ANSI code anymore, so you need to use the Windows API.
To complement Jocelyn's answer, the same ANSI code sequences can be used on Windows with recent update by making sure the console is initialized to handle the sequences:
-- Make sure the console is allocated in a non-console application.
io.output.end_of_file.do_nothing
-- Set console to terminal mode.
initialize_terminal
-- Use ANSI codes to color text.
print ("%/27/[31mSome_red_txt")
where
initialize_terminal
external "C inline"
alias "[
#ifdef EIF_WINDOWS
{
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut == INVALID_HANDLE_VALUE) return;
DWORD dwMode = 0;
if (!GetConsoleMode(hOut, &dwMode)) return;
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOut, dwMode);
}
#endif
]"
end
After such initialization, print statements work the same on Windows and Linux.
If output can go not only to the console, but also to a file, a pipe, etc., error status of setting the terminal mode on Windows console can be recorded in the external feature and used later to avoid outputting ANSI sequences in such cases.

How can I know that the user hit the ESC key in a console with ncurses (Linux)?

I have a problem in detecting whether I just got a plain ESC key (just code 27) or whether it was another special key such as an Arrow Up which sends me three bytes: ESC [ A (27 91 65).
Now, I understand escape sequences, what I don't understand is how can I possibly know that the user actually typed ESC instead of a special key since both start with 27 and ESC is only 27?
Note that I use the wgetch() function from ncurses as in:
// initialization not shown initscr() should be enough for this test
while(!f_should_exit)
{
int c(wgetch(f_win_input));
// show codes of what the user types
//
printf("got [%d] ", c);
// prints 27 when I hit ESC
// prints 27 91 65 when I hit Arrow Up
}
I use the ESC and arrow keys all the time in vim so I would imagine that there is an easy way to specifically detect which key was pressed?!
This is a standard feature of X/Open Curses. The manual page for wgetch discusses it in keypad mode:
When a character that could be the beginning of a function key is received (which, on modern terminals, means an escape character), curses
sets a timer. If the remainder of the sequence does not come in within
the designated time, the character is passed through; otherwise, the
function key value is returned. For this reason, many terminals experience a delay between the time a user presses the escape key and the escape is returned to the program.
By default, keypad is not set to true for a given window, i.e., the library does not do this (your program must, if you want function-keys):
keypad(win, TRUE);
The timeouts are described in ncurses' input-options manual page. To distinguish an escape character from a function (or cursor, or keypad key), you could use notimeout, as mentioned in the discussion of nodelay:
While interpreting an input escape sequence, wgetch(3x) sets a timer
while waiting for the next character. If notimeout(win, TRUE) is
called, then wgetch does not set a timer. The purpose of the timeout
is to differentiate between sequences received from a function key and
those typed by a user.

How do I clear the current line of stdout?

I'm trying to make a status indicator in Rust that prints to stdout. In other languages, I've used a function that clears the current line of stdout while leaving the others untouched. I can't seem to find a Rust equivalent. Is there one? Here's a small example of what I'm looking for
for i in 0..1000 {
stdio::print(format!("{}", i).as_slice));
stdio::clear();
}
On an ANSI terminal (almost everything except Command Prompt on Windows), \r will return the cursor to the start of the current line, allowing you to write something else on top of it (new content or whitespace to erase what you have already written).
print!("\r")
There is nothing available in the standard library to do this in a platform-neutral manner.
Utilizing the ASCII code for backspace is one option, for example:
print!("12345");
print!("{}", (8u8 as char));
This will end up outputting "1234" after the 5 is removed as a result of printing the backspace character (ascii code 8). Strangely, Rust does not recognize \b as a valid character escape.

Is it possible to display text in a console with a strike-through effect?

I have already looked into ANSI escape codes, but it looks like only underlining is supported.
Do I miss something or is there another option?
If it is not possible, is there something equivalent in the meaning of "this is deprecated"?
According to the ECMA-48 standard for terminals, SGR (Select Graphic Rendition) code number 9 is supposed to enable crossed-out text. However, the ANSI escape code wikipedia page says that it's not widely supported, and I'm not aware of any that do. I'd suspect that's because DEC's VTxxx series didn't support it.
An alternative solution for applications written in C11 or C++11 is to use the Unicode combining long stroke overlay character.
In C++11 you can write code something like this:
#include <iostream>
#include <string>
std::string strikethrough(const std::string& text) {
std::string result;
for (auto ch : text) {
result.append(u8"\u0336");
result.push_back(ch);
}
return result;
}
int main() {
std::cout << strikethrough("strikethrough") << std::endl;
}
The code prefixes each character in the input text with the stroke overlay \u0336. Note that the function assumes that text is encoded in a singlebyte encoding such as ASCII or Latin. If the input is in UTF-8 it must be converted to UTF-32 first to get the character boundaries.
The output then is s̶t̶r̶i̶k̶e̶t̶h̶r̶o̶u̶g̶h in a UTF-8 capable terminal. I don't know why the first character has no strike-through, must be a terminal issue. I could work around this by printing at least one character before the strikethrough function call.
The Unicode solution also generates a slightly different locking in my terminal (terminator) compared to the ANSI escape sequence mentioned above. The former renders the line exactly in the middle of the text whereas the latter renders it a bit below.
This works for me.
$ echo -e `echo "this is a strikethrough text" | sed 's/.\{1\}/&\\\u0336/g'`
couldn't find anything easier than this:
$ echo -e "\e[9myour text goes here\e"

How can we make two inputs appear on the same line?

In c++, if we make program to take input from user, it is either some integer or character.
After that input, the next output or next input is written on the next line automatically.
#include <iostream>
int main()
{
int a,b;
std::cout<<"Enter two numbers to add\n";
std::cin>>a;
std::cin>>b;
std::cout<< a+b;
}
the output is like this
Enter two numbers to add
3
5
8
I want 3 and 5 written in same line..
The word you're looking for is called "parsing". You take the entire input in as 1 variable, and split it up using whatever method is appropriate for you. Some programming languages have some built-in methods for breaking up a string input into an array based on a value you supply. You might want to take a look at: Split a string in C++?
That the input is appearing on two seperate lines has nothing to do with your program; this is because, while typing the input, you pressed <Enter> after 3. The resulting newline was rendered by your terminal / console, not your program.
Using istream::operator>>( int ) will automatically skip leading whitespace. So your user could also write 3 5 on one line. std::cin>>a; would consume the 3, and std::cin>>b; would skip the space and consume the 5. Your terminal / console would look like this:
Enter two numbers to add
3 5
8
Note that this is completely unrelated to your program code, though. If the user presses <Enter> between numbers, there is nothing you can do about it, short of taking over complete control of the terminal / console.
This can be done, using _getch() on Windows, ncurses on many other systems, or whatever the OS in question provides. You would be reading keypresses directly, without the terminal / console echoing what is entered. You would then be responsible for the echo, line editing etc.
That is a completely different question, though.

Resources