我遇到了一个奇怪的问题。 我有一个WinForms应用程序打开另一个程序(计费系统模拟器),将其设置为子窗口,然后禁用它。这样工作正常,用户无法将任何键发送到该子窗口,并且winforms应用程序执行其操作,将命令发送到子窗口。
然而,已经发现推动 shift 或控制,即使winforms应用程序没有焦点,也会导致错误计费系统模拟器,因为它们不是有效密钥。在winforms应用程序运行时,用户已经开始不使用 shift 或 control 键,但这显然不是一个实用的解决方案。
我的尝试解决方案是:
OnKeyDown
以停止这些密钥。但是,当winforms应用程序未处于焦点时,仍然无法解决发送到子窗口的 shift 和 alt 键的问题。我可以在winforms应用程序运行时全局停止 shift 和 alt ,但我认为这不是有效的。所以我需要以某种方式在全局钩子中停止winforms应用程序及其子项的keypress
,但允许全局。任何想法/想法?
这是my code。
答案 0 :(得分:2)
我认为你的情景没有一个好的答案...... = \
您可以尝试以下 hack 。如果它们关闭,它将“释放”Control / Shift,然后你发送信息:
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int extraInfo);
[DllImport("user32.dll")]
static extern short MapVirtualKey(int wCode, int wMapType);
private void button1_Click(object sender, EventArgs e)
{
if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
{
keybd_event((int)Keys.ShiftKey, (byte)MapVirtualKey((int)Keys.ShiftKey, 0), 2, 0); // Shift Up
}
if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
{
keybd_event((int)Keys.ControlKey, (byte)MapVirtualKey((int)Keys.ControlKey, 0), 2, 0); // Control Up
}
// ... now try sending your message ...
}
这显然不是万无一失。
答案 1 :(得分:0)
我看了globalKeyboardHook
的唯一构造函数,看起来它只是为全局钩子设计的。您可以添加另一个重载以挂钩到当前正在运行的模块中,如下所示:
class globalKeyboardHook {
[DllImport("kernel32")]
private static extern int GetCurrentThreadId();
[DllImport("user32")]
private static extern IntPtr SetWindowsHookEx(int hookType, KeyBoardProc proc, IntPtr moduleHandle, int threadId);
[DllImport("user32")]
private static extern int CallNextHookEx(IntPtr hHook, int nCode, IntPtr wParam, IntPtr lParam);
public globalKeyboardHook(bool currentModuleOnly){
if(currentModuleOnly){
proc = KeyBoardCallback;
//WH_KEYBOARD = 0x2
hhook = SetWindowsHookEx(2, proc, IntPtr.Zero, GetCurrentThreadId());
} else hook();
}
public delegate int KeyBoardProc(int nCode, IntPtr wParam, IntPtr lParam);
public int KeyBoardCallback(int nCode, IntPtr wParam, IntPtr lParam) {
if (nCode >= 0) {
Keys key = (Keys)wParam;
var lp = lParam.ToInt64();
//your own handling with the key
if ((lp >> 31) == 0)//Key down
{
//your own code ...
} else { //Key up
//your own code ...
}
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
KeyBoardProc proc;
//other code ...
}
//then use the new overload constructor instead of the parameterless constructor:
globalHook = new globalKeyboardHook(true);
注意:您可以根据我上面发布的内容(评论KeyDown
)实施您自己的KeyUp
和your own code ...
事件。经过一些搜索后,我了解WH_KEYBOARD_LL
仅支持全局挂钩,而WH_KEYBOARD
仅适用于thread hook
。那应该是你想要的而不是WH_KEYBOARD_LL
。
BTW,我怀疑在这种情况下可以使用您的应用程序可以注册/添加的IMessageFilter
。它还支持PreFilterMessage
方法,帮助您拦截application-level
处的任何键和鼠标消息。您应该尝试搜索,这很容易理解。