3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

日本語プログラミング言語Mindの小技 「一文字直接入力」~Win32ApiのReadConsoleWで復活~

Last updated at Posted at 2025-09-14

はじめに

日本語プログラミング言語Mindの小技「一文字直接入力」について説明したいと思います。

対象読者

日本語プログラミング言語Mindのユーザー、または日本語プログラミング言語に興味のある方

この小技に関連するMind言語マニュアル

この小技に関連するMind言語仕様の記述はMind8プログラミングマニュアルに記載がありません。

Mind7の付属の上級者向けドキュメントmind7\doc\console.docmに記載があります。

C3. 廃止になった単語
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄

 ■一文字の入力機能
 UNIXでは一文字だけを入力(一行入力してから一文字取り出すのではなく、リアルタイムに一文字を得る意味で)する機能が環境依存になってしまうため、Ver.7ではサポートしません。
これに関連して以下のものが廃止になっています。
(変数)
 「先行入力文字」「先行入力文字列)
(処理単語)
 「一文字入力」「任意キーを待つ」「キー入力有り?」「一文字直接入力」
 「桁数指定で文字列入力」「スプーリング」

本機能(本記事)は、Mind7以降廃止された「一文字直接入力」(ついでに「キー入力有り?」)を、Win32ApiのReadConsoleWを使ってMind5の実装に近い状態で復活させてみようとする試みです。

本機能(本記事)は、下記のバージョンに対応しています。Mind8のLinux版は対応していません。

対応バージョン

■Mind7 ■Mind8 ■Mind9
■Windows版 □Linux版

小技の解説

Mindの小技「一文字直接入力」は一行入力してから(Enterキー押下で入力完了して)一文字取り出すのではなく、リアルタイムに一文字を得る単語です。

VT(仮想ターミナル)モード変更を実装したMindのWin32Api関連単語を使って今回も実装します。Windowsコマンドプロンプトをリアルタイム入力に対応するには、クックドモードというモードを無効化する必要があります。このモード変更はVT(仮想ターミナル)モード変更と手順は一緒で、カレントモードをマスクする値が異なるだけです。

クックドモードを無効化した後にWin32ApiのReadConsoleWで入力文字を読み取ります。

MindのAPI呼び出し手順3ステップ
「モジュールをロード」でシステムAPIのDLL名を指定します。
「モジュールの関数アドレスを得る」に「モジュールをロード」で取得したハンドラを指定して関数アドレスを取得します。
関数アドレスを取得した後は、引数の数に応じて「アドレス指定でAPI呼出しn」(n=0~8)を実行します。

この3つのステップを1つの処理単語にまとめた「API呼出しn」(n=0~8)がありますが、これは「モジュールをロード」が毎回内部で呼び出すので、同一モジュールの複数関数を組み合わせて実装する場合は前記3ステップで記述することが推奨されています。

本記事もステップ分離で記述します。

Mindプログラムソース

ライブラリ

"win32consoleapi2.src
ローカル。

モジュール名は                  文字列定数 「kernel32」。
関数名1は         文字列定数 「GetStdHandle」。
関数名2は         文字列定数 「GetConsoleMode」。
関数名3は         文字列定数 「SetConsoleMode」。
関数名4は         文字列定数 「ReadConsoleW」。
STD_INPUT_HANDLEは           数値     -10。
ENABLE_ECHO_INPUTは          数値     4。 
ENABLE_LINE_INPUTは          数値     2。
成功は                         数値 1。
失敗は                         数値 0。
有効は                         数値 1。
無効は                         数値 0。

モジュールロード失敗表示とは  (・ → ・)
    「APIモジュールのロードに失敗しました。」を 一行表示し 改行すること。
関数アドレス取得失敗表示とは  (・ → ・)
    「関数アドレス取得に失敗しました。」を 一行表示し 改行すること。
クックドモードを無効化失敗表示とは  (・ → ・)
    「クックドモードを無効化に失敗しました。」を 一行表示し 改行すること。
クックドモードを有効化失敗表示とは  (・ → ・)
    「クックドモードを有効化に失敗しました。」を 一行表示し 改行すること。
CONモード取得失敗表示とは  (・ → ・)
    「CONモードの取得に失敗しました。」を 一行表示し 改行すること。
コンソール読込失敗表示とは  (・ → ・)
    「コンソール読込に失敗しました。」を 一行表示し 改行すること。

ANDNOTとは (変数 変数 → 変数)
        変数1は 変数
        変数2は 変数
    変数2に 入れ
    変数1に 入れ
    変数2を NOTして 変数2に 入れ
    変数1と 変数2で ANDすること。    

