3

我遇到了一个奇怪的问题。我有一个 WinForms 应用程序,它打开另一个程序(计费系统模拟器),将其设置为子窗口,然后将其禁用。这很好用,用户不能向该子窗口发送任何键,winforms 应用程序会做它的事情,向子窗口发送命令。

但是,我们发现,即使 winforms 应用程序没有焦点,按下shiftor也会导致计费系统模拟器出错,因为它们不是有效的键。control用户已经开始在 winforms 应用程序运行时不使用shiftorcontrol键,但这显然不是一个实用的解决方案。

我尝试的解决方案是:

  1. 按下这些键时捕获的全局键盘挂钩。
  2. 在 winforms 应用程序中覆盖OnKeyDown以停止这些键。

然而,当 winforms 应用程序不在焦点时,这仍然不能解决shift和键被发送到子窗口的问题。alt我可以在 winforms 应用程序运行时全局停止shiftalt但我认为这是无效的。因此,我需要以某种方式在全局挂钩中停止keypresswinforms 应用程序及其子项,但在全局范围内允许。有什么想法/想法吗?

这是我的代码

4

2 回答 2

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 ...
    }

这显然不是万无一失的。

于 2013-10-28T16:11:00.307 回答
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和事件。经过一番搜索,我了解到仅支持全局钩子,而仅用于。那应该是您想要的,而不是.KeyUpyour own code ...WH_KEYBOARD_LLWH_KEYBOARDthread hookWH_KEYBOARD_LL

顺便说一句,我怀疑IMessageFilter在这种情况下可以使用您的应用程序注册/添加的内容。它还支持一种PreFilterMessage方法,可帮助您拦截application-level. 您应该尝试搜索它,这很容易理解。

于 2013-10-28T16:01:26.460 回答