Afficher le clavier tactile (TabTip.exe) dans l’édition Windows 10 Anniversary

Dans Windows 8 et Windows 10 avant la mise à jour d’anniversaire, il était possible d’afficher le clavier tactile en démarrant

C:\Program Files\Common Files\microsoft shared\ink\TabTip.exe 

Il ne fonctionne plus dans la mise à jour Windows 10 Anniversary; le processus TabTip.exe est en cours d’exécution, mais le clavier n’est pas affiché.

Y a-t-il un moyen de le montrer par programmation?

METTRE À JOUR

J’ai trouvé une solution de contournement – cliquez avec la souris sur l’icône du clavier tactile dans la barre d’état système. Voici le code en Delphi

 // Find tray icon window function FindTrayButtonWindow: THandle; var ShellTrayWnd: THandle; TrayNotifyWnd: THandle; begin Result := 0; ShellTrayWnd := FindWindow('Shell_TrayWnd', nil); if ShellTrayWnd > 0 then begin TrayNotifyWnd := FindWindowEx(ShellTrayWnd, 0, 'TrayNotifyWnd', nil); if TrayNotifyWnd > 0 then begin Result := FindWindowEx(TrayNotifyWnd, 0, 'TIPBand', nil); end; end; end; // Post mouse click messages to it TrayButtonWindow := FindTrayButtonWindow; if TrayButtonWindow > 0 then begin PostMessage(TrayButtonWindow, WM_LBUTTONDOWN, MK_LBUTTON, $00010001); PostMessage(TrayButtonWindow, WM_LBUTTONUP, 0, $00010001); end; 

MISE À JOUR 2

