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

Mar*_*ryl 39 c# windows delphi touch winforms

当我在平板电脑模式下在Windows 10上运行WinForms(或Delphi,请参见最后)应用程序时,当输入框被聚焦时,触摸键盘不会自动弹出.

我相信这应该自动发生,无需任何额外的代码/设置.


对于测试,我有一个单一TextBox控件的最简单的VS 2015 WinForms桌面应用程序.

在此输入图像描述

它只是Visual Studio创建的默认Windows窗体应用程序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;
Run Code Online (Sandbox Code Playgroud)

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

  • 我试图notepad.exe在Windows 10上运行Windows XP版本.它会自动弹出触摸键盘.我怀疑Windows XP对触摸键盘有任何明确的支持.

  • 我也尝试了一些古老的MFC应用程序(例如2005年的FileZilla 2.2.15).它还会在所有输入框上弹出触摸键盘.同样,我很确定,MFC也没有明确支持触摸键盘.

  • 对于基于wxWidgets构建的应用程序(例如FileZilla 3.x)也是如此.


看起来WinForms中有一些东西会阻止自动弹出窗口.有趣的是,自动弹出功能:

  • for(editable)组合框(ComboBoxDropDownStyle = DropDown)
  • 用于密码模式下的文本框(TextBox.PasswordChar)
  • 用于富文本框(RichTextBox)
  • 当硬件键盘被"移除"时输入框具有焦点(我通过翻转联想瑜伽笔记本上的屏幕来测试),但从未过后.

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

大多数"解决方案"都提供如下代码:

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

但我不敢相信这可能是"官方"的方式.如果没有别的,那么因为没有干净的方法来隐藏通过运行打开的键盘TabTip.exe(解决方案包括杀死进程或发送Esc密钥的黑客).

实际上,上述黑客攻击在Windows 10周年更新中似乎不再起作用:


有趣的是,我在Delphi/C++ Builder/VCL应用程序中看到了相同的行为.键盘不会弹出编辑框(TEdit).它会弹出组合框(TComboBox)和密码模式下的编辑框(PasswordChar).有趣的是,不是因为TRichEdit.NET的显着差异RichTextBox,可能值得研究.

这个(未答复的)问题描述了一个相同的行为:
应用程序编写的Delphi XE8 touch在编辑框键盘中没有出现在Windows 10中.

jar*_*ler 10

我已经走了几次这条路,并且只能实现这个taptip.exe选项.然后通过杀死进程关闭窗口.我还发现,如果您愿意,可以使用某些注册表黑客将键盘默认设置为手写面板.但那只能在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");
Run Code Online (Sandbox Code Playgroud)

我需要赞扬这篇文章的注册表想法:Windows 8桌面应用程序:打开tabtip.exe到二级键盘(对于数字文本框)


Ofe*_*lon 9

根本原因似乎是Winforms的textBox不是AutomationElement,而其他提到的控件(ComboBoxes等)是.

引用Markus von und zu Heber 接受的答案:

我们在文章" Windows 8+上的WPF应用程序中的文本框自动触摸键盘 "中找到了它,但它对于winforms也非常好(甚至更容易!).谢谢Dmitry Lyalin!

  1. 在您的项目中插入对UIAutomationClient.dll的引用

  2. 在应用程序主窗口的form-load-handler中,插入以下代码:

    var asForm = System.Windows.Automation.AutomationElement.FromHandle(this.Handle);
    
    Run Code Online (Sandbox Code Playgroud)

  • 调用`AutomationElement.FromHandle(handle)`确实有我想要的效果.但这只是一个副作用.你实际上可以将任何东西传递给方法,包括像`(IntPtr)( - 1)`这样的无效句柄.重要的是方法实现使用内部类`UiaCoreApi`.它的类初始化程序做了一些魔术,使触摸键盘弹出编辑框.但它也做了数以万计的其他事情,并加载了许多不相关的集合,都有未知的副作用,我不愿意盲目使用. (2认同)

小智 6

据我所知,启动osk.exetabtip.exe几乎是启动这项工作的"标准"方式.到目前为止,我还没有找到"官方"解决方案.

但是,如果我这样做,我不会杀死进程或发送密钥尝试解除键盘.相反,您可以在启动进程时获取窗口句柄,并使用它来最小化窗口并将其隐藏在任务栏中.

这里的某个人已经得到了窗口句柄只是为了关闭它,但它给你的想法:从WPF显示和隐藏Windows 8屏幕键盘

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


Mar*_*ryl 1

正如Ofek Shilon 的回答所暗示的那样,触摸键盘似乎可以利用UI 自动化


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

为了将 UI 自动化神奇地注入到应用程序中,UiaCoreApi必须触发程序集内部类的类初始值设定项。

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

AutomationElement.FromHandle(IntPtr)(-1)
Run Code Online (Sandbox Code Playgroud)

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

要将接口的实现绑定到控件,请使用=处理WM_GETOBJECT窗口消息lParamRootObjectId

有关实现的示例,请参见


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