マウスイベントを取得するには?

解決


スプーン  2005-11-03 09:23:20  No: 18415

CallNextHookExについてお伺いします。
マウスが自アプリではなくて他のアプリケーションへ移動した瞬間を察知したいのですが?どのように書けばいいのでしょうか?
引数の意味について低脳な私に理解できるよう説明いただければ幸いです。
よろしくお願いします。


Mr.XRAY  URL  2005-11-03 21:01:13  No: 18416

CallNextHookExと質問のタイトルの文章の中身との関連がわかりませんが,
(ネットでCallNextHookExを検索してみて下さい)

この「移動した瞬間」というのはどのような状態のことを意味するのでしょう.
Windowsでは,常にメッセージが飛び交っています.これがイベントと結び
つくわけです.マウスがどこに移動した,クリックした時のメッセージ(イ
ベント)などです.それこそ「瞬間,瞬間」にイベント(メッセージ)は発生
しています.飛び交うメッセージは,マウスのものだけではありません.
アプリが起動した,終了した.等も全てメッセージです.

# Delphiでは,自アプリのメッセージの処理が簡単にできるように,例えば
# Bottonのイベントがオブジェクトインスペクタから作成できるようになっ
# ているわけです.

もし,質問の意味が,現在デスクトップに表示されているある他のアプリ,
つまり,Formなどの矩形(四角形)領域の中に入った時というのであれば,
単にマウスの移動メッセージを監視して,その矩形領域内にマウスの座標
があれば「入った瞬間」というこになるかも知れません.
何故なら,イベント(メッセージ)は「瞬間,瞬間」に発生しているからです.

これが他のアプリ全てとなると面倒です.起動中のアプリ全てを調べる必
要がありますからね.
スプーンさんが,何故「移動した瞬間」を知りたいか,またその「移動し
た瞬間」をどのように利用したいのかがわかれば,その「移動した瞬間」
の意味が私にも理解でき,対応策も考えることができるかも知れません.


スプーン  2005-11-04 00:32:19  No: 18417

Mr.XRAY様
返信ありがとうございます。
>スプーンさんが,何故「移動した瞬間」を知りたいか,またその「移動し
>た瞬間」をどのように利用したいのかがわかれば,その「移動した瞬間」
>の意味が私にも理解でき,対応策も考えることができるかも知れません.

現在図形の後書き処理でこまっています。
複数の図形をLineTo等の描画関数を使用してcanvasにXOR描画しそれをマウスムーブイベントで移動させています。
この移動中に他のアプリのFormにマウスが入ったときに(入っている間も)移動中の図形を消したいと思っています。

よろしくおねがいします。


Mr.XRAY  URL  2005-11-04 04:57:20  No: 18418

これはどこのCanvasに描画しているのでしょう.
それと,「他のアプリのFormにマウス...」とありますが,描画対象のcanvas
の外側に行ったら,ということとは違うのですか?
図形を消したいというのは,ゲームとかなんかのかな.

例えば,Form1のcanvasに描画しているとして,Form1のサプクラス関数と
いうものを利用する手もあります.以下,参考コードです.
Form1の外側にでた時だけ,Form1の中に入った最初だけ動作するコードが
必要であればフラグ(変数)を利用したり,対象図形の有無で判断するとこ
とも考えられます.

procedure TForm1.FormCreate(Sender: TObject);
begin
     //Form1のサブクラス化
     OriginalProc:=Form1.WindowProc;
     Form1.WindowProc:=Form1SubClassProc;
end;

procedure TForm1.Form1SubClassProc(var Message: TMessage);
var
    APoint : TPoint;
begin
     //Form1の元のWindowProcを実行
     OriginalProc(Message);
     case Message.Msg of
     WM_MOUSEMOVE:
       begin
         APoint.x:=Message.LParamLo;
         APoint.y:=Message.LParamHi;
         if PtInRect(Form1.ClientRect,APoint) then begin
           //マウスがForm1内にある
           //あるいは入った
         end else begin
           //マウスがForm1外にある
           //あるいは出た
         end;
       end;
     end;
end;

Form1の外側のマウス座標値が必要な場合は,マウスのフックが必要と思わ
れます.う〜ん,MouseLeaveの方がいいのかな.
図形を消さない方針であれば,マウス移動している時はForm1の外側にマウ
スを移動させないという考えもあるんでけどね.


スプーン  2005-11-04 06:34:07  No: 18419

Mr.XRAY様
ありがとうございます。
早速コードを組み込んでみます。

