C言語:標準入力と矢印キー

C言語のプログラムで矢印キーの入力を受けるにはどうすればよいか?

Windowsの場合

_getch() でキー入力を受け取ると、矢印キーなどは以下のような値になる。

キー キー
0xE0, 0x48(H) Home 0xE0, 0x47(G)
0xE0, 0x50(P) End 0xE0, 0x4F(O)
0xE0, 0x4D(M) PgUp 0xE0, 0x49(I)
0xE0, 0x4B(K) PgDn 0xE0, 0x51(Q)
Enter 0x0D(CR) Delete 0xE0, 0x53(S)
Esc 0x1B(ESC) BackSpase 0x08(BS)
#include <stdio.h>
#include <conio.h>

int main()
{
    while (1) {
        while (!_kbhit()) {;}
        printf("kbhit: ");
        int ch = _getch();
        if (ch == 0xE0) {
            ch = _getch();
            switch (ch) {
            case 0x48: printf("Up\n");    break;
            case 0x50: printf("Down\n");  break;
            case 0x4D: printf("Right\n"); break;
            case 0x4B: printf("Left\n");  break;
            default: printf("Special Key %02X\n", ch); break;
            }
            continue;
        }
        printf("'%c' (%02X)\n", ch, ch);
        if (ch == 'q') break;
    }
    printf("\nQuit\n");
    return 0;
}

Linuxの場合 (1)

以前の記事で、Linuxで kbhit() / getch() 相当の機能を実現する方法を述べた。
関連:Linuxで kbhit() と getch() - 滴了庵日録

この場合、矢印キーなどは以下のような値になる。

キー キー
0x1B(ESC), 0x5B([), 0x41(A) Home 0x1B(ESC), 0x5B([), 0x48(H)
0x1B(ESC), 0x5B([), 0x42(B) End 0x1B(ESC), 0x5B([), 0x46(F)
0x1B(ESC), 0x5B([), 0x43(C) PgUp 0x1B(ESC), 0x5B([), 0x35(5), 0x7E(~)
0x1B(ESC), 0x5B([), 0x44(D) PgDn 0x1B(ESC), 0x5B([), 0x36(6), 0x7E(~)
Enter 0x0A(LF) Delete 0x1B(ESC), 0x5B([), 0x33(3), 0x7E(~)
Esc 0x1B(ESC) BackSpase 0x7F(DEL)
#include <stdio.h>
#include "kbhit.h"

int main()
{
    kb_begin();

    while (1) {
        while (!kbhit()) { ; }
        printf("kbhit: ");
        int ch = getch();
        if (ch == 0x1B) {
            ch = getch();
            if(ch == 0){
                printf("ESC\n");
            }
            else if(ch == '['){
                ch = getch();
                switch (ch) {
                case 'A': printf("Up\n");    break;
                case 'B': printf("Down\n");  break;
                case 'C': printf("Right\n"); break;
                case 'D': printf("Left\n");  break;
                default: printf("Special Key %02X\n", ch); break;
                }
            }
            continue;
        }
        printf("'%c' (%02X)\n", ch, ch);
        if (ch == 'q') break;
    }
    printf("\nQuit\n");
    kb_end();

    printf("\nQuit\n");
    return 0;
}

Linuxの場合 (2)

もう一つの方法として、ncursesライブラリを使うやりかたもある。

まず、Ubuntu等では下記のコマンドでライブラリをインストールする。

sudo apt install libncurses5-dev

ncursesライブラリでは、矢印キーなどは以下のような値になる。

キー 定数名 / 値 キー 定数名
KEY_UP Home KEY_HOME
KEY_DOWN End KEY_END
KEY_RIGHT PgUp KEY_PPAGE
KEY_LEFT PgDn KEY_NPAGE
Enter 0x0A(LF) Delete KEY_DC
Esc 0x1B(ESC) BackSpase KEY_BACKSPACE
#include <ncurses.h>

int main()
{
    initscr(); // ncursesモードの初期化
    raw();     // 入力をバッファリングせずに受け取る      
    noecho();  // 入力文字を画面に表示しない
    keypad(stdscr, TRUE); // 特殊キー入力を有効にする      

    while (1) {
        int ch = getch();
        printw("getch: ");
        switch(ch) {
            case KEY_UP:    printw("Up\n");    break;
            case KEY_DOWN:  printw("Down\n");  break;
            case KEY_RIGHT: printw("Right\n"); break;
            case KEY_LEFT:  printw("Left\n");  break;
            default: 
                printw("'%c' (%02X)\n", ch, ch);
        }
        if (ch == 'q') break;
        refresh();  // 画面を更新
    }
    printf("\nQuit\n");
    endwin();  // ncursesモードの終了
    return 0;
}

printf()のかわりにprintw()を使うことに注意。
ビルドは以下のようにライブラリを指定する。

gcc main.c -lncurses