C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

WndProcによるマウス押下状態取得

[トピック内 12 記事 (1 - 12 表示)]  << 0 >>

■97964 / inTopicNo.1)  WndProcによるマウス押下状態取得
  
□投稿者/ プログラマー (5回)-(2021/08/13(Fri) 18:41:58)

分類:[.NET 全般] 

いつもお世話になっております。
VB.NETに関する質問です。

フォーム内でマウスクリックがされたこと示すウィンドウメッセージを、WndProcを使って取得したいのですが
どうすればよいでしょうか?
出来れば「押下した瞬間」ではなく「押下されている状態」を取得できるようにしたいです。

ご教授お願い致します。

Public Class Form1
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
'ここで状態を取得したい
End Sub
End Class
引用返信 編集キー/
■97965 / inTopicNo.2)  Re[1]: WndProcによるマウス押下状態取得
□投稿者/ とっちゃん (733回)-(2021/08/13(Fri) 23:47:36)
No97964 (プログラマー さん) に返信
> フォーム内でマウスクリックがされたこと示すウィンドウメッセージを、WndProcを使って取得したいのですが
> どうすればよいでしょうか?
> 出来れば「押下した瞬間」ではなく「押下されている状態」を取得できるようにしたいです。
>
> ご教授お願い致します。
>
> Public Class Form1
> Protected Overrides Sub WndProc(ByRef m As Message)
> MyBase.WndProc(m)
> 'ここで状態を取得したい
> End Sub
> End Class

ここで状態を取得したいのところで Control.MouseButtons プロパティで参照すればよいと思います。
・Control.MouseButtons プロパティ(.NET Framework 4.8)
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.control.mousebuttons?WT.mc_id=DT-MVP-32182&view=netframework-4.8

何のメッセージでも状態判定できます。

もし、API が使いたいのだ!ということであれば、GetAsyncKeyState API で判定できます(マウスの左ボタンなら、VK_LBUTTON)。
・GetAsyncKeyState API
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate?WT.mc_id=DT-MVP-32182

仮想キーコード(GetAsyncKeyState などに渡す値)は以下を参照してください。
・Virtual-Key Codes
https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes?WT.mc_id=DT-MVP-32182

引用返信 編集キー/
■97966 / inTopicNo.3)  Re[2]: WndProcによるマウス押下状態取得
□投稿者/ プログラマー (7回)-(2021/08/14(Sat) 17:39:56)
とっちゃんさん回答ありがとうございます。

フォームの表示・非表示を行うとマウスイベントが正常に取得できないケースがあります。

※フォーム1(スタートアップ時表示)
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
SetDesktopBounds(0, 0, 640, 480)
Form2.Show()
Form2.Hide()
Form2.SetDesktopBounds(640, 0, 640, 480)
End Sub

Private Sub Form1_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
Hide()
Form2.Show()
End Sub

Private Sub Form1_MouseUp(sender As Object, e As MouseEventArgs) Handles Me.MouseUp
Stop
End Sub
End Class

※フォーム2
Public Class Form2
Private Sub Form2_MouseUp(sender As Object, e As MouseEventArgs) Handles Me.MouseUp
Stop
End Sub
End Class

MouseUpイベントが取得出来ればよいのですが、上記コードではマウスボタンを離した時のイベントがどちらのフォームでも発生しません。
そのためTimerコントロールを用いてウィンドウメッセージを取得するしかないと思い、質問いたしました。


> もし、API が使いたいのだ!ということであれば、GetAsyncKeyState API で判定できます(マウスの左ボタンなら、VK_LBUTTON)。
> ・GetAsyncKeyState API
> https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate?WT.mc_id=DT-MVP-32182

上記URLではC++のコードしか記載されていませんが、VB.NETの場合はどのように書けばよろしいでしょうか?
お手数をお掛けしますが、回答お願いいたします。


引用返信 編集キー/
■97967 / inTopicNo.4)  Re[3]: WndProcによるマウス押下状態取得
□投稿者/ KOZ (161回)-(2021/08/14(Sat) 18:23:31)
No97966 (プログラマー さん) に返信
> MouseUpイベントが取得出来ればよいのですが、上記コードではマウスボタンを離した時のイベントがどちらのフォームでも発生しません。
> そのためTimerコントロールを用いてウィンドウメッセージを取得するしかないと思い、質問いたしました。

