Is there a way to register hotkeys to toggle a form from an invisible(hidden) program? I’ve tired normal methods and they only work when the form is either visible, or the active window. Thank you in advance for any help!
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.KeyPreview = True
Me.ShowInTaskbar = False
Me.ShowIcon = False
Me.Visible = False
End Sub
This is the code that hides the program.
You want to use Global Hotkeys. Just make sure you unregister when the program closes.
From a MSDN article that helped me in the past:
Firstly, you need to know the Virtual-Key Codes.
http://msdn2.microsoft.com/en-us/library/ms927178.aspx You can then
P/Invoke RegisterHotKey/UnregisterHotKey APIs to register/Unregister
the hotkey. Code sample: Register multiple hotkeys such as Alt+D,
Alt+C, etc.
Imports System.Runtime.InteropServices
Public Class Form1
Public Const MOD_ALT As Integer = &H1 'Alt key
Public Const WM_HOTKEY As Integer = &H312
<DllImport("User32.dll")> _
Public Shared Function RegisterHotKey(ByVal hwnd As IntPtr, _
ByVal id As Integer, ByVal fsModifiers As Integer, _
ByVal vk As Integer) As Integer
End Function
<DllImport("User32.dll")> _
Public Shared Function UnregisterHotKey(ByVal hwnd As IntPtr, _
ByVal id As Integer) As Integer
End Function
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
RegisterHotKey(Me.Handle, 100, MOD_ALT, Keys.D)
RegisterHotKey(Me.Handle, 200, MOD_ALT, Keys.C)
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_HOTKEY Then
Dim id As IntPtr = m.WParam
Select Case (id.ToString)
Case "100"
MessageBox.Show("You pressed ALT+D key combination")
Case "200"
MessageBox.Show("You pressed ALT+C key combination")
End Select
End If
MyBase.WndProc(m)
End Sub
Private Sub Form1_FormClosing(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.FormClosingEventArgs) _
Handles MyBase.FormClosing
UnregisterHotKey(Me.Handle, 100)
UnregisterHotKey(Me.Handle, 200)
End Sub
End Class
Related
I use the code below to start a cmd.exe windows and move it into a panel after execution. At this moment, the child window is resized to fit into Panel1 on my Form1. I would like it to be the other way around: my Form1 (and thus Panel1) should resize to fit the size of the child window, so no matter what the size of the default cmd.exe window is on the local computer.
Does anybody know how I should do that?
Thanks for any help in advance!
Kind regards,
Eric
Imports System.Runtime.InteropServices
Public Class Form1
Private WithEvents Tmr As New Timer With {.Interval = 100}
Private Const HWND_BOTTOM As Integer = &H1
Private WithEvents proc As New Process
<DllImport("user32.dll", EntryPoint:="SetParent")>
Private Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", EntryPoint:="SetWindowPos")>
Private Shared Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As UInteger) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.Text = "My title"
proc.EnableRaisingEvents = True
proc.StartInfo.FileName = "cmd"
proc.Start()
Tmr.Start()
End Sub
Private Sub Tmr_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Tmr.Tick
If SetParent(proc.MainWindowHandle, Panel1.Handle) <> IntPtr.Zero Then
Tmr.Stop()
SetWindowPos(proc.MainWindowHandle, New IntPtr(HWND_BOTTOM), 0, 0, Panel1.ClientSize.Width, Panel1.ClientSize.Height, 0)
End If
End Sub
Private Sub Proc_Exited(ByVal sender As Object, ByVal e As System.EventArgs) Handles proc.Exited
Invoke(Sub() Close())
End Sub
End Class
As suggested by #Jimi, I used DwmGetWindowAttribute to retrieve the size of the child, before moving it into the panel. Afterwards I use ShowWindow to maximize it, to get rid of the borders.
The changed code can be found in a different post of mine.
I’m working on a project that I need to register a hot key for, any I’m running into a wall trying to figure out how to add another letter modifier to the hotkey registrar. For example, CTRL+SHIFT, A+B. As of right now the code that I’m running works, but it only accepts one letter modifier. Can anyone show me where I’m going wrong? I was hoping it was as simple as adding the ‘And’ operant or ‘+’ to concatenate it as a string. Here’s an example of what I have that works.
Imports System.Runtime.InteropServices
Public Class Form1
Public Const MOD_ALT As Integer = &H1
Public Const MOD_SHIFT As Integer = &H4
Public Const MOD_CTRL As Integer = &H2
Public Const MOD_WIN As Integer = &H8
Public Const WM_HOTKEY As Integer = &H312
<DllImport("User32.dll")>
Public Shared Function RegisterHotKey(ByVal hwnd As IntPtr, ByVal id As Integer, ByVal fsModifiers As Integer, ByVal vk As Integer) As Integer
End Function
<DllImport("User32.dll")>
Public Shared Function UnregisterHotKey(ByVal hwnd As IntPtr, ByVal id As Integer) As Integer
End Function
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
RegisterHotKey(Me.Handle, 100, MOD_ALT Or MOD_SHIFT, Keys.A)'alt+shift,A
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_HOTKEY Then
Dim id As IntPtr = m.WParam
Select Case (id.ToString)
Case "100"
MessageBox.Show("You pressed alt+shift, A", "Hello", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End Select
End If
MyBase.WndProc(m)
End Sub
Private Sub Form1_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
UnregisterHotKey(Me.Handle, 100)
End Sub
End Class
Like I said, this works so far, CTRL+SHIFT, A. What I’d like to do is modify it to accept an additional modifier key like, CTRL+SHIFT, A+B. Thank you in advance for your help!
I was using hot keys, but out of nowhere, they are not working anymore. It's very confusing.
It happened when my friend checked my code through team-viewer. Then it stopped working.
Public Class Form2
Public Const MOD_ALT As Integer = &H1 'Alt key
Public Const WM_HOTKEY As Integer = &H312
<DllImport("User32.dll")> _
Public Shared Function RegisterHotKey(ByVal hwnd As IntPtr, _
ByVal id As Integer, ByVal fsModifiers As Integer, _
ByVal vk As Integer) As Integer
End Function
<DllImport("User32.dll")> _
Public Shared Function UnregisterHotKey(ByVal hwnd As IntPtr, _
ByVal id As Integer) As Integer
End Function
Private Sub Form2_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
RegisterHotKey(Me.Handle, 100, MOD_ALT, Keys.E)
RegisterHotKey(Me.Handle, 200, MOD_ALT, Keys.A)
Me.TopMost = True
Me.ShowInTaskbar = False
Me.TransparencyKey = Me.BackColor
Dim leftpos As Long
Dim toppos As Long
leftpos = (My.Computer.Screen.WorkingArea.Right - 2) - Me.Width
toppos = (My.Computer.Screen.WorkingArea.Bottom - 2) - Me.Height
Me.Location = New Point(leftpos, toppos)
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_HOTKEY Then
Dim id As IntPtr = m.WParam
Select Case (id.ToString)
Case "100"
Application.Exit()
Case "200"
Form3.Show()
End Select
End If
MyBase.WndProc(m)
End Sub
Private Sub Form2_FormClosing(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.FormClosingEventArgs) _
Handles MyBase.FormClosing
UnregisterHotKey(Me.Handle, 100)
UnregisterHotKey(Me.Handle, 200)
End Sub
Private Sub TextBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyDown
If e.KeyCode = Keys.Enter Then
Form3.Show()
Form3.Activate()
End If
End Sub
End Class
i fixed some api function signatures with the help of a good guy IronRazer in dreamincode as per the below
<DllImport("user32.dll", EntryPoint:="RegisterHotKey")> _
Private Shared Function RegisterHotKey(ByVal hWnd As IntPtr, ByVal id As Integer, ByVal fsModifiers As Integer, ByVal vk As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("user32.dll", EntryPoint:="UnregisterHotKey")> _
Private Shared Function UnregisterHotKey(ByVal hWnd As IntPtr, ByVal id As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
and it worked fine.
I am creating a customized menu and I want the menu to close when the user clicks anywhere else on the form. I tried using .LostFocus, but that only works if the thing they click on can take the focus. Lots of things don't take focus and therefore the menu stays open. I need a listener on the button that says, "if the mouse was clicked and it wasn't on you, then do something (close)".
Any suggestions?
Thanks.
You could create a MouseDown-Eventhandler for every Control in your form
For Each c As Control In Me.Controls
AddHandler c.MouseDown, AddressOf c_MouseDown
Next
Then check if the sender of the event is not your button
Private Sub c_MouseDown(sender As Object, e As MouseEventArgs)
If sender Is Button1 Then
MsgBox("Open costumized menu")
Else
MsgBox("Replace this with 'close something'")
End If
End Sub
Edit: Of course you have to create an eventhandler for the form too
AddHandler Me.MouseDown, AddressOf c_MouseDown
Best to put the handler in the constructor
Setup the MouseClick event handler in the form constructor, like this:
Public Sub New()
Me.MouseClick += mouseClick
End Sub
Then you can write your event handler code, like this:
Private Sub mouseClick(sender As Object, e As MouseEventArgs)
' Do whatever logic you want here
' For example you can capture which mouse button was clicked, like this:
If e.Button = MouseButtons.Left Then
End If
End Sub
Thanks for the info, but I solved my question by using the code on this page:
http://www.daniweb.com/software-development/vbnet/threads/369609/detecting-a-mouse-click
Apparently using a Hook is the only way to detect ANY mouse click. It even detects clicks outside of my program.
The only way to do it is with the hook.
Here is some code. You should still read up on it. And you will need to go to project / properties / Debug and uncheck enable the visual studio hosting process checkbox.
This code will count all your left and right mouse clicks anywhere on the screen while the form is running.
For the Form you want it in:
Public Class Form1
Private WithEvents MouseDetector As MouseDetector
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
MouseDetector = New MouseDetector
End Sub
Private Sub Form1_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
RemoveHandler MouseDetector.MouseLeftButtonClick, AddressOf MouseDetector_MouseLeftButtonClick
RemoveHandler MouseDetector.MouseRightButtonClick, AddressOf MouseDetector_MouseRightButtonClick
MouseDetector.Dispose()
End Sub
Private Sub MouseDetector_MouseLeftButtonClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MouseDetector.MouseLeftButtonClick
If IsNumeric(LabelLeft.Text) Then
LabelLeft.Text = CInt(LabelLeft.Text) + 1
Else
LabelLeft.Text = 1
End If
End Sub
Private Sub MouseDetector_MouseRightButtonClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MouseDetector.MouseRightButtonClick
If IsNumeric(LabelRight.Text) Then
LabelRight.Text = CInt(LabelRight.Text) + 1
Else
LabelRight.Text = 1
End If
End Sub
End Class
Add a class to the project and name it MouseDetector and copy the following code into it.
Imports System.Runtime.InteropServices
Imports System.Reflection
Imports System.Windows.Forms
Public Class MouseDetector
Public Event MouseLeftButtonClick(ByVal sender As Object, ByVal e As MouseEventArgs)
Public Event MouseRightButtonClick(ByVal sender As Object, ByVal e As MouseEventArgs)
Private Delegate Function MouseHookCallback(ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As Integer
Private MouseHookCallbackDelegate As MouseHookCallback
Private MouseHookID As Integer
Public Sub New()
If MouseHookID = 0 Then
MouseHookCallbackDelegate = AddressOf MouseHookProc
MouseHookID = SetWindowsHookEx(CInt(14), MouseHookCallbackDelegate, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly.GetModules()(0)), 0)
If MouseHookID = 0 Then
'error
End If
End If
End Sub
Public Sub Dispose()
If Not MouseHookID = -1 Then
UnhookWindowsHookEx(MouseHookID)
MouseHookCallbackDelegate = Nothing
End If
MouseHookID = -1
End Sub
Private Enum MouseMessages
WM_LeftButtonDown = 513
WM_LeftButtonUp = 514
WM_LeftDblClick = 515
WM_RightButtonDown = 516
WM_RightButtonUp = 517
WM_RightDblClick = 518
End Enum
<StructLayout(LayoutKind.Sequential)> _
Private Structure Point
Public x As Integer
Public y As Integer
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure MouseHookStruct
Public pt As Point
Public hwnd As Integer
Public wHitTestCode As Integer
Public dwExtraInfo As Integer
End Structure
<DllImport("user32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function CallNextHookEx( _
ByVal idHook As Integer, _
ByVal nCode As Integer, _
ByVal wParam As IntPtr, _
ByVal lParam As IntPtr) As Integer
End Function
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall, SetLastError:=True)> _
Private Shared Function SetWindowsHookEx _
(ByVal idHook As Integer, ByVal HookProc As MouseHookCallback, _
ByVal hInstance As IntPtr, ByVal wParam As Integer) As Integer
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall, SetLastError:=True)> _
Private Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Integer
End Function
Private Function MouseHookProc(ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As Integer
If nCode < 0 Then
Return CallNextHookEx(MouseHookID, nCode, wParam, lParam)
End If
Dim MouseData As MouseHookStruct = Marshal.PtrToStructure(lParam, GetType(MouseHookStruct))
Select Case wParam
Case MouseMessages.WM_LeftButtonUp
RaiseEvent MouseLeftButtonClick(Nothing, New MouseEventArgs(MouseButtons.Left, 1, MouseData.pt.x, MouseData.pt.y, 0))
Case MouseMessages.WM_RightButtonUp
RaiseEvent MouseRightButtonClick(Nothing, New MouseEventArgs(MouseButtons.Right, 1, MouseData.pt.x, MouseData.pt.y, 0))
End Select
Return CallNextHookEx(MouseHookID, nCode, wParam, lParam)
End Function
End Class
Just in case its useful to someone at some point... This builds on Daniel's answer and other similar suggestions I've found via a web search. This does 2 things I didn't see in other examples. #1 - only add the click handler to non-input controls, and #2, it recursively adds the click handler for controls that contain other controls. This one goes 4 levels deep.
'Add Click Handler to all non-input controls
Private Sub FrmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each c1 As Control In Me.Controls
If Not c1.CanSelect Then
AddHandler c1.MouseClick, AddressOf ClickHandler
For Each c2 As Control In c1.Controls
If Not c2.CanSelect Then
AddHandler c2.MouseClick, AddressOf ClickHandler
For Each c3 As Control In c2.Controls
If Not c3.CanSelect Then
AddHandler c3.MouseClick, AddressOf ClickHandler
For Each c4 As Control In c3.Controls
If Not c4.CanSelect Then
AddHandler c4.MouseClick, AddressOf ClickHandler
End If
Next
End If
Next
End If
Next
End If
Next
End Sub
'Click Handler
Private Sub ClickHandler(sender As Object, e As MouseEventArgs) Handles Me.MouseClick
MsgBox("Do something!!!")
End Sub
Hello I am trying to use RegisterHeyKeys in VB.NET however I got it to work with 2 hotkeys I tried just adding in the third and it's giving a too many arguments. This is probably something really simple and I'm also a nub so go easy. lol. Any help would be greatly appreciated.
Here is the code so far:
Public Const MOD_CONTROL As Integer = &H11
Public Const MOD_SHIFT As Integer = &H10
Public Const WM_HOTKEY As Integer = &H312
<DllImport("User32.dll")> _
Public Shared Function RegisterHotKey(ByVal hwnd As IntPtr, _
ByVal id As Integer, ByVal fsModifiers As Integer, _
ByVal vk As Integer) As Integer
End Function
<DllImport("User32.dll")> _
Public Shared Function UnregisterHotKey(ByVal hwnd As IntPtr, _
ByVal id As Integer) As Integer
End Function
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
RegisterHotKey(Me.Handle, 100, MOD_CONTROL, MOD_SHIFT, Keys.D2)
RegisterHotKey(Me.Handle, 200, MOD_CONTROL, MOD_SHIFT, Keys.D3)
RegisterHotKey(Me.Handle, 300, MOD_CONTROL, MOD_SHIFT, Keys.D4)
End Sub
The problem as I see it is you have added two modifiers MOD_CONTROL and MOD_SHIFT and seperated them with a comma saying that you have five parameters to the function even though it only takes four. Try Oring together your Modifers like this. You also should verify your modifier keys with the Documentation they appear to not be correct.
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
RegisterHotKey(Me.Handle, 100, MOD_CONTROL Or MOD_SHIFT, Keys.D2)
RegisterHotKey(Me.Handle, 200, MOD_CONTROL Or MOD_SHIFT, Keys.D3)
RegisterHotKey(Me.Handle, 300, MOD_CONTROL Or MOD_SHIFT, Keys.D4)
End Sub
From the documentation it states(emphasis mine):
fsModifiers [in]
Type: UINT
The keys that must be pressed in combination with the key specified by the uVirtKey parameter in order to generate the WM_HOTKEY message. The fsModifiers parameter can be a combination of the following values.
Value Meaning
MOD_ALT 0x0001 Either ALT key must be held down.
MOD_CONTROL 0x0002 Either CTRL key must be held down.
MOD_NOREPEAT 0x4000 Changes the hotkey behavior so that the keyboard auto-repeat does not yield multiple hotkey notifications.
Windows Vista and Windows XP/2000: This flag is not supported.
MOD_SHIFT 0x0004 Either SHIFT key must be held down.
MOD_WIN 0x0008 Either WINDOWS key was held down. These keys are labeled with the Windows logo. Keyboard shortcuts
that involve the WINDOWS key are reserved for use by the operating system
Here is a Working example of your program.
Public Const MOD_CONTROL As Integer = &H2
Public Const MOD_SHIFT As Integer = &H4
Public Const WM_HOTKEY As Integer = &H312
<DllImport("User32.dll")> _
Public Shared Function RegisterHotKey(ByVal hwnd As IntPtr, _
ByVal id As Integer, ByVal fsModifiers As Integer, _
ByVal vk As Integer) As Integer
End Function
<DllImport("User32.dll")> _
Public Shared Function UnregisterHotKey(ByVal hwnd As IntPtr, _
ByVal id As Integer) As Integer
End Function
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
RegisterHotKey(Me.Handle, 100, MOD_CONTROL Or MOD_SHIFT, Keys.D2)
RegisterHotKey(Me.Handle, 200, MOD_CONTROL Or MOD_SHIFT, Keys.D3)
RegisterHotKey(Me.Handle, 300, MOD_CONTROL Or MOD_SHIFT, Keys.D4)
End Sub
Protected Overrides Sub DefWndProc(ByRef m As System.Windows.Forms.Message)
MyBase.DefWndProc(m)
If m.Msg = WM_HOTKEY Then
Select Case CType(m.WParam, Integer)
Case 100
NotifyIcon1.Text = "Hello"
NotifyIcon1.ShowBalloonTip(2000, "", NotifyIcon1.Text, ToolTipIcon.Info)
Case 200
NotifyIcon1.Text = "World"
NotifyIcon1.ShowBalloonTip(2000, "", NotifyIcon1.Text, ToolTipIcon.Info)
Case 300
NotifyIcon1.Visible = False
If Not Visible Then Visible = True
End Select
End If
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Me.Hide()
NotifyIcon1.Icon = Me.Icon
NotifyIcon1.Visible = True
End Sub