1 OverView
さて、Cursesであります。
あ、受け狙いじゃなくて、僕がElixirを理解するために、必要な経験だと思って書いております。
まずは、Cursesから紹介したいと思います。Cursesと呼んでますが、現在主流となっているのはncurses。
ncurses(new curses)は、ターミナルベースのユーザーインターフェースを作成するためのライブラリです。
もともとはSystem V Release 4.0(SVr4)のcursesライブラリのエミュレーションとして開発されましたが、
現在では多くの機能拡張が行われています
端末ベースのアプリ、特にvimやEmacsなどのテキストエディタでお世話になっていると思います。
https://invisible-island.net/ncurses/announce.html
見覚えあるUNIXのアプリケーション、多くないですか?
こいつをElixirから使得る様になるのが、ExNcursesです。
今回は、どういうものか?を先に書こうと思います。
回 | 内容 |
---|---|
第一回 | Elixirへのex_ncursesへのインストール説明 |
第二回 | ElixirのAPIの説明 |
しなくてはなりません | |
第三回 | Elixirで、スカッシュゲームを作ってみよう |
第四回 | ExNCursesのサンプルコード解説 |
2. 解説なんぞを。
2.1 まずは、ExNCursesの解説から。
最初に、一番ややこしいところを説明しましょう。読み飛ばしてくれて構いません。
ぶっちゃけ、後でわかるw
まずは、hexdocの引用から行きましょう。
https://hexdocs.pm/ex_ncurses/ExNcurses.html
ExNcurses lets Elixir programs create text-based user interfaces using ncurses.
ExNcursesは、Elixirプログラムがncursesを使用してテキストベースのユーザーインターフェースを作成できるようにします。
続いて、
Aside from keyboard input, ExNcurses looks almost like a straight translation of the C-based ncurses API. ExNcurses sends key events via messages.
キーボード入力を除けば、ExNcursesはCベースのncurses APIのほぼ直訳のように見えます。ExNcursesはキーイベントをメッセージとして送信します。
「ExNcursesはCベースのncurses APIのほぼ直訳のように見えます」
ここが重要で、非常に簡単に、テキストベースのWindowを出すアプリケーションを構築出来ます。
また、「ExNcursesはキーイベントをメッセージとして送信します」と言う部分についてですが、これまた、簡単です。
画面に対して、キーが押された場合、
ハンドルするコードは、以下の様なものになります。 抜粋すると…
# ターミナルからの入力を待ち受けます。ユーザーがキーを押すのを待ち、その入力を処理します。
ExNcurses.listen()
receive do
# :ex_ncursesのプロセスから、イベントを受け取っている
{:ex_ncurses, :key, key} ->
handle_key(state, key)
end
# wasdそれぞれのキーをハンドルする、上記のhandle_keyと、関数の引数keyでパターンマッチングしている。
defp handle_key(state, ?w), do: %{state | direction: :up}
defp handle_key(state, ?a), do: %{state | direction: :left}
defp handle_key(state, ?s), do: %{state | direction: :down}
defp handle_key(state, ?d), do: %{state | direction: :right}
…これだけです。うん、これだけなんだ、「あ、Elixirの機能知らんと出来ないな」ってところは。
2.2 そしてサンプル…みたら驚くよ。
では、Hello worldから行きましょう。
Application.ensure_started(:ex_ncurses)
ExNcurses.initscr()
ExNcurses.mvprintw(4, 8, "Hello, 🐄\n")
ExNcurses.refresh()
ExNcurses.getch()
ExNcurses.endwin()
一行ずつ解説していきます。
ぶっちゃけ、Copilotに解説させた方が早いってくらいにシンプルです。
- Application.ensure_started(:ex_ncurses):
この行は、:ex_ncurses アプリケーションが開始されていることを確認します。ライブラリを使用する前に初期化するために必要なステップです。 - ExNcurses.initscr():
描画用の画面を初期化します。ExNcurses を使用する際に最初に呼び出す関数です。 - ExNcurses.mvprintw(4, 8, "Hello, 🐄\n"):
この関数はカーソルを画面上の位置 (4, 8) に移動し、文字列 "Hello, 🐄\n" を表示します。座標 (4, 8) は画面上の行と列の位置を表します。 - ExNcurses.refresh():
この関数は画面を更新して、行われた変更を反映させます。新しい内容を表示するためにこの関数を呼び出す必要があります。 - ExNcurses.getch():
この関数はユーザーの入力(キー押下)を待ちます。プログラムを一時停止して、ユーザーがキーを押すのを待つ役割を果たします。 - ExNcurses.endwin():
この関数は ncurses セッションを終了し、ターミナルを通常の状態に戻します。ncurses の使用が終わったら最後に呼び出す関数です。
くれぐれも1.のensure_startedを忘れない様にお願いします。
このプロセスが、Elixirのアプリケーションと、端末のキーの入力などを取り持ちます。
さて、ここからは本当に簡単、ExNcurses.initscr()で画面を初期化したら、その初期化した画面に対して、描画(上の例ではExNcurses.mvprintw)、描画を追えたら、ExNcurses.refresh/0で画面をリフレッシュしたら、画面に文字列が表示されます。
この、描画する関数を呼び出す -> 全部呼び出すのが終わったら、リフレッシュを言う流れを覚えてください。難しいのはここだけですね。
2.3 ウィンドウについて
Linuxの端末なのに、複数の画面に分かれてるアプリケーション、見たことないですな?
え?見たことない?ではEmacsを…とか言うと怒られるので、サンプルを実行してみましょう。
マルチ画面にする前に、まずは、端末の画面の中に、新しい画面を作成し、そこに対して"Hello, Window!"と描画してみましょう。
defmodule NcursesExample do
def run do
Application.ensure_started(:ex_ncurses)
ExNcurses.initscr()
win = ExNcurses.newwin(10, 20, 5, 5) # 新しいウィンドウの作成
# winウィンドウ内のカーソル位置を(y, x)に移動します。これにより、次に描画される文字の位置が指定されます。
ExNcurses.wmove(win, 1, 1)
ExNcurses.waddstr(win, "Hello, Window!") # ウィンドウに文字列を表示
ExNcurses.wrefresh(win) # ウィンドウを更新
ExNcurses.getch() # キー入力を待つ
ExNcurses.delwin(win) # ウィンドウを削除
ExNcurses.endwin()
end
end
NcursesExample.run()
表示する座標が変わってることに気づきでしょうか?
新しい関数を紹介しておきましょう。
ExNcurses.newwin(nlines, ncols, begin_y, begin_x)
説明: 新しいウィンドウを作成します。
パラメータ:
- nlines: ウィンドウの行数
- ncols: ウィンドウの列数
- begin_y: ウィンドウの開始位置(y座標)
- begin_x: ウィンドウの開始位置(x座標)
戻り値: 作成されたウィンドウのポインタ
ExNcurses.wmove(win, y, x)
説明: 指定したウィンドウ内でカーソルを新しい位置に移動します。
パラメータ:
- win: ウィンドウのポインタ
- y: 新しい行位置
- x: 新しい列位置
戻り値: 成功した場合は0、失敗した場合はエラーコード
ExNcurses.wprintw(win, "Hello, Window!")
説明: 指定したウィンドウに文字列を書き込みます。
パラメータ:
- win: ウィンドウのポインタ
- str: 書き込む文字列
戻り値: 成功した場合は0、失敗した場合はエラーコード
これらの関数を使用することで、ex_ncursesライブラリを使ったウィンドウ操作が可能になります。詳細はこちらで確認できます。
では、お待ちかね、Windowを増やしてみましょう。
defmodule NcursesExample do
def run do
Application.ensure_started(:ex_ncurses)
ExNcurses.initscr()
win1 = ExNcurses.newwin(10, 20, 5, 5) # 新しいウィンドウの作成
win2 = ExNcurses.newwin(10, 20, 5, 26) # 新しいウィンドウの作成
# winウィンドウ内のカーソル位置を(y, x)に移動します。これにより、次に描画される文字の位置が指定されます。
ExNcurses.wmove(win1, 1, 1)
ExNcurses.wmove(win2, 1, 1)
ExNcurses.waddstr(win1, "Hello, Window1!") # ウィンドウに文字列を表示
ExNcurses.waddstr(win2, "Hello, Window2!") # ウィンドウに文字列を表示
ExNcurses.wrefresh(win1) # ウィンドウを更新
ExNcurses.wrefresh(win2) # ウィンドウを更新
ExNcurses.getch() # キー入力を待つ
ExNcurses.delwin(win1) # ウィンドウを削除
ExNcurses.delwin(win2) # ウィンドウを削除
ExNcurses.endwin()
end
end
NcursesExample.run()
Windowsが二枚に増えましたね。
Hello, windows1とHello, windows2が別々のWindowsに「それぞれの座標に」描写されている
ことにご注意ください。
まとめ
さて、今回は端末への描写、Windowの作成をやってみました。
出来るのと便利は違う、と怒られそうなサンプルばかりになりましたね。
では、次回は「Elixirで、スカッシュゲームを作ってみよう」と題して、便利であることを
ごらんに入れたいと思います。
ほら、あれですよ!あれ!
「一週間待ってください、本物のEx_ncursesを御覧に入れますよ」
って山岡士郎がかっこつけるやつです。。。うん、がんばるね。