- 締切済み
マウス自体の移動量の取得
カーソルの移動量(GetCursorPosで可)でなく、マウス自体の移動量を取得する事は出来ないのでしょうか? マウスカーソルはディスプレイの端に行くと動作が止まってしまいます。とにかく2次元の自由な動作を取得してアプリで使用したいのですが、マウスの動作が最適です。そこで、マウスカーソルは動作を停止させ(止めて)、マウス自体の移動量が取得できないかいろいろ試しました。 試したのが以下の方法です。 ・マウスカーソルを画面の中央に強制移動、 ・マウスカーソルを消す(タイプをcrNoneに設定)、 ・マウスの移動を検知すると、中央からの移動量取得 ・再び、見えないマウスを中央に強制移動 しかし、メッセージキューに入っている情報がFIFOの様で、移動量取得と中央への強制移動が同期せず、うまく値が取れません。 何か方法があれば御教授お願いいたします。BCBで開発しています。
- みんなの回答 (7)
- 専門家の回答
みんなの回答
すいません、関係ない回答してしまいました。ごめんなさい。
僕はC++を使っているので、Win32APIについて(ちなみにXP使用)。GetMouseMovePointsEx()を使えば、カーソルが画面から出た時の座標も取得できます。ただWindowsが勝手に画面内に戻すので、「画面から出る」と「画面内に戻る」はメッセージにはならないようです。余計なお世話かもしれませんが、Windowsはカーソルの位置x、yそれぞれをshort(2バイトの2の補数表現)で扱うので、そのまま使うとマイナスの値が65500ぐらいになるかもしれません。
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>以下上記の繰り返し、となるのでだけれど、PeekMessageでは実際のマウスの移動でなく、 >SetCursorPosのキューに入っている移動の方を削除しているということはありえませんか。 では、順番を逆にして、SetCursorPosを呼んだ後にPeekMessageでキューから削除してみてはどうですか? ただし、無条件に削除するのではなくmsg構造体の中を見て 座標がSetCursorPosで指定した座標が入るのを確認するまで。もちろん指定した座標が入ってたら削除しちゃだめですよ。
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>例えば、右側にマウスをずーと動かし続けると、10回のサンプル間はマウスカーソルは右に動き続け、 >11回目のサンプル(FromMouseMoveが呼ばれた時)で中央に強制移動し、12回目以降はマウスカーソルは再び右側に動き始める、となります。 一応ヒントを。 SetCursorPosを呼ぶ直前に、PeekMessageでWM_MOUSEMOVEをキューから削除すれば平気かと。 念のために書いておきますが、マウスの移動情報から必ずメッセージ生成が行われているわけではありません。システムに負荷がかかると簡単にマウスカーソルの移動がとまっちゃうことから一目瞭然ですよね。
- kmb01
- ベストアンサー率45% (63/138)
BCBで作ってみたけど、質問の方法で上手く動いていますよ。 void __fastcall TForm1::FormShow(TObject *Sender) { ShowCursor(FALSE); int cx = ClientWidth/2; int cy = ClientHeight/2; TPoint pt0(cx, cy); TPoint pt = ClientToScreen(pt0); SetCursorPos(pt.x, pt.y); } void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { static int sX, sY; int cx = ClientWidth/2; int cy = ClientHeight/2; if (X==cx && Y==cy) return; sX += X-cx; sY += Y-cy; AnsiString s; Caption = s.sprintf("%d %d", sX, sY); TPoint pt0(cx, cy); TPoint pt = ClientToScreen(pt0); SetCursorPos(pt.x, pt.y); }
補足
実際にプログラミングして頂き大変恐縮です。 私も同じようなコードを試しました。一見うまく動いているようですが、動作のログを取ると思ったように動いていません。 最下行で SetCursorPos()でカーソルを移動しているのですが、次の FromMouseMove が呼ばれた時には未だカーソルは強制的に中央に移動していません。例えば、右側にマウスをずーと動かし続けると、10回のサンプル間はマウスカーソルは右に動き続け、11回目のサンプル(FromMouseMoveが呼ばれた時)で中央に強制移動し、12回目以降はマウスカーソルは再び右側に動き始める、となります。つまり、何時、マウスカーソルが中央に移動したかプログラム側では判定の方法が無いのです。 この方法で、マウス自体の絶対移動変移量を取る事はできないのでしょうか。
- taka_tetsu
- ベストアンサー率65% (1020/1553)
APIレベルではがんばっても無理ですね。 一番低レベルなWH_MOUSE_LLフックを使っても座標までしか取れません。 マウスカーソルではなく、マウスそのものの移動量を取得したいとなると、デバイスドライバを書かないと無理じゃないでしょうかね。
- neKo_deux
- ベストアンサー率44% (5541/12319)
実際の処理が見えませんが、これでOKなハズです。 画面端から逆の端にマウスをワープさせるオンラインソフト WarpPointer 2.21 http://www.vector.co.jp/soft/win95/util/se070373.html ループ 1.05 http://www.vector.co.jp/soft/win95/util/se141539.html Warp 1.02 http://www.vector.co.jp/soft/win95/util/se128267.html みたいな事が実際に出来ますし。 -- > メッセージキューに入っている情報が などの原因まで分かっているのなら、余分にメッセージを取り出すとかなんとか。
お礼
回答ありがとうございます。 マウスをワープさせるコードは何となくイメージできます。本当は、マウスカーソル自体を動作させないで、マウスからの動作量だけを取得したいと思っています。メッセージキューについてもBCBで開発していることもあり、いまいち自信もなく、もっとスマートな方法があればと思っています。
お礼
ヒントをありがとうございます。できるということなので、なんとかがんばりたいと思います。 ちょっとやってみたのですがうまくいかず、月曜日以降、更に試行錯誤してみようと思います(これから出かけてしまいますので)。
補足
やっぱりできないのでは? マウスを見えるようして、変移量をTMemoに表示させながらチェックしました。そして、SetCursorPosの直前に以下を入れました。 MSG msg; while(PeekMessage(&msg, NULL, WM_MOUSEMOVE,WM_MOUSEMOVE, PM_REMOVE)); WM_MOUSEFIRST/WM_MOUSELASTを指定してあげればマウスカーソルが移動中のマウスクリックは無視しますので、構文自体は合っているようです。 シーケンシャルに考えてみると FromMouseMove (WM_MOUSEMOVE) __X,Yの処理 __PeekMessageでWM_MOUSEMOVEの除去 __SetCursorPosでマウス移動 FromMouseMove (WM_MOUSEMOVE) __X,Yの処理 __PeekMessageでWM_MOUSEMOVEの除去 __SetCursorPosでマウス移動 以下上記の繰り返し、となるのでだけれど、PeekMessageでは実際のマウスの移動でなく、SetCursorPosのキューに入っている移動の方を削除しているということはありえませんか。仮にそうだとすると、何時SetCursorPosが終了したかの判定は無理では無いでしょうか?宜しければコメントをいだだければ幸いです。