ウィンドウメッセージを取得してみる ACT-3

サンプルスクリプト

今回はメッセージ取得のサンプルスクリプトを書いてみましょう。

とはいったものの、メッセージ取得というものは、メニューやツールバー、あるいはコモンコントロールなどと組み合わせることでその本領を発揮するのであって、メッセージ単体の機能となると、マウス入力やキー入力といった、HSP標準機能でも充分対応できるものばっかりなんですよね……。

まあ、とにかく、何か書いてみるとしましょう。前回も述べましたが、スクリプトの全体構造は以下の通り。

  1. ウィンドウをサブクラス化する
  2. 取得するメッセージを設定する(複数ある場合はその数だけ指定)
  3. メインループ中で以下の操作を行なう
    1. メッセージが取得されているかどうかを調べる
    2. メッセージが取得されている場合には、そのメッセージに応じた処理をする
    3. メッセージが取得されていない場合には、waitまたはawaitを実行する。また、ループごとに実行すべき処理があれば、それを実行する。

とりあえず、ウィンドウがアクティブ化/非アクティブ化されたときに送られるWM_ACTIVATEメッセージを取得してみましょう。WM_ACTIVATEのメッセージコードは0x0006です。

#define  WM_ACTIVATE    0x0006

WM_ACTIVATE
    fActive    =  wParam & 0xFFFF;
    fMinimized = (wParam >> 16) & 0xFFFF;
    hwndPre    =  lParam;

fActivewParamの下位ワード値)はアクティブ化フラグで、ウィンドウが非アクティブ化される場合は0 (WA_INACTIVE) が、ウィンドウがアクティブ化される場合は1 (WA_ACTIVE) または 2 (WA_CLICKACTIVE) になります。fMinimizedwParamの上位ワード値)は、ウィンドウが最小化されている場合は0以外の値に、最小化されていない場合は0になります。hwndPrelParamの値)は、このウィンドウに代わってアクティブ(または非アクティブ)になったウィンドウのハンドルになります。

    #include "llmod.as"
    #include "hsgetmsg.as"

    ; メッセージコードの定義
    #define WM_ACTIVATE    0x0006

    ; ウィンドウのサブクラス化
    set_subclass
    hwnd = stat                    ; ウィンドウハンドル

    ; 取得メッセージ設定
    set_message WM_ACTIVATE

    dup msg,  msgval.1
    dup wprm, msgval.2
    dup lprm, msgval.3

*mainloop
    ; メッセージを取得
    get_message  msgval
    if msgval {
        if msg == WM_ACTIVATE : gosub *OnActivate
    } else {
        wait 10                    ; wait または await を実行
    }
    goto *mainloop

*OnActivate
    fActive = wprm & 0xFFFF        ; アクティブ化されたかどうかのフラグ
    if fActive {
        mes "アクティブ化されました"
    } else {
        mes "非アクティブ化されました"
    }
    return

上のスクリプトを実行させてみましょう。ウィンドウをいったん非アクティブにしてからもう一度アクティブにすると、メッセージが表示されます。本当は、メッセージが送られてきたときにdialog命令でメッセージボックスを表示しようと思ったのですが、そうするとメッセージボックスが表示されたり閉じられたりするたびにウィンドウがアクティブ・非アクティブになって無限に続いてしまうので、ウィンドウにメッセージを表示しています。

このスクリプトでは、変数の別名を与えるdup命令を使って、メッセージコードやwParamlParamを別の変数として扱えるようにしています。

dup msg,  msgval.1         ; メッセージコード
dup wprm, msgval.2         ; wParam パラメータ
dup lprm, msgval.3         ; lParam パラメータ

このようにしておくと、メッセージが送られた場合に、get_message命令でメッセージを取得した時点でそれぞれの変数がメッセージコード、wParamパラメータ、lParamパラメータになるので、スクリプトがわかりやすくなります。

補足:メインルーチンの組み方

あまり気にすることでもないのですが、メインルーチンで繰り返しのループをどう組むかについて、ちょっと書いておきましょう。

上のスクリプトのメインループ(メッセージ待機ループ)は以下のように書かれています。

*mainloop
    get_message msgval
    if msgval {
        ; ここで各種メッセージ処理を行なう
        if msg == ... : ...
        if msg == ... : ...
    } else {
        wait 10
        ; 必要ならばここでループごとの処理
        ...
    }
    goto *mainloop

しかし、人によっては、例えば次のように組んでしまうかもしれません。

*mainloop
    wait 10                ; ここで wait または await を実行
    get_message msgval
    if msgval {
        ; ここで各種メッセージ処理を行なう
        if msg == ... : ...
        if msg == ... : ...
    }
    ; 必要ならばここでループごとの処理
    ...
    goto *mainloop

このようなスクリプトを作成した場合、1つのメッセージ処理が行なわれるたびに、必ず1度はwait命令が実行されることになります。しかし、たくさんのメッセージを取得するように設定していてそれらが連続して送られてくる場合や、メッセージが立て続けに送られてくる場合、wait命令を1回実行するだけで複数のメッセージを受け取っている可能性があります。1つ目のメッセージ処理の後に、waitを実行することなく次のメッセージを処理するようにした方が、その分だけ反応速度が高まることになりますよね。したがって、最初に書いてある手順で作成したほうが良いことがわかりますね。

もう少し別の組み方で、次のように書いてもいいでしょう。

*mainloop
    wait 10                ; ここで wait または await を実行
    repeat
        ; 取得メッセージがない場合は repeat ループから抜ける
        get_message msgval : if msgval == 0 : break
        ; ここで各種メッセージ処理を行なう
        if msg == ... : ... : continue      ; continue は無くてもいいですが
        if msg == ... : ... : continue
        if msg == ... : ...
    loop
    ; 必要ならばここでループごとの処理
    ...
    goto *mainloop

こちらの書き方なら、最初の書き方と比べても、速度の面で変化はないはずです。自分が見やすい方で書けばいいでしょう。まあ、こちらのほうではrepeatloopを使っているので、このループからgotoで抜け出してしまうという、HSP初心者が最も陥りやすい罠にはまらないようにする注意は必要ですけどね。