帮助实现全局键盘钩子 [英] Help in implementing global keyboard hook

查看:73
本文介绍了帮助实现全局键盘钩子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在VB2008中编写一个在系统托盘中运行的简单程序。我想设置一个热键组合(例如Ctrl + Alt + Shift + K),它将触发子程序。



到目前为止,我已经能够获取程序以响应组合键,但仅当表单未最小化到系统托盘时。以下是一些示例代码:



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:

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







如果我将 ShowInTaskbar 更改为 True 在MainFormSizeChanged处理程序中,程序将响应键组合,即使最小化到系统托盘(可能是因为它仍在任务栏中)。虽然这是一个解决方案,但它并不像它应该的那样正确。



我认为解决方案是使用全局键盘钩,但这超出了我的经验水平。



我已经为此代码 [ ^ ](使用键盘钩子捕获printscreen键)并确认键盘钩子即使最小化到托盘,代码也能正常工作。但是我很难看到如何调整代码以使用我的组合键。



一个稍微不同的keyhook实现可以在这段代码 [ ^ ]。我还为此代码添加了系统托盘功能,它在最小化时也能正常工作。但同样,我无法实现这一目标,并对其进行调整以响应我的组合键。



是否有人有任何代码建议或链接可能对我有帮助得到这个吗?




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?

推荐答案

对于你的应用程序,它看起来像一个完全成熟的Global Hook将是一个矫枉过正。您的问题可能更加专业化:通过全局热键触发某些内容。这可以通过这种方式使用Windows API RegisterHotKey

http://msdn.microsoft.com/en-us/library/ms646309%28v=vs.85%29.aspx [< a href =http://msdn.microsoft.com/en-us/library/ms646309%28v=vs.85%29.aspxtarget =_ blanktitle =New Window> ^ ] 。







我完全复制了你的场景(没有 NotifyIcon ,这完全无关紧要)。 一切正常。您可能遇到的问题:

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[^].



I fully reproduced your scenario (without NotifyIcon, which is totally irrelevant). It all works. The problems you could experience:
  1. 您没有显示 MainFormLoad 叫做。有可能在那时表单句柄还没有准备好。稍后再做,例如,在 Form.Shown 的处理程序中。
  2. 更真实的问题:当窗口最小化时,你希望显示消息框,并说问题不是消息框。但实际上这是一个问题。表单被隐藏/最小化,因此激活了一些其他应用程序。实际显示消息框,但隐藏在顶部激活的窗口后面。仔细检查。
  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


退出所有对Me.ShowInTaskbar / ShowInTaskbar的调用以及热键都可以在MainForm最小化到系统托盘时工作。
Comment out all calls to Me.ShowInTaskbar / ShowInTaskbar and the hotkey works even when the MainForm is minimized to the System Tray.


我查看了那边的代码示例。如果没有坏事,它会起作用。看起来你在评论中忽略了我的建议。但主要的是:您再次隐藏未显示的代码的重要细节。问题是设计师生成的代码。



制作全面的样本非常简单;你不必上传任何东西。这样做:

  • 在一个文件中完成所有操作;在这个简单的例子中,这已经足够了。
  • 显然,你不需要任何设计师。在一个文件中使用Main和表单类(或两个,但是1就足够了。)
  • 使用事件的匿名处理程序在一行中注册热键显示
  • FormClosing 中取消注册。
  • 最后,抛出 MainFormLoad ;我很久以前就建议了,你为什么还有呢?
  • 在重写的WndProc中,删除可怕的案例100(为什么,为什么它在标记?!!);你只有一个热键!
  • 删除所有不相关的东西,比如 MainFormSizeChanged (它做了什么?无论如何都没有意义!完全没有意义)。
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).


这篇关于帮助实现全局键盘钩子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