I am trying to find out if the windows 10 virtual touch keyboard is visible or not to know whether to open it or not from my application. THe following code has worked fine
I discovered yet another undocumented COM API that returns the position of the touch keyboard. It returns the bounds of the keyboard window or zeroes if the keyboard is hidden. I tested it in Windows 8.1, Windows 10 and Windows 10 Fall Creators Update and it works fine.
Now some bad news: in all versions prior to Fall Creators Update it only reports accurate results if the active window and the touch keyboard are located on the same monitor. If this is not the case - the API just returns the previous cached value. I'm guessing it has something to do with the fact that this API was meant to be used to calculate occlusion of the touch keyboard and your app's window. (It's called inside Windows::UI::ViewManagement::InputPane.get_OccludedRect() UWP API).
So if you don't care about supporting older versions or multi-monitor scenarios - use it. Otherwise I would suggest checking the Windows version and falling back to the previous method (GetIsOpenLegacy() from my other answer).
The API:
[ComImport, Guid("228826af-02e1-4226-a9e0-99a855e455a6")]
class ImmersiveShellBroker
{
}
[ComImport, Guid("9767060c-9476-42e2-8f7b-2f10fd13765c")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IImmersiveShellBroker
{
void Dummy();
IInputHostManagerBroker GetInputHostManagerBroker();
}
[ComImport, Guid("2166ee67-71df-4476-8394-0ced2ed05274")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IInputHostManagerBroker
{
void GetIhmLocation(out Rect rect, out DisplayMode mode);
}
[StructLayout(LayoutKind.Sequential)]
struct Rect
{
public int Left, Top, Right, Bottom;
}
enum DisplayMode
{
NotSupported = 0,
Floating = 2,
Docked = 3,
}
Usage example:
// do this once:
var brokerClass = new ImmersiveShellBroker();
var broker = (IImmersiveShellBroker)brokerClass;
var ihm = broker.GetInputHostManagerBroker();
Marshal.ReleaseComObject(broker);
// now ihm reference can be cached and used later:
Rect rect;
DisplayMode mode;
ihm.GetIhmLocation(out rect, out mode);
Note: looks like GetIhmLocation() always returns DisplayMode.NotSupported instead of the actual mode prior to Windows 10.