[C#] C# –Launch Windows standard touch keyboard
Windows has a touch keyboard executable file called tabtip.exe (“C: /Program Files / Common Files / Microsoft Shared / ink / tabtip.exe”), and you can use the touch keyboard by executing this. I will.
There is also a screen keyboard called osk.exe, but I won’t cover it this time. (The UI is not for touch & ScrLk and some buttons that are troublesome if pressed, so I do not want to use it too much)
code
(Corrected on 2020/09/02) Moved TabTip.exe startup process from Open method to Toggle method. Fixed to execute Open method via Task.
using System;
using System.Diagnostics;
using System.Threading;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
/// <summary>
/// Windows standard touch keyboard operation class.
/// </ summary>
public class WinTouchKeyboard
{
[ComImport, Guid ("D5120AA3-46BA-44C5-822D-CA8092C1FC72")]
private class FrameworkInputPane
{
}
[ComImport, System.Security.SuppressUnmanagedCodeSecurity,
InterfaceType (ComInterfaceType.InterfaceIsIUnknown),
Guid ("5752238B-24F0-495A-82F1-2FD593056796")]
private interface IFrameworkInputPane
{
[PreserveSig]
int Advise (
[MarshalAs (UnmanagedType.IUnknown)] object pWindow,
[MarshalAs (UnmanagedType.IUnknown)] object pHandler,
out int pdwCookie
);
[PreserveSig]
int AdviseWithHWND (
IntPtr hwnd,
[MarshalAs (UnmanagedType.IUnknown)] object pHandler,
out int pdwCookie
);
[PreserveSig]
int Unadvise (
int pdwCookie
);
[PreserveSig]
int Location (
out Rectangle prcInputPaneScreenLocation
);
}
[ComImport, Guid ("4ce576fa-83dc-4F88-951c-9d0782b4e376")]
private class UIHostNoLaunch
{
}
[ComImport, Guid ("37c994e7-432b-4834-a2f7-dce1f13b834b")]
[InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
private interface ITipInvocation
{
void Toggle (IntPtr hwnd);
}
[DllImport ("user32.dll", SetLastError = false)]
private static extern IntPtr GetDesktopWindow ();
/// <summary>
/// TabTip.exe path
/// </ summary>
public static string TabTipPath {get; set;} = "C: / Program Files / Common Files / Microsoft Shared / ink / tabtip.exe";
/// <summary>
/// Open the touch keyboard.
/// If the touch keyboard is displayed, do nothing.
/// </ summary>
/// <param name = "delayMsec"> Waiting time until the touch keyboard is displayed.
/// Adjust the wait time if the touch keyboard closes instantly in response to the TAB key. (About 200-300 msec) </ param>
public static void Open (int delayMsec)
{
if (IsVisible ())
{
return;
}
Task.Run (() =>
{
if (delayMsec> 0)
{
Thread.Sleep (delayMsec);
}
// Touch keyboard ON / OFF switching
Toggle ();
});
}
/// <summary>
/// Close the touch keyboard.
/// If the touch keyboard is not displayed, do nothing.
/// </ summary>
public static void Close ()
{
if (! IsVisible ())
{
return;
}
// Touch keyboard ON / OFF switching
Toggle ();
}
/// <summary>
/// Switch ON / OFF of touch keyboard
/// </ summary>
public static void Toggle ()
{
// Switch the display with UIHostNoLaunch.Toggle
try
{
UIHostNoLaunch uiHostNoLaunch = null;
try
{
uiHostNoLaunch = new UIHostNoLaunch ();
var tipInvocation = (ITipInvocation) uiHostNoLaunch;
tipInvocation.Toggle (GetDesktopWindow ());
}
finally finally
{
if (uiHostNoLaunch! = null)
{
Marshal.ReleaseComObject (uiHostNoLaunch);
}
}
}
catch (COMException)
{
// If tabtip.exe is not running, new UIHostNoLaunch () will throw a COMException.
I also thought that //Process.GetProcessesByName should be checked in advance,
// Even if COMException is ignored, there is no significant speed difference, so do not check.
}
// If an exception occurs in the above process, tabtip.exe is not started, so start it.
Process.Start (TabTipPath);
}
/// <summary>
/// Get the display status of the touch keyboard.
/// </ summary>
/// <returns> true: Show false: Hide </ returns>
public static bool IsVisible ()
{
// Get the position and size of the touch keyboard, and if the width is 0, it is considered hidden.
Rectangle bounds = GetBounds ();
return (bounds.Width! = 0);
}
/// <summary>
/// Get the position and size of the touch keyboard.
/// </ summary>
/// <returns> Touch keyboard position / size </ returns>
public static Rectangle GetBounds ()
{
IFrameworkInputPane inputPane = null;
Rectangle rect;
try
{
// Get the position and size of the touch keyboard, and if the width is 0, it is considered hidden.
inputPane = (IFrameworkInputPane) new FrameworkInputPane ();
inputPane.Location (out rect);
}
finally finally
{
if (inputPane! = null)
{
Marshal.ReleaseComObject (inputPane);
}
}
return rect;
}
}
I made it into a class by referring to the post on Stackoverflow.Launching the touch keyboard (Tabtip.exe) from non-admin account on Windows 10 Show touch keyboard (TabTip.exe) in Windows 10 Anniversary edition Determine if Windows 10 Touch Keyboard is Visible or Hidden
I have confirmed that it works on Win10Pro 1903. It is unknown if it will work with other versions. (Please let me know if it works on other than Win10) ITipInvocation and UIHostNoLaunch are COMs that are not officially documented by MS, so I can’t say if they can be used, but they work for the time being.
When closing the touch keyboard, there were cases where the tabtip.exe process was forcibly killed, or SendMessage was sent WM_SYSCOMMAND + SC_CLOSE to close the window.
- -tabtip.exe quits (tabtip.exe must be restarted each time)
- -The touch keyboard may remain even if the “IPTIP_Main_Window” window disappears.
It seems that it is better not to close with these methods because of the problem.