none
Mouse Position in Controlbox RRS feed

Answers

  • Hi. Yes I mean the ControlBox area of the form.  I want my main menu top pop up if user hovers over the area where main menu will be displayed.

    That's actually a very different question.  The ControlBox area of the form is not a part of the form's client area, and therefore you will not get mousehover events generated for mouse movements in that area.  I think that the only way you will be able to detect what you want is to add a hook for mouse movements and decode the mouse position information according to the form location values.  For instance:
    https://sim0n.wordpress.com/2009/03/28/vbnet-mouse-hook-class/

    • Marked as answer by Riversteel Sunday, February 18, 2018 12:14 AM
    Sunday, February 18, 2018 12:08 AM

All replies

  • Hi

    What is 'the Controlbox frame' ?


    Regards Les, Livingston, Scotland

    Saturday, February 17, 2018 11:46 PM
  • Is there a way to determine mouse position within the Controlbox frame?

    Is ControlBox a control?

    You get the current mouse cursor position from the cursor object:
    https://msdn.microsoft.com/en-us/library/system.windows.forms.cursor%28v=vs.110%29.aspx

    You convert that to a position within the current control using this:
    https://msdn.microsoft.com/en-us/library/system.windows.forms.control.pointtoclient(v=vs.110).aspx

    Or do you mean within the ControlBox area of the form?  In that case you would use the same code to calculate the mouse position in the form, and then conpare that to the ControlBox size to see which part of the ControlBox the mouse cursor is in.  Depending on why you want this information you may need to adjust for the form's border.

    Saturday, February 17, 2018 11:50 PM
  • Hi. Yes I mean the ControlBox area of the form.  I want my main menu top pop up if user hovers over the area where main menu will be displayed.

    It works fine for below code where mouse is hovering over form itself, but I would also like menu to display when user hovers over controlbox frame area.

     Public Sub on_mouse_hover_frmGameScreen(ByVal sender As Object, ByVal e As EventArgs)
            Dim x, y As Integer
            get_mouse_position_in_frmGameScreen(x, y)
            If y <= 35 Then
                msMain.Visible = True
            Else
                msMain.Visible = False
            End If
        End Sub
        Private Sub get_mouse_position_in_frmGameScreen(ByRef x As Integer, ByRef y As Integer)
            x = Cursor.Position.X - Me.Location.X
            y = Cursor.Position.Y - Me.Location.Y
        End Sub

    Saturday, February 17, 2018 11:57 PM
  • Hi. Yes I mean the ControlBox area of the form.  I want my main menu top pop up if user hovers over the area where main menu will be displayed.

    That's actually a very different question.  The ControlBox area of the form is not a part of the form's client area, and therefore you will not get mousehover events generated for mouse movements in that area.  I think that the only way you will be able to detect what you want is to add a hook for mouse movements and decode the mouse position information according to the form location values.  For instance:
    https://sim0n.wordpress.com/2009/03/28/vbnet-mouse-hook-class/

    • Marked as answer by Riversteel Sunday, February 18, 2018 12:14 AM
    Sunday, February 18, 2018 12:08 AM
  • Ah okay  makes sense.  Thank you.
    Sunday, February 18, 2018 12:15 AM
  • Ah okay  makes sense.  Thank you.
    I have mouse hook code for mouse move in controlbox but not mouse hover. I can post it tomorrow from the library if you want it. But you would have to use appropriate logic about launching a menu since an event is raised whenever the mouse is moved inside the area of the control box and not just once on hover.

    La vida loca

    Monday, February 19, 2018 8:22 AM
  • Library closed today so I will put code up tomorrow for this. This code launches a ContextMenuStrip if the cursor enters the ControlBox. And another ContextMenuStrip will not launch until the first is closed.

    La vida loca

    Monday, February 19, 2018 11:15 PM
  • Is there a way to determine mouse position within the Controlbox frame?

    Here's some code. See the commented out line for where to display the ContextMenuStrip. One line displays it in the Forms client rectangle and the other covers the ControlBox with it.

    Also note the SystemInformation values for different items in a Windows Form.

    Just add the code to a blank Form as a test.

    Option Strict On
    
    Imports System.Runtime.InteropServices
    
    Public Class Form1
    
        Dim ControlBoxWidth As Integer = 0
        Dim ControlBoxHeight As Integer = 0
        Dim BordersWidth As Integer = 0
        Dim ButtonBorderWidth As Integer = 0
        Dim CaptionBarHeight As Integer = 0
        WithEvents ContextMenuStrip1 As New ContextMenuStrip
    
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Location = New Point(CInt((Screen.PrimaryScreen.WorkingArea.Width / 2) - (Me.Width / 2)), CInt((Screen.PrimaryScreen.WorkingArea.Height / 2) - (Me.Height / 2)))
            ControlBoxWidth = (SystemInformation.MenuBarButtonSize.Width * 5)
            ControlBoxHeight = SystemInformation.MenuBarButtonSize.Height
            BordersWidth = SystemInformation.FrameBorderSize.Width
            ButtonBorderWidth = SystemInformation.BorderSize.Width
            CaptionBarHeight = SystemInformation.CaptionHeight
            MouseHook.Start()
            AddHandler MouseHook.MouseMove, AddressOf Mouse_Move
            ContextMenuStrip1.Items.Add("Hello")
            ContextMenuStrip1.Items.Add("Goodbye")
            AddHandler ContextMenuStrip1.ItemClicked, AddressOf ContextMenuStrip1Items_Click
        End Sub
    
        Private Sub Form1_FormClosing(sender As Object, e As EventArgs) Handles Me.FormClosing
            MouseHook.Stop()
        End Sub
    
        Private Sub ContextMenuStrip1Items_Click(sender As Object, e As ToolStripItemClickedEventArgs)
            MessageBox.Show("OK")
        End Sub
    
        Private Sub Mouse_Move(ByVal sender As Object, ByVal e As EventArgs)
            Me.Text = Cursor.Position.X.ToString & "|" & Cursor.Position.Y.ToString
            If Cursor.Position.X > Me.Left + Me.Width - ControlBoxWidth - (BordersWidth * 2) - (ButtonBorderWidth * 4) AndAlso Cursor.Position.X < Me.Right - BordersWidth + (ButtonBorderWidth * 2) _
                And Cursor.Position.Y > Me.Top AndAlso Cursor.Position.Y < Me.Top + ControlBoxHeight + (ButtonBorderWidth * 3) Then
                ContextMenuStrip1.Show(Me, New Point(Me.Width - ControlBoxWidth - (BordersWidth * 2) - (ButtonBorderWidth * 7), -(CaptionBarHeight + BordersWidth))) ' Places ContextMenuStrip over ControlBox
                ' ContextMenuStrip1.Show(Me, New Point(100, 100)) ' Commented out but places ContextMenuStrip at 100, 100
            End If
        End Sub
    
    End Class
    
    Public NotInheritable Class MouseHook
    
        Public Shared Event MouseMove As EventHandler
    
        Public Shared Sub Start()
            _hookID = SetHook(_proc)
        End Sub
    
        Public Shared Sub [Stop]()
            UnhookWindowsHookEx(_hookID)
        End Sub
    
        Private Shared _proc As LowLevelMouseProc = AddressOf HookCallback
        Private Shared _hookID As IntPtr = IntPtr.Zero
    
        Private Shared Function SetHook(ByVal proc As LowLevelMouseProc) As IntPtr
            Using curProcess As Process = Process.GetCurrentProcess()
                Using curModule As ProcessModule = curProcess.MainModule
                    Dim hook As IntPtr = SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle("user32"), 0)
                    If hook = IntPtr.Zero Then
                        Throw New System.ComponentModel.Win32Exception()
                    End If
                    Return hook
                End Using
            End Using
        End Function
    
        Private Delegate Function LowLevelMouseProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
    
        Private Shared Function HookCallback(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
            If nCode >= 0 AndAlso MouseMessages.WM_MOUSEMOVE = CType(wParam, MouseMessages) Then
                Dim hookStruct As MSLLHOOKSTRUCT = CType(Marshal.PtrToStructure(lParam, GetType(MSLLHOOKSTRUCT)), MSLLHOOKSTRUCT)
                RaiseEvent MouseMove(Nothing, New EventArgs())
            End If
            Return CallNextHookEx(_hookID, nCode, wParam, lParam)
        End Function
    
        Private Const WH_MOUSE_LL As Integer = 14
    
        Private Enum MouseMessages
            WM_MOUSEMOVE = &H200
            WM_LBUTTONDOWN = &H201
            WM_LBUTTONUP = &H202
            WM_LBUTTONDBLCLK = &H203
            WM_MBUTTONDOWN = &H207
            WM_MBUTTONUP = &H208
            WM_MBUTTONDBLCLK = &H209
            WM_MOUSEWHEEL = &H20A
            WM_MOUSEHWHEEL = &H20E
            WM_RBUTTONDBLCLK = &H206
            WM_RBUTTONDOWN = &H204
            WM_RBUTTONUP = &H205
        End Enum
    
        <StructLayout(LayoutKind.Sequential)> _
        Private Structure POINT
            Public x As Integer
            Public y As Integer
        End Structure
    
        <StructLayout(LayoutKind.Sequential)> _
        Private Structure MSLLHOOKSTRUCT
            Public pt As POINT
            Public mouseData As UInteger
            Public flags As UInteger
            Public time As UInteger
            Public dwExtraInfo As IntPtr
        End Structure
    
    
        <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Private Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal lpfn As LowLevelMouseProc, ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr
        End Function
    
        <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Private Shared Function UnhookWindowsHookEx(ByVal hhk As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function
    
        <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Private Shared Function CallNextHookEx(ByVal hhk As IntPtr, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
        End Function
    
        <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Private Shared Function GetModuleHandle(ByVal lpModuleName As String) As IntPtr
        End Function
    
    End Class


    La vida loca

    Tuesday, February 20, 2018 8:08 PM
  • Hi. Yes I mean the ControlBox area of the form.  I want my main menu top pop up if user hovers over the area where main menu will be displayed.

    It works fine for below code where mouse is hovering over form itself, but I would also like menu to display when user hovers over controlbox frame area.

     You don't really need to use a mouse hook to do this.  Below is two different ways to do it,  the first example being the better of the two in my opinion since it does not use a constantly running timer like the second example.

     You can try the first example by creating a new form project with 1 Timer and 1 MenuStrip added to the form.  Add a few items to the menu too.

     It works by detecting the WM_NCMOUSEMOVE and WM_MOUSEMOVE to Start/Restart a Timer with it's interval set to the system's MouseHoverTime.  If that time expires before the mouse is moved or the mouse leaves the area of interest,  then the MenuStrip becomes visible.  The MenuStrip will stay visible until the mouse leaves the form or the area of interest,  unless the menu is active (has a dropdown menu opened).

    Public Class Form1
        Private Const WM_MOUSEMOVE As Integer = &H200
        Private Const WM_NCMOUSELEAVE As Integer = &H2A2
        Private Const WM_NCMOUSEMOVE As Integer = &HA0
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Timer1.Interval = SystemInformation.MouseHoverTime
            MenuStrip1.Visible = False
        End Sub
    
        Protected Overrides Sub WndProc(ByRef m As Message)
            MyBase.WndProc(m)
            If Me.Focused Then
                If m.Msg = WM_NCMOUSEMOVE OrElse m.Msg = WM_MOUSEMOVE Then
                    Dim ptf As New Point(MousePosition.X - Me.Left, MousePosition.Y - Me.Top)
                    Dim MenuBottom As Integer = (Me.PointToScreen(Me.ClientRectangle.Location).Y - Me.Top) + MenuStrip1.Height
                    Dim BrdrWdth As Integer = (Me.Width - Me.ClientSize.Width) \ 2
                    Dim TriggerMenuBounds As New Rectangle(BrdrWdth, BrdrWdth, Me.ClientSize.Width, MenuBottom)
                    If TriggerMenuBounds.Contains(ptf) Then
                        If Not MenuStrip1.Visible AndAlso MouseButtons = MouseButtons.None Then
                            Timer1.Stop()
                            Timer1.Start()
                        End If
                    Else
                        Timer1.Stop()
                        MenuStrip1.Visible = False
                    End If
                End If
                If m.Msg = WM_NCMOUSELEAVE Then
                    Dim ptf As New Point(MousePosition.X - Me.Left, MousePosition.Y - Me.Top)
                    Dim BrdrWdth As Integer = (Me.Width - Me.ClientSize.Width) \ 2
                    Dim InnerBounds As New Rectangle(BrdrWdth, BrdrWdth, Me.ClientSize.Width, Me.ClientSize.Height)
                    If Not InnerBounds.Contains(ptf) Then
                        Timer1.Stop()
                        MenuStrip1.Visible = False
                    End If
                End If
            End If
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Timer1.Stop()
            If MouseButtons = MouseButtons.None Then
                MenuStrip1.Visible = True
            End If
        End Sub
    End Class
    
     

     

     This example uses a constantly running timer to create the same exact effect as the above example does.  It requires the same controls on the form as the above example too.

    Public Class Form1
        Private LastPosition As Point = Point.Empty
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            MenuStrip1.Visible = False
            Timer1.Interval = SystemInformation.MouseHoverTime \ 2
            Timer1.Start()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            If Me.Focused Then
                If MouseButtons = MouseButtons.None Then
                    Dim CaptionBounds As New Rectangle(Me.Left + ((Me.Width - Me.ClientSize.Width) \ 2), Me.Top, Me.ClientSize.Width, (Me.Height - Me.ClientSize.Height) - ((Me.Width - Me.ClientSize.Width) \ 2))
                    CaptionBounds.Height += MenuStrip1.Height
                    If CaptionBounds.Contains(MousePosition) Then
                        Dim mp As New Point(MousePosition.X - Me.Left, MousePosition.Y - Me.Top)
                        If Not MenuStrip1.Visible AndAlso LastPosition = mp Then
                            MenuStrip1.Visible = True
                        End If
                        LastPosition = mp
                    Else
                        If (From i As ToolStripItem In MenuStrip1.Items.Cast(Of ToolStripItem) Where i.Pressed).Count < 1 Then
                            LastPosition = Point.Empty
                            MenuStrip1.Visible = False
                        End If
                    End If
                End If
            Else
                LastPosition = Point.Empty
                MenuStrip1.Visible = False
            End If
        End Sub
    End Class
    
     

     Both examples above do this...  Notice the menu does not become visible if the mouse is moving over the caption area or the menu area,  unless the mouse hovers in the same spot for the system's MouseHoverTime (typically 400 milliseconds).

     


    If you say it can`t be done then i`ll try it

    Wednesday, February 21, 2018 1:05 AM
  • Nice non-email replying Razerz. You can get the mouses hover time System.Information.MouseHoverTime zfh-2 or fyi. (:

    La vida loca

    Wednesday, February 21, 2018 1:05 PM