質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

2回答

1970閲覧

C# マウスのグローバルフック マウスの左をクリックしてもマウスの移動で判定される

konan1234

総合スコア7

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2017/12/15 04:47

c#でマウスのグローバルフックを使って、マウスのイベントを監査するシステムを作っています。
何とか動くようになったのですが、マウスのイベントを拾う処理が上手く行きません。

現象ですが、マウスを左クリックしても、マウスの移動として判定されてしまいます。
詳細

定義
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205,
WM_LBUTTONDBLCLK = 0x0203,
WM_MBUTTONDOWN = 0x0207,
WM_MBUTTONUP = 0x0208
}

マウスをクリックしたら動くメソッド
private IntPtr HookFunc(int nCode, IntPtr wParam, IntPtr lParam)
{
// parse system messages
if (nCode >= 0)
{
if (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
if (LeftButtonDown != null)
LeftButtonDown((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)));
if (MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
if (LeftButtonUp != null)
LeftButtonUp((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)));
if (MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam)
if (RightButtonDown != null)
RightButtonDown((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)));
if (MouseMessages.WM_RBUTTONUP == (MouseMessages)wParam)
if (RightButtonUp != null)
RightButtonUp((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)));
if (MouseMessages.WM_MOUSEMOVE == (MouseMessages)wParam)
if (MouseMove != null)
MouseMove((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)));
if (MouseMessages.WM_MOUSEWHEEL == (MouseMessages)wParam)
if (MouseWheel != null)
MouseWheel((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)));
if (MouseMessages.WM_LBUTTONDBLCLK == (MouseMessages)wParam)
if (DoubleClick != null)
DoubleClick((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)));
if (MouseMessages.WM_MBUTTONDOWN == (MouseMessages)wParam)
if (MiddleButtonDown != null)
MiddleButtonDown((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)));
if (MouseMessages.WM_MBUTTONUP == (MouseMessages)wParam)
if (MiddleButtonUp != null)
MiddleButtonUp((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)));
}
return CallNextHookEx(hookID, nCode, wParam, lParam);
}

マウスを左クリックしたら WM_LBUTTONDOWNの判定をされるはずが、WM_MOUSEMOVEに判定されます。
ちなみにマウスのホイールをクリックしたらWM_MOUSEWHEELで判定されるのでプログラムに問題はないと思います。
この原因が分かりません。OSや環境、使用しているマウスによって変わってしまうのでしょうか。

アドバイスの方、よろしくお願いいたします

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2017/12/15 07:01

読みにくいです。ソースをコードブロックに入れてください。プログラミングをする人に言うのは初歩的過ぎて失礼に当たりますが、例えばコードブロックという言葉の意味がわからない場合は質問するのではなくググってください。
guest

回答2

0

フック用プロシージャ内で参照している引数と値が間違っているのでは。

WM_LBUTTONDOWNはWindowメッセージを示す値なのでフック用プロシージャのnCodeに入るはずです。
WM_LBUTTONDOWNメッセージの場合、wParam は仮想キーコード、lParamはマウスのX,Y座標です。
※※追記していますが、これは私の間違いです。※※

詳細はMSDNをご覧ください。
WM_LBUTTONDOWN message


追記(2017/12/20)
+評価をいただいていましたが、コメントでご指摘のようにマウスフック用のプロシージャのnCodeにはWM_LBUTTONDOWNは入りません。質問者様のコードで正しいです。この点、私の間違いでしたのでお詫びいたします。機会があれば回答の評価を下げてください。すみません。


追記#2(2017/12/20) 動作を確認しました。

私の先の回答、フック用プロシージャのwParamにWM_LBUTTONDOWNが入る件については間違った指摘を載せてしまいすみません。申し訳なかったので、こちらでも動作確認してみました。質問者様がご提示のコードは全部ではないと思いましたので、以下のマイクロソフトのサンプルコードを流用して試しました。
Visual C# .NET では、ウィンドウ フックを設定する方法

結果、マウスを動かさなくても(マウスカーソルを動かさない)、WM_MOUSEMOVE時にプロシージャが呼ばれました。

ただ、左クリックではWM_LBUTTONDOWN、右クリックではWM_RBUTTONDOWNの時に期待するように呼ばれています。WM_MOUSEMOVEはマウスの操作にもよりますが、左クリックでは
WM_LBUTTONDOWN --> WM_MOUSEMOVE --> WM_MOUSEMOVE とのように複数回呼ばれました。これはWindows 7(64ビット) と Windows 10(64ビット)のどちらでも同じでした。
(プログラムは Visual Studio 2017, .NET Framework 4.6.1で作成)

質問者様のケースでも、WM_MOUSEMOVEもあるものの、WM_LBUTTONDOWNも受信できているのではないでしょうか。

投稿2017/12/19 09:37

編集2017/12/20 09:04
dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2017/12/20 06:48

ご指摘ありがとうございます。仰る通りですね。
guest

0

回答とは言えませんが、気になった部分があったのでコメントさせていただきます。

C#

1if (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)

上記のコードではIntPtr型のwParamを列挙型MouseMessagesに変換されています。
IntPtr型はint型と互換性がありますがIntPtrのコンストラクタを見ての通り、内部の変数を64bitの整数値と解釈することもできます。

C#

1if (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam.ToInt32())

最低でも上記程度の型指定はしたほうが厳密な型指定という意味で安心かもしれません。

読む限りはグローバルフックでイベント取得後の振り分け処理には問題なさそうなので、行き詰っているようであれば、グローバルフックのソースコードのほうをあげてもらえると言えることが増えるかもです。

投稿2017/12/15 16:14

tsubaki961

総合スコア73

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2017/12/15 21:31 編集

ToInt32() の必要はありません。わずかに速度が低下するだけで何のメリットもありません。型こそ IntPtr 型ですが、マウスメッセージであるかぎり取りうる範囲は 32 ビットに収まります。
tsubaki961

2017/12/15 23:10

IntPtrとintの扱うビット数が同じなのは知っていたのですが、取りうる値の範囲はまた別だと思っていました。ToInt32()は速度の低下を招くだけでメリットないのですね。勉強になりました。教えて下さりありがとうございます。
konan1234

2017/12/16 02:05

みなさん回答して頂きありがとうございます。少々調べたのですが、 デバックでマウスを移動、左クリックしても押してるボタンはxbutton2となってました。ただ、マウスを移動、左クリックしても、移動で判定されるのは解決出来ない状態です…
hihijiji

2017/12/19 09:17

tsubaki961さんのコードしか見てませんが ```if (MouseMessages.WM_LBUTTONDOWN == MouseMessages.WM_LBUTTONDOWN & wParam)``` では?
hihijiji

2017/12/19 09:23

演算の優先順位を間違えてました if ((MouseMessages.WM_LBUTTONDOWN & wParam) == MouseMessages.WM_LBUTTONDOWN)
konan1234

2017/12/20 02:27

教えていただいた条件式にすると以下のエラーが発生しました… 演算子 '&' を 'bool' と 'System.IntPtr' 型のオペランドに適用することはできません
hihijiji

2017/12/22 03:03

型を合わせて下され。 要は wParam には複数の状態が一緒に入ってくるので、== 演算子で単純には比較できません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問