Home > プログラム > マウスホイールのグローバルフックについて。

マウスホイールのグローバルフックについて。

タイトルの中身は続きで。

今日夕方からデカロンやってたんですよ。
今GWイベントで6発連続イベントとかやってるんですが、詳細はデカロンサイト見てもらうとして、今日はその中のひとつ。
謎の石像破壊イベントでした。
100体召喚されて、倒すと100%の確立でアゲート系アイテム(レアアイテム)をドロップするってイベント。
6連発イベントの時点で某アスガルドとは違う感じがしますね。
スゲェ。
で、18時から本日二回目の召喚イベントが始まったんですが、人多すぎた為か、1鯖にログインできなくなっていました。
すると運営からのシャウトで、現在復旧中との事。
他鯖には普通にログインできたからわかったけど、某アスガルドみたいに掲示板での告知よかよっぽど分かりやすいと思った。
スゲェ。
で、無事イベントも19時から再開されて、終了にいたりました。
まぁおれは石像破壊できなかったんですがね。
人が殴ってる奴見ただけ。
100体て。少ないしw

まぁそれはよかったんですが、狩りしようと思って準備してると運営からのシャウトが再び。
運営シャウト
すごいねこれ。
某アスガルドでこれやったら毎時間2倍になっちゃうよねー。
全鯖に適用だし。

デカロンはまだまだがんばってると思いました。

あ、アスはまだ好きですよ?一応。



で、タイトルの中身ですが。
興味ない方はサッパリ内容が分からないと思いますが、気にしないでください。
記事自体無視してくださって結構です。


何してたかっていうと、グローバルフックについて色々調べてました。
グローバルフックって何?って、ざっくり言うとWindowsのメッセージを横から乗っ取って、本来の処理に追加機能つけたり、本来とは違う処理をさせたりするような事へのとっかかりです。

例えば、メモ帳ありますよね。Windowsのアクセサリに入ってるテキストエディタ。
あれで、キーボードの「A」押したら「あ」って出ますよね。メモ帳に。
これは、キーボードの「A」押したときにWindowsに「キーボードの[A]押しましたよ。後の処理お願いしますね^^b」ってメッセージが届くんです。
ソレを受けた人(ホントは違うけどここではメモ帳とします)が、日本語入力中なのかを調べて、テキスト入力部分に「あ」と出力するって流れになります。
で、今回やってたのはそのメッセージを横取りしていろいろやっちゃおうって感じの物ですね。

ここまでついて来られてますでしょうか?
ついて来られてなくても先いきますが。

具体的に何をやっていたかというと、「マウスホイールの回転数計測アプリ」を作ってました。
なんに使うんだってなると、使い道はまったくありませんが。
以前同僚とふざけたツールの話をしてて、それがコレでした。
朝一で起動して、マシン落とすときに「今日は↑回転2400回、↓回転9030回でしたね」みたいなメッセージ出すツール。
欠片も意味の無いツールですね。

でもまぁ勉強がてら作ってみようと思ったわけです。

どうやって実現するのか?
自分でつくったアプリなら、自分の中で起こったイベント逐一見張って、マウスホイールが回ったら内部変数加算していけばすむんですが、実際PC使ってるときの回転数が知りたいわけなのでこれではダメダメです。
手法としては上記で説明したグローバルフックを使うわけです。

Windows上の全てのメッセージの中からマウスホイールが回りましたよって言うメッセージを横取りして、発生回数をアプリの内部変数に足し込んで、処理をWindowsにそのまま返してあげればOKです。

グローバルフック自体はそこそこWebにサンプルとかあったので、そう苦労しなかったんですが、「マウスホイールの回転方向の取得」で血吐くかと思いました。
サンプルが殆ど無いってわけでもないんだけど、Winの基礎知識希薄だから見たサンプルでは理解できなかったわけです。

ここからコード説明に入ります。
探してる人が他にも居るかもしれないので。

グローバルフックの基本は、猫でもわかるプログラミング WindowsSDK第二部 第160章 メッセージフックの基礎あたりを見れば分かりやすいと思います。
DLLの作成方法等も別の章に載っているので至れり尽くせりです。

上記リンク先を参考にグローバルフックのDLLは作成できました。
次は肝心のホイール回ったメッセージの拾い方ですね。
マウスホイールが回った時に発生するメッセージは
WM_MOUSEWHEEL
です。

これをヘルプに突っ込むと、英語のMSDNでツラツラと説明が書いてあります。
ざっくりと斜め読みすると、wParamの上位ビットに移動量、下位ビットにkeyFlgとかいうのが入ってる模様。
今回知りたいのがマウスホイールの移動量だから、wParamの上位ビットを調べれば良さそうです。

ここまではそれなりにすんなりいけた。

