在C中读取按键;例如:箭头键、回车键

eimct9ow  于 2023-02-21  发布在  其他
关注(0)|答案(2)|浏览(177)

我知道如何使用事件来测试某个键是否被按下,但在C语言中我从未发现如何做到这一点。
我真正需要的是一个监听向上、向下、向左和向右箭头键的“KeyListener”。我需要它在 Linux 中工作,因此不需要Windows库。如果可能,不使用第三方库对我来说是最好的选择。
我想要的伪代码:

int main() {
 
    // key listener {
    // if(key == up) { // do something }
    // if(key == down) { // do something }
    // if(key == left) { // do something }
    // if(key == right) { // do something }
    // }
}
pxyaymoc

pxyaymoc1#

也可以使用SDL来读取键盘。

SDL_Event event;
  .
  .
  /* Poll for events. SDL_PollEvent() returns 0 when there are no  */
  /* more events on the event queue, our while loop will exit when */
  /* that occurs.                                                  */
  while( SDL_PollEvent( &event ) ){
    /* We are only worried about SDL_KEYDOWN and SDL_KEYUP events */
    switch( event.type ){
      case SDL_KEYDOWN:
        printf( "Key press detected\n" );

        if (event.key.keysym.sym==SDLK_UP) 
            printf( "It was the UP key\n" );

        break;
      case SDL_KEYUP:
        printf( "Key release detected\n" );
        break;

      default:
        break;
    }
  }
  .
  .

来源:http://www.libsdl.org/docs/html/guideinputkeyboard.html

wydwbb8l

wydwbb8l2#

这里有一个黑客基于我的另一个答案在这里:Capture characters from standard input without waiting for enter to be pressed。我在C或C++中使用bash系统调用来读取和解析箭头键按下。箭头键按下是3个字符,所以我一次解析3个字符,并找出是哪个箭头键。
无需按Enter键(这与使用getc()命令不同,该命令仅在按Enter键时返回)。按下箭头键后会立即检测到它们。
read_system_call_via_pipe__arrow_keypresses.c

#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h>  // For `uint8_t`, `int8_t`, etc.
#include <stdio.h>   // For `printf()`
#include <stdlib.h>

#define BUFSIZE 32

typedef enum arrowKey_e
{
    ARROWKEY_UNKNOWN = 0,
    ARROWKEY_UP,
    ARROWKEY_DOWN,
    ARROWKEY_LEFT,
    ARROWKEY_RIGHT,
} arrowKey_t;

// Modeled after my answer here: https://stackoverflow.com/a/54728664/4561887
const char* arrowKeyGetName(arrowKey_t arrowKey)
{
    const char* arrowKeyName = "TBD";

    switch (arrowKey)
    {
        case ARROWKEY_UNKNOWN:
            arrowKeyName = "ARROWKEY_UNKNOWN";
            break;
        case ARROWKEY_UP:
            arrowKeyName = "ARROWKEY_UP";
            break;
        case ARROWKEY_DOWN:
            arrowKeyName = "ARROWKEY_DOWN";
            break;
        case ARROWKEY_LEFT:
            arrowKeyName = "ARROWKEY_LEFT";
            break;
        case ARROWKEY_RIGHT:
            arrowKeyName = "ARROWKEY_RIGHT";
            break;
    }

    return arrowKeyName;
}

// Read a keyboard key press and return the character pressed, or a negative
// number in the event of an error.
// NB: for help reading output from system calls, see here:
//  1. https://stackoverflow.com/a/28971647/4561887
//  2. https://stackoverflow.com/a/18297075/4561887
arrowKey_t readArrowKeyPress()
{
    arrowKey_t arrowKeyPressed = ARROWKEY_UNKNOWN;

    // This bash cmd is from my answer here:
    // https://stackoverflow.com/a/70979348/4561887
    // `-n3` here means to read 3 chars at once, since an arrow key press
    // comes in as 3 chars.
    // The `-t .01` forces a timeout of that many seconds, which means the loop
    // interval will be this fast.
    const char* cmd = "bash -c 'read -s -t .1 -n3 c && printf \"%s\" \"$c\"'";
    FILE *fp = popen(cmd, "r");
    if (fp == NULL)
    {
        printf("\nError opening pipe!\n");
        return arrowKeyPressed;
    }

    char buf[BUFSIZE] = {0};
    char* retval1 = fgets(buf, BUFSIZE, fp);
    if (retval1 == NULL)
    {
        // printf("\nFailed to read cmd response.\n");
        // Timeout occured; just exit.
        return arrowKeyPressed;
    }

    // See meaning of this return value here:
    // https://stackoverflow.com/questions/43116/how-can-i-run-an-external-program-from-c-and-parse-its-output/28971647#comment60311936_28971647
    int retval2 = pclose(fp);
    if (retval2 == -1)
    {
        printf("\nError obtaining the cmd's exit status code.\n");
        return arrowKeyPressed;
    }
    else if (retval2 != 0)
    {
        printf("\nCommand exited with exit status code %i.\n", retval2);
        return arrowKeyPressed;
    }

    // Map the readings to arrow keys
    if ((buf[0] == 27) && (buf[1] == 91) && (buf[2] == 65))
    {
        arrowKeyPressed = ARROWKEY_UP;
    }
    else if ((buf[0] == 27) && (buf[1] == 91) && (buf[2] == 66))
    {
        arrowKeyPressed = ARROWKEY_DOWN;
    }
    else if ((buf[0] == 27) && (buf[1] == 91) && (buf[2] == 67))
    {
        arrowKeyPressed = ARROWKEY_RIGHT;
    }
    else if ((buf[0] == 27) && (buf[1] == 91) && (buf[2] == 68))
    {
        arrowKeyPressed = ARROWKEY_LEFT;
    }

    return arrowKeyPressed;
}

// int main(int argc, char *argv[])  // alternative prototype
int main()
{
    printf("Press any arrow key. Press Ctrl + C to quit.\n");
    fflush(stdout);

    while (true)
    {
        arrowKey_t arrowKeyPressed = readArrowKeyPress();
        if (arrowKeyPressed == ARROWKEY_UNKNOWN)
        {
            continue;
        }
        printf("Key pressed = %s\n", arrowKeyGetName(arrowKeyPressed));
    }

    return 0;
}

示例构建和运行输出:

eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=gnu17 read_arrow_keypresses_system_call.c -o bin/a && bin/a
Press any arrow key. Press Ctrl + C to quit.
Key pressed = ARROWKEY_DOWN
Key pressed = ARROWKEY_UP
Key pressed = ARROWKEY_LEFT
Key pressed = ARROWKEY_RIGHT
Key pressed = ARROWKEY_UP
Key pressed = ARROWKEY_DOWN
Key pressed = ARROWKEY_LEFT
Key pressed = ARROWKEY_RIGHT
Key pressed = ARROWKEY_UP
Key pressed = ARROWKEY_DOWN
Key pressed = ARROWKEY_LEFT
Key pressed = ARROWKEY_RIGHT

相关问题