I am working on a WPF/C# application for completing forms. I am trying to find a way to determine if the TapTip keyboard (TabTip.exe / metro-like keyboard for windows 8 desktop) is minimized / not visible in windows 8.
I have been able to detect if the osk keyboard (osk.exe / windows accessibility on-screen keyboard) is minimized, but the same process does not seem to work with the TabTip keyboard.
To detect if the keyboard is minimized I:
1. Find the keyboard's process
2. Get the MainWindowHandle
3. Use the showCmd property of the WINDOWPLACEMENT (found using MainWindowHandle)
4. Use showCmd value to determine if window is minimized
The problems I have run into are:
- the TabTip process has a MainWindowHandle of 0 (so I can't use it to find the WINDOWPLACEMENT information)
- the values for WINDOWPLACEMENT.showCmd are the same when TabTip is open and minimized
In order to find the handle of the TabTip window I used ENUMWINDOWS to get all the window handles, GETWINDOWTHREADPROCESSID to get the process ids, then compared the ids to the TabTip process id.
Any help with this would be appreciated. Also this is my first post. I think I did this right, but if not please let me know how to fix it.
The only way to close the TabTip is to click the close button present on it.
These are examples on models with Android™ 8.0 and 9. If Device Preferences is not shown on your TV menu, skip it. HOME — Settings — (Device Preferences) — Keyboard — Current keyboard — Select Gboard. HOME — Settings — (Device Preferences) — Keyboard — Manage keyboards — Turn on Gboard.
Go to Start , then select Settings > Ease of Access > Keyboard, and turn on the toggle under Use the On-Screen Keyboard. A keyboard that can be used to move around the screen and enter text will appear on the screen. The keyboard will remain on the screen until you close it.
This totally works!
//
// 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;
}
I tried a few different methods before finding one which works. Using IsWindowVisible()
didn't work and I also didn't have any joy with GetWindowPlacement()
or GetIconic()
. In the end I used GetWindowLong()
and checked for the WS_VISIBLE
coming back. A quick console app to demonstrate is as follows:
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;
}
}
}
If I remember correctly, the window class name for TabTip.exe
is IPTip_Main_Window
. You can use the Win32 API FindWindow
to get the HWND
of TabTip.exe
. This is more reliable than using the window title and recommended as some windows can have empty titles (or the title can change).
Your current approach using EnumWindows
could be flawed due to a single process having many windows (or windows with child windows). You can use a tool like Spy++
to find the actual window you want and the respective class name.
You can still use GetWindowHandleThreadProcessId
to retrieve the processID
at that point, though I do not think you will need it for simple window state monitoring.
Also, try using Win32 APIs instead of whatever is built into the CLR. For example GetWindowPlacement
.
Note from MSDN:
The flags member of WINDOWPLACEMENT retrieved by this function is always zero. If the window identified by the hWnd parameter is maximized, the showCmd member is SW_SHOWMAXIMIZED. If the window is minimized, showCmd is SW_SHOWMINIMIZED. Otherwise, it is SW_SHOWNORMAL.
Hope that helps, if you still need further assistance leave a comment and I'll make an edit once I get back to my Win8 machine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With