Mostra tastiera touch (TabTip.exe) in Windows 10 Anniversary edition

In Windows 8 e Windows 10 prima dell’aggiornamento di Anniversary era ansible visualizzare la tastiera touch all’avvio

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

Non funziona più nell’aggiornamento di Windows 10 Anniversary; il processo TabTip.exe è in esecuzione, ma la tastiera non viene mostrata.

C’è un modo per mostrarlo a livello di programmazione?

AGGIORNARE

Ho trovato una soluzione alternativa: un clic del mouse falso sull’icona della tastiera touch nella barra delle applicazioni. Ecco il codice in Delfi

 // 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; 

AGGIORNAMENTO 2

Un’altra cosa che ho trovato è che l’impostazione di questa chiave di registro ripristina le vecchie funzionalità all’avvio di TabTip.exe mostra la tastiera touch

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

OK, ho invertito la progettazione di quello che fa Explorer quando l’utente preme quel pulsante nella barra delle applicazioni.

Fondamentalmente crea un’istanza di un’interfaccia non documentata ITipInvocation e chiama il suo metodo Toggle(HWND) , passando la finestra del desktop come argomento. Come suggerisce il nome, il metodo mostra o nasconde la tastiera in base al suo stato corrente.

Si noti che explorer crea un’istanza di ITipInvocation ad ogni clic del pulsante. Quindi credo che l’istanza non dovrebbe essere memorizzata nella cache. Ho anche notato che explorer non chiama mai Release() sull’istanza ottenuta. Non ho molta familiarità con COM, ma questo sembra un bug.

Ho provato questo in Windows 8.1, Windows 10 e Windows 10 Anniversary Edition e funziona perfettamente. Ecco un esempio minimale in C che ovviamente manca di alcuni controlli di errore.

 #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; } 

