Skip to content

Instantly share code, notes, and snippets.

@reagent
Last active September 13, 2021 15:13
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save reagent/9743630 to your computer and use it in GitHub Desktop.
Save reagent/9743630 to your computer and use it in GitHub Desktop.
Curses + C Example
#include <ncurses.h>
#include <unistd.h>
#define DELAY 35000
int main(int argc, char *argv[]) {
int x = 0,
y = 0;
int max_x = 0,
max_y = 0;
int next_x = 0;
int direction = 1;
initscr();
noecho();
curs_set(FALSE);
getmaxyx(stdscr, max_y, max_x);
x = max_x / 2;
y = max_y / 2;
while (1) {
getmaxyx(stdscr, max_y, max_x);
y = max_y / 2;
clear();
mvprintw(y, x, "o");
refresh();
usleep(DELAY);
next_x = x + direction;
if (next_x >= max_x || next_x < 0) {
direction*= -1;
} else {
x+= direction;
}
}
endwin();
return 0;
}
CFLAGS=-Wall
LDFLAGS=-lncurses
all: demo
clean:
rm -rf demo
@xaymup
Copy link

xaymup commented Sep 25, 2014

demo.c: In function ‘main’:
demo.c:19:10: error: ‘FALSE’ undeclared (first use in this function)
demo.c:19:10: note: each undeclared identifier is reported only once for each function it appears in
demo.c:21:10: error: ‘stdscr’ undeclared (first use in this function)

What's going on here?

@ButchDean
Copy link

What does your makefile look like? This works fine for me.

CFLAGS = -g -Wall
LDFLAGS = -lncurses

.PHONY: clean

all:
    gcc $(CFLAGS) demo.c -o demo $(LDFLAGS)

clean:
    rm -rf demo

@Focx-o
Copy link

Focx-o commented Dec 17, 2014

Sir what if i want to use KEY_F(1) to exit from this loop ? .. i don't want to use ctrl+c to exit ..

@erm3nda
Copy link

erm3nda commented Feb 14, 2017

@reagent
Nice example :-)
It looks like 1/3 stage of a pong game :-) based on ncurses.

@ButchDean
Thank you for posting a proper makefile.
I think that @xaymup has added reference to variable without declare it first.

@Meliodus
Read: http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/keys.html
Read more: https://www.mkssoftware.com/docs/man3/curs_getch.3.asp

char ch; // declare it first
ch = getchar();
printf( "Input Char Is :%c", ch ); // press F1 then look for return, should be int 265
if ( ch == 265 ) {
    printf( "Got it" )
    }
}

Even easier, using KEY_F(num) to avoid remembering the int value:

ch = getchar()
if ( ch == KEY_F(1) ) {
    printr( "Got %c !", ch )
}

The problem is that usually F keys are binded to somewhat at the OS and the program will not respond to them unless you add proper binding to the SO at the execute time.

--- About your question:
So, case you wanna exit with single key (ctrl+c will work anyway), you need to ad something like that at the start or end of loop:

if ((ch = getchar()) == 100) { // 100 means a "d"
  break;
}

The problem with that is that the loop freezes (waits) untill getchar() returns something.
To solve that you have to use any kind of keyboard detector. More info about it (kbhits()) at: http://stackoverflow.com/questions/13547471/c-programming-check-if-key-pressed-without-stopping-program

I tried the Linux version of kbhits but ended with:

gcc -Wall demo.c -o demo -lncurses
In file included from demo.c:4:0:
kbhit.c: In function ‘_kbhit’:
kbhit.c:16:9: error: unknown type name ‘termios’
... and much more lines...

... that i've pasted to: http://pastebin.com/1VRdFdPQ.

So, finally i read a bit more on the ncurses docs and found the timeout() function, being the solution like this:

timeout(10)
if ((ch = getch()) == 100) { // 100 means a "d". Note also that i used getch() not getchar()
  break;
}

Code working that stops with d (i can't bind to f1, try on your own) HERE: http://pastebin.com/xyfm7LNa
Going to sleep :-D

Copy link

ghost commented Dec 16, 2017

haha!

@jcsahnwaldt
Copy link

You should replace LDFLAGS by LDLIBS. Here's a quote from the entry for LDFLAGS in the GNU make manual:

Libraries (-lfoo) should be added to the LDLIBS variable instead.

You could then simplify your Makefile to something like this:

CFLAGS = -g -Wall
LDLIBS = -lncurses

.PHONY: clean

all: demo

clean:
    rm -rf demo

@pauljones0
Copy link

pauljones0 commented Oct 18, 2020

@Meliodus @erm3nda I found a better way to exit the program. If you state that the getch() should be non-blocking, it instantly is.

Just call this in the main:
nodelay(stdscr, TRUE)

then do the other stuff:

int ch;
if ((ch = getch()) == KEY_F(1)) {//F1 will make you escape here
break();
}

should do the trick.

See for more details:
https://www.gnu.org/software/guile-ncurses/manual/html_node/Getting-characters-from-the-keyboard.html
http://www.cs.ukzn.ac.za/~hughm/os/notes/ncurses.html#using

@arydevy
Copy link

arydevy commented Dec 2, 2020

Sir what if i want to use KEY_F(1) to exit from this loop ? .. i don't want to use ctrl+c to exit ..

change it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment