最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - How can I detect when user press arrow key? - Stack Overflow

programmeradmin0浏览0评论

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
Add a comment  | 

2 Answers 2

Reset to default 2

This 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!!! :)

发布评论

评论列表(0)

  1. 暂无评论