Click here to Skip to main content
15,884,975 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm writing a simple program in VB2008 that runs in the system tray. I would like to set a hotkey combination (for instance Ctrl+Alt+Shift+K) that will trigger a subroutine.

So far, I've been able to get the program to respond to a key combination, but only if the form is not minimized to the system tray. Here is some example code to demonstrate:

VB
Imports System.Runtime.InteropServices
Public Partial Class MainForm
	
	Public Const MOD_ALT As Integer = &H1
	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	
	
	Public Sub New()
		Me.InitializeComponent()
	End Sub
	
	Sub MainFormLoad(sender As Object, e As EventArgs)
		RegisterHotKey(Me.Handle, 100, MOD_CONTROL + MOD_ALT + MOD_SHIFT, Keys.K)
		ContextMenuStrip1.Enabled = False
	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"
			MsgBox("Ctrl + Alt + Shift + K was pressed")
			End Select
		End If
		MyBase.WndProc(m)
	End Sub    
	
	Sub MainFormFormClosing(sender As Object, e As FormClosingEventArgs)
		e.Cancel = True
		Me.WindowState = FormWindowState.Minimized
		Me.ShowInTaskbar = False
		ContextMenuStrip1.Enabled = True
	End Sub
	
	Sub ShowToolStripMenuItemClick(sender As Object, e As EventArgs)
		Me.WindowState = FormWindowState.Normal
		Me.ShowInTaskbar = True
		ContextMenuStrip1.Enabled = False
	End Sub
	
	Sub ExitToolStripMenuItemClick(sender As Object, e As EventArgs)
		UnregisterHotKey(Me.Handle, 100)
		End
	End Sub
	
	Sub MainFormSizeChanged(sender As Object, e As EventArgs)
		If Me.WindowState = FormWindowState.Minimized Then
		ShowInTaskbar = False
		ContextMenuStrip1.Enabled = True
		End If
	End Sub
	
End Class



If I change ShowInTaskbar to True in the MainFormSizeChanged handler, the program will respond to the key combination even when minimized to the system tray (presumably because it is still in the taskbar). While this is a solution, its not as 'proper' as it should be.

I think the solution is to use a global keyboard hook, but this is going beyond my level of experience.

I've added a notify icon and context menu script to this code[^](which uses a keyboard hook to capture the printscreen key) and confirmed that the keyboard hook code does work even when minimized to the tray. But I'm having a hard time seeing how to adapt the code to work with my key combination.

A slightly different keyhook implementation can be found in this code[^]. I also added systray functionality to this code and it too works when minimized. But again, I'm not able to make the leap and adapt this to respond to my key combination.

Does anyone have any code suggestions or links that might help me get this working?
Posted
Comments
Sergey Alexandrovich Kryukov 18-Aug-14 16:16pm    
For the global hook, according to Microsoft documentation, .NET is not enough, because the hook should be installed in a separate native DLL. Do you know any native languages to use Windows API and install the hook and organize the collaboration between this module and a .NET assembly? Yes, this is not easy, especially hard to debug, but I guess you need something minimal, just capturing a hot hey.
From your post, it's not clear where is your problem, specifically. If you could create and show some short but comprehensive code sample (it could activate any .NET UI at all, just for example), it would be a good starting point.

Do you use System.Windows.Forms.NotifyIcon?

—SA

For your application, it looks like a fully-fledged Global Hook would be an overkill. Your problem is probably much more specialized: to trigger something from by a global hot key. This can be done this way using the Windows API RegisterHotKey:
http://msdn.microsoft.com/en-us/library/ms646309%28v=vs.85%29.aspx[^].

[EDIT]

I fully reproduced your scenario (without NotifyIcon, which is totally irrelevant). It all works. The problems you could experience:
  1. You did not show where MainFormLoad is called. It is possible that at that moment the form handle is not ready yet. Do it later, for example, in the handler of Form.Shown.
  2. More real problem: when a window is minimized, you expected to show the message box, and say that the problem is not the message box. But it is actually a problem. The form is hidden/minimized, so some other application is activated. The message box is actually shown, but hidden behind the activated window on top. Check up carefully.


—SA
 
Share this answer
 
v3
Comments
Member 10993529 18-Aug-14 16:54pm    
Hello Sergey! I also originally thought that a global hook would be overkill, but RegisterHotKey doesn't seem to work(at least not as shown in the code posted). When the app is minimized, the key combination produces no result.

Yes, I did use the NotifyIcon.

To duplicate the problem, please follow these steps:

Copy the code found in the question into a new VB project.
Add a form called MainForm.
Add a context menu strip called contextMenuStrip1.
Add a notify icon called notifyIcon1.
Be sure to bind the notifyIcon1 to the contextMenuStrip1.

