在 WinForms 输入焦点上自动弹出平板电脑触摸键盘

Automatically pop up tablet touch keyboard on WinForms input focus

当我 运行 在 Windows 10 上以平板电脑模式运行 WinForms(或 Delphi,见最后)应用程序时,触摸键盘不会 pop up automatically , 当输入框获得焦点时。

我相信这应该会自动发生,无需任何额外的 code/setup。


为了测试,我有一个最简单的 VS 2015 WinForms 桌面应用程序,只有一个 TextBox control

它只是 Visual Studio 创建的默认 Windows Forms Application C# 项目。没有添加代码,没有更改属性。只是添加了 TextBox,通过从 工具箱 中删除(同样没有更改属性):

this.textBox1 = new System.Windows.Forms.TextBox();
this.textBox1.Location = new System.Drawing.Point(64, 27);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(100, 20);
this.textBox1.TabIndex = 0;

验证我的弹出窗口应该是自动的假设:


WinForms 中似乎有什么东西损坏了,阻止了自动弹出窗口。有趣的是,自动弹出有效:


我已经通过 运行 宁 TabTip.exe 看到了关于显式弹出窗口的所有提示。例如:

大多数“解决方案”都提供这样的代码:

var progFiles = @"C:\Program Files\Common Files\Microsoft Shared\ink";
var keyboardPath = Path.Combine(progFiles, "TabTip.exe");
this.keyboardProc = Process.Start(keyboardPath);

但我无法相信这会是“官方”方式。如果没有别的,那么因为没有干净的方法来隐藏 运行 宁 TabTip.exe 打开的键盘(解决方案包括像终止进程或发送 Esc键)。

实际上,上述技巧在 Windows 10 周年更新中似乎不再有效:


有趣的是,我在 Delphi/C++ Builder/VCL 应用程序中看到了相同的行为。键盘不会弹出编辑框(TEdit). It does pop up for combo boxes (TComboBox) and for edit boxes in a password mode (PasswordChar). Interestingly not for TRichEdit,与 .NET 的显着区别 RichTextBox,这可能值得研究。

这个(未回答的)问题描述了一个相同的行为:
Application written Delphi XE8 touch in edit boxes keyboard not appear in Windows 10.

据我所知,启动 osk.exetabtip.exe 几乎是完成这项工作的 "standard" 方法。到目前为止,我还没有找到 "official" 解决方案。

但是,如果是我这样做,我就不会终止进程或发送按键来尝试关闭键盘。相反,您可以在启动进程时获取 window 句柄,并使用它来最小化 window 并将其从任务栏中隐藏。

这里有人得到了 window 句柄只是为了关闭它,但它给了你一个想法:Show & hiding the Windows 8 on screen keyboard from WPF

如果你需要我,请告诉我,我会看看是否有时间做一个完整的例子。

我已经在这条路上走了几次,但只能实现 taptip.exe 选项。然后通过终止进程来关闭 window。我还发现,如果您愿意,通过一些注册表黑客攻击,您可以将键盘默认设置为手写面板。但那只能在 Win8 中工作,在 Win10 中失败。以下是我所做的,以防其他人发现这有用:

RegistryKey registryKey = Registry.CurrentUser.CreateSubKey("Software\Microsoft\TabletTip\1.7");

registryKey?.SetValue("KeyboardLayoutPreference", 0, RegistryValueKind.DWord);
registryKey?.SetValue("LastUsedModalityWasHandwriting", 1, RegistryValueKind.DWord);

Process.Start(@"C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe");

我需要感谢这个 post 的注册表创意:Windows 8 Desktop App: Open tabtip.exe to secondary keyboard (for numeric textbox)

根本原因似乎是 Winforms 的文本框不是 AutomationElement,而其余提到的控件(组合框等)是。

引用 Markus von und zu Heber 的 accepted answer here:

We found it in the article "Automatic Touch Keyboard for TextBoxes in WPF Applications on Windows 8+", but it also works very good (and even easier!) for winforms. Thank you, Dmitry Lyalin!

  1. Insert a reference to UIAutomationClient.dll to your project

  2. In the form-load-handler of the application's main window, insert the following code:

    var asForm = System.Windows.Automation.AutomationElement.FromHandle(this.Handle);
    

正如 , it seems that the touch keyboard can leverage the UI automation 所暗示的那样。


可以使用 UIAutomationClient.dll 的 UI 自动化实现。

为了将 UI 自动化神奇地注入到应用程序中,必须触发程序集内部 class UiaCoreApi 初始化器 class UiaCoreApi

On 可以通过调用看似无操作来实现这一点:

AutomationElement.FromHandle(IntPtr)(-1)

另一种方法是显式实现自动化 UI。为此,为相应的输入控件实现 ITextProvider/IValueProvider 接口。

要将接口的实现绑定到控件,请使用 lParam = RootObjectId 处理 WM_GETOBJECT window message

有关实施示例,请参阅


尽管有趣的是,触摸键盘开箱即用的控件(如组合框或密码编辑框,请参阅答案)未实现 WM_GETOBJECT/RootObjectId.他们背后一定有不同的机器。

使用 RichTextBox 而不是 TextBox 控件。 RichTextBox支持触摸键盘,当获得焦点时会自动弹出键盘。 (类似于组合框等其他输入控件)

RichTextBox 也支持与 TextBox 相同的属性,因此在大多数情况下它应该是一个小改动。 (两个控件都派生自 TextBoxBase)

我注意到,如果触摸键盘在弹出后被关闭,您可能需要在控件上点击两次才能使其重新弹出。