C#WPF如何在鼠标单击控件时不激活主窗口 简明的
我正在尝试用C#创建一个屏幕键盘应用程序。这个键盘应该像屏幕上的键盘一样,在用户单击按钮时模拟键盘输入。例如,当用户单击“A”按钮时,它应该在输入框中键入C#WPF如何在鼠标单击控件时不激活主窗口 简明的,c#,wpf,C#,Wpf,我正在尝试用C#创建一个屏幕键盘应用程序。这个键盘应该像屏幕上的键盘一样,在用户单击按钮时模拟键盘输入。例如,当用户单击“A”按钮时,它应该在输入框中键入A(在另一个应用程序中) 因为我昨晚才有这个想法,现在就开始开发,所以我只做了一个非常简单的测试ui: 它只有一个按钮“A” 问题 问题之一是将窗口设置为鼠标单击时不激活。多亏了我发表的评论,我现在有了以下代码: protected override void OnSourceInitialized(EventArgs e)
A
(在另一个应用程序中)
因为我昨晚才有这个想法,现在就开始开发,所以我只做了一个非常简单的测试ui:
它只有一个按钮“A”
问题
问题之一是将窗口设置为鼠标单击时不激活。多亏了我发表的评论,我现在有了以下代码:
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
var winH = (HwndSource) PresentationSource.FromVisual(this);
// set mouse activate false
winH.AddHook(WndProc);
}
#region WndProc
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATE = 0x0003;
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg != WM_MOUSEACTIVATE)
return IntPtr.Zero;
handled = true;
return new IntPtr(MA_NOACTIVATE);
}
#endregion WndProc
然而,代码并不能很好地工作。仅当单击主窗口的背景(空白)时,才禁用鼠标激活。如果单击按钮
,窗口将被激活。因为wpf控件没有HWND,所以我不能AddHook
此外,尽管单击main窗口的空白部分
并不会将应用程序带到最前面,但当应用程序在任务栏上突出显示时,似乎仍会激活它
附录-完整代码
MainWindow.xaml:
<Window x:Class="OnScreenKeyPad.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:OnScreenKeyPad"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="200"
WindowStyle = "None"
AllowsTransparency="True" >
<StackPanel>
<Button x:Name="KeyA" Content="A" Width="50" Margin="10"/>
</StackPanel>
</Window>
更新1
我已记录了WindowProc消息列表:
ID Event
33 WM_MOUSEACTIVATE
32 WM_SETCURSOR
513 WM_LBUTTONDOWN
NA OnMouseDownPreviewEvent
70 WM_WINDOWPOSCHANGING
71 WM_WINDOWPOSCHANGED
28 WM_ACTIVATEAPP
134 WM_NCACTIVATE
6 WM_ACTIVATE
641 WM_IME_SETCONTEXT
642 WM_IME_NOTIFY
7 WM_SETFOCUS
8 WM_KILLFOCUS
641 WM_IME_SETCONTEXT
641 WM_IME_SETCONTEXT
7 WM_SETFOCUS
641 WM_IME_SETCONTEXT
641 WM_IME_SETCONTEXT
132 WM_NCHITTEST
512 WM_NCHITTEST
132 WM_MOUSEFIRST
514 WM_LBUTTONUP
533 WM_CAPTURECHANGED
132 WM_NCHITTEST
NA ButtonOnClickEvent
现在我大概明白了为什么代码不起作用了MOUSEACTIVATE
在单击鼠标按钮后立即触发,这是在实际的鼠标按钮事件(ID 513)之前。尽管处理了MOUSEACTIVATE
并阻止了窗口激活,但鼠标按钮事件将再次激活ID为28的窗口WM_ACTIVATEAPP
。我已经检查了这些事件的文档,没有一个可以被阻止
也许我可以使用一个标签,并利用它的PreviewMouseDown
事件。您需要设置WS\u EX\u NOACTIVATE窗口样式,而不是自己尝试吃掉消息:
private const int WS_EX_NOACTIVATE = 0x08000000;
private const int GWL_EXSTYLE = -20;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
protected override void OnSourceInitialized(EventArgs e)
{
var hWnd = new WindowInteropHelper(this).Handle;
int style = GetWindowLong(hWnd, GWL_EXSTYLE);
SetWindowLong(hWnd, GWL_EXSTYLE, style | WS_EX_NOACTIVATE);
base.OnSourceInitialized(e);
}
以防你不知道,Windows内置了一个屏幕键盘,可以处理所有这些问题,还有许多你还没有遇到的问题(比如口音和非欧洲字符)。如果你的问题特别提到“问题1”,“问题2”,那么你是在邀请一个“过于宽泛”的结尾。每个问题请回答一个问题。@Neil是的,类似但不一样。我不需要这么多的键,但只需要WASD、箭头键、esc等。@spender没有意识到这一点,现在我想可以了:)“第一个问题是将窗口设置为在鼠标单击时不激活。”为什么?如果窗口未激活,应用程序应如何响应按钮单击?
private const int WS_EX_NOACTIVATE = 0x08000000;
private const int GWL_EXSTYLE = -20;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
protected override void OnSourceInitialized(EventArgs e)
{
var hWnd = new WindowInteropHelper(this).Handle;
int style = GetWindowLong(hWnd, GWL_EXSTYLE);
SetWindowLong(hWnd, GWL_EXSTYLE, style | WS_EX_NOACTIVATE);
base.OnSourceInitialized(e);
}