确定Windows 10 Touch键盘是可见还是隐藏

mik*_*esl 4 c# windows winapi touch virtual-keyboard

我试图找出Windows 10虚拟触摸键盘是否可见,以确定是否从我的应用程序打开它.以下代码已经工作正常,直到最新的Windows 10更新15063或可能在它之前.好像微软改变了窗口样式的东西,但我无法弄明白.

    public static bool IsKeyboardVisible()
    {
        IntPtr keyboardHandle = GetKeyboardWindowHandle();
        // Specifies we wish to retrieve window styles.
        int GWL_STYLE = -16;

        //The window is disabled. See http://msdn.microsoft.com/en-gb/library/windows/desktop/ms632600(v=vs.85).aspx.
        UInt32 WS_VISIBLE =               0x10000000;
        UInt32 WS_DISABLED =              0x08000000;
        UInt32 WS_POPUP =                 0x80000000;


        bool visible = false;
        bool disabled = false;

        if (keyboardHandle != IntPtr.Zero)
        {
            UInt32 style = GetWindowLong(keyboardHandle, GWL_STYLE);
            visible = ((style & WS_VISIBLE) == WS_VISIBLE);
            disabled = ((style & WS_DISABLED) == WS_DISABLED); // ref https://stackoverflow.com/questions/11065026/get-window-state-of-another-process
            log.InfoFormat("style:{0:X4} visible:{1} disabled:{2}", style, visible, disabled);
        }

        return visible && !disabled ;
    }
Run Code Online (Sandbox Code Playgroud)

这与以下内容有关:在Windows 10周年纪念版中显示触摸键盘(TabTip.exe)

tor*_*vin 5

我用Spy ++做了一些研究.看起来Fall Creators Update(版本1709)中的新键盘由另一个窗口托管.这个窗口有Windows.UI.Core.CoreWindow类和Microsoft Text Input Application标题.

以下代码适用于所有Windows 10版本,包括新的1803和更早的Windows版本(我相信从Windows 8开始).

static class TouchKeyboard
{
    public static bool GetIsOpen()
    {
        return GetIsOpen1709() ?? GetIsOpenLegacy();
    }

    private static bool? GetIsOpen1709()
    {
        var parent = IntPtr.Zero;
        for (;;)
        {
            parent = FindWindowEx(IntPtr.Zero, parent, WindowParentClass1709);
            if (parent == IntPtr.Zero)
                return null; // no more windows, keyboard state is unknown

            // if it's a child of a WindowParentClass1709 window - the keyboard is open
            var wnd = FindWindowEx(parent, IntPtr.Zero, WindowClass1709, WindowCaption1709);
            if (wnd != IntPtr.Zero)
                return true;
        }
    }

    private static bool GetIsOpenLegacy()
    {
        var wnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, WindowClass);
        if (wnd == IntPtr.Zero)
            return false;

        var style = GetWindowStyle(wnd);
        return style.HasFlag(WindowStyle.Visible)
            && !style.HasFlag(WindowStyle.Disabled);
    }

    private const string WindowClass = "IPTip_Main_Window";
    private const string WindowParentClass1709 = "ApplicationFrameWindow";
    private const string WindowClass1709 = "Windows.UI.Core.CoreWindow";
    private const string WindowCaption1709 = "Microsoft Text Input Application";

    private enum WindowStyle : uint
    {
        Disabled = 0x08000000,
        Visible = 0x10000000,
    }

    private static WindowStyle GetWindowStyle(IntPtr wnd)
    {
        return (WindowStyle)GetWindowLong(wnd, -16);
    }

    [DllImport("user32.dll", SetLastError = false)]
    private static extern IntPtr FindWindowEx(IntPtr parent, IntPtr after, string className, string title = null);

    [DllImport("user32.dll", SetLastError = false)]
    private static extern uint GetWindowLong(IntPtr wnd, int index);
}
Run Code Online (Sandbox Code Playgroud)

更新:我更新了答案和代码以与Redstone 4(v1803)兼容.