如何让UWP应用不获取焦点,保留外部文本光标?
解决方案:UWP手写应用避免抢占外部焦点
核心思路
UWP没有HWND直接设置无激活属性的机制,但可以通过应用视图非激活模式结合模拟键盘输入实现需求,同时保留HandwritingView的手写识别功能。
具体实现步骤
1. 设置应用视图为非激活模式
在App.xaml.cs的OnLaunched方法中,将应用视图配置为启动和交互时不抢占焦点:
protected override void OnLaunched(LaunchActivatedEventArgs e) { Frame rootFrame = Window.Current.Content as Frame; if (rootFrame == null) { rootFrame = new Frame(); rootFrame.NavigationFailed += OnNavigationFailed; Window.Current.Content = rootFrame; } if (e.PrelaunchActivated == false) { if (rootFrame.Content == null) { rootFrame.Navigate(typeof(MainPage), e.Arguments); } Window.Current.Activate(); // 关键:设置应用视图为非激活模式 var currentView = CoreApplication.GetCurrentView(); currentView.ActivationMode = CoreApplicationViewActivationMode.NonActivated; currentView.SetPreferredMinSize(new Size(1440, 1300)); } }
2. 调整控件焦点行为
禁用TextBox的焦点获取能力,避免交互时触发焦点抢占:
public MainPage() { this.InitializeComponent(); tbHandWriteView.IsHandwritingViewEnabled = true; tbHandWriteView.HandwritingView.InputDeviceTypes = Windows.UI.Core.CoreInputDeviceTypes.Touch | Windows.UI.Core.CoreInputDeviceTypes.Pen; tbHandWriteView.HandwritingView.PlacementAlignment = HandwritingPanelPlacementAlignment.TopLeft; tbHandWriteView.HandwritingView.Width = 1000; tbHandWriteView.HandwritingView.Height = 1000; tbHandWriteView.HandwritingView.Visibility = Visibility.Visible; // 禁用TextBox的焦点相关属性 tbHandWriteView.IsTabStop = false; tbHandWriteView.FocusVisualPrimaryThickness = new Thickness(0); tbHandWriteView.FocusVisualSecondaryThickness = new Thickness(0); // 监听手写完成事件,将识别文本发送到外部光标 tbHandWriteView.HandwritingView.TextSubmitted += HandwritingView_TextSubmitted; tbHandWriteView.HandwritingView.TryOpen(); }
3. 模拟键盘输入传递文本
手写完成后,通过Windows API模拟键盘输入,将识别文本直接发送到当前激活的外部窗口(需添加Windows Desktop Extensions for the UWP引用):
private async void HandwritingView_TextSubmitted(HandwritingView sender, HandwritingPanelTextSubmittedEventArgs args) { string recognizedText = args.SubmittedText; if (!string.IsNullOrEmpty(recognizedText)) { // 短暂延迟确保外部窗口重新获得焦点 await Task.Delay(100); // 逐字符模拟键盘输入 foreach (char c in recognizedText) { SimulateKeyPress(c); } // 清空本地TextBox内容 tbHandWriteView.Text = ""; } } // 模拟键盘输入的辅助方法 private void SimulateKeyPress(char c) { INPUT input = new INPUT(); input.type = INPUT_KEYBOARD; input.ki.wVk = 0; input.ki.wScan = c; input.ki.dwFlags = KEYEVENTF_UNICODE; input.ki.time = 0; input.ki.dwExtraInfo = IntPtr.Zero; SendInput(1, ref input, Marshal.SizeOf(input)); // 模拟按键释放 input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; SendInput(1, ref input, Marshal.SizeOf(input)); } // 导入Windows API [DllImport("user32.dll", SetLastError = true)] private static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize); private struct INPUT { public int type; public KEYBDINPUT ki; } private struct KEYBDINPUT { public ushort wVk; public ushort wScan; public uint dwFlags; public uint time; public IntPtr dwExtraInfo; } private const int INPUT_KEYBOARD = 1; private const uint KEYEVENTF_UNICODE = 0x0004; private const uint KEYEVENTF_KEYUP = 0x0002;
4. 配置应用清单(可选)
在Package.appxmanifest中添加桌面扩展支持,确保模拟输入功能正常:
<Package ...> <Applications> <Application ...> <Extensions> <uap:Extension Category="windows.desktop"> <uap:Desktop> <uap:DesktopApplication Path="YourApp.exe" /> </uap:Desktop> </uap:Extension> </Extensions> </Application> </Applications> </Package>
关键说明
CoreApplicationViewActivationMode.NonActivated是UWP实现无焦点窗口的核心,确保应用不会抢占外部窗口焦点;- 模拟键盘输入是跨窗口传递文本的可靠方式,无需依赖窗口句柄交互;
- 非激活模式下应用部分系统交互功能会受限,需根据实际需求调整。
内容的提问来源于stack exchange,提问作者Kai-Han Lo
相关产品推荐
相关产品推荐