クックドモードを変更するとは  (1/0:有効/無効 → 1/0:成功/失敗)
        有効化フラグは    変数
        モジュールハンドラは 変数
        関数アドレス1は   変数
        関数アドレス2は   変数
        関数アドレス3は   変数
        失敗フラグは         変数
        hConsoleは      変数
        currentModeは    変数
        maskは              変数

    有効化フラグに 入れ
    hConsoleを クリアし
    currentModeを クリアし
    失敗フラグを クリアし
    モジュール名を モジュールをロードし モジュールハンドラに 入れ
    エラー?
    ならば モジュールロード失敗表示し 失敗をかえす
    つぎに

    モジュールハンドラと 関数名1で
         モジュールの関数アドレスを得て 関数アドレス1に 入れる
    エラー?
    ならば 関数アドレス取得失敗表示し 失敗フラグを セットする
    つぎに
    モジュールハンドラと 関数名2で
         モジュールの関数アドレスを得て 関数アドレス2に 入れる
    エラー?
    ならば 関数アドレス取得失敗表示し 失敗フラグを セットする
    つぎに
    モジュールハンドラと 関数名3で
         モジュールの関数アドレスを得て 関数アドレス3に 入れる
    エラー?
    ならば 関数アドレス取得失敗表示し 失敗フラグを セットする
    つぎに

    失敗フラグが 偽?
    ならば
        ※GetStdHandle(STD_OUTPUT_HANDLE)
        STD_INPUT_HANDLEと 関数アドレス1で アドレス指定でAPI呼出し1して
        hConsoleに 入れ
        ※GetConsoleMode(hConsole, currentMode)
        hConsoleと  currentModeの アドレスと 関数アドレス2で アドレス指定でAPI呼出し2して
        ゼロ?
        ならば CONモード取得失敗表示し 失敗をかえし
        さもなければ
            ※「currentMode:」を 表示し currentModeを 数値表示し 改行し
            ENABLE_ECHO_INPUTと ENABLE_LINE_INPUTを ORして maskに 入れ
            有効化フラグが 有効に 等しい
            ならば
                ※「有効化実行」を 一行表示し
                hConsoleと currentModeと maskで ORして
                ※SetConsoleMode(hConsole, currentMode Or mask)
                関数アドレス3で アドレス指定でAPI呼出し2して
            さもなければ
                ※「無効化実行」を 一行表示し
                hConsoleと currentModeと maskで ANDNOTして
                ※SetConsoleMode(hConsole, currentMode And Not mask)
                関数アドレス3で アドレス指定でAPI呼出し2して
            つぎに
            ゼロ?
            ならば 
                有効化フラグが 真?
                ならば     クックドモードを有効化失敗を表示し
                さもなければ  クックドモードを無効化失敗を表示し 
                つぎに
                失敗をかえし
            さもなければ 成功をかえし
            つぎに
        つぎに
    つぎに
  モジュールハンドラで モジュールを解放すること。

    グローバル。

クックドモードを無効化するとは  (・ → 1/0:成功/失敗)
    無効で クックドモードを変更すること。

クックドモードを有効化するとは  (・ → 1/0:成功/失敗)
    有効で クックドモードを変更すること。


コンソール1文字読込するとは  (・ → 1/0:成功/失敗、文字)
        モジュールハンドラは 変数
        関数アドレス1は   変数
        関数アドレス4は   変数
        失敗フラグは         変数
        hConsoleは      変数
        chは         変数
        readは        変数

    hConsoleを クリアし
    失敗フラグを クリアし
    モジュール名を モジュールをロードし モジュールハンドラに 入れ
    エラー?
    ならば モジュールロード失敗表示し 空列と 失敗をかえす
    つぎに

    モジュールハンドラと 関数名1で
         モジュールの関数アドレスを得て 関数アドレス1に 入れる
    エラー?
    ならば 関数アドレス取得失敗表示し 失敗フラグを セットする
    つぎに
    モジュールハンドラと 関数名4で
         モジュールの関数アドレスを得て 関数アドレス4に 入れる
    エラー?
    ならば 関数アドレス取得失敗表示し 失敗フラグを セットする
    つぎに

    失敗フラグが 偽?
    ならば
        ※GetStdHandle(STD_INPUT_HANDLE)
        STD_INPUT_HANDLEと 関数アドレス1で アドレス指定でAPI呼出し1して
        hConsoleに 入れ
        ※ReadConsoleW(hInput, &ch, 1, &read, NULL);
        hConsoleと  chの アドレスと 1と readの アドレスと $$NULLと
        関数アドレス4で アドレス指定でAPI呼出し5して
        ゼロ?
        ならば コンソール読込失敗表示し 空列と 失敗をかえす
        さもなければ
            chと 成功をかえす
        つぎに
    つぎに
  モジュールハンドラで モジュールを解放すること。

