Mostrar teclado sensível ao toque (TabTip.exe) na edição de aniversário do Windows 10

No Windows 8 e no Windows 10 antes da atualização do Aniversário, foi possível mostrar o teclado de toque ao iniciar

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

Não funciona mais na atualização de aniversário do Windows 10; o processo TabTip.exe está sendo executado, mas o teclado não é mostrado.

Existe uma maneira de mostrá-lo programaticamente?

ATUALIZAR

Eu encontrei uma solução – clique do mouse falso no ícone do teclado de toque na bandeja do sistema. Aqui está o código em 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; 

ATUALIZAÇÃO 2

Outra coisa que eu encontrei é que a configuração desta chave de registro restaura a funcionalidade antiga ao iniciar TabTip.exe mostra teclado sensível ao toque

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

OK, eu revisei o que o explorador faz quando o usuário pressiona esse botão na bandeja do sistema.

Basicamente, ele cria uma instância de uma interface não documentada ITipInvocation e chama seu método Toggle(HWND) , passando a janela da área de trabalho como um argumento. Como o nome sugere, o método mostra ou oculta o teclado, dependendo de seu estado atual.

Por favor, note que o explorador cria uma instância de ITipInvocation em cada clique de botão. Então, acredito que a instância não deve ser armazenada em cache. Também notei que o explorador nunca chama Release() na instância obtida. Eu não estou muito familiarizado com o COM, mas isso parece um bug.

Eu testei isso no Windows 8.1, Windows 10 e Windows 10 Anniversary Edition e funciona perfeitamente. Aqui está um exemplo mínimo em C que obviamente carece de algumas verificações de erro.

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

Aqui está a versão C # também:

 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(); } 

Update: per @EugeneK comentários, acredito que tabtip.exe é o servidor COM para o componente COM em questão, portanto, se seu código obtém REGDB_E_CLASSNOTREG , ele provavelmente deve executar o tabtip.exe e tente novamente.

A única solução que encontrei para trabalhar é enviando PostMessage como você mencionou na resposta 1. Aqui está a versão C # do caso, caso alguém precise dele.

 [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, } 

Detecto 4 situações ao tentar abrir o Teclado de Toque na Atualização de Aniversário do Windows 10

  1. O teclado está visível – quando “IPTIP_Main_Window” está presente, NÃO está desativado e está visível
  2. O teclado não está visível – quando “IPTIP_Main_Window” está presente, mas está desativado
  3. O teclado não está visível – quando “IPTIP_Main_Window” está presente, mas NÃO está desativado e NÃO está visível
  4. O teclado não está visível – quando “IPTIP_Main_Window” NÃO está presente

1 – nada a fazer

2 + 3 – ativando via COM

4 – cenário mais interessante. Em alguns dispositivos que iniciam o processo TabTip abre o teclado de toque, em alguns – não. Portanto, devemos iniciar o processo TabTip, aguardar a exibição da janela “IPTIP_Main_Window”, verificar sua visibilidade e ativá-la via COM se necessário.

Eu faço pequena biblioteca para o meu projeto, você pode usá-lo – osklib

Ainda há algum mistério sobre como o teclado de toque é definido como visível pela Atualização de Aniversário do Windows 10. Eu estou realmente tendo exatamente o mesmo problema e aqui estão as informações mais recentes que eu encontrei:

  • O Windows 10 1607 funciona em dois modos: Desktop e Tablet. Enquanto no modo Desktop, o TabTip.exe pode ser chamado, mas não será exibido. Enquanto no modo Tablet, tudo funciona bem: TabTip.exe mostra-se quando chamado. Portanto, uma solução de trabalho de 100% é configurar seu computador no modo Tablet, mas quem quer que seu desktop / laptop funcione no modo tablet? Não eu de qualquer maneira!

  • Você pode usar a chave ” EnableDesktopModeAutoInvoke ” (HKCU, DWORD definida como 1) e, em alguns computadores que executam o 1607, ela funcionou muito bem no Modo Desktop. Mas por algumas razões desconhecidas, não está funcionando no meu touchpad da HP.

Observe que esse valor do Registro é a opção “Mostrar o teclado de toque no modo de área de trabalho, se não houver um teclado conectado” nos parâmetros do Windows> touch

  • Você pode usar o código de Torvin para mostrar TabTip.exe (como mencionado TabTip.exe deve ser executado quando você faz o COM), ele está funcionando bem em alguns computadores que executam 1607 (incluindo o meu touchpad HP! Yay!) Mas ele não fará nada em alguns outros comps com as mesmas janelas Build.

Até agora testado em 4 computadores diferentes e eu não consigo fazer algo funcionar bem em todos …

Eu também tive o mesmo problema. Demorei muito tempo e tive dor de cabeça, mas graças a Alexei e Torvin eu finalmente consegui trabalhar no Win 10 1709. A checagem de visibilidade era a dificuldade. Talvez o Nuget OSKlib possa ser atualizado. Deixe-me resumir o sulco completo (com certeza meu código tem algumas linhas desnecessárias agora):

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

O problema parece ser com a configuração do sistema operacional Windows. Eu enfrentei o mesmo problema com o aplicativo que eu estava desenvolvendo. Com o código do Windows 8 e 10 (antes da atualização), o teclado chamado funcionou bem, mas após a atualização não funcionou. Depois de ler este artigo , fiz o seguinte:

  1. Pressione Win + I para abrir o aplicativo Configurações

  2. Clicado em Dispositivos> Digitação

  3. Virou ” Mostrar automaticamente o teclado sensível ao toque em aplicativos em janelas quando não há teclado conectado ao dispositivo ” LIGADO.

    Logo depois que o teclado começar a aparecer no Windows 10 também.

A implementação do IValueProvider / ITextProvider no seu controle é uma maneira correta de conseguir isso, conforme descrito aqui: https://stackoverflow.com/a/43886052/1184950

O código a seguir sempre funcionará, pois usa o mais recente MS Api
Eu colocá-lo em uma dll (Necessário para um projeto Delphi), mas é um simples C
Também é útil para obter o tamanho do teclado e ajustar o layout do aplicativo

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

Use este método:

  1. Crie o arquivo osk.bat e salve-o na pasta do programa, por exemplo. C:\My Software\osk.bat

  2. Digite este osk.bat o seguinte cmd:

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

  3. Use o Windows Script para executar este arquivo bat

    oWSH = CREATEOBJECT("wscript.shell")

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

Em Win10 Ver 1803, DesktopMode, não há nenhuma maneira confiável de
alterna o “Touch Keyboard” em | off [ITipInvocation.Toggle ()];
nem você pode descobrir com segurança se está “up” (na canvas)
[IFrameworkInputPane.Location ()]; ambas as rotinas falham aleatoriamente .

Em vez disso, verifique se “TabTIP.EXE” e “…. InputApp.EXE”
só funciona quando o teclado está “up” (na canvas).

Para ativar e desativar o teclado (de X.CPP em 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); 
Intereting Posts