检测屏幕键盘是否打开(TabTip.exe)

时间:2014-01-02 21:31:59

标签: c# windows-8 keyboard touch on-screen-keyboard

我正在使用WPF / C#应用程序来填写表单。我试图找到一种方法来确定TapTip键盘(用于Windows 8桌面的TabTip.exe /类似地铁的键盘)是否在Windows 8中最小化/不可见。

我已经能够检测到osk键盘(osk.exe / windows可访问性屏幕键盘)是否被最小化,但是相同的过程似乎不适用于TabTip键盘。

检测键盘是否最小化I:
1.找到键盘的过程
2.获取MainWindowHandle
3.使用WINDOWPLACEMENT的showCmd属性(使用MainWindowHandle找到)
4.使用showCmd值确定窗口是否最小化

我遇到的问题是:
  - TabTip进程的MainWindowHandle为0(因此我无法使用它来查找WINDOWPLACEMENT信息)
  - 当TabTip打开并最小化时,WINDOWPLACEMENT.showCmd的值相同

为了找到TabTip窗口的句柄,我使用ENUMWINDOWS来获取所有窗口句柄,使用GETWINDOWTHREADPROCESSID获取进程ID,然后将id与TabTip进程id进行比较。

任何有关此的帮助将不胜感激。这也是我的第一篇文章。我想我做对了,但如果没有,请告诉我如何解决它。

3 个答案:

答案 0 :(得分:12)

在找到一个有效的方法之前,我尝试了几种不同的方法。使用IsWindowVisible()没有用,我也没有对GetWindowPlacement()GetIconic()感到高兴。最后,我使用了GetWindowLong()并检查了WS_VISIBLE的回复情况。一个快速的控制台应用程序演示如下:

using System;
using System.Diagnostics;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Threading;

namespace CSharpTesting
{
    class Program
    {
        /// <summary>
        /// The window is initially visible. See http://msdn.microsoft.com/en-gb/library/windows/desktop/ms632600(v=vs.85).aspx.
        /// </summary>
        public const UInt32 WS_VISIBLE  = 0X94000000;
        /// <summary>
        /// Specifies we wish to retrieve window styles.
        /// </summary>
        public const int GWL_STYLE = -16;

        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(String sClassName, String sAppName);

        [DllImport("user32.dll", SetLastError = true)]
        static extern UInt32 GetWindowLong(IntPtr hWnd, int nIndex);

        static void Main(string[] args)
        {
            // Crappy loop to poll window state.
            while (true)
            {
                if (IsKeyboardVisible())
                {
                    Console.WriteLine("keyboard is visible");
                }
                else
                {
                    Console.WriteLine("keyboard is NOT visible");
                }

                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// Gets the window handler for the virtual keyboard.
        /// </summary>
        /// <returns>The handle.</returns>
        public static IntPtr GetKeyboardWindowHandle()
        {
            return FindWindow("IPTip_Main_Window", null);
        }

        /// <summary>
        /// Checks to see if the virtual keyboard is visible.
        /// </summary>
        /// <returns>True if visible.</returns>
        public static bool IsKeyboardVisible()
        {
            IntPtr keyboardHandle = GetKeyboardWindowHandle();

            bool visible = false;

            if (keyboardHandle != IntPtr.Zero)
            {
                UInt32 style = GetWindowLong(keyboardHandle, GWL_STYLE);
                visible = (style == WS_VISIBLE);
            }

            return visible;
        }
    }
}

答案 1 :(得分:1)

如果我没记错的话,TabTip.exe的窗口类名称为IPTip_Main_Window。您可以使用Win32 API FindWindow获取HWND的{​​{1}}。这比使用窗口标题更可靠,因为有些窗口可以有空标题(或标题可以更改),因此建议使用。

使用EnumWindows的当前方法可能存在缺陷,因为单个进程具有许多窗口(或具有子窗口的窗口)。您可以使用TabTip.exe之类的工具查找所需的实际窗口以及相应的类名。

您仍然可以使用GetWindowHandleThreadProcessId来检索Spy++,但我认为您不需要它来进行简单的窗口状态监控。

此外,尝试使用Win32 API而不是CLR中内置的任何API。例如GetWindowPlacement

来自MSDN的说明:

  

此函数检索的WINDOWPLACEMENT的标志成员是   总是零。如果由hWnd参数标识的窗口是   最大化后,showCmd成员为SW_SHOWMAXIMIZED。如果窗口是   最小化,showCmd是SW_SHOWMINIMIZED。否则就是   SW_SHOWNORMAL。

希望有帮助,如果你还需要进一步的帮助,请留下评论,我会在我回到Win8机器后进行编辑。

答案 2 :(得分:1)

这完全有用!

//
// BOOL IsVirtualKeyboardVisible()
//
// Returns TRUE if Virtual Keyboard/Input Pane is visible
// Returns FALSE if Virtual Keyboard/Input Pane is not visible

__declspec(dllexport) BOOL __cdecl IsVirtualKeyboardVisible()
{
    BOOL    bRet = FALSE;
    RECT    InputPaneScreenLocation = { 0, 0, 0, 0 };

    __try
    {
        HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

        IFrameworkInputPane *IinputPane = NULL;

        if (SUCCEEDED(hr))
        {
            //
            // http://msdn.microsoft.com/en-us/library/windows/desktop/hh706967(v=vs.85).aspx
            //
            hr = CoCreateInstance(__uuidof(FrameworkInputPane), 0, CLSCTX_ALL, __uuidof(IFrameworkInputPane), (LPVOID*)&IinputPane);
            IinputPane->Location(&InputPaneScreenLocation);

            if (InputPaneScreenLocation.bottom == 0 && InputPaneScreenLocation.left == 0 &&
                InputPaneScreenLocation.right == 0 && InputPaneScreenLocation.top == 0)
            {
                // VKB is not visible
                bRet = FALSE;
            }
            else
            {
                // VKB is visible
                bRet = TRUE;
            } 
        }

    }   // try
    __finally
    {
        CoUninitialize();
    }

    return bRet;
}