10

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

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

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

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

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

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

4

3 回答 3

12

在找到一种可行的方法之前,我尝试了几种不同的方法。使用没有用,我也对orIsWindowVisible()没有任何乐趣。最后我使用并检查了回来。一个用于演示的快速控制台应用程序如下: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;
        }
    }
}
于 2014-07-22T14:48:22.200 回答
2

这完全有效!

//
// 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;
}
于 2014-06-30T22:01:21.910 回答
1

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

EnumWindows由于单个进程具有许多窗口(或具有子窗口的窗口),您当前的使用方法可能存在缺陷。您可以使用类似工具Spy++来查找所需的实际窗口和相应的类名。

您仍然可以使用它GetWindowHandleThreadProcessId来检索processID那个点,但我认为您不需要它来进行简单的窗口状态监视。

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

来自 MSDN 的注释:

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

希望对您有所帮助,如果您仍需要进一步的帮助,请发表评论,一旦我回到我的 Win8 机器,我将进行编辑。

于 2014-01-02T21:41:57.457 回答