関数
今回作る関数は下の4つだけです。
//マウスジェスチャのスタート void StartMouseGesture(MOUSEGESTURE *lpmg, HWND hwnd, int x, int y); //マウスジェスチャの終わり void EndMouseGesture(MOUSEGESTURE *lpmg); //マウスジェスチャの判定を行う。 MGARROW TestMouseGesture(MOUSEGESTURE *lpmg, int x, int y); //移動情報のリセット void ResetDirection(MOUSEGESTURE *lpmg);
最後のリセット関数は内部的に必要となるだけの関数なので、使用者は使うことがありません。行っているのは「direc」の移動距離リセットと有効化です。
マウスジェスチャのスタート
この関数は「WM_*BUTTONDOWN」に仕掛けます。
//マウスジェスチャのスタート void StartMouseGesture(MOUSEGESTURE *lpmg, HWND hwnd, int x, int y){ //有効化 lpmg->enable = TRUE; //リセット ResetDirection(lpmg); lpmg->old.x = x; lpmg->old.y = y; //押されている間だのキャプチャを開始 SetCapture(hwnd); }
マウスジェスチャ構造体、ウィンドウハンドル、位置を使ってマウスジェスチャの準備をします。また「SetCapture」を呼び出しています。
マウスジェスチャの判定
ここがマウスジェスチャの心臓部です。これは「WM_MOUSEMOVE」に仕掛けるのが妥当でしょう。
//マウスジェスチャの判定を行う。 MGARROW TestMouseGesture(MOUSEGESTURE *lpmg, int x, int y){ //有効なときだけ判定する。 if(lpmg->enable){ int ox = lpmg->old.x,oy = lpmg->old.y; int direc = (int)MG_NONE; //情報を入れ替えておく lpmg->old.x = x; lpmg->old.y = y; //移動量を判定して縦横どっちに動くかを判定 if(abs(ox - x) > abs(oy - y)){ if(ox > x){ lpmg->direc[MG_LEFT].length += ox - x; lpmg->direc[MG_RIGHT].length = 0; direc = (int)MG_LEFT; } else if(x >ox){ lpmg->direc[MG_RIGHT].length += x - ox; lpmg->direc[MG_LEFT].length = 0; direc = (int)MG_RIGHT; } } else { if(oy > y){ lpmg->direc[MG_UP].length += oy - y; lpmg->direc[MG_DOWN].length = 0; direc = (int)MG_UP; } else if(y >oy){ lpmg->direc[MG_DOWN].length += y - oy; lpmg->direc[MG_UP].length = 0; direc = (int)MG_DOWN; } } //移動を検知したとき if(direc !=MG_NONE){ if(lpmg->direc[direc].enable && lpmg->direc[direc].length > lpmg->range){ ResetDirection(lpmg); //同じ向きが2度入力されないようにする。 lpmg->direc[direc].enable=FALSE; return (MGARROW)direc; } } } return MG_NONE; }
直感に反しないよう私なりに調整してあります。流れは次のようになります。
- マウスジェスチャが有効かの判定。
- 縦横の移動量を判定。
- 左右(または上下)どちらへ移動しているのかを判定。
- 移動量を加算。反対への移動量を0。
- その移動が有効であるかを判定。
- 移動量が検出量に達しているかを判定。
もっと良い工夫をお持ちの方もいると思います。いろいろな人に試してもらいながらどんな仕組みにするのかを決定すると良いと思います。
マウスジェスチャの終わり
ボタンが離されると、「SetCapture」の魔法が解けてしまいます。よって、「WM_*BUTTONUP」あたりに、この関数を仕掛けるのが妥当だと思います。
//マウスジェスチャの終わり void EndMouseGesture(MOUSEGESTURE *lpmg){ //マウスキャプチャの終わり ReleaseCapture(); lpmg->enable = FALSE; }
一応「ReleaseCapture」を呼び出しておいてください。
サンプルの使い方
まずはどこかに「MOUSEGESTURE構造体」を作ってください。次に「ZeroMemory」で全体を初期化した後、「range」に適当な値をセットしてください。
そしたら、ウィンドウプロシージャの設定をします。「WM_*BUTTONDOWN」の中で「StartMouseGesture」を、「WM_MOUSEMOVE」の中で「TestMouseGesture」を、「WM_*BUTTONUP」の中で「EndMouseGesture」を呼び出すようにセットしてください。
これで「TestMouseGesture」を呼び出すたびに「MGARROW列挙型」で値が返ってくるようになります。
まとめ
マウスジェスチャはアプリケーションに大きな魅力を付加します。使いこなせばボタンにカーソルを移動することなく素早く操作できるようになります。
ぜひ、実装を検討してみてください。
参考資料
- 猫でも分かるプログラミング Windows SDK編 第2部 『第101章 マウス・キャプチャー』
- WisdomSoft 『標準 WindowsAPI』
