天天看點

C語言編寫Linux終端環境下無緩沖鍵盤輸入 ,并識别上下左右光标鍵鍵盤中上、下、左、右四個光标鍵所對應的ASCII碼值為多少

自己重構了遊戲《2048》并且重構了它的最好啟發式AI解法,并上傳到了Gitee中的 ​​鬼&泣​​​ / ​​2048-heuristic​​的devilmaycry分支,在這個過程中編寫了一個C語言版的“無緩沖鍵盤輸入 ,并識别上下左右光标鍵”的代碼,這裡記錄一下以備以後使用時檢視。

代碼位址:

​​cpp_source/environment/keyboard_run_app.cpp​​

 第一部分代碼:

struct termios cooked, raw;

// 恢複之前的鍵盤輸入和終端緩存的設定
void keyboard_close(int sig=0)
{
    int kfd = 0;
    (void)sig;
    PRINT_ATTR_REC                      // 終端字型顔色恢複
    // system("clear");                 // 情況螢幕
    tcsetattr(kfd, TCSANOW, &cooked);//在程式結束時在恢複原來的配置
    exit(0);
}


// 設定鍵盤輸入,設定終端無緩存輸入
void keyboard_open()
{
    signal(SIGINT, keyboard_close);    // 捕獲Ctrl+C, 中斷退出

    int kfd = 0;

    // get the console in raw mode
    tcgetattr(kfd, &cooked); // 得到 termios 結構體儲存,然後重新配置終端
    memcpy(&raw, &cooked, sizeof(struct termios));
    raw.c_lflag &=~ (ICANON | ECHO);
    // Setting a new line, then end of file
    raw.c_cc[VEOL] = 1;
    raw.c_cc[VEOF] = 2;
    tcsetattr(kfd, TCSANOW, &raw);
}      

keyboard_open函數設定無緩沖的鍵盤輸入模式并儲存原始的終端設定。在signal函數中設定對ctrl+c的捕獲并進行終端設定的恢複操作及程式退出操作。

第二部分,對光标鍵的處理

#define KEYCODE_R 185

#define KEYCODE_L 186

#define KEYCODE_U 183

#define KEYCODE_D 184

相關代碼:

fflush(stdin);
        // get the next event from the keyboard
        if(read(kfd, &c, 3) < 0)
        {
            perror("read(): Error!!! ");
            exit(-1);
        }

        all_sum = c[0]+c[1]+c[2];
        // printf("sum:  %d \n", s);

        switch(all_sum)
        {
            case KEYCODE_L:
                _info = "Left Button Pressed, Numbers of attempt: "+std::to_string(i);
                // printf("[******] Wrong input, Left Button Pressed, Numbers of attempt: %d\n", i);
                move = 2;
                break;
            case KEYCODE_R:
                _info = "Right Button Pressed, Numbers of attempt: "+std::to_string(i);
                // printf("[******] Wrong input, Right Button Pressed, Numbers of attempt: %d\n", i);
                move = 3;
                break;
            case KEYCODE_U:
                _info = "Up Button Pressed, Numbers of attempt: "+std::to_string(i);
                // printf("[******] Wrong input, Up Button Pressed, Numbers of attempt: %d\n", i);
                move = 0;
                break;
            case KEYCODE_D:
                _info = "Down Button Pressed, Numbers of attempt: "+std::to_string(i);
                // printf("[******] Wrong input, Down Button Pressed, Numbers of attempt: %d\n", i);
                move = 1;
                break;
            default:
                printf("[******] Wrong input, value: %c = 0x%02X = %d, Numbers of attempt: %d\n", c[0], c[0], c[0], i);
        }      

由于光标鍵是組合鍵,是以需要讀入三個字元才能判斷,這裡采用的函數為:read(kfd, &c, 3) ,畢竟神奇的地方是這個函數可以在較短時間(如:0.0001秒)内最多讀入三個字元,是以該函數可以識别所有的鍵盤按鍵的輸入,不僅可以識别組合ASCII碼的按鍵,而且還能識别單ASCII碼的按鍵。這種一次性最多讀入N個字元的操作比較少見,這裡也不是很懂,也就當記錄一下不深入研究了,本想用python語言實作類似的功能最後還是沒有成功,或許這種功能還是系統原生的C語言比較好實作一些。

==============================================

提醒一下,這個代碼隻有片段不能直接運作編譯,在Gitee上的該部分代碼是作為子子產品存在的,并沒有編寫main函數,如果想編譯執行還需要自己手動加上main函數,由于隻需要簡單的添加入口main函數即可編譯執行這裡也就不過多給出代碼了。