🐯

curses サンプルと PDCurses のビルド

2025/01/13に公開

コンソール画面描画ライブラリの ncurses、PDCurses を使って何か作ってみたく思い、とりあえずサンプル。

unix系 (mac linux) は ncurses で、windows,dos 系は PDCurses で。

PDCurses は Watcom C/C++ を使えば Windows 用だけでなく dos32、dos16 用も作れるので… dos アプリを比較的楽につくれるかな、と。(→ dos アプリ作れることが目標の一つ)

curses 系での hello サンプル

getch() の timeout 設定をすれば、たとえば 50ミリ秒なら 20FPS 動作のゲーム的なモノが容易に作れるので、表示を点滅、カーソルキーで移動、ESC か Q で終了するサンプル。
※ キー入力したら timeout 時間より早く過ぎるだろうで正確な時間ではないけれど。

hello.c
// カーソル移動できる Hello world! 表示. ESC か Q で終了.
#if defined(USE_PDCURSES)
#include <curses.h>
#else
#include <ncurses.h>
#endif

int main(void) {
    // 初期化.
    enum { N = 12};                                     // Hello world! 文字数.
    int  x, y, w, h, count = 0;
    initscr();                                          // curses:(スクリーン)初期化.
    noecho();                                           // curses:キー入力で表示を行わない.
    cbreak();                                           // curses:入力バッファリングしない.
    keypad(stdscr, TRUE);                               // curses:カーソルキーを有効にする.
    curs_set(0);                                        // curses:カーソルを表示しない.
    timeout(50);                                        // curses:50ミリ秒でgetchをtimeoutさせる指定.
    getmaxyx(stdscr, h, w);                             // curses:画面サイズ取得.
    x = (w - N) / 2;                                    // x初期位置:画面中央.
    y = (h - 1) / 2;                                    // y初期位置:画面中央.

    // 20FPS ループ.
    for (;;) {
        int k = getch();                                // curses:1文字入力. 50ミリ秒でtimeout.
        if (k == 0x1b || k == 'q' || k == 'Q')          // ESCまたは Q キーで終了.
            break;
        x = x - (k == KEY_LEFT) + (k == KEY_RIGHT);     // 左右カーソルキーで増減.
        y = y - (k == KEY_UP  ) + (k == KEY_DOWN );     // 上下カーソルキーで増減.
        x = (x < 0) ? 0 : (x > w - N) ? (w - N) : x;    // x移動範囲チェック.
        y = (y < 0) ? 0 : (y > h - 1) ? (h - 1) : y;    // y移動範囲チェック.

        erase();                                        // curses:画面バッファ クリア.
        move(y, x);                                     // curses:表示位置設定.
        if (count & 0x0c)                               // フレーム数をみて点滅させる.
            addstr("Hello world!");                     // curses:Hello world! 表示.
        ++count;                                        // フレームカウンタ更新.
        refresh();                                      // curses:画面バッファを実画面に反映.
    }
    // 終了.
    endwin();                                           // curses 終了.
    return 0;
}

mac や linux は、 ncurses が最初からあるか brew や apt 等で楽にインストールできるだろうで既にあるものとして。

cc -o hello hello.c -lncurses

だけで済むと思うので ncurses を基本として、PDCurses を使う場合は USE_PDCURSES を定義してコンパイル。

Windows コマンドラインでのコンパイラの設定

コマンドラインで各種 C/C++ コンパイラを選んで使うのは少々面倒くさいものなので、

setcc.bat : https://github.com/tenk-a/samples/blob/cmake_toolchain_and_pdcurses/curses_hello/bld/setcc.bat

というような設定バッチを作って使っている。新規コンソール窓ごとに

setcc vc143        ※ vc2022 x64 版
setcc vc141 win32  ※ vc2017 win32 版
setcc watcom       ※ c:\watcom

のような指定の1つを一度実行。(指定可能なコンパイラは、ヘルプか bat の中身参照)

基本的にコンパイラのデフォルト・インストールをベースに設定しているが、個人の環境に合わせて修正して使う想定。

PDCurses のビルド

Windows で VC や mingw であれば vcpkg を使うのもいいし、msys2/mingw だと ncurses が使えると思うけど、dos16,dos32 向けも試したいので、windows,dos については自前で PDCurses をビルドしてみる。

