通常HSPのbgsrc命令で作成したウィンドウはドラッグ移動はできない。 もしドラッグ移動を望むのであれば、何かしらの方法でマウスクリックされた位置を "ウィンドウ内部でなく、キャプションバーである"ように偽装する必要がある。 偽装方法としてはWM_NCHITTESTイベントのreturn値をキャプションバーの上であることを表す値を返すか、 ウィンドウ内のクリック動作時に、キャプションバーをクリックされたことにするイベントを送るかといった手段がある。 前者の場合、"HITTESTが偽装されているため、ウィンドウ内をクリックされたことを検出できない"という問題が出る。 そのため後者の方法をとることにする。
また、ウィンドウはディスプレイの外に出ないようになっている。(これがwin8で動作障害かもしれない。) ウィンドウを移動する際、WM_MOVINGメッセージが来て、デフォルトの移動先が確認できる。 このデフォルトの移動先を捻じ曲げることで、 移動を制限したり移動するとウィンドウが拡大しながら動くウィンドウが作れる。
|
ウィンドウ内でのドラッグを検知したい状況は珍しいことじゃない。ペイントソフトなどを作ればよくある。 クリック開始を検知する方法はonclickでもoncmdでもstickでもgetkeyでもいろいろあるが、 クリックを離すタイミングを感知できる方法はstick,getkeyあたりに限られ、常時監視する必要がある上に、 mousex,mouseyのシステム変数で位置を取得できないためginfoを使って取得し、相対座標に直すことになる。 常時監視しても問題ない状況ならいいが、そのためだけにループを組むと処理の負荷が気になるところ。 そんなことをしなくても、 API関数のSetCaptureを用いるとクライアント領域外にあるマウスに関するイベントを取得できる。 ただし、用がすんだらきちんとReleaseCaptureで解放してあげないとひどいことになります。 実用上は、マウスボタンが押された際(WM_LBUTTONDOWN)にSetCaptureを呼びだすことで、 ほぼ確実にマウスボタンが離されたときのイベント(WM_LBUTTONUP)が取得できる。 ドラッグの終了が分かればいいので、このときにReleaseCaptureを呼べばいい。
上のソースでは何も対処していない。 マウス操作のソフトで、クライアントウィンドウの外にマウスが移動した際、 最後に乗っていた場所を記憶してメニュー項目が点灯したままになったりすることがある。 これはmousex,mouseyの値が「最後にマウスがウィンドウ上にいた際の位置(ちょっと違うけど)」なため起こる現象である。 通常、ウィンドウ外にマウスが行ったことを感知するには、 ginfoを用いてマウス座標をウィンドウ相対座標に変換し、それをmousex,mouseyと比較することになる。 こうするとドラッグ操作と同様に、監視のためにループを回すことになってしまう。 だが、そんなことをしなくてもWindows側から通知してもらう方法がある。 通知はWM_MOUSELEAVEというイベントで、ウィンドウの上からマウスポインタが離れた際に発行される。 しかし、このイベントはTrackMouseEventというAPI関数で要求しないと発行してくれない。 このAPI関数の有効期間は、一度WM_MOUSELEAVEを発行するまでなので、 いつでもマウスポインタが離れたことを知りたいのであればマウスポインタがウィンドウ内に戻ってきた際に もう一度呼ぶ必要がある。
|
システムメニューとは、ウィンドウの上部のバーや、タスクボタンの上で右クリックすると出るやつである。 改変に関しては探せば出てくるだろうけどせっかくなので。 システムメニューにはデフォルトで「元の大きさに戻す」や「最大化」などがあるが、 これらを消すと、その機能が使用不能になる。特に閉じれないのは致命傷になりかねない。 ちなみに、標準のHSPウィンドウは「移動」「最小化」「閉じる」「元のサイズに戻す」の4種が使える可能性がある。 流れとしては、GetSystemMenuを呼び、システムメニューのハンドルを取得。 DeleteMenuやInsertMenuItemAなどにハンドルを渡してメニューを改変、 最後にDrawMenuBarを呼んで完了となる。 最大化を消してみる例を出しておく。
DeleteMenuの第3引数にMF_BYPOSITION(0x400)を指定すると上から何番目のメニューを消すという指定ができるが、 他のツール類によってシステムメニューが拡張されているケースがあるため、MF_BYCOMMANDのほうが安全だと思われる。 追加の際にはInsertMenu等の関数で行え、これを解釈するにはWM_SYSCOMMANDを確認する必要がある。 HSPで作成できるウィンドウにはいくつか種類があるが、 screen命令で作成できるウィンドウはシステムメニューを標準で利用できる。(ツールウィンドウであっても) bgsrc命令で作成したウィンドウに関しては、システムメニューを持つものの、通常では出現させることができない。 bgsrcで作成したウィンドウが、他のウィンドウと同様にタスクバーを右クリックした際にメニューが出るようにするには、 そのウィンドウにWS_SYSMENUを付与すればいい。 WS_SYSMENUを付与するにはSetWindowLongを用いる。
|
ランチャーへの登録の際ドラッグドロップが利用できたら便利なことは当然である。 すると、ランチャーにショートカットファイルがドラッグドロップされる場合を考慮するべきである。 しかし、ddacceptにせよDragQueryFileAにせよ取得できるのはドロップインされたショートカットファイルのパスである。 それをランチャーにそのまま登録してしまうと、 「ランチャー導入したらデスクトップのショートカット撤去出来るよね」 という声に答えることは当然できない。撤去した時点でリンク切れである。 ショートカットファイルがドロップインされた場合の措置は、 上記のリンク切れを解消するのであれば良い。 解消方法として、Lnksではショートカット先を取得しそれを保持することにしている。 その方法はいくつかあるのだろうが、 COMオブジェクトであるIShellLinkを使ってショートカット先を取得する方法を選んだ。
余談になるが、COMをうまく扱えばDirectXにアクセスしてDLLなしにDirect3Dを扱えたりする。 HSP側ではGUIDとして"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"という形で定義するが、 関数がGUIDを要求する際、REFIID型(GUID*型)で要求してるため、 引数指定をstrとして上の文字列を渡しても認識できない。 なので、str を GUIDが入っている配列 という変換コードを組んでおくと若干楽ができる。 COMを使う局面が多いソースでは変換関数を作る価値はあるのではないだろうか。 |