.Net 键盘挂钩额外 KeyUp 事件
我有一个业务需求,对于消息框,用户不能按回车键接受默认选项,而必须按选项键。例如。给定一个带有“是/否”选项的消息框,用户必须按 Y 或 N 键。现在我已经使用键盘挂钩在下面实现了这一点,但是当代码返回时,KeyUp 事件也会返回到调用代码。
所以问题是:如何在返回调用代码之前刷新所有键盘事件?
我已经删除了样板代码,但如果您需要它,请告知。
调用代码:
private static ResultMsgBox MsgResultBaseNoEnter(string msg, string caption, uint options)
{
ResultMsgBox res;
_hookID = SetHook(_proc);
try
{
res = MessageBox(GetForegroundWindow(), msg, caption, options);
}
finally
{
UnhookWindowsHookEx(_hookID);
}
return res;
}
和 Hook 代码:
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode == VK_RETURN)
return (IntPtr)(-1);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
I have a business requirement that for message boxes, the user cannot press the enter key to accept the default option, but has to press the key of the option. eg. Given a MessageBox with the options Yes/No, the user must press the Y or N keys. Now I've implemented this below using keyboard hooks, but when the code returns, the KeyUp event also gets returned to the calling code as well.
So the question is: How do I flush all the keyboard events before returning to the calling code?
I've removed boiler plate code, but if you need it, please advise.
The calling code:
private static ResultMsgBox MsgResultBaseNoEnter(string msg, string caption, uint options)
{
ResultMsgBox res;
_hookID = SetHook(_proc);
try
{
res = MessageBox(GetForegroundWindow(), msg, caption, options);
}
finally
{
UnhookWindowsHookEx(_hookID);
}
return res;
}
And the Hook Code:
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode == VK_RETURN)
return (IntPtr)(-1);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
将这些代码行添加到您的类中(或其他类可以使用的某个静态类中):
调用
RemoveAllKeyMessages()
正是您想要的。Add these lines of code somewhere in your class (or in some static class that can be used by other classes):
Calling
RemoveAllKeyMessages()
does exactly what you want.实际上你不能刷新键盘事件,但你可以阻止线程的消息循环接收该事件。
您应该为
WH_GETMESSAGE
挂钩安装一个处理程序。钩子过程的 lParam 是一个指向 MSG 结构的指针。检查该结构后,您可以更改它以避免消息传递到调用消息处理器。您应该将消息更改为 WM_NULL。.NET 中的实际过程有点长,需要单独的文章。但简单地说,方法如下:
将此类完全按原样复制到项目中的新 C# 文件中:
这是一个帮助器类,可以完成您所需的一切。我的实际类有点长,可以处理更多的钩子类型,但我清除了代码以使其更小。
之后,您的代码应如下所示:
如果您遇到任何其他问题,请告诉我。
Actually you can't flush the keyboard events, but you can prevent the event to be received by the thread's message loop.
You should install a handler for
WH_GETMESSAGE
hook. The lParam of your hook procedure is a pointer to an MSG structure. After examining the structure, you can change it to avoid the message to be passed to the calling message processor. You should change the message to WM_NULL.The actual procedure in .NET is a little long an requires a separate article. But briefly, here is how:
Copy this class exactly as is, in a new C# file in your project:
This is a helper class that does all you need. My actual class was a little longer and could handle a few more hook types, but I cleared out the code to make it smaller.
After this, your code should look like this:
If you encountered any other problem, let me know.
谢谢独角兽博士。除了细微的变化外,PeekMessage 和RemoveAllKeyMessages 方法运行良好。
我一直在对这个问题进行更多研究,显然这是一个已知问题(甚至在 Microsoft connect 中被列为“无法修复”问题):MessageBox 接受 KeyDown 事件上的输入选项,然后关闭窗口,然后返回的窗口稍后将收到 KeyUp 事件。
据我所知,此 KeyUp 事件将在将来的某个时刻发生,但不会立即发生。 (RemoveAllKeyMessages 本身并没有解决问题。)我只是调整了轮询它的方法,如下所示。我已重命名该方法以指示它是针对 MessageBox 问题的自定义用途。
除非存在明显的缺陷(除非消息框不发送 KeyUp 事件),否则这应该是其他有类似问题的解决方案。
Thanks MD.Unicorn. The PeekMessage and RemoveAllKeyMessages method is working out well except for a minor change.
I've been doing more research on this issue and apparently it is a known problem (even listed as a Won't Fix issue in Microsoft connect) that the MessageBox accepts the input option on the KeyDown event and then closes the window, then the returned window will receive the KeyUp event at a later time.
As I know this KeyUp event will occur as some point in the future but not immediately. (The RemoveAllKeyMessages by itself didn't fix the problem.) I simply adjusted the method to poll for it as follows. I've renamed the method to indicate it's custom use for the MessageBox problem.
Unless there is an obvious flaw (other than if the messagebox doesn't send the KeyUp event), this should be the solution for others having a similar problems.