Activate ContextMenuStrip when the Form doesn't have focus

Viewed 100
  1. I am able to display ContextMenuScript (CMS) successfully outside windows form.
  2. I can Select/Click items using mouse pointer.
  3. However, it doesn't likes keyboard control (arrow up/down, escape) when form is not focused.
  4. If the form is focused and CMS showed, then keyboard can control it but not when not focused :(.
  5. I need help with code which will help to achieve this without form being focused.

Regards

   Public Const CTRL_Key As Integer = &H2
   Public Const Hot_Key As Integer = &H312
   Public Declare Function RegisterHotKey Lib "user32" (ByVal hwnd As IntPtr, ByVal id As Integer, ByVal fsModifiers As Integer, ByVal vk As Integer) As Integer
   Public Declare Function UnregisterHotKey Lib "user32" (ByVal hwnd As IntPtr, ByVal id As Integer) As Integer

   Private Sub Hot_Key_Register() Handles MyBase.Load
    RegisterHotKey(Me.Handle, 100, CTRL_Key, Keys.NumPad1)
    RegisterHotKey(Me.Handle, 200, CTRL_Key, Keys.NumPad2)
    RegisterHotKey(Me.Handle, 300, CTRL_Key, Keys.NumPad3)
   End Sub

   Protected Overrides Sub WndProc(ByRef Window_Message As Message)

    If Window_Message.Msg = Hot_Key Then
        Dim id As IntPtr = Window_Message.WParam
        Select Case (id.ToString)
            Case "100"
                CMS_01.Show(Cursor.Position.X, Cursor.Position.Y)
            Case "200"
                CMS_02.Show(Cursor.Position.X, Cursor.Position.Y)
            Case "300"
                CMS_03.Show(Cursor.Position.X, Cursor.Position.Y)
        End Select
    End If
    MyBase.WndProc(Window_Message)
   End Sub
1 Answers

Option 1 - Using NotifyIcon

The easiest fix which you can use is using an invisible NotifyIcon component as it handles this case in its internal code.

Drop an instance of NotifyIcon on your form and then to use it for showing context menu, assign the context menu strip to its ContextMenuStrip property and then call its ShowContextMenu private method using reflection.

Example

Private Sub ShowContextMenu(menu As ContextMenuStrip)
    NotifyIcon1.Visible = False
    NotifyIcon1.ContextMenuStrip = menu
    Dim m = NotifyIcon1.GetType().GetMethod("ShowContextMenu",
        Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)
    m.Invoke(NotifyIcon1, Nothing)
End Sub
Protected Overrides Sub WndProc(ByRef Window_Message As Message)
    If Window_Message.Msg = Hot_Key Then
        Dim id As IntPtr = Window_Message.WParam
        Select Case (id.ToString)
            Case "100"
                ShowContextMenu(CMS_01)
        End Select
    End If
    MyBase.WndProc(Window_Message)
End Sub

Option 2 - Using Native Window

And here is the fix without using NotifyIcon, using NativeWindow. The following piece of code cares about the active window and if the current form is active, it doesn't use the native window, otherwise it creates and uses native window.

Example

Private window As NativeWindow
Private Sub ShowContextMenu(menu As ContextMenuStrip, p As Point)
    If (Form.ActiveForm IsNot Me) Then
        If (window Is Nothing) Then
            window = New NativeWindow()
            window.CreateHandle(New CreateParams())
        End If
        SetForegroundWindow(window.Handle)
    End If
    menu.Show(p)
End Sub

And show the menu:

ShowContextMenu(CMS_01, Cursor.Position)

Just keep in mind to release the window handle when closing/disposing the form:

If (window IsNot Nothing) Then
    window.DestroyHandle()
    window = Nothing
End If
Related