windows - 在 Windows 10 周年纪念版中显示触摸键盘 (TabTip.exe)

标签 windows winapi touch windows-10 windows-10-desktop

在 Anniversary 更新之前的 Windows 8 和 Windows 10 中,可以通过启动显示触摸键盘

C:\Program Files\Common Files\microsoft shared\ink\TabTip.exe

它不再适用于 Windows 10 周年更新; TabTip.exe 进程正在运行,但未显示键盘。

有没有办法以编程方式显示它?

更新

我找到了一个解决方法 - 假鼠标点击系统托盘中的触摸键盘图标。这是 Delphi 中的代码

// Find tray icon window
function FindTrayButtonWindow: THandle;
var
  ShellTrayWnd: THandle;
  TrayNotifyWnd: THandle;
begin
  Result := 0;
  ShellTrayWnd := FindWindow('Shell_TrayWnd', nil);
  if ShellTrayWnd > 0 then
  begin
    TrayNotifyWnd := FindWindowEx(ShellTrayWnd, 0, 'TrayNotifyWnd', nil);
    if TrayNotifyWnd > 0 then
    begin
      Result := FindWindowEx(TrayNotifyWnd, 0, 'TIPBand', nil);
    end;
  end;
end;

// Post mouse click messages to it
TrayButtonWindow := FindTrayButtonWindow;
if TrayButtonWindow > 0 then
begin
  PostMessage(TrayButtonWindow, WM_LBUTTONDOWN, MK_LBUTTON, $00010001);
  PostMessage(TrayButtonWindow, WM_LBUTTONUP, 0, $00010001);
end;

更新 2

我发现的另一件事是设置此注册表项可在启动 TabTip.exe 时恢复旧功能显示触摸键盘

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\TabletTip\1.7\EnableDesktopModeAutoInvoke=1

最佳答案

好的,当用户按下系统托盘中的那个按钮时,我对资源管理器的行为进行了逆向工程。

基本上,它创建了一个未记录的接口(interface) ITipInvocation 的实例并调用其 Toggle(HWND) 方法,将桌面窗口作为参数传递。顾名思义,该方法根据键盘的当前状态显示或隐藏键盘。

请注意,每次点击按钮时,资源管理器都会创建一个 ITipInvocation 实例。所以我认为不应该缓存实例。我还注意到,资源管理器从不在获取的实例上调用 Release()。我不太熟悉 COM,但这看起来像是一个错误。

我在 Windows 8.1、Windows 10 和 Windows 10 周年纪念版中对此进行了测试,它运行良好。这是 C 中的一个最小示例,显然缺少一些错误检查。

#include <initguid.h>
#include <Objbase.h>
#pragma hdrstop

// 4ce576fa-83dc-4F88-951c-9d0782b4e376
DEFINE_GUID(CLSID_UIHostNoLaunch,
    0x4CE576FA, 0x83DC, 0x4f88, 0x95, 0x1C, 0x9D, 0x07, 0x82, 0xB4, 0xE3, 0x76);

// 37c994e7_432b_4834_a2f7_dce1f13b834b
DEFINE_GUID(IID_ITipInvocation,
    0x37c994e7, 0x432b, 0x4834, 0xa2, 0xf7, 0xdc, 0xe1, 0xf1, 0x3b, 0x83, 0x4b);

struct ITipInvocation : IUnknown
{
    virtual HRESULT STDMETHODCALLTYPE Toggle(HWND wnd) = 0;
};

int WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HRESULT hr;
    hr = CoInitialize(0);

    ITipInvocation* tip;
    hr = CoCreateInstance(CLSID_UIHostNoLaunch, 0, CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER, IID_ITipInvocation, (void**)&tip);
    tip->Toggle(GetDesktopWindow());
    tip->Release();
    return 0;
}

这也是 C# 版本:

class Program
{
    static void Main(string[] args)
    {
        var uiHostNoLaunch = new UIHostNoLaunch();
        var tipInvocation = (ITipInvocation)uiHostNoLaunch;
        tipInvocation.Toggle(GetDesktopWindow());
        Marshal.ReleaseComObject(uiHostNoLaunch);
    }

    [ComImport, Guid("4ce576fa-83dc-4F88-951c-9d0782b4e376")]
    class UIHostNoLaunch
    {
    }

    [ComImport, Guid("37c994e7-432b-4834-a2f7-dce1f13b834b")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    interface ITipInvocation
    {
        void Toggle(IntPtr hwnd);
    }

    [DllImport("user32.dll", SetLastError = false)]
    static extern IntPtr GetDesktopWindow();
}

更新:根据@EugeneK 的评论,我相信 tabtip.exe 是相关 COM 组件的 COM 服务器,因此如果您的代码得到 REGDB_E_CLASSNOTREG ,它可能应该运行 tabtip.exe 并重试。

关于windows - 在 Windows 10 周年纪念版中显示触摸键盘 (TabTip.exe),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38774139/

相关文章:

xcode - UIBarButtonItem,设置专属触摸

android - Android 中事件处理方法返回的 bool 值的含义是什么

linux - 为本地文件设置到期日期 - Windows/Linux

c# - 获取鼠标指针下方的窗口句柄,同时忽略半透明窗口

c++ - 能不能每次读完串口就清空串口?

c++ - 使用 Win32 进行组织的典型约定是什么?

c++ - 停止与 Windows 开始栏重叠的应用程序窗口

javascript - 检测手指何时离开屏幕上的对象

c# - 无法使用 prnmngr.vbs 在远程计算机上设置默认打印机

python - 在 Windows 上安装 Python 3.6 的路径是什么?