ローカル語を捨てる。

「クックドモードを変更する」は「VTモードを変更する」とマスクの値だけが異なり、基本的にロジックはいっしょなので、後にライブラリをリファクタリングしてマージしようと思いますが、今回は独立して記述しています。

「VTモードを変更する」のときはMindの「NOT」の存在に気づかず、ANDNOTするとき内部でビット反転マスクで「XOR」していましたが、今回は「NOT」で対応しています。

メインプログラム

coninput.src
"win32consoleapi2"を コンパイルする。

一文字直接入力とは  (・ → 文字)
    コンソール1文字読込し
    0に 等しい ならば 捨て 実行終わり つぎに。

キー入力有り?とは  (・ → 真偽)
    コンソール1文字読込し
    0に 等しい ならば 捨て 実行終わり つぎに
    ※複写し ダブル表示し 改行し
    (入力文字が) $$NULLに 等しい
    ならば 偽をかえし
    さもなければ 真をかえし
    つぎに。 

メインとは  (・ → ・) 
    クックドモードを無効化し
    0に 等しい ならば 実行終わり つぎに
    「クックモードを無効化しました。」を 一行表示し
    
    一文字直接入力し ダブル表示し 改行し
    キー入力有り?
    ならば 「キー入力有り」を 一行表示し 改行し
    つぎに
    クックドモードを有効化し
    「クックモードを有効化しました。」を 一行表示。

「キー入力有り?」の実装はかなり想像で書いています。「コンソール1文字読込」を使えばできそうだったので、ついでに書いてみました。入力された文字は判定に使われていますが、複写などでそれも使うようにすることもできます。また、ループしてずっと監視しているわけではなく、キーが押されてなにかコードが入ったかを判定しています。PureMind5.2と異なる動作の場合はまた実装しなおします。(そのとき余裕があれば(^-^;)

コンパイル結果

ではコンパイルしてみます。下位ライブラリはfileを指定します。

Mind9

下図はMind9βです。

C:\developments\vscode\mind9>mind coninput file   

日本語プログラミング言語 Mind Version 8.11 for Windows
          Copyright(C) 1985 Scripts Lab. Inc.
コンパイル中 .. 終了
Coping.. C:\mind9-beta\mind9-beta\bin\mindex.exe --> coninput.exe

Mind8

C:\developments\vscode\mind9>mind coninput file

日本語プログラミング言語 Mind Version 8.07 for Windows
          Copyright(C) 1985 Scripts Lab. Inc.
コンパイル中 .. 終了
Coping.. c:\pmind\bin\mindex.exe --> coninput.exe

Mind7

C:\developments\vscode\mind9>mind conclear file
日本語プログラミング言語 Mind Version 7.5 for Windows
          Copyright(C) 1985-2004 Scripts Lab. Inc.
          Single user license.  Serial No:********
コンパイル中 - 終了
Coping.. C:\mind7\bin\mindexec.exe -> coninput.exe

実行結果

つづいて実行してみます。

Mind8の結果です。記述は割愛していますがMind7/9βも同じです。

C:\developments\vscode\mind9>coninput
クックドモードを無効化しました。
00A90061
キー入力有り

クックドモードを有効化しました。

C:\developments\vscode\mind9>

入力動作なので、これだけではちょっとわかりにくいかもしれません。半角文字を入力した場合はキーを押しただけで反応しました。カナ漢字変換ありの場合は変換確定Enter直後に反応します。

「キー入力有り?」は現状、Enterキーを含めてなにかキーを押さないと制御が移らないので、ちょっと本来の動作と違いそうです(^-^;

参考情報

この小技「一文字直接入力」を使った記述例の記事はまだありません。

おわりに

いかがでしたでしょうか?なにかの参考になれば幸いです。2025年は日本語プログラミング言語Mind生誕40周年です。

本記事シリーズのご紹介

本記事シリーズ「日本語プログラミング言語Mindの小技」は「日本語プログラミング言語Mind生誕40周年プロジェクト」の一環です。

興味を持たれた方は日本語プログラミング言語Mind公式サイトにアクセスすると、Mindコンパイラをダウンロードできます。

面白い!、楽しい、カンタン、難しいのも書ける!みんなでやってみよう:relaxed:

3
1
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?