説明が悪くてすみません。
>これはどこのCanvasに描画しているのでしょう.
メインForm上のPaintBoxです。ゲームのように図形が移動するアプリを作成しています。
>描画対象のcanvasの外側に行ったら,ということとは違うのですか?
こういう場合も含まれますが、こちらは解決しています。
自アプリが非アクティブの場合は自アプリの前面に他のアプリのFormがある場合があるのです。
この状態のときに、そのアプリにマウスが入った場合のイベントを取得したいのです。
また、MouseLeaveを使ってみたのですが、自アプリ内の別コンポーネントに入るイベントは拾うことはできましたが、他のアプリのFormに入った時のイベントは拾うことができませんでした。

質問した後で思いついたのですが、他のアプリにフォーカスが移動する直前に後書き線処理をする(線を消す)というのでも良いのかもしれません。。


Mr.XRAY  URL  2005-11-04 08:17:35  No: 18420

>こういう場合も含まれますが、こちらは解決しています。

状況が少しだけわかってきました.
前に提示したコードは,実は,該当アプリのForm全体ではなく,多分Imageか
PaintBox内で図形を移動して,その外側への移動を検出するではないかと
予想したものです.Form1を書換えて使用するのではないかと予想しました.

したがって,自アプリ以外以外のイベントは捕捉できません.
自アプリ以外のイベント(メッセージ)を捕捉するには,グローバルフック
を使用する必要があります.

マウスのグローバルフックを実現するには,フック関数をDLLにしなければ
実現できません.DLLにしなくてもグローバルフックを実現するには,
WH_JOURNALRECORDを使用します.

申し訳ありませんが,詳しい動作仕様がまだ理解できていません.
以下のサンプルが参考になれば幸いです.

http://homepage2.nifty.com/Mr_XRAY/Delphi/plSamples/T_HookKeyMouseEvent.htm


Mr.XRAY  URL  2005-11-04 08:27:32  No: 18421

追記です.ローカルでもグローバルフックでも同じメッセージであれば
(ex WM_MOUSEMOVE)
lParam,wParamなどから,マウス座標値等を取得する方法は同じです.
メッセージ型(WM_...)に応じたWin32APIのヘルプを参考にして下さい.


スプーン  2005-11-04 22:57:56  No: 18422

Mr.XRAY様
ありがとうございます。
以下のソースでテストしたところマウスが他のアプリのフォームに入った瞬間のイベントは取得できませんでした。
しかしForm1.Edit2.TextにはWIN98の場合は他のアプリに入ったとき変化が現れますが、WINXPですと変化はありませんでした。

function WatchProc(nCode:Integer;wPara:WPARAM;lPara:LPARAM):LRESULT; 
stdcall;
var
  event:  pEVENTMSG;
  P : TPOINT;
  Msg_ : Integer;
begin

  if nCode < 0 then begin
    Result := CallNextHookEx(JournalHook, nCode, wPara, lPara)
  end else begin
    Result := 0;
    Form1.Edit2.Text:= intTostr(lPara);
    if nCode = HC_ACTION then begin
        event := pEVENTMSG(lPara);

        case event^.Message of
          //WM_SYSKEYDOWN:  Msg_ := 1;
          //WM_KEYDOWN:     Msg_ := 2;
          //WM_SYSKEYUP:    Msg_ := 3;
          //WM_KEYUP:       Msg_ := 4;
          //WM_MOUSEMOVE:   Msg_ := 5;
          WM_MOUSELEAVE:   Msg_ := 6;
          //WM_LBUTTONDOWN: Msg_:= 7;
          //WM_LBUTTONUP:   Msg_:= 8;
          //WM_RBUTTONDOWN: Msg_ := 9;
          //WM_RBUTTONUP:   Msg_ := 10;
        else
          Msg_ := 0;
        end;

        if Msg_ = 6 then
        begin
          Form1.Edit1.Text:='OK';  
        end;
    end;
  end;
end;
>メッセージ型(WM_...)に応じたWin32APIのヘルプを参考にして下さい.
勉強します。


Mr.XRAY  URL  2005-11-05 03:32:52  No: 18423

理由はわかりませんが,WM_MOUSELEAVE  は検出できないようです.
WH_JOURNALRECORDフックで検出可能なのは,先に示したサンプルページで
記述しているメッセージだけのようです.
(サンプルコード中のメッセージについては全て動作確認済み)

WM_MOUSEMOVEでマウスの位置で確認するしかないですね.
後は,WH_MOUSEフックを使用したDLLを作成する方法でしょうか.


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加