So I am building terminal based snake game and for snake to turn around i need to know when user presses arrow keys
This is my code for now
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
char get_key() {
struct termios oldt, newt;
char ch;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
int main() {
system("clear");
int snake_health = 3;
bool horizontal = true;
for (int i = 0; i <= snake_health; i++) {
if (i == snake_health)
printf(">");
else
printf("=");
}
while (1) {
char key = getchar();
if (key == 's') {
break;
}
printf("%c", key);
system("clear");
}
return 1;
}
I tried getchar() but it won't have any use in my project couse I want to get inputs in real time, other than that I have only tried what you can see in code but it won't work for arrow keys.
So I am building terminal based snake game and for snake to turn around i need to know when user presses arrow keys
This is my code for now
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
char get_key() {
struct termios oldt, newt;
char ch;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
int main() {
system("clear");
int snake_health = 3;
bool horizontal = true;
for (int i = 0; i <= snake_health; i++) {
if (i == snake_health)
printf(">");
else
printf("=");
}
while (1) {
char key = getchar();
if (key == 's') {
break;
}
printf("%c", key);
system("clear");
}
return 1;
}
I tried getchar() but it won't have any use in my project couse I want to get inputs in real time, other than that I have only tried what you can see in code but it won't work for arrow keys.
Share Improve this question edited Feb 4 at 11:51 Lundin 215k46 gold badges277 silver badges432 bronze badges asked Feb 3 at 22:14 skami0_0skami0_0 112 bronze badges 3- 2 Arrow keys typically send an escape sequence which consists of a number of characters. You may what to use a library for this, like ncurses or pdcurses. – Ted Lyngmo Commented Feb 3 at 22:17
- 1 Have a look: stackoverflow/a/75499310/2055998 – PM 77-1 Commented Feb 3 at 22:22
- Also, you might have a look at: "stackoverflow/questions/23189872/…" This happens to be in reference to a C++ program but substituting <stdlib.h> for <iostream.h> and declaring the snake structure within the "main" function should allow you to play around and give you ideas. Also note the solution of making the key input a "wchar_t" definition. – NoDakker Commented Feb 4 at 1:42
2 Answers
Reset to default 2This works for me on Linux.
It detects the arrow keys and prints the other characters.
You will need to add code to move the snake and probably do not want to print the other characters.
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define KEY_ESCAPE 0x001b
#define KEY_ENTER 0x000a
#define KEY_UP 0x0105
#define KEY_DOWN 0x0106
#define KEY_LEFT 0x0107
#define KEY_RIGHT 0x0108
#define STDIN 0
struct termios original, changed;
void termset ( void) {
tcgetattr ( STDIN, &original);
changed = original;
changed.c_lflag &= ~( ICANON | ECHO); // echo off and read character as available
}
int kbhit ( ) {
int bytesWaiting;
usleep ( 1200);
ioctl ( STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
int getch ( void) {
int c;
c = getchar ( );
if ( c == KEY_ESCAPE) {
c = getchar ( );
if ( c == '[') {
switch ( getchar ( )) {
case 'A':
c = KEY_UP;
break;
case 'B':
c = KEY_DOWN;
break;
case 'C':
c = KEY_RIGHT;
break;
case 'D':
c = KEY_LEFT;
break;
default:
c = 0;
break;
}
}
}
return c;
}
void clearScreen ( ) {
printf ( "\033[1;1H");//move to top left corner
printf ( "\033[2J");//clear screen
fflush ( stdout);
}
int main( void) {
termset ( );
tcsetattr ( STDIN, TCSANOW, &changed);
clearScreen ( );
printf ( "s or Enter to exit\n");
while ( 1) {
if ( kbhit ( )) {
int c = getch ( );
if ( EOF == c) {
break;
}
switch ( c) {
case KEY_UP:
printf ( "KEY_UP\n");
break;
case KEY_DOWN:
printf ( "KEY_DOWN\n");
break;
case KEY_RIGHT:
printf ( "KEY_RIGHT\n");
break;
case KEY_LEFT:
printf ( "KEY_LEFT\n");
break;
default:
printf ( "%c", c);
fflush ( stdout);
}
if ( '\n' == c || 's' == c) {
break;
}
}
}
tcsetattr ( STDIN, TCSANOW, &original);
return 0;
}
The quickest answer is: USE n/curses library. curses handles the multicharacter key sequences of function (like arrow) keys and gives you a special code for them. If you don't, then you have to parse the special sequence of keys generated for each key (and curses also handles that the sequences are sent without delay) so the best way to do it is using curses library. curses also makes your code terminal type independent (it will work equally in the linux console, in an HP serial terminal or in an xterm) Handles the screen update (not updating parts of the screen ---and saving terminal traffic--- which already show as expected) in an optimized way, that allows you quick screen update. It also handles the input of individual characters (raw mode) possible, without having to press return key after your input.
And vi
uses it!!! :)