リポジトリ: https://github.com/wmcbrine/PDCurses

Windows 版は wincon フォルダ、DOS 版は dos フォルダで、とりあえず、そのフォルダ内で make してライブラリ生成。

そのフォルダを作業場とするので、makeオプション変えたりコンパイラを変えたりする都度、中間ファイルを消す必要があり。

※ 環境変数 PDCURSES_SRCDIR を使えば別フォルダでの作業ができるが、今回は無精。

windows 版ビルド

Windows 用に用意されている make オプションは

WIDE=Y UTF8=Y DEBUG=Y DLL=Y

WIDE は wide文字=unicode対応(cursesw)版の追加、UTF8 は char 版での utf-8 対応、DEBUG はデバッグ用コンパイル。DLL は vc, mingw のみですが shared ライブラリ生成。

現環境的には WIDE対応 UTF-8 対応でいいので、

:: vc  (vc11-vc14.3で確認)
nmake -f makefile.vc  WIDE=Y UTF8=Y
:: mingw (msys2の mingw32 ucrt64 で確認)
make  -f makefile     WIDE=Y UTF8=Y
:: watcom (1.9 2.0beta で確認)
wmake -f makefile.wcc WIDE=Y UTF8=Y
:: borland (bcc32c 使用. 一時期無料公開されてたbcc10.1で確認)
tmake -f makefile.bcc WIDE=Y UTF8=Y

のような感じに make 。
といっても先のhello.cはUTF8使ってないので WIDE も UTF8 も無くてよく。

なお vc は Cランタイムライブラリ(CRT) が DLL 版になる。
Static CRT 版で生成したい場合は

:: Release用
nmake -f makefile.vc WIDE=Y UTF8=Y  "CC=cl -nologo -MT"
:: Debug用
nmake -f makefile.vc WIDE=Y UTF8=Y DEBUG=Y "CC=cl -nologo -MTd"

のように CC の設定を上書き指定することで対応。
※最近は -MT がデフォルトになってる? DLL版に強制する場合は上記の MT を MD に置換。

dos 版ビルド

dos 版は WIDE UTF8 対応はなく、char 版のみ。

watcom 版 wmake では、

  • MODEL=s|c|m|l|h|f
  • DEBUG=Y

が指定可能。

wmake -f makefile.wcc MODEL=?

f=flat で 32bit dos(dos4gw) 用、
s=small,c=compact,m=medium,l=large,h=huge で 16bit dos用。

djgpp は、こちらで試した mingw 用 djgpp クロスコンパイラ環境を使用。
make の引数としては DEBUG=Y の選択だけなので、普通に make するだけ。

※ 他に borland 用の makefile.bcc もあるけれど、手元に動く環境ないので未検証。

4. PDCurses を使った hello のコンパイル

いろいろ無精して PDCurses/wincon、PDCurses/dos に hello.c をコピーして、そこでコンパイル。

:: vc
cl -DUSE_PDCURSES -I.. hello.c pdcurses.lib kernel32.lib user32.lib advapi32.lib
:: mingw djgpp
gcc -DUSE_PDCURSES -I.. -o hello.exe hello.c pdcurses.a
:: borland win32
bcc32c -DUSE_PDCURSES -I.. hello.c pdcurses.lib
:: watcom win32/dos32
wcl386 -DUSE_PDCURSES -I.. hello.c pdcurses.lib
:: watcom dos16 small model
wcl -DUSE_PDCURSES -I.. -ms hello.c pdcurse.lib

出来たものが実行できれば吉。
Windows 版はそのままコンソール窓で、dos 版は dosbox-x で確認。16bit dos版については msdos player でも可。

demos

ライブラリをビルドした直後、ターゲットとして demos を指定すれば PDCurses 本来のサンプル・デモがビルドできる。(本来見るべきサンプル...)

nmake -f makefile.vc WIDE=Y UTF8=Y demos # win版vc.
wmake -f makefile.wcc MODEL=S demos # dos-small版.
等等。
ソースと、出来た exe の動作を見比べてみるなり。

※ CP437(WIDE,UTF8無) と CP65001(WIDE,UTF8有) での違い確認、とか。

おわりに

cmake 使ったビルド環境がごてごてしてきたので別頁に。

Discussion