Une autre chose que j’ai trouvée est que la configuration de cette clé de registre restaure d’anciennes fonctionnalités lors du démarrage de TabTip.exe montre un clavier tactile

 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\TabletTip\1.7\EnableDesktopModeAutoInvoke=1 

    OK, j’ai inversé l’ingénierie de l’explorateur lorsque l’utilisateur appuie sur ce bouton dans la barre d’état système.

    Fondamentalement, il crée une instance d’une interface non documentée ITipInvocation et appelle sa méthode Toggle(HWND) , en passant la fenêtre du bureau en tant qu’argument. Comme son nom l’indique, la méthode affiche ou masque le clavier en fonction de son état actuel.

    Veuillez noter que l’explorateur crée une instance de ITipInvocation à chaque clic sur le bouton. Je pense donc que l’instance ne doit pas être mise en cache. J’ai également remarqué que l’explorateur n’appelle jamais Release() sur l’instance obtenue. Je ne suis pas trop familier avec COM, mais cela ressemble à un bug.

    Je l’ai testé dans Windows 8.1, Windows 10 et Windows 10 Anniversary Edition et cela fonctionne parfaitement. Voici un exemple minimal en C qui manque évidemment de vérifications d’erreur.

     #include  #include  #pragma hdrstop // 4ce576fa-83dc-4F88-951c-9d0782b4e376 DEFINE_GUID(CLSID_UIHostNoLaunch, 0x4CE576FA, 0x83DC, 0x4f88, 0x95, 0x1C, 0x9D, 0x07, 0x82, 0xB4, 0xE3, 0x76); // 37c994e7_432b_4834_a2f7_dce1f13b834b DEFINE_GUID(IID_ITipInvocation, 0x37c994e7, 0x432b, 0x4834, 0xa2, 0xf7, 0xdc, 0xe1, 0xf1, 0x3b, 0x83, 0x4b); struct ITipInvocation : IUnknown { virtual HRESULT STDMETHODCALLTYPE Toggle(HWND wnd) = 0; }; int WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HRESULT hr; hr = CoInitialize(0); ITipInvocation* tip; hr = CoCreateInstance(CLSID_UIHostNoLaunch, 0, CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER, IID_ITipInvocation, (void**)&tip); tip->Toggle(GetDesktopWindow()); tip->Release(); return 0; } 

    Voici la version C # également:

     class Program { static void Main(ssortingng[] args) { var uiHostNoLaunch = new UIHostNoLaunch(); var tipInvocation = (ITipInvocation)uiHostNoLaunch; tipInvocation.Toggle(GetDesktopWindow()); Marshal.ReleaseComObject(uiHostNoLaunch); } [ComImport, Guid("4ce576fa-83dc-4F88-951c-9d0782b4e376")] class UIHostNoLaunch { } [ComImport, Guid("37c994e7-432b-4834-a2f7-dce1f13b834b")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface ITipInvocation { void Toggle(IntPtr hwnd); } [DllImport("user32.dll", SetLastError = false)] static extern IntPtr GetDesktopWindow(); } 

    Mise à jour: par @EugeneK commentaires, je crois que tabtip.exe est le serveur COM pour le composant COM en question, donc si votre code obtient REGDB_E_CLASSNOTREG , il devrait probablement exécuter tabtip.exe et réessayer.

    La seule solution que j’ai trouvée pour fonctionner est d’envoyer PostMessage comme vous l’avez mentionné dans la réponse 1. Voici la version C # de ce dernier au cas où quelqu’un en aurait besoin.

     [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern IntPtr FindWindow(ssortingng sClassName, ssortingng sAppName); [DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, ssortingng lclassName, ssortingng windowTitle); [DllImport("User32.Dll", EntryPoint = "PostMessageA")] static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam); var trayWnd = FindWindow("Shell_TrayWnd", null); var nullIntPtr = new IntPtr(0); if (trayWnd != nullIntPtr) { var trayNotifyWnd = FindWindowEx(trayWnd, nullIntPtr, "TrayNotifyWnd", null); if (trayNotifyWnd != nullIntPtr) { var tIPBandWnd = FindWindowEx(trayNotifyWnd, nullIntPtr, "TIPBand", null); if (tIPBandWnd != nullIntPtr) { PostMessage(tIPBandWnd, (UInt32)WMessages.WM_LBUTTONDOWN, 1, 65537); PostMessage(tIPBandWnd, (UInt32)WMessages.WM_LBUTTONUP, 1, 65537); } } } public enum WMessages : int { WM_LBUTTONDOWN = 0x201, WM_LBUTTONUP = 0x202, WM_KEYDOWN = 0x100, WM_KEYUP = 0x101, WH_KEYBOARD_LL = 13, WH_MOUSE_LL = 14, } 

    Je détecte 4 situations lorsque vous essayez d’ouvrir le clavier tactile sur Windows 10 Mise à jour anniversaire

    1. Le clavier est visible – lorsque “IPTIP_Main_Window” est présent, NON désactivé et visible
    2. Le clavier n’est pas visible – lorsque “IPTIP_Main_Window” est présent mais désactivé
    3. Le clavier n’est pas visible – lorsque “IPTIP_Main_Window” est présent mais non désactivé et non visible
    4. Le clavier n’est pas visible lorsque “IPTIP_Main_Window” n’est PAS présent

    1 – rien à faire

    2 + 3 – activation via COM

    4 – scénario le plus intéressant. Dans certains appareils, le processus TabTip ouvre le clavier tactile, sur certains – non. Nous devons donc démarrer le processus TabTip, attendre que la fenêtre “IPTIP_Main_Window” apparaisse, vérifier sa visibilité et l’activer via COM si nécessaire.

    Je fais une petite bibliothèque pour mon projet, vous pouvez l’utiliser – osklib

    Il y a toujours un certain mystère sur la manière dont le clavier tactile est visible dans Windows 10 Anniversary Update. J’ai en fait le même problème et voici les dernières infos que j’ai trouvées:

    • Windows 10 1607 fonctionne en deux modes: Desktop et Tablet. En mode bureau, TabTip.exe peut être appelé mais ne sera pas affiché. En mode tablette, tout fonctionne bien: TabTip.exe se montre lorsqu’il est appelé. Donc, une solution 100% de travail consiste à configurer votre ordinateur en mode tablette, mais qui veut que son ordinateur de bureau / portable fonctionne en mode tablette? Pas moi quand même!

    • Vous pouvez utiliser la EnableDesktopModeAutoInvokeEnableDesktopModeAutoInvoke ” (HKCU, DWORD définie sur 1) et sur certains ordinateurs exécutant 1607, cela fonctionnait bien en mode bureau. Mais pour des raisons inconnues, cela ne fonctionne pas sur mon pavé tactile HP.

    Veuillez noter que cette valeur de registre est l’option “Afficher le clavier tactile en mode bureau s’il n’y a pas de clavier connecté” dans les parameters Windows> toucher

    • Vous pouvez utiliser le code de Torvin pour afficher TabTip.exe (comme mentionné précédemment, TabTip.exe devrait être actif lorsque vous utilisez le matériel COM), il fonctionne correctement sur certains ordinateurs équipés du 1607 (y compris mon touchpad HP! Yay!). sur d’autres comps avec les mêmes fenêtres Build.

    Jusqu’à présent testé sur 4 ordinateurs différents et je suis incapable de faire quelque chose de bien sur tous …

    J’ai eu le même problème aussi. Cela m’a pris beaucoup de temps et de maux de tête, mais grâce à Alexei et Torvin, j’ai finalement réussi à le faire fonctionner sur Win 10 1709. Le problème de la visibilité était le contrôle de la visibilité. Peut-être que le Nuget OSKlib pourrait être mis à jour. Permettez-moi de résumer la sulotion complète (pour sûr mon code a des lignes inutiles maintenant):

     using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.ComponentModel; using Osklib.Interop; using System.Runtime.InteropServices; using System.Threading; namespace OSK { public static class OnScreenKeyboard { static OnScreenKeyboard() { var version = Environment.OSVersion.Version; switch (version.Major) { case 6: switch (version.Minor) { case 2: // Windows 10 (ok) break; } break; default: break; } } private static void StartTabTip() { var p = Process.Start(@"C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe"); int handle = 0; while ((handle = NativeMethods.FindWindow("IPTIP_Main_Window", "")) <= 0) { Thread.Sleep(100); } } public static void ToggleVisibility() { var type = Type.GetTypeFromCLSID(Guid.Parse("4ce576fa-83dc-4F88-951c-9d0782b4e376")); var instance = (ITipInvocation)Activator.CreateInstance(type); instance.Toggle(NativeMethods.GetDesktopWindow()); Marshal.ReleaseComObject(instance); } public static void Show() { int handle = NativeMethods.FindWindow("IPTIP_Main_Window", ""); if (handle <= 0) // nothing found { StartTabTip(); Thread.Sleep(100); } // on some devices starting TabTip don't show keyboard, on some does ¯\_(ツ)_/¯ if (!IsOpen()) { ToggleVisibility(); } } public static void Hide() { if (IsOpen()) { ToggleVisibility(); } } public static bool Close() { // find it int handle = NativeMethods.FindWindow("IPTIP_Main_Window", ""); bool active = handle > 0; if (active) { // don't check style - just close NativeMethods.SendMessage(handle, NativeMethods.WM_SYSCOMMAND, NativeMethods.SC_CLOSE, 0); } return active; } public static bool IsOpen() { return GetIsOpen1709() ?? GetIsOpenLegacy(); } [DllImport("user32.dll", SetLastError = false)] private static extern IntPtr FindWindowEx(IntPtr parent, IntPtr after, ssortingng className, ssortingng title = null); [DllImport("user32.dll", SetLastError = false)] private static extern uint GetWindowLong(IntPtr wnd, int index); private static bool? GetIsOpen1709() { // if there is a top-level window - the keyboard is closed var wnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, WindowClass1709, WindowCaption1709); if (wnd != IntPtr.Zero) return false; var parent = IntPtr.Zero; for (;;) { parent = FindWindowEx(IntPtr.Zero, parent, WindowParentClass1709); if (parent == IntPtr.Zero) return null; // no more windows, keyboard state is unknown // if it's a child of a WindowParentClass1709 window - the keyboard is open wnd = FindWindowEx(parent, IntPtr.Zero, WindowClass1709, WindowCaption1709); if (wnd != IntPtr.Zero) return true; } } private static bool GetIsOpenLegacy() { var wnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, WindowClass); if (wnd == IntPtr.Zero) return false; var style = GetWindowStyle(wnd); return style.HasFlag(WindowStyle.Visible) && !style.HasFlag(WindowStyle.Disabled); } private const ssortingng WindowClass = "IPTip_Main_Window"; private const ssortingng WindowParentClass1709 = "ApplicationFrameWindow"; private const ssortingng WindowClass1709 = "Windows.UI.Core.CoreWindow"; private const ssortingng WindowCaption1709 = "Microsoft Text Input Application"; private enum WindowStyle : uint { Disabled = 0x08000000, Visible = 0x10000000, } private static WindowStyle GetWindowStyle(IntPtr wnd) { return (WindowStyle)GetWindowLong(wnd, -16); } } [ComImport] [Guid("37c994e7-432b-4834-a2f7-dce1f13b834b")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface ITipInvocation { void Toggle(IntPtr hwnd); } internal static class NativeMethods { [DllImport("user32.dll", EntryPoint = "FindWindow")] internal static extern int FindWindow(ssortingng lpClassName, ssortingng lpWindowName); [DllImport("user32.dll", EntryPoint = "SendMessage")] internal static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam); [DllImport("user32.dll", EntryPoint = "GetDesktopWindow", SetLastError = false)] internal static extern IntPtr GetDesktopWindow(); [DllImport("user32.dll", EntryPoint = "GetWindowLong")] internal static extern int GetWindowLong(int hWnd, int nIndex); internal const int GWL_STYLE = -16; internal const int GWL_EXSTYLE = -20; internal const int WM_SYSCOMMAND = 0x0112; internal const int SC_CLOSE = 0xF060; internal const int WS_DISABLED = 0x08000000; internal const int WS_VISIBLE = 0x10000000; } } 

    Le problème semble être lié à la configuration de Windows. J’ai rencontré le même problème avec l’application que je développais. Avec Windows 8 et 10 (avant la mise à jour), le code appelé clavier fonctionnait correctement, mais après la mise à jour, cela ne fonctionnait pas. Après avoir lu cet article , j’ai suivi:

    1. Appuyez sur Win + I pour ouvrir l’application Paramètres

    2. Cliqué sur Devices> Typing

    3. Activée “Affiche automatiquement le clavier tactile dans les applications fenêtrées lorsqu’il n’y a pas de clavier connecté à votre appareil “.

      Juste après ce clavier commençant à apparaître dans Windows 10 également.

    L’implémentation de IValueProvider / ITextProvider dans votre contrôle est une manière correcte d’y parvenir, comme décrit ici: https://stackoverflow.com/a/43886052/1184950

    Le code suivant fonctionnera toujours car il utilise la dernière version de MS Api
    Je l’ai mis dans un dll (Nécessaire pour un projet Delphi) mais c’est un simple C
    Aussi utile pour obtenir la taille du clavier et ajuster la disposition de l’application

     //******************************************************************* // // RETURNS KEYBOARD RECTANGLE OR EMPTY ONE IF KEYBOARD IS NOT VISIBLE // //******************************************************************* RECT __stdcall GetKeyboardRect() { IFrameworkInputPane *inputPane = NULL; RECT prcInputPaneScreenLocation = { 0,0,0,0 }; HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (SUCCEEDED(hr)) { hr = CoCreateInstance(CLSID_FrameworkInputPane, NULL, CLSCTX_INPROC_SERVER, IID_IFrameworkInputPane, (LPVOID*)&inputPane); if (SUCCEEDED(hr)) { hr=inputPane->Location(&prcInputPaneScreenLocation); if (!SUCCEEDED(hr)) { } inputPane->Release(); } } CoUninitialize(); return prcInputPaneScreenLocation; } 

    Utilisez cette méthode:

    1. Créez le fichier osk.bat et enregistrez-le dans votre dossier de programme, c.-à-d. C:\My Software\osk.bat

    2. Tapez ce fichier osk.bat comme suit:

      "C:\Program Files\Common Files\Microsoft Shared\Ink\Tabtip.exe"

    3. Utilisez Windows Script pour exécuter ce fichier bat

      oWSH = CREATEOBJECT("wscript.shell")

      oWSH.Run("osk.bat", 0, .T.)

    Dans Win10 Ver 1803, DesktopMode, il n’existe aucun moyen fiable de
    basculer le “Touch Keyboard” sur | off [ITipInvocation.Toggle ()];
    vous ne pouvez pas non plus découvrir avec certitude si c’est “up” (à l’écran)
    [IFrameworkInputPane.Location ()]; les deux routines échouent au hasard .

    Au lieu de cela, assurez-vous que “TabTIP.EXE” et “…. InputApp.EXE”
    ne fonctionne que lorsque le clavier est “haut” (à l’écran).

    Pour activer ou désactiver le clavier (à partir de X.CPP dans Jeff-Relf.Me/X.ZIP):

     if ( WM == WM_HOTKEY && C == 'K' ) { // A mouse button takes me here. Jeff-Relf.Me/g600.PNG if ( KillProc = 1, Running( L"TabTIP.EXE" ), KillProc = 1, Running( L"WindowsInternal.ComposableShell.Experiences.TextInput.InputApp.EXE" ) ) // The keyboard was _On_ ( ie its processes were running ), // so it was "turned _Off_" (killed); and we're done. goto Done ; // The keyboard was _Off_ ( ie no running processes ). // Turn it _On_: Launch( L"%CommonProgramFiles%/microsoft shared/ink/TabTIP.EXE" ); Sleep(99); static const GUID CLSID_UIHostNoLaunch = { 0x4CE576FA, 0x83DC, 0x4f88, 0x95, 0x1C, 0x9D, 0x07, 0x82, 0xB4, 0xE3, 0x76 }; static const GUID IID_ITipInvocation = { 0x37c994e7, 0x432b, 0x4834, 0xa2, 0xf7, 0xdc, 0xe1, 0xf1, 0x3b, 0x83, 0x4b }; static struct ITipInvocation : IUnknown { virtual HRESULT STDMETHODCALLTYPE Toggle( HWND wnd ) = 0 ; } * Tog ; Tog = 0, CoCreateInstance( CLSID_UIHostNoLaunch, 0, CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER, IID_ITipInvocation, (void**) & Tog ); // Firefox and Chrome need this: Tog ? Tog->Toggle( GetDesktopWindow() ), Tog->Release() : 0 ; } - - - - - - - - - - - - - // To get the process list, and kill stuff: #include  int KillProc ; int Running( wchar * EXE ) { int Found ; HANDLE PIDs, aProc ; PROCESSENTRY32 aPID = { sizeof aPID }; PIDs = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); Process32First( PIDs, &aPID ); while ( Found = !strCmpI( aPID.szExeFile, EXE ), KillProc && Found && ( aProc = OpenProcess( PROCESS_TERMINATE, 0, aPID.th32ProcessID ), aProc ? TerminateProcess( aProc, 9 ), CloseHandle( aProc ) : 0 ), !Found && Process32Next( PIDs, &aPID ) ); KillProc = 0, CloseHandle( PIDs ); return Found ; } Launch( wchar * Cmd ) { wchar _Cmd[333]; static PROCESS_INFORMATION Stat ; static STARTUPINFO SU = { sizeof SU }; SetEnvironmentVariable( L"__compat_layer", L"RunAsInvoker" ); ExpandEnvironmentSsortingngs( Cmd, _Cmd, 333 ), Cmd = _Cmd ; if ( CreateProcess( 0, Cmd, 0,0,1,0,0,0, &SU , &Stat ) ) CloseHandle( Stat.hProcess ), CloseHandle( Stat.hThread ); } // CoInitialize(0);