Ecco anche la versione C #:

 class Program { static void Main(string[] 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(); } 

Aggiornamento: per i commenti di @EugeneK, credo che tabtip.exe sia il server COM per il componente COM in questione, quindi se il tuo codice ottiene REGDB_E_CLASSNOTREG , probabilmente dovrebbe eseguire tabtip.exe e riprovare.

L’unica soluzione che ho trovato per funzionare è l’invio di PostMessage come hai menzionato nella risposta 1. Ecco la versione di C # nel caso qualcuno ne avesse bisogno.

 [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern IntPtr FindWindow(string sClassName, string sAppName); [DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string 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, } 

Rilevo 4 situazioni quando provo ad aprire Touch Keyboard su Windows 10 Anniversary Update

  1. La tastiera è visibile – quando “IPTIP_Main_Window” è presente, NON disabilitato e IS visibile
  2. La tastiera non è visibile – quando “IPTIP_Main_Window” è presente ma disabilitata
  3. La tastiera non è visibile – quando “IPTIP_Main_Window” è presente ma NON disabilitata e NON visibile
  4. La tastiera non è visibile – quando “IPTIP_Main_Window” NON è presente

1 – niente da fare

2 + 3: triggerszione tramite COM

4 – scenario più interessante. In alcuni dispositivi che iniziano il processo TabTip si apre la tastiera touch, su alcuni – no. Quindi, dobbiamo avviare il processo TabTip, attendere la finestra che appare “IPTIP_Main_Window”, controllarlo per visibilità e triggersrlo tramite COM se necessario.

Creo una piccola biblioteca per il mio progetto, puoi usarla – osklib

C’è ancora un po ‘di mistero su come la tastiera touch è impostata su Windows 10 Anniversary Update. In realtà sto avendo lo stesso identico problema e qui ci sono le ultime informazioni che ho trovato:

  • Windows 10 1607 funziona in due modalità: desktop e tablet. Mentre è in modalità Desktop, TabTip.exe può essere chiamato ma non verrà visualizzato. Mentre è in modalità Tablet, tutto funziona correttamente: TabTip.exe si mostra quando chiamato. Quindi una soluzione al 100% è impostare il computer in modalità Tablet ma chi vuole che il suo desktop / laptop funzioni in modalità tablet? Non io comunque!

  • È ansible utilizzare la chiave ” EnableDesktopModeAutoInvoke ” (HKCU, DWORD impostato su 1) e su alcuni computer che eseguono 1607 ha funzionato benissimo in modalità Desktop. Ma per alcuni motivi sconosciuti, non funziona sul mio touchpad HP.

Si noti che questo valore di registro è “Mostra tastiera touch sulla modalità desktop se non è disponibile la tastiera collegata” nei parametri di Windows> touch

  • Puoi usare il codice di Torvin per mostrare TabTip.exe (come menzionato TabTip.exe dovrebbe essere in esecuzione quando fai le cose di COM), sta funzionando bene su alcuni computer che eseguono 1607 (incluso il mio touchpad HP! Yay!) Ma non farà nulla su altri comps con le stesse windows Build.

Finora testato su 4 computer diversi e non riesco a ottenere qualcosa che funzioni bene su tutti …

Ho avuto lo stesso problema anche io. Mi ci è voluto molto tempo e mal di testa, ma grazie ad Alexei e Torvin ho finalmente lavorato a Win 10 1709. Il controllo della visibilità era la difficoltà. Forse l’OSKlib Nuget potrebbe essere aggiornato. Consentitemi di riassumere la solu-zione completa (di sicuro il mio codice ora contiene alcune linee non necessarie):

 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, string className, string 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 string WindowClass = "IPTip_Main_Window"; private const string WindowParentClass1709 = "ApplicationFrameWindow"; private const string WindowClass1709 = "Windows.UI.Core.CoreWindow"; private const string 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(string lpClassName, string 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; } } 

Il problema sembra essere con l’impostazione del sistema operativo Windows. Ho riscontrato lo stesso problema con l’app che stavo sviluppando. Con Windows 8 e 10 (prima dell’aggiornamento) il codice che chiamava tastiera funzionava bene, ma dopo l’aggiornamento non funzionava. Dopo aver letto questo articolo , ho seguito:

  1. Premuto Win + I per aprire l’app Impostazioni

  2. Clic su Dispositivi> Digitazione

  3. Ruotato ” Mostra automaticamente la tastiera touch nelle app in finestra quando non ci sono tasti attaccati al dispositivo ” ON.

    Subito dopo la tastiera che inizia a mostrare anche in Windows 10.

L’implementazione di IValueProvider / ITextProvider nel controllo è un modo corretto per ottenere ciò, come descritto qui: https://stackoverflow.com/a/43886052/1184950

Il seguente codice funzionerà sempre poiché utilizza l’ultimo MS Api
Lo metto in una DLL (necessaria per un progetto Delphi) ma è un semplice C
Utile anche per ottenere le dimensioni della tastiera e la regolazione del layout dell’applicazione

 //******************************************************************* // // 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; } 

Usa questo metodo:

  1. Creare il file osk.bat e salvarlo nella cartella del programma, ad es. C:\My Software\osk.bat

  2. Digitare in questo osk.bat il seguente cmd:

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

  3. Usa Windows Script per eseguire questo file bat

    oWSH = CREATEOBJECT("wscript.shell")

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

In Win10 Ver 1803, DesktopMode, non c’è un modo affidabile per
triggers la “Tastiera tattile” on | off [ITipInvocation.Toggle ()];
né puoi scoprire in modo affidabile se è “su” (sullo schermo)
[IFrameworkInputPane.Location ()]; entrambe le routine falliscono casualmente .

Invece, assicurarsi che “TabTIP.EXE” e “…. InputApp.EXE”
si esegue solo quando la tastiera è “su” (sullo schermo).

Per triggersre e distriggersre la tastiera (da X.CPP in 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" ); ExpandEnvironmentStrings( 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);