C++ ncursesとthreadで処理を継続しながらキーボード入力を受け付ける方法

photo of person typing on computer keyboard

コンソールゲームのプログラミング等では、ユーザーのキー入力がない状態でも画面描画を更新し続け、かつユーザーがキーボード入力をした際に次の描画処理に反映させるということがあります。

このような要件は以下の二つを組み合わせることで実現可能です。

  • ncursesによるキー入力処理
  • threadによるmainとは別スレッドによるリアルタイム処理の継続

本記事では簡単なサンプルアプリケーションを使って実際にncursesとthredを組み合わせてリアルタイムキー入力アプリケーションのデモを作ります.

目次

サンプルプロジェクトのファイル構成

CMakeLists.txt
main.cpp

ファイルの中身

#include <ncurses.h>
#include <future>

bool now_playing = true;
int i = 0;

void loop_test1();
void loop();
void draw();

int main() {
    loop_test1();
}

void loop_test1()
{
    initscr(); //start ncurses window
    noecho(); //キーが入力されても表示しない
    curs_set(1);//カーソルを非表示

    //Thread start
    auto th_loop = std::thread([] {loop();});

    while(now_playing) {
        char ch = getch();
        switch (ch) {
            case 'a':
                i++;
                break;
            case 'b':
                i--;
                break;
        }
    }
    th_loop.join();
    endwin(); // end ncurses window
}

void loop()
{
    while (now_playing)
    {
        clear();
        draw();
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        refresh();
    }
}

void draw()
{
    printw("%d ", i);
}
cmake_minimum_required(VERSION 3.24)
project(timer_test)

set(CMAKE_CXX_STANDARD 17)

add_executable(timer_test main.cpp)


find_package(Curses REQUIRED)
include_directories(${CURSES_INCLUDE_DIR})
target_link_libraries(timer_test ${CURSES_LIBRARIES})

ビルドと実行

$ cmake .
$ make
$ ./timer_test

カウンターの初期値は1です。aを押すとカウンターが1増加します。bを押すとカウンターが1減少します。1秒ごとに現在のカウンターの値を描画します。

処理の説明

  • loop_test1()の中でキーボード入力の処理をループします。
    • キーボード操作によってクラスをスコープに持つカウンターの変数を増減します。
  • loop()の中で画面描画の処理をループします。
    • クラスをスコープに持つカウンターの変数を参照して描画します。
よかったらシェアしてね!
目次