I have recently been introduced to ncurses for asynchronous keyboard key listening, and getting on well with it. One issue i'm facing is that you can only have text on the visible screen, no scrollbars. I was wondering if its possible to keep using ncurses as it is so lovely, but have the program still keep the scrollbars rather than getting to the last line and staying there.
scroll(). You have to set scrollok(win, TRUE) first. Actually if you just want to spew data like a normal terminal you only need to set scrollok() by itself.
#include <ncurses.h>
int main(void)
{
int i = 0;
initscr();
scrollok(stdscr,TRUE);
while(1)
{
printw("%d - lots and lots of lines flowing down the terminal\n", i);
++i;
refresh();
}
endwin();
return 0;
}
Related
I am redirecting the ncurses hmi to a different, already existing terminal. While the output part works fine (and is therefore not shown here), the input misses keys which then appear in the terminal as though they had been entered without ncurses.
#include <stdio.h>
#include <curses.h>
int main(int argc, char *argv[])
{
FILE *fd = fopen(argv[1], "r+");
SCREEN *scr = newterm(nullptr, fd, fd);
set_term(scr);
noecho();
keypad(stdscr, TRUE);
while (true) {
int ch = wgetch(stdscr);
printf("In %d\r\n", ch);
}
return 0;
}
I create two terminals on Ubuntu and get the name of one (let's call it the 'curses-terminal') using 'tty'. This name is then used as argument when starting the above in the other terminal.
When typing in the curses-terminal, I expect the codes of the keys to appear in the other terminal without seeing anything in the curses-terminal.
Instead, I see some of the characters diffuse into the curses-terminal without their code being displayed in the other one. This happens with normal characters when typing more quickly, but it happens especially with arrow keys and ALT- combinations, where the error rate is >> 50%.
Are there any settings which I have forgotten?
Using G.M.'s hint, I was able to reliably get all input.
Run
tail -f /dev/null
in the curses-terminal before attaching the ncurses app.
Should you be tempted (like me) though to send this command from within your app after fopen, you may end up frustrated.
I am currently trying to create a 'screen' in the console so that whenever the screen is refreshed it is cleared and then re-drawn; an example would be a program like Vim.
So far, I have used escape codes to clear the screen and then reposition the cursor after drawing some row markers. However, when this process is looped, the row markers get drawn below the previous ones, rather than in the same position again.
So if I draw 24 row markers each on a newline, then refresh the screen, I end up with 48 row marks each on a new line, rather than just the row markers in the same position again.
I have provided the example code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void drawRows()
{
for(int i = 0; i < 24; i++) write(STDOUT_FILENO, "~\r\n", 3);
}
void refreshScreen()
{
write(STDOUT_FILENO, "\x1b[2J", 4);
write(STDOUT_FILENO, "\x1b[H", 3);
drawRows();
write(STDOUT_FILENO, "\x1b[H", 3);
}
int main()
{
while(1) {
refreshScreen();
getchar();
}
return 0;
}
You can run it, enter some text and press enter. I think this should redraw the ~s in the same position but they just get get drawn below.
What am I doing wrong?
but they just get get drawn below
I guess the behavior you are describing is related that your process is "stuck" on getchar(), so the loop is not executing, because the input is line buffered. You have to set the terminal to raw mode first.
A 10 second google search resulted in https://viewsourcecode.org/snaptoken/kilo/index.html this link, which looks like a good introduction.
I am trying to clear my console each time I am going to printf something in it (Windows environment with GCC compiler). I am using CygWin and the only way I could manage to do it was with system("cmd /c cls");. That works fine but it causes the screen to blink for a fraction of a second which is obviously annoying.
Is there any alternative way of clearing console screen?
First thing I'd do is stop using cmd to do it. CygWin, assuming you're running somewhere within the shell and not a Windows console, has a "native" option in that you can use either of:
clear
tput clear
to clear the screen, without invoking the external cmd interpreter.
So, from within a program running in CygWin, you can clear the screen with a simple:
system("clear");
Of course, if you don't want to run any external executables, you can achieve the same end with curses. By way of example, the following program clears the screen for you (make sure you include -lcurses at the end of the compilation command):
#include <curses.h>
int main (void) {
WINDOW *w = initscr();
clear(); refresh(); sleep(2);
endwin();
return 0;
}
Don't get hung up on the fact that it's restored on exit, you wouldn't be using this program as a screen clearing stand-alone thing. Instead, the statements would be incorporated into your own program, between the initscr() and endwin() calls, something like:
#include <curses.h>
int main (void) {
char buf[2],
*msg = "Now is the time for all good men to come to lunch.";
WINDOW *w = initscr();
buf[1] = '\0';
clear();
refresh();
while (*msg != '\0') {
buf[0] = *msg++; addstr(buf);
if ((buf[0] == ' ') || (buf[0] == '.')) {
refresh();
sleep(1);
}
}
endwin();
return 0;
}
This program clears the screen using curses then outputs a message in word-sized chunks.
this web page:
http://man7.org/linux/man-pages/man4/console_codes.4.html
contains the common ESC sequences for handling the terminal screen/cursor position, etc
this part of the linked info is probably what you want to implement.
These escape sequences can be placed at the beginning of the buffer that you are using to output your data/text
Of special interest is ESC [ 2 j: which erases the whole screen
J ED Erase display (default: from cursor to end of display).
ESC [ 1 J: erase from start to cursor.
ESC [ 2 J: erase whole display.
ESC [ 3 J: erase whole display including scroll-back
buffer (since Linux 3.0).
I am searching for a way to automatically take a screenshot of my X server if a window is created or the contents of a windows have changed.
I am currently achieving this by listening to X11 events, but not all changes are reported.
Look at XDamageNotifyEvent, XDamageQueryExtension, XDamageCreate, XDamageSubtract from the Damage extension. This extension is used to track changing window contents.
http://www.freedesktop.org/wiki/Software/XDamage
A good source of sample code would be anything that makes thumbnails of windows. Also, any compositing window manager (Compiz, some flavors of metacity, etc.) would contain damage-tracking code.
Without the extension, you basically have to poll (update window contents in a timeout).
I know this post is quite dead. And yet, the documentation of X11 is terrible, and it took me a long time to get XDamage working in any regard. So here is an example that will print a line to the console every time the root X11 window changes, based on the documentation mentioned in Havoc's post, and loosely based on this link:
#include <stdio.h>
#include <stdlib.h>
#include <X11/extensions/Xdamage.h>
#include <X11/Xlib.h>
#include <signal.h>
int endnow = 0;
void cleanup(int SIGNUM){
endnow = 1;
}
int main(){
Display *display;
display = XOpenDisplay(":0");
if(!display){
perror("could not open display");
exit(1);
}
Window root = DefaultRootWindow(display);
int damage_event, damage_error, test;
//this line is necessary to initialize things
test = XDamageQueryExtension(display, &damage_event, &damage_error);
/*The "event" output is apparently the integer that appears in the
Xevent.type field when XNextEvent returns an XDamage event */
printf("test = %d, event = %d, error = %d\n",test,damage_event, damage_error);
//This is the handler for the XDamage interface
//See the XDamage documentation for more damage report levels
// http://www.freedesktop.org/wiki/Software/XDamage
Damage damage = XDamageCreate(display, root, XDamageReportNonEmpty);
signal(SIGINT,cleanup);
// XCloseDisplay(display);
while(endnow == 0){
XEvent event;
XNextEvent(display,&event);
printf("event.type = %d\n",event.type);
//this line resets the XDamage handler
XDamageSubtract(display,damage,None,None);
}
XCloseDisplay(display);
printf("done\n");
exit(0);
}
Naturally, if you run this from a console on the same screen as your display :0, every line it prints it will activate itself, and be kinda unstable. But it is a good demonstration if you run it from an ssh terminal on another computer.
I'm learning to program in C and want to be able to type characters into the terminal while my code is running without pressing return. My program works, however when I call initscr(), the screen is cleared - even after calling filter(). The documentation for filter suggests it should disable clearing - however this is not the case for me.
#include <stdio.h>
#include <curses.h>
#include <term.h>
int main(void) {
int ch;
filter();
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
while((ch = getch()) != EOF);
endwin();
return 0;
}
Why does the above code still clearr the screen, and what could be done to fix it?
I'm using Debian Lenny (stable) and gnome-terminal if that helps.
You would see your screen cleared in a curses application for one of these reasons:
your program calls initscr (which clears the screen) or newterm without first calling filter, or
the terminal initialization clears the screen (or makes it appear to clear, by switching to the alternate screen).
In the latter case, you can suppress the alternate screen feature in ncurses by resetting the enter_ca_mode and exit_ca_mode pointers to NULL as done in dialog. Better yet, choose a terminal description which does what you want.
Further reading:
Why doesn't the screen clear when running vi? (xterm FAQ)
Extending the answer by mike.dld, this works for me on MacOS X 10.6.6 (GCC 4.5.2) with the system curses library - without clearing the screen. I added the ability to record the characters typed (logged to a file "x"), and the ability to type CONTROL-D and stop the program rather than forcing the user to interrupt.
#include <stdio.h>
#include <curses.h>
#include <term.h>
#define CONTROL(x) ((x) & 0x1F)
int main(void)
{
FILE *fp = fopen("x", "w");
if (fp == 0)
return(-1);
SCREEN *s = newterm(NULL, stdin, stdout);
if (s == 0)
return(-1);
cbreak();
noecho();
keypad(stdscr, TRUE);
int ch;
while ((ch = getch()) != EOF && ch != CONTROL('d'))
fprintf(fp, "%d\n", ch);
endwin();
return 0;
}
Basically, curses is designed to take over the screen (or window, in the case of a windowed terminal). You can't really mix curses with stdio, and you can't really use curses to just input or output something without messing with the rest of the screen. There are partial workarounds, but you're never really going to be able to make it work the way that it sounds like you want to. Sorry.
I'd suggest either rewriting your program to use curses throughout, or investigating alternatives like readline.
Use newterm() instead of initscr(), you should be fine then. And don't forget about delscreen() if you follow this advice.