When the app is **not minimized** a message box with "Ctrl + Alt + Shift + K was pressed" will appear. But when the app **is minimized** to the systray, nothing happens. I don't think its a matter of the msgbox. If I alter the code to display a different icon when the key combination is triggered, the same problem occurs: no reaction when app is in the systray.

So, to me it looks like a global key is the only thing that will work. :)
Sergey Alexandrovich Kryukov 18-Aug-14 17:34pm    
What a second. How do you know it does not work, maybe you UI does not respond correctly? Use the debugger, after all. If the hotkey is captured at all, this is another question.
The message box is something which you do, you did not even include it in the description. By the way, notify icon is not the form minimized to a tray. The form and the NotifyIcon instance are unrelated.
Put a break point on the line after "If m.Msg = WM_HOTKEY Then". Do you capture the hot key?

(And sorry for the redundant answer.)

—SA
Sergey Alexandrovich Kryukov 18-Aug-14 17:55pm    
Please see the update to my answer, after [EDIT]. All works.
—SA
Member 10993529 18-Aug-14 18:30pm    
I can't get it to work. Adding the breakpoint also doesn't seem to change the outcome. In my original post, I included this code below:

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"
MsgBox("Ctrl + Alt + Shift + K was pressed")
End Select
End If
MyBase.WndProc(m)
End Sub


Please add a second form to the app called Form2.
Replace the MsgBox line in the code above with: Form2.Show()

If I do this, I get the following results:
With the app mainform not minimized, the key combination causes Form2 to display
but...
With the app main form minimized to the systray, the key combination does not cause Form2 to display.

Sergey, if you are able to show Form2 when the mainform is minimized, could you post your code? Perhaps I am overlooking a mistake that you (as someone with more experienced) corrected?
Sergey Alexandrovich Kryukov 18-Aug-14 18:36pm    
Now, why calling Form2.Show()? Was it hidden? Call Form2.Activate.
If the form was closed, you cannot show it again.
No matter, all information shows that the hot key does work. You just do you UI not in appropriate way.
And again, did you do it all under the debugger?
(Case "100" is redundant and unacceptably bad style of programming.)
—SA
Comment out all calls to Me.ShowInTaskbar / ShowInTaskbar and the hotkey works even when the MainForm is minimized to the System Tray.
 
Share this answer
 
I looked at your code sample on that side. It would work if not could of bad things. It looks like you ignored my advice in comments. But main thing is: you again hide important detail on the code you don't show. The problem is the code generated by the designer.

Making the comprehensive sample is pretty simple; you don't have to upload anything. Do this:
  • Do it all in one file; in this simple case, it's more than enough.
  • Apparently, you don't need any Designer. Have Main and the form class (or two, but 1 is enough) in one file.
  • Register hot key in one line using anonymous handler of the event Shown.
  • Unregister it in FormClosing.
  • Finally, throw out MainFormLoad; I advised it long time ago, why do you still have it?
  • In overridden WndProc, remove dreaded case "100" (why, why it is in "" marks?!!); you have only one hot key!
  • Remove all unrelated stuff, like MainFormSizeChanged (what it does? make no sense anyway! no sense at all).


If it will work you will add other detail one by one, checking this hot key feature each time. At least you will know when it screws up.

Apparently, you don't have a feel what is complete code. Part of the code is in the auto-generated designer code. So 1) open the file and see what it does, 2) don't use the designed posting questions like that, so we could see minimal but comprehensive code; 3) even in working programming, listen to a good advice: never ever add any event handlers in designed, do it in your code using anonymous syntax. Keep this part under your control, not the Designer's.

—SA
 
Share this answer
 
v3
Comments
Member 10993529 19-Aug-14 12:48pm    
Sergey, thanks for your input!

Your comment "Apparently, you don't have a feel what is complete code" is totally true. As a beginner in this field it seems that I am learning by trial and error... which can be very frustrating.

I will follow your last suggestion and rebuild the whole project, step by step. Hopefully I will learn some things along the way.

I need to get past this trial and error phase. Is there a good in-depth book that you could recommend? It seems like a book would be a much better way to learn this than by looking at several different sources of information via the Internet.

Thanks very much Sergey!
Sergey Alexandrovich Kryukov 19-Aug-14 13:07pm    
A little advice: create one small project from scratch and figure out what files are source code and what are not. Which ones can be deleted? Say, the code auto-generated by the Form designer is still source code: if you delete it, the form or custom control will be lost. In contrast, WPF designer generates a lot of code which you can delete, because real source is XAML. Learn how to write projects without the designer, at least on some simplest samples. This problem is a good reason to start with it.

I'm telling you, the present problem is not a problem at all; you just have this little inaccurate parts. If you fix them, you will have hot key working. And then add other code.

—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900