唐突にコードを貼り付ける。
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(hMyHook, nCode, wParam, lParam);
if ( wp == WM_MOUSEWHEEL ) {
MOUSEHOOKSTRUCT *pmh;
pmh = (MOUSEHOOKSTRUCT *)lParam;
ここで呼び元アプリに対してユーザメッセージを投げる
}
return CallNextHookEx(hMyHook, nCode, wParam, lParam);
}
これフックプロシージャの中身なんですが、太字になってる部分でwParamの上位ビットを調べると、何か数字入ってるけど絶対移動量じゃない値が入っています。
大体サンプルからして見ると、wParamにはメッセージの種類が入ってる筈なので、それの上位ビットが移動量によって変わるわけも無く。
明らかに何かが間違っているようでした。

ちなみに、フックは
SetWindowsHookEx( WH_MOUSE, HookProc, hInst, 0 );
でやってました。

一応lParamの中身はMOUSEHOOKSTRUCTのポインタが正しく入ってはいる様でした。
ホイールをクリクリした座標が取れていたので。

となると、セットしてるポインタの型が違う感じ。
WM_NCLBUTTONDOWNとかを拾って座標取るならこれでいいみたいですが、ホイールの情報は入っていません。

困った。

何かいいサイトが無いかとWebを漁ってみると、フックを「WH_GETMESSAGE」でやってて、HookProcでのメッセージ判定を
MSG *msg = (MSG *)lp;
でやってるサンプルを発見。
これでやってみて、WM_MOUSEWHEELのwParamを見て見ればどうだろうと思ってHookProc等を変更。
まずフックを
SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)MyHookProc, hInst, NULL);
でやる。
次にHookProcを以下のように書き換え。

/*-----------------------------------------------*/
/* フックプロシージャ
/*-----------------------------------------------*/
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(hHook, nCode, wParam, lParam);

MSG *msg = (MSG *)lParam;

// マウスホイールのメッセージを対象アプリに渡す
if(msg != NULL && msg->message == WM_MOUSEWHEEL) {
PostMessage( hWnd, WM_MOUSEWHEEL_CHECK, msg->wParam, 0 );
}

return CallNextHookEx(hHook, nCode, wParam, lParam);
}

太字の部分を書き換えました。
コレをデバッグしてみると、お見事。
msg->wParamにきちっとマウスホイールの上下が入っていました。
あとはコレを実際カウントを制御しているexeに対して通知してあげればいいわけですね。
PostMessage( hWnd, WM_MOUSEWHEEL_CHECK, msg->wParam, 0 );
がそれにあたります。

ちなみに、WM_MOUSEWHEEL_CHECKというのは独自MSGとして以下のように定義してあります。
#define WM_MOUSEWHEEL_CHECK WM_APP + 1 // dllからのメッセージ
別に「WM_MOUSEWHEEL_CHECK」ではなく「WM_MOUSEWHEEL」を送っても良かったんですが、lParamで色々小細工できるように独自MSGを作って見た次第です。


高々マウスホイールの回転方向を判断するだけでかなり時間を食いました。
どうもHookProcでのMSG判定を勘違いしていたというか単に知識不足だったわけですが。

雑ですが、フックのスケルトンにでもして色々実験して行たらな〜とか。

で、今回の成果物であるWheelCheckerを意味も無く公開してみようと思います。
細かいツールとかは結構作ってるけど、Webで公開するのは初めてかも。
まぁ上記記事を見た方なら理解できると思いますが、利用価値は皆無です。
スタートアップには勝手に登録されませんので、PC起動時〜PC終了時まで自動的にカウントアップというわけには行きませんが、それなりにマウスホイールの移動量を検知してくれます。
また、これをいろんなPCで実行して見ましたが、マウスドライバのせいなのかホイールの誤作動等もチェックできます。
目で確認になりますがw

マウスホイールの誤作動というのは、例えば下スクロールさせていたのに急に逆方向である上に戻ったりするアレです。
あんまし発動率は高くないのかもしれませんが、家のメインマシンではマトモにホイール作業ができないくらい発生したり。

他にはm片方のスクロールだけ倍動くとかもあるみたいです。
ひどいのだと5倍くらいまでは見たことあります。
5倍だとアプリ側が処理できなくてあたかも普通のように動いてましたが。

とりあえず長い前置きのような物でしたが、同じようなハマリ方をされている人が居るかもしれませんので記事にしてみた次第です。
誰かの役にたてればイイナ、と。

ソースは人に見せられるほどいいもんじゃないので公開しないことにしておきます。
「もし」要望があればお答えしますが。
コレが問題のアプリになります。
NortonAntiVirusでウイルスチェックを行っています。
ご利用は自己責任でお願いしますね。
WheelChecker Download
あーつかれた。
なれない記事書くもんじゃないなー(^_^;)

Comments:0

Comment Form

Home > プログラム > マウスホイールのグローバルフックについて。

Recent Comments
Recent Trackback
Search
Meta
Links
Feeds

Page Top