14

我想写一个虚拟键盘,比如用于触摸屏电脑的 Windows 屏幕键盘。但是我的虚拟键盘从正在使用的应用程序中窃取焦点时遇到问题。即使用户单击它,Windows 屏幕键盘也会将焦点保持在当前应用程序上。有没有办法在 C# 中对 windows 窗体做同样的事情?

我现在唯一能做的就是将键盘事件发送到特定的应用程序,例如以下代码中的记事本。如果我可以使表单不可聚焦,我可以使用 GetForegroundWindow 获得当前聚焦的窗口。

[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName,string lpWindowName);


[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);

private void button1_Click(object sender, EventArgs e)
{
    IntPtr calculatorHandle = FindWindow("notepad", null);
    SetForegroundWindow(calculatorHandle);
    SendKeys.SendWait("111");
}

有没有办法做到这一点?关于让表单将键盘事件发送到正在使用的应用程序的更好方法的任何建议?

谢谢!!

4

2 回答 2

16

它解决了!

我已经尝试了gehho的解决方案,但我还需要覆盖该CreateParams方法:

private const int WS_EX_NOACTIVATE = 0x08000000;
protected override CreateParams CreateParams
{
    get
    {
        var createParams = base.CreateParams;

        createParams.ExStyle |= WS_EX_NOACTIVATE;
        return createParams;
    }
}
于 2010-03-11T19:42:58.067 回答
9

与其在单击您的窗口后尝试重置活动窗口,不如尝试阻止您的窗口接收焦点/被激活。

看看这篇文章。最后,作者简要说明了如何做到这一点:

如何防止我的窗口在显示时获得激活和焦点?

在 Windows Forms 2.0 中有一个名为 ShowWithoutActivation 的新属性——您需要在 Form 上覆盖它。在本机应用程序中,您可以使用带有 SWP_NOACTIVATE 标志的 SetWindowPos 或带有 SW_SHOWNA 标志的 ShowWindow。

此外,在本文中,他提供了一个 Windows 窗体的代码示例:

如果你想要一个完整的表单,你现在可以覆盖一个名为的属性 ShowWithoutActivation

公共类 NoActivateForm : 表单
{
    受保护的覆盖 bool ShowWithoutActivation => true;  
}

请记住,这不会一直“阻止”激活——您仍然可以通过调用Activate(), Focus()... 等方法来激活。如果您想防止点击客户区激活窗口,您可以处理该WM_MOUSEACTIVATE消息。

私有常量 int WM_MOUSEACTIVATE = 0x0021,MA_NOACTIVATE = 0x0003;

受保护的覆盖无效 WndProc(参考消息 m)
{
    如果(m.Msg == WM_MOUSEACTIVATE)
    {
         m.Result = (IntPtr)MA_NOACTIVATE;
         返回;
    }
    base.WndProc(参考 m);
}
于 2010-03-11T07:40:54.410 回答