I am trying to access keystrokes in C. I can access alphanumeric keys. How can I access Control, Shift and Alt key?
Plus I read somewhere that sometimes while entering text in console, OS masks backspace key. I would like to know where user pressed backspace key. It's not same as knowing when '\n' was pressed.
GNU C. Ubuntu 11.
Dietrich Epp answered in a comment: use ncurses library.
See also this question
And you might make an X11 client graphical application; in that case use a graphical toolkit library like GTK or Qt
If you want to make a console application, use ncurses or perhaps readline
And your question, when taken literally, has no sense: the strict C standard don't know what a key or a keystroke is (the only I/O operations mentioned in the standard are related to <stdio.h> thru FILE). This is why most people uses additional libraries and standards (in addition of those required by ISO C), eg. Posix...
The simple answer is "you can't", at least not easily or without downloading third party libraries.
Most C programs shouldn't have to know anything about the keyboard or the screen. Standard C is only concerned with reading from and writing to files (the keyboard and screen being special-case files).
Assuming you have a good reason for wanting to access the keyboard directly, you should be looking at the ncurses library (http://www.gnu.org/software/ncurses/ncurses.html). Ncurses knows how many different (virtual) terminals and keyboards work, and it presents a uniform interface to them. It lets you paint the screen and create a substitute graphical interface using only blocks of text.
Since you use Ubuntu, try running the "aptitude" command to see a good example of what ncurses can do.
Related
Apologies if this is unclear, but I'm really not sure how to describe this.
See, my issue is that I'm trying to read from the text for user input using fgets(), however, I also need to know if the user presses a special key like /b (backspace) since ideally I want it to start deleting characters from the line before if the current line is empty, like a text editor, which isn't possible with C.
Anyways, let me know if you need more information, thanks in advance.
EDIT: Thought I'd go ahead and post what I have as of now in case someone comes across this later with the same issue to get a better idea
for (; ;)
{
int i;
int key = getch();
if (key == '/b')
{
printf("Hello World");
}
else
{
buffer[i++] = key; // adding character to text user is writing
}
i++;
}
note that this code doesn't work at the moment because of a linker error and something with the /b, but in essence, this could work.
EDIT 2: Thank you chqrlie for bringing up the right way to refer to special characters. Forgot you had to use the backslash for them.
You can certainly write text editors in C :-) A lot of them are.
However, you can't write them in portable C because the facilities required for interactive character-by-character terminal I/O don't exist in standard C. They don't exist because standard C doesn't assume that there is such a thing as a terminal (lots of embedded CPUs don't have any such thing, for example), and it would go far beyond the mandate of ISO C to try to standardise the disparate communications protocols of the various operating systems which do have terminal-like I/O.
getch is an obsolete interface in the Windows conio.h header, and also one of the interfaces in the Curses library, which is available for many operating systems (including Windows). It has nothing to do with fgets, which is part of standard C, and it cannot be implemented using fgets.
It seems likely that what you are trying to do could best be accomplished using an implementation of Curses. (If you're using Linux, as suggested by your avatar, you would be looking for Ncurses.) You might want to look at the Forms library built on top of Ncurses, which provides higher-level input facilities, like editable text boxes.
Another common input-handling library, GNU readline, might also be useful, but it doesn't handle multiline input forms so it would probably be a lot more work.
I'm having a hard time even googling this, because I don't know the right keywords. Some command-line apps (such as vi and less) take over the whole console screen and present an interactive interface to the user. Upon exiting such an app, the screen is returned to the state it was in before the app was launched. I want to write a program that behaves in this fashion, but again, I don't even know what this is called, so I can't find any documentation for how it's accomplished.
So, my question is threefold:
What keywords can I use to find documentation on this?
If you are so inclined, links to such documentation would be helpful.
Lastly, can I accomplish this in a scripting language like Ruby, or even bash? I have no problem with C, but the environment I work in is more amenable to interpreted languages.
As said in some comments, you are looking for ncurses. The Linux Documentation Project have a very good HOWTO on ncurses for C that I used myself to start on it
https://tldp.org/HOWTO/NCURSES-Programming-HOWTO/
The feature you are describing is the alternate screen buffer. I think that [N]Curses will enable this by default. There are certainly curses bindings for Ruby, Python, and other scripting languages.
you can even access ncurses in bash by using the tput program. The whole ncurses library (like curses before it) works by sending escape sequences to the terminal. The xterm program emulates a vt100 terminal (and also a Tektronic terminal) and there were various combinations of characters which would move the cursor, clear the screen, draw various characters etc. These would generally start with an escape character, hence the name: escape sequence. You also sometimes see these escape sequences in people's PS1 shell variables with the \e to provide the escape character; often used to colour the prompt or set the window title.
tput refers to the terminfo database to figure out what the escape sequences are to perform the functions you've asked it to do.
see the manual page, type:
man 5 terminfo
for more details
I have to draw a box in C, using ncurses;
First, I have defined some values for simplicity:
#define RB "\e(0\x6a\e(B" (ASCII 188,Right bottom, for example)
I have compiled with gcc, over Ubuntu, with -finput-charset=UTF-8 flag.
But, if I try to print with addstr or printw, I get the hexa code.
What I`m doing wrong?
ncurses defines the values ACS_HLINE, ACS_VLINE, ACS_ULCORNER, ACS_URCORNER, ACS_LLCORNER and ACS_LRCORNER. You can use those constants in addch and friends, which should result in your seeing the expected box characters. (There's lots more ACS characters; you'll find a complete list in man addch.)
ncurses needs to know what it is drawing because it needs to know exactly where the cursor is all the time. Outputting console control sequences is not a good idea; if ncurses knows how to handle the sequence, it has its own abstraction for the feature and you should use that abstraction. The ACS ("alternate character set") defines are one of those abstractions.
A few issues:
if your program writes something like "\e(0\x6a\e(B" using addstr, then ncurses (any curses implementation) will translate the individual characters to printable form as described in the addch manual page.
ncurses supports line-drawing for commonly-used pseudo-graphics using symbols (such as ACS_HLINE) which are predefined characters with the A_ALTCHARSET attribute combined. You can read about those in the Line Graphics section of the addch manual page.
the code 0x6a is ASCII j, which (given a VT100-style mapping) would be the lower left corner. The curses symbol for that is ACS_LRCORNER.
you cannot write the line-drawing characters with addstr; instead addch, addchstr are useful. There are also functions oriented to line-drawing (see box and friends).
running in Ubuntu, your locale encoding is probably UTF-8. To make your program work properly, it should initialize the locale as described in the Initialization section of the ncurses manual page. In particular:
setlocale(LC_ALL, "");
Also, your program should link against the ncursesw library (-lncursesw) to use UTF-8, rather than just ncurses (-lncurses).
when compiling on Ubuntu, to use the proper header definitions, you should define _GNU_SOURCE.
BTW, maybe I'm probably arriving somewhat late to the party but I'll give you some insight that might or not shed some light and skills for your "box drawing" needs.
As of 2020 I'm involved in a funny project on my own mixing Swift + Ncurses (under OSX for now, but thinking about mixing it with linux). Apparently it works flawlessly.
The thing is, as I'm using Swift, internally it all reduces to "importing .h and .c" files from some Darwin.ncurses library the MacOS Xcode/runtime offers.
That means (I hope) my newly acquired skills might be useful for you because apparently we're using the very same .h and .c files for our ncurses needs. (or at least they should be really similar)
Said that:
As of now, I "ignored" ACS_corner chars (I can't find them under swift/Xcode/Darwin.ncurses runtime !!!) in favour of pure UTF "corner chars", which also exist in the unicode pointspace, look:
https://en.wikipedia.org/wiki/Box-drawing_character
What does it mean? Whenever I want to use some drawing box chars around I just copy&paste pure UTF-8 chars into my strings, and I send these very strings onto addstr.
Why does it work? Because as someone also answered above, before initializing ncurses with initscr(), I just claimed "I want a proper locale support" in the form of a setlocale(LC_ALL, ""); line.
What did I achieve? Apparently pure magic. And very comfortable one, as I just copy paste box chars inside my normal strings. At least under Darwin.ncurses/OSX Mojave I'm getting, not only "bounding box chars", but also full UTF8 support.
Try the "setlocale(LC_ALL, ""); initscr();" approach and tell us if "drawing boxes" works also for you under a pure C environment just using UTF8 bounding box chars.
Greetings and happy ncursing!
I am implementing a shell-like program where user types command (defined by me). Just like this.
>cmd
result blah blah blah
>
When I use arrow keys it outputs raw characters like ^[[A.
>^[[A
I also notice sqlite3 behaves like this at least in the version I compiled on my computer.
How to prevent this and let <- and -> keys move cursor left and right?
GNU Readline is a library specifically designed for this task (that is, allowing the user to edit commands typed at an interactive command-driven program). Note that this library is distributed under the GPL (not the LGPL); if that won't work for you, editline is a similar library with a BSD-style license.
I note that you say this is homework, so you might want to ask your instructor whether you are expected to implement cursor motion and line editing yourself. If so, ncurses (as mentioned by jDourlens) is the next step down in terms of abstraction, and if you really want to do everything yourself, read up on termios and the VT-220 control sequences (nearly all terminal emulators used nowadays emulate the VT220 or one of its descendants).
I have found a slightly simpler way to do that. Run rlwrap [your program] instead of [your program].
For example, it works fine with sqlite3 as rlwrap sqlite3
To let the user navigate in cmd with the keyboards arrows you may have to use termcaps.
http://www.gnu.org/software/termutils/manual/termcap-1.3/html_chapter/termcap_2.html
If you want to be easier to deal with termcaps that are a bit complex you shoul use Ncurses.
http://www.gnu.org/software/ncurses/ncurses.html
Good luck to deal with termcaps if you chosse this solution, it's some pain in the ass!
You may take a look to Ncurses. It's a library that let you control almost everything in terminals. The specific function you want is noecho(), which stops terminals from showing users' input.
I am writing a program that's similar to a shell. Once started up, there's a prompt and you enter in some app-specific commands.
So far this works just fine. However, I want to add support for command history like in Bash, so the user could hit the up or down arrow and see previously entered commands.
I have included the ncurses library, and I have done a simple hello world test with getch() to make sure the up and down arrows are reported correctly.
The thing that's bothering me is that it seems to be a requirement that I call initscr() which will clear the screen in order for me to use getch().
OKAY SO THE QUESTION IS:
Does anybody know a way to use ncurses getch() function without calling initscr() first? If not, can I make it not clear the screen? Basically, I'm looking to have getch() act the same as getchar(), if that makes sense.
Thanks in advance!
EDIT: I think the best example of this is how Python runs in interactive mode.
Curses wants to fully control the screen, and to optimize writes to the screen, especially over slow serial lines. To do this, it needs to know what is on the screen, and the only reasonable way to do that with most terminals is to start from an empty screen and keep track of what you write to the terminal.
Thus, I suspect (n)curses is the wrong tool for your shell. You probably need to go down a step on the abstraction layer and use terminfo and non-blocking reads from the terminal (standard input) instead.
(This is not very helpful. Sorry.)
It might be simpler to use an interface like readline() rather than resorting to full-blown ncurses.
You could just call your program from within rlwrap and have the functionality without the pain...
Here is another discussion about this. The provided solutions are:
"The 'filter()' function lets you use curses as a single-line."
"You can write something equivalent in C, using setupterm to get the
terminal data, and tparm, tputs for formatting and output."
Of course there is the third option to get the ncurses source code and modify it so it doesn't clear the screen anymore.
Have you considered the simple expedient of creating a custom terminfo or termcap entry lacking a sequence to clear the screen and then switching your terminal setting to that right before running your program? You could also just use newterm() and set_term() in ncurses. This used to be easier with termcap, since you could include another terminal and override some of its capabilities.