在 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;
验证我的弹出窗口应该是自动的假设:
我试过 运行 Windows XP 版 notepad.exe
Windows 10. 它会自动弹出触摸键盘。我怀疑 Windows XP 是否明确支持触摸键盘。
我还尝试了一些古老的 MFC 应用程序(例如 2005 年的 FileZilla 2.2.15)。它还会在所有输入框上弹出触摸键盘。同样,我很确定 MFC 也没有明确支持触摸键盘。
基于 wxWidgets 构建的应用程序也是如此(例如 FileZilla 3.x)。
WinForms 中似乎有什么东西损坏了,阻止了自动弹出窗口。有趣的是,自动弹出有效:
- (可编辑)组合框(
ComboBox
和 DropDownStyle = DropDown
)
- 对于密码模式下的文本框(
TextBox.PasswordChar
)
- 富文本框 (
RichTextBox
)
- 当输入框获得焦点时,硬件键盘被“移除”(我通过在 Lenovo Yoga 笔记本上翻转屏幕进行测试),但之后就没有了。
我已经通过 运行 宁 TabTip.exe
看到了关于显式弹出窗口的所有提示。例如:
- How to use Windows On-Screen Keyboard in C# WinForms
- Open and close Windows 8 touch keyboard tabtip under desktop
- How do I close the on-screen keyboard process from C# winform correctly?
- Keyboard Winforms on Windows 10 (surface)
大多数“解决方案”都提供这样的代码:
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 周年更新中似乎不再有效:
- Show touch keyboard (TabTip.exe) in Windows 10 Anniversary edition
有趣的是,我在 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.exe
或 tabtip.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!
Insert a reference to UIAutomationClient.dll to your project
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。
有关实施示例,请参阅
- tombam 对 How to use Windows On-Screen Keyboard in C# WinForms
的回答
- 或直接投稿文章Implementing TextBox with on-screen touch keyboard.
尽管有趣的是,触摸键盘开箱即用的控件(如组合框或密码编辑框,请参阅答案)未实现 WM_GETOBJECT
/RootObjectId
.他们背后一定有不同的机器。
使用 RichTextBox 而不是 TextBox 控件。 RichTextBox支持触摸键盘,当获得焦点时会自动弹出键盘。 (类似于组合框等其他输入控件)
RichTextBox 也支持与 TextBox 相同的属性,因此在大多数情况下它应该是一个小改动。 (两个控件都派生自 TextBoxBase)
我注意到,如果触摸键盘在弹出后被关闭,您可能需要在控件上点击两次才能使其重新弹出。
当我 运行 在 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;
验证我的弹出窗口应该是自动的假设:
我试过 运行 Windows XP 版
notepad.exe
Windows 10. 它会自动弹出触摸键盘。我怀疑 Windows XP 是否明确支持触摸键盘。我还尝试了一些古老的 MFC 应用程序(例如 2005 年的 FileZilla 2.2.15)。它还会在所有输入框上弹出触摸键盘。同样,我很确定 MFC 也没有明确支持触摸键盘。
基于 wxWidgets 构建的应用程序也是如此(例如 FileZilla 3.x)。
WinForms 中似乎有什么东西损坏了,阻止了自动弹出窗口。有趣的是,自动弹出有效:
- (可编辑)组合框(
ComboBox
和DropDownStyle = DropDown
) - 对于密码模式下的文本框(
TextBox.PasswordChar
) - 富文本框 (
RichTextBox
) - 当输入框获得焦点时,硬件键盘被“移除”(我通过在 Lenovo Yoga 笔记本上翻转屏幕进行测试),但之后就没有了。
我已经通过 运行 宁 TabTip.exe
看到了关于显式弹出窗口的所有提示。例如:
- How to use Windows On-Screen Keyboard in C# WinForms
- Open and close Windows 8 touch keyboard tabtip under desktop
- How do I close the on-screen keyboard process from C# winform correctly?
- Keyboard Winforms on Windows 10 (surface)
大多数“解决方案”都提供这样的代码:
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 周年更新中似乎不再有效:
- Show touch keyboard (TabTip.exe) in Windows 10 Anniversary edition
有趣的是,我在 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.exe
或 tabtip.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!
Insert a reference to UIAutomationClient.dll to your project
In the form-load-handler of the application's main window, insert the following code:
var asForm = System.Windows.Automation.AutomationElement.FromHandle(this.Handle);
正如
可以使用 UIAutomationClient.dll
的 UI 自动化实现。
为了将 UI 自动化神奇地注入到应用程序中,必须触发程序集内部 class UiaCoreApi
初始化器 class UiaCoreApi
。
On 可以通过调用看似无操作来实现这一点:
AutomationElement.FromHandle(IntPtr)(-1)
另一种方法是显式实现自动化 UI。为此,为相应的输入控件实现 ITextProvider
/IValueProvider
接口。
要将接口的实现绑定到控件,请使用 lParam
= RootObjectId
处理 WM_GETOBJECT
window message。
有关实施示例,请参阅
- tombam 对 How to use Windows On-Screen Keyboard in C# WinForms 的回答
- 或直接投稿文章Implementing TextBox with on-screen touch keyboard.
尽管有趣的是,触摸键盘开箱即用的控件(如组合框或密码编辑框,请参阅答案)未实现 WM_GETOBJECT
/RootObjectId
.他们背后一定有不同的机器。
使用 RichTextBox 而不是 TextBox 控件。 RichTextBox支持触摸键盘,当获得焦点时会自动弹出键盘。 (类似于组合框等其他输入控件)
RichTextBox 也支持与 TextBox 相同的属性,因此在大多数情况下它应该是一个小改动。 (两个控件都派生自 TextBoxBase)
我注意到,如果触摸键盘在弹出后被关闭,您可能需要在控件上点击两次才能使其重新弹出。