投稿者 魔界の仮面弁士  (社会人) 投稿日時 2020/3/31 11:30:37
> 変える必要がありますし、汎用で作るのは少し面倒になります。
Cursor.Position を使えば、現在のカーソル位置をスクリーン座標で得ることができます。

> Dim eventSourceControl As Button = DirectCast(sender, Button)
親コントロールは Parent プロパティ、親フォームは FindForm メソッドで得られるので、
それぞれのクライアント座標に変換するために、こういう方法が使えるかもしれません。

Dim posScreen = Cursor.Position
Dim posSelf = eventSourceControl.PointToClient(posScreen)
Dim posContainer = eventSourceControl.Parent.PointToClient(posScreen)
Dim posForm = eventSourceControl.FindForm().PointToClient(posScreen)



> MouseUpイベントはそのときのマウスの位置とは関係がなく、MouseDownイベントを発生させたボタンと同じボタンで発生します。

たとえば Label を MouseDown した後、Button の上で MouseUp したとしても、
Button の MouseUp イベントは発生しません。
(ドラッグ処理を実装するような場合は、むしろその方が扱いやすい)

しかし、どこで MouseDown されたとしても、常に MouseUp した場所の座標を
捕らえたいような場合には、かわりに RawInput を使うこともできます。
https://www.nuget.org/packages/SharpDX.RawInput/

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

    Private Sub RawInput_MouseInput(sender As Object, e As SharpDX.RawInput.MouseInputEventArgs)
        Dim isMouseDown = e.ButtonFlags.HasFlag(SharpDX.RawInput.MouseButtonFlags.LeftButtonDown)
        Dim isMouseUp = e.ButtonFlags.HasFlag(SharpDX.RawInput.MouseButtonFlags.LeftButtonUp)

        '左マウスボタンが操作されていないので、何もしない 
        If Not (isMouseDown OrElse isMouseUp) Then Return

        '現在のマウス位置のコントロールを調べる 
        Dim child = HitTest(Me, MousePosition)

        'それが Button でない場合は何もしない 
        If TypeOf child IsNot Button Then Return

        'MouseDown 箇所のボタンを赤く染める 
        If isMouseDown Then child.BackColor = Color.Red

        'MouseUp 箇所のボタンを青く染める 
        If isMouseUp Then child.BackColor = Color.Blue
    End Sub

    Private Shared Function HitTest(root As Control, screenPos As Point) As Control
        Dim current = root
        Dim last As Control = Nothing
        Do Until current Is Nothing
            last = current
            current = current.GetChildAtPoint(current.PointToClient(screenPos))
        Loop
        Return last
    End Function

End Class