By default you can't get the terminal input in Unix without waiting for the User to press enter.
How can I get the input instantly? I am using gdc on debian Linux so I can't use ncurses.
Thanks.
ncurses is a good solution that should work on almost any linux installation with any compiler...
But if you don't want to use ncurses, there's a few other options:
My terminal.d offers it and works on most terminals, but not as many as ncurses (I'd say I cover 98% of typical setups but there's a LOT of variations out there and i didn't try to be as comprehensive as ncurses): https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff/blob/master/terminal.d
Look near the bottom of the file for a version(Demo) void main(). RealTimeConsoleInput gives you an event loop with instant input and other info if you want it (mouse, resize, etc.).
You can also just change the terminal mode with the proper tcgetattr and tcsetattr calls and then do everything else normally. You'll want to import core.sys.posix.termios; and import core.sys.posix.unistd; for the functions, then the rest is done the same as in C.
Here's how to do that:
termios old;
tcgetattr(1, &old);
scope(exit) tcsetattr(1, TCSANOW, &old); // put the terminal back to how it was
auto n = old;
n.c_lflag &= ~ICANON; // turn off canonical mode
tcsetattr(1, TCSANOW, &n); // do the change
Then you can use the input instantly.
Related
The question
Is there a method to prevent an X session from starting the screensaver, going into power save mode, or performing a screen blank from code?
What I'm working with
Language: C/C++
GUI framework: GTK3
Hardware: Raspberry Pi 3B
Software: Raspbian 10 - Buster
My program needs to run on screen for long periods (up to 12 hours) with the GUI running without user interaction. The GUI acts as a status monitor for systems in field (if the screen goes black, something went wrong).
What I know
GTK3 can determine if the screensaver is active
GTK3 has a boolean property to report if the screensaver of the system is active (see here), but no other references are made in the documentation.
Raspbian uses screen blanking
Raspbian does not come installed with xscreensaver or other package to control the screen off time. Instead, it relies mostly on X to "blank screen". This can be managed with the xset command as a superuser. The canonical way to do this is reported in the hardware-specific Stack Exchange (here).
End-users cannot be trusted
In my case, the program will be used by folks who are barely computer literate. The result must be user-friendly and not expect the user to ever touch a terminal, let alone to make permanent changes to the startup config of X. While one option would be to distribute the program as a customized Raspbian disk image, I would like to explore other options.
I need to see an example
While there were some places to start using this question, implementing them is problematic. When I attempt to use the following MWE with and without the commented line, nothing happens. I cannot simulate the screen blanking function.
#include <X11/extensions/scrnsaver.h>
int main() {
// XScreenSaverSuspend;
XForceScreenSaver;
usleep(1000000);
return 0;
}
You have to pass parameters to the function:
void XScreenSaverSuspend(Display *dpy, Bool suspend);
#include <X11/extensions/scrnsaver.h>
int main() {
XScreenSaverSuspend (display, True);
usleep(1000000);
return 0;
}
But I don't think you have time to see the result with this program and when program ends the screensaver goes back to its previous state.
For your GTK framework, you can obtain the Display use:
Display *
gdk_x11_display_get_xdisplay (GdkDisplay *display);
Docs here.
For X:
/* use the information from the environment variable DISPLAY
to create the X connection:
*/
Display * dis = XOpenDisplay((char *)0); // or ":0.0"
A hacky, OS-specific solution:
Raspbian does not appear to require super user elevation to modify the xset. Adding the line to the code:
system("xset -dpms");
system("xset s off");
is sufficient to turn off the power management settings and the screensaver.
This is obviously sloppy, and it potentially leaves the OS in an undesirable state if the program breaks before these have a chance to be reset to default values. More elegant answers are encouraged.
There are multiple questions that ask about capturing keystrokes, but the solutions provided have some complications.
ncurses termios structure/stty
-Changes the console settings so that SIGSTOP/SIGTERM would leave the setting in effect for the terminal.
X based solutions
-requires X server to be running(not that is is a huge problem, but it seems unnecessary to bring X server calls into a console application)
/dev/input/event*
-requires root
Vim seems to be able to capture keystrokes without root, an X server, and without changing the console settings. Does anyone know how vim is able to achieve this in linux?
Look at TTY raw mode -- there is a ioctl call which allows you to get individual keystrokes -- i.e. taking the tty out of line mode which is the default.
A quick search on ioctl raw give this link which looks ok.
How can you set a string to be used instead of standard input? For example, when running the latex command in Unix it will always find some trivial errors, to skip through all errors you have to enter "r" into the command line (I now know that with latex specifically you can use -interactionmode nonstopmode, but is there a more general solution to do this?)
Is there anyway to specify that this should be done automatically? I tried redirecting standard input to read from a file containing "r\n", but this didn't work.
How can I achieve this?
Not all applications that need input can be satisfied with their stdin redirected.
This is because the app can call the isatty C function (if written in C, or some equivalent call for other languages) to determine if the input come from a tty or not.
In such situation, there is a valuable tool to use, and this is expect.
latex --interaction=MODE
where MODE is one of:
errorstopmode: stop at every error and ask for input
scrollmode: scroll over non-fatal errors, but stop at fatal errors (such as "file not found")
nonstopmode: scroll over non-fatal errors, abort at fatal errors
batchmode: like nonstopmode, but don't show messaes at the terminal
For interactive use, errorstopmode (the default) is fine, for non-interactive use, nonstopmode and batchmode are better.
But beware, there are no trivial errors: all errors must be fixed, and all warnings should be fixed if possible.
Redirecting stdin works without problems here:
/tmp $ tex '\undefined\end' <<< r
This is TeX, Version 3.1415926 (TeX Live 2010)
! Undefined control sequence.
<*> \undefined
\end
? OK, entering \nonstopmode...
(see the transcript file for additional information)
No pages of output.
Transcript written on texput.log.
You've got two plausible answers detailing the way to handle Latex specifically. One comment indicates that you need a more general answer.
Most usually, the tool recommended for the general solution is 'expect'. It arranges for the command to have a pseudo-tty connected for input and output, and the command interacts with the pseudo-tty just as it would your real terminal. You tell 'expect' to send certain strings and expect certain other strings, with conditional code and regular expressions to help you do so.
Expect is built using Tcl/Tk. There are alternative implementations for other languages; Perl has an Expect module, for example.
From the man page:
-interaction mode
Sets the interaction mode. The mode can be either batchmode, nonstopmode, scrollmode, and errorstopmode. The meaning of these modes is the same as that of the corresponding \commands.
Looks like -interaction nonstopmode might help you.
I'm writing a game in assembly, and I need to check if a key was pressed.
So, how is kbhit implemented in Linux?
Thanks.
Google turned up a kbhit implementation for Linux in C: http://cboard.cprogramming.com/c-programming/63166-kbhit-linux.html
You could either compile this as is and call it from your assembly code, or if you really want to you could convert it to assembly.
I assume that you want also key releases. I also assume you are on the console (for X, XKeyEvent has enough info).
First, you have to put your terminal (i.e: console) in non-canonical or in raw mode. If you don't do this, you won't see any input until there is a line delimiter or EOF on input. See my answer to your previous question.
Then, to get key releases, you want to set the keyboard to RAW or MEDIUMRAW mode (this has nothing to do with terminal raw mode, this is very Linux and console specific, see console_ioctl(4)). Don't forget to set the keyboard back to its original mode before exiting.
There's a nice article about this here.
How to make a Linux program in the Command Line Interface who display a nice user interface?
For example when I use "wget" to download a file from internet, I can see the download advancement in the Command Line Interface. How can I do that?
ncurses is a popular option, there are APIs for lots of programming languages.
Take a look at curses. It is a library for text based UI.
You can get a basic interface by using \r to go to the beginning of the current line.
Slightly more advanced is ncurses.
The next step up is Newt.
If you want to do a GUI for Bash scripts or to wrap around other command line utilities, you can use dialog (man page).
Here two great dialog tutorial to get you started :
Dialog: An Introductory Tutorial
Improve Bash Shell Scripts Using Dialog.
If you only need a progress bar, this can be done directly with a simple print (that prints the bar), followed by the carriage return character (ANSI character #13), which puts you back at the beginning of the line. The line can then be later updated by printing over it.
For more complicated needs, ncurses is indeed the standard way to go.
I wouldn't call wget's progress report as a 'nice gui', but anyway, the classic library for building graphical interfaces without X Windows is Linux and UNIX systems is ncurses.
Recently a C# version of ncurses has been started, check out details here
If you're using Mono, you could use MonoCurses
Try curses, it is a well documented API for text based UI.Also, there is so much open source projects that are using curses for you see and learn
wget does not really have a GUI, all I see is stuff that you can already achieve using stdout and echos (e.g. printf() or std::cout)
Anyways, for simple dialog boxes of the MessageBox kind, but not limited to that, also have a look at dialog
http://linux.die.net/man/1/dialog
http://hightek.org/dialog/
You can just use ANSI escape codes. A simple example in bash
echo -e "\033[H\033[2J \033[20;20H \033[4mThis is a underlined line.\033[0m"
One should mention FTXUI. Functional Terminal (X) User interface: A simple C++ library for terminal-based user interfaces!
Cross-Platform
Support for UTF8 and fullwidth chars (→ 测试)
No dependencies
etc