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

C# 在WinForms输入焦点上自动弹出平板电脑触摸键盘,c#,windows,winforms,delphi,touch,C#,Windows,Winforms,Delphi,Touch,当我在Windows 10上运行WinForms(或Delphi,见结尾)应用程序时,当输入框处于焦点时,触摸键盘不会自动弹出 我相信这应该是自动发生的,没有任何额外的代码/设置 作为一个测试,我有一个最简单的VS 2015 WinForms桌面应用程序 它只是VisualStudio创建的默认Windows窗体应用程序C#项目。没有添加代码,没有更改属性。通过从工具箱中删除,只添加了文本框(同样没有更改属性): this.textBox1=new System.Windows.Forms.

当我在Windows 10上运行WinForms(或Delphi,见结尾)应用程序时,当输入框处于焦点时,触摸键盘不会自动弹出

我相信这应该是自动发生的,没有任何额外的代码/设置


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

它只是VisualStudio创建的默认Windows窗体应用程序C#项目。没有添加代码,没有更改属性。通过从工具箱中删除,只添加了
文本框
(同样没有更改属性):

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

要验证我关于弹出窗口应该是自动的假设,请执行以下操作:

  • 我已尝试在Windows 10上运行Windows XP版本的
    notepad.exe
    。它会自动弹出触摸键盘。我怀疑WindowsXP是否明确支持触摸键盘

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

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


看起来WinForms中有什么东西被破坏了,阻止了自动弹出。有趣的是,自动弹出窗口可以工作:

  • 用于(可编辑)组合框(
    ComboBox
    带有
    DropDownStyle=DropDown
  • 对于密码模式下的文本框()
  • 对于富文本框(
    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);
但我不敢相信这会是“官方”的方式。如果没有其他原因,那么是因为没有干净的方法来隐藏通过运行
TabTip.exe打开的键盘(解决方案包括终止进程或发送Esc键等黑客)

实际上,上述黑客行为在Windows 10周年更新中似乎不再有效:


有趣的是,我在Delphi/C++Builder/VCL应用程序中看到了相同的行为。编辑框()的键盘不会弹出。对于组合框()和密码模式下的编辑框(),它确实会弹出。有趣的是,与.NET
RichTextBox
相比,有什么显著的区别可能值得研究

这个(未回答的)问题描述了一个相同的行为:

.

据我所知,启动
osk.exe
tabtip.exe
几乎是实现这一目标的“标准”方式。到目前为止,我还没有找到“官方”解决方案

但是,如果是我这样做的话,我就不会停止进程,也不会发送按键试图关闭键盘。相反,您可以在启动进程时获得窗口句柄,并使用该句柄最小化窗口并将其隐藏在任务栏中

这里有人拿到了窗户把手,只是想把它关上,但它给了你一个想法:


如果您需要我,请告诉我,我会看看是否有时间编写一个完整的示例。

我在这方面已经做了几次,并且只能够实现
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");

我需要赞扬这篇文章的注册理念:

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

引用Markus von und zu Heber的话:

我们在文章“”中找到了它,但它也非常有效(甚至 更简单!)用于winforms。谢谢你,Dmitry Lyalin

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

  • 在应用程序主窗口的窗体加载处理程序中,插入以下代码:

    var asForm = System.Windows.Automation.AutomationElement.FromHandle(this.Handle);
    
  • 正如所暗示的,触摸键盘似乎可以利用


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

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

    On可以实现这一点,例如,通过调用似乎没有操作:

    AutomationElement.FromHandle(IntPtr)(-1)
    

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

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

    有关实现的示例,请参见

    • 汤姆巴姆的回答
    • 或者直接从海报的文章


    尽管有趣的是,触摸键盘的控件(如组合框或密码编辑框,请参见答案)没有实现
    WM_GETOBJECT
    /
    RootObjectId
    。它们后面一定有不同的机器。

    用RichTextBox代替