(1) Form1 の上でマウスボタンを押す
(2) Form1 を隠して Form2 を表示
(3) マウスボタンが離されたイベントを取得

ということでしょうか?

(2) の後で、Form1 でも Form2 のどちらでもいいのですが、Capture プロパティを True にすれば、MouseUp イベントが発生します。
引用返信 編集キー/
■97968 / inTopicNo.5)  Re[3]: WndProcによるマウス押下状態取得
□投稿者/ とっちゃん (734回)-(2021/08/14(Sat) 19:49:32)
No97966 (プログラマー さん) に返信

>>もし、API が使いたいのだ!ということであれば、GetAsyncKeyState API で判定できます(マウスの左ボタンなら、VK_LBUTTON)。
>>・GetAsyncKeyState API
>>https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate?WT.mc_id=DT-MVP-32182
>
> 上記URLではC++のコードしか記載されていませんが、VB.NETの場合はどのように書けばよろしいでしょうか?
> お手数をお掛けしますが、回答お願いいたします。
>
>
Control.MouseButtons では判定できませんでしたか?
それとも、「APIが使いたいのだ!」ということでしょうか?

後者であれば、改めて書いてもらえばと思います。

引用返信 編集キー/
■97969 / inTopicNo.6)  Re[4]: WndProcによるマウス押下状態取得
□投稿者/ プログラマー (8回)-(2021/08/14(Sat) 20:09:37)
KOZ さん回答ありがとうございます。

> (1) Form1 の上でマウスボタンを押す
> (2) Form1 を隠して Form2 を表示
> (3) マウスボタンが離されたイベントを取得
>
> ということでしょうか?

はい、そのような操作を想定しています。


> (2) の後で、Form1 でも Form2 のどちらでもいいのですが、Capture プロパティを True にすれば、MouseUp イベントが発生します。

Hideで非表示にした場合ですとイベントが発生しましたが、以下のように記述するとCaptureをTrueにしてもイベントが発生しません。
最初の質問ではソースを簡略化してましたが、実際は以下の方法での表示・非表示を想定しています。失礼いたしました。
この場合でもMouseUpイベントを取得することは可能でしょうか?

Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
SetDesktopBounds(0, 0, 640, 480)
Form2.Show()
Form2.Opacity = 0
Form2.ShowInTaskbar = False
Form2.SetDesktopBounds(640, 0, 640, 480)
End Sub

Private Sub Form1_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
Opacity = 0
ShowInTaskbar = False
Form2.Opacity = 100
Form2.ShowInTaskbar = True
Capture = True
End Sub

Private Sub Form1_MouseUp(sender As Object, e As MouseEventArgs) Handles Me.MouseUp
Stop
End Sub
End Class
引用返信 編集キー/
■97970 / inTopicNo.7)  Re[4]: WndProcによるマウス押下状態取得
□投稿者/ プログラマー (9回)-(2021/08/14(Sat) 20:21:01)
No97968 (とっちゃん さん) に返信

> Control.MouseButtons では判定できませんでしたか?

MouseMoveイベント内に以下のコードを記述しましたが、判定できませんでした。

If e.Button = MouseButtons.Left Then
Stop
End If

改めてAPIを用いた処理を教えていただきたいです。
よろしくお願いします。
引用返信 編集キー/
■97971 / inTopicNo.8)  Re[5]: WndProcによるマウス押下状態取得
□投稿者/ とっちゃん (735回)-(2021/08/14(Sat) 21:21:10)
No97970 (プログラマー さん) に返信
> ■No97968 (とっちゃん さん) に返信
>
>>Control.MouseButtons では判定できませんでしたか?
>
> MouseMoveイベント内に以下のコードを記述しましたが、判定できませんでした。
>
> If e.Button = MouseButtons.Left Then
> Stop
> End If
>
> 改めてAPIを用いた処理を教えていただきたいです。
> よろしくお願いします。

MouseEventArgs のメンバーの e.Button ではなく、Control.MouseButtons という Control クラスのスタティック(Shared)プロパティです。

一度こちらの「リファレンス」に目を通してみてください。
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.control.mousebuttons?WT.mc_id=DT-MVP-32182&view=netframework-4.8


引用返信 編集キー/
■97972 / inTopicNo.9)  Re[6]: WndProcによるマウス押下状態取得
□投稿者/ プログラマー (10回)-(2021/08/15(Sun) 06:07:58)
> MouseEventArgs のメンバーの e.Button ではなく、Control.MouseButtons という Control クラスのスタティック(Shared)プロパティです。
>
> 一度こちらの「リファレンス」に目を通してみてください。
> https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.control.mousebuttons?WT.mc_id=DT-MVP-32182&view=netframework-4.8

MouseUpイベントが発生しないので、上記リファレンス通りの書き方をしても正常に動作しませんでした。
引用返信 編集キー/
■97974 / inTopicNo.10)  Re[7]: WndProcによるマウス押下状態取得
□投稿者/ 魔界の仮面弁士 (3161回)-(2021/08/15(Sun) 10:36:13)
No97972 (プログラマー さん) に返信
>>MouseEventArgs のメンバーの e.Button ではなく、Control.MouseButtons という Control クラスのスタティック(Shared)プロパティです。
> MouseUpイベントが発生しないので、上記リファレンス通りの書き方をしても正常に動作しませんでした。

MouseUp イベントを使う必要があるなどとは、誰も言っていませんよ。

もちろん MouseDown や MouesUp 中でも利用できますが、
No97965 でも書かれているように、いつでもどのタイミングでも利用できます。
たとえば WndProc 中や Timer_Tick あるいは Button_Click や PictureBox_Paint でも呼び出せます。

 'Left, Middle, Right, XButton1, XButton2
 Dim leftButtonPressing As Boolean = MouseButtons.HasFlag(MouseButtons.Left)

この System.Windows.Forms.Control クラスの MouseButtons プロパティとは
内部的には GetKeyState API を呼び出すだけの処理です。

これと既に紹介されている GetAsyncKeyState API との違いですが、
GetKeyState が、Windows Message 取得時のキー入力状態を取得するものであるのに対し、
GetAsyncKeyState が、IRQ (ハードウェア割り込み)レベルでのキー取得となっています。

ほとんどの場合は MouseButtons で事足りるとは思いますが、高負荷状態などで
メッセージループを捌き切れていない状態(それは大抵、作りこみがマズイという
ことでもあるのですが)の場合、MouseButtons では期待する結果が得られないかもしれません。

仮に MouseButtons で拾えないケースにおいても、GetAsyncKeyState であれば、
現在のマウスボタンやキーボード状態を得ることができるでしょう。宣言例はこちら。
http://kchon.blog111.fc2.com/blog-entry-137.html
https://www.chuken-engineer.com/entry/2019/06/20/000247

この時、マウスボタンを表す定数値として
 Public Const VK_LBUTTON As Integer = 1 '← No97965 にて紹介済み
 Public Const VK_RBUTTON As Integer = 2
 Public Const VK_MBUTTON As Integer = 4
 Public Const VK_XBUTTON1 As Integer = 5
 Public Const VK_XBUTTON2 As Integer = 6
を利用できますが、これらは同値が System.Windows.Forms.Keys 列挙体として
 Keys.LButton
 Keys.RButton
 Keys.MButton
 Keys.XButton1
 Keys.XButton2
として定義済みのため、あえて定数を切りなおさずとも、これらを利用して呼び出すこともできます。


ただしこうした呼び出しは、セキュリティ系のソフトによって検出されやすくなります。

たとえば Timer 等で常時監視するような操作は、危険性のあるソフトウェア(たとえばキーロガーなど)と
誤解されてしまい、ブロックや駆除対象になりえます。その点は注意が必要でしょう。
引用返信 編集キー/
■97976 / inTopicNo.11)  Re[5]: WndProcによるマウス押下状態取得
□投稿者/ 魔界の仮面弁士 (3163回)-(2021/08/15(Sun) 12:48:32)
No97969 (プログラマー さん) に返信
>> (1) Form1 の上でマウスボタンを押す
>> (2) Form1 を隠して Form2 を表示
>> (3) マウスボタンが離されたイベントを取得
>> ということでしょうか?
> はい、そのような操作を想定しています。

No97964 時点では「押下されている状態」を取得とありましたが、
No97969 時手では「離されたイベント」を取得ということで、
質問内容が変化していますね。(^^;

マウスボタンが離されたタイミングを取得するのが目的なら、
WM_INPUT メッセージを処理する手法もあります。
https://j.mp/3jSFlNu


しかしこの場合、自前で API 宣言を連ねるよりも、
SharpDX.RawInput を NuGet 参照するのが手っ取り早いでしょう。

Imports SharpDX.RawInput
Public Class Form1
 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  Device.RegisterDevice(SharpDX.Multimedia.UsagePage.Generic, SharpDX.Multimedia.UsageId.GenericMouse, DeviceFlags.None)

  SetDesktopBounds(0, 0, 640, 480)
  Form2.Show()
  Form2.Opacity = 0
  Form2.ShowInTaskbar = False
  Form2.SetDesktopBounds(640, 0, 640, 480)
 End Sub

 Private Sub RawInput_MouseInput(sender As Object, e As MouseInputEventArgs)
  If e.ButtonFlags.HasFlag(MouseButtonFlags.LeftButtonUp) Then
   RemoveHandler Device.MouseInput, AddressOf RawInput_MouseInput

   Stop
  End If
 End Sub

 Private Sub Form1_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
  If e.Button.HasFlag(MouseButtons.Left) Then
   Opacity = 0
   ShowInTaskbar = False
   Form2.Opacity = 100
   Form2.ShowInTaskbar = True
   AddHandler Device.MouseInput, AddressOf RawInput_MouseInput
  End If
 End Sub
End Class


> Hideで非表示にした場合ですとイベントが発生しましたが、以下のように記述するとCaptureをTrueにしてもイベントが発生しません。

MouesDown 時と MouseUp 時とで、キャプチャしたウィンドウのハンドルが異なるため、
Capture プロパティが期待動作しなくなっています。

ShowInTaskBar はフォーム生成前に呼び出し、そのあとは変更すべきではありません。
これはフォーム起動時に呼び出される CreateParams プロパティの ExStyle で利用される設定値だからです。

Windows API 側の制限により、この値はハンドル生成時にしか指定できないため、
フォーム生成後に切り替えた場合は、現在のウィンドウ ハンドルが作り直されることになります。

Debug.WriteLine(Me.Handle)
Me.ShowInTaskbar = False
' Me.RecreateHandle() 'ShowInTaskbar の変更により、内部的に RecreateHandle が呼ばれる
Debug.WriteLine(Me.Handle) 'それにより、ウィンドウハンドルが別の値になる
引用返信 編集キー/
■97985 / inTopicNo.12)  Re[6]: WndProcによるマウス押下状態取得
□投稿者/ プログラマー (11回)-(2021/08/17(Tue) 18:26:22)
魔界の仮面弁士さん回答ありがとうございます。

> No97964 時点では「押下されている状態」を取得とありましたが、
> No97969 時手では「離されたイベント」を取得ということで、
> 質問内容が変化していますね。(^^;

「離された瞬間」を取得するより、Timerコントロールを用いて一定間隔ごとに「押下されている状態」をチェックする方が確実だと思い質問しましたが・・・
確かにおっしゃる通りです。失礼いたしました。

> しかしこの場合、自前で API 宣言を連ねるよりも、
> SharpDX.RawInput を NuGet 参照するのが手っ取り早いでしょう。

このようなやり方があったのですね。

> MouesDown 時と MouseUp 時とで、キャプチャしたウィンドウのハンドルが異なるため、
> Capture プロパティが期待動作しなくなっています。
>
> ShowInTaskBar はフォーム生成前に呼び出し、そのあとは変更すべきではありません。
> これはフォーム起動時に呼び出される CreateParams プロパティの ExStyle で利用される設定値だからです。
>
> Windows API 側の制限により、この値はハンドル生成時にしか指定できないため、
> フォーム生成後に切り替えた場合は、現在のウィンドウ ハンドルが作り直されることになります。

詳しく説明していただきありがとうございます。
この点を考慮して書き直してみます。

この質問は解決済みとさせていただきます。
ご回答くださった方々有難うございました。
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