34 votes

Afficher le clavier tactile (TabTip.exe) dans l'édition anniversaire de Windows 10

Dans Windows 8 et Windows 10 avant l'Anniversaire de mise à jour, il était possible d'afficher le clavier tactile de départ

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

Il ne fonctionne plus sur Windows 10 Anniversaire de mise à jour; l' TabTip.exe processus est en cours, mais le clavier n'est pas montré.

Est-il un moyen de le montrer par programmation?

Mise à JOUR

J'ai trouvé une solution de contournement - faux clic de souris sur le clavier tactile de l'icône 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é est que la définition de cette clé de registre restaure les vieux de la fonctionnalité lors du démarrage TabTip.exe montre tactile-clavier

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

29voto

torvin Points 322

OK, je l'ingénierie inverse de ce que l'explorateur n'lorsque l'utilisateur appuie sur ce bouton dans la barre d'état système.

Fondamentalement, il crée une instance d'un sans-papiers de l'interface ITipInvocation et appelle sa Toggle(HWND) méthode, en passant bureau fenêtre comme un 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 sur chaque clic sur le bouton. Je crois donc que l'instance ne doit pas être mis en cache. J'ai aussi remarqué que l'explorateur ne les appelle jamais Release() sur le résultat de l'instance. Je ne suis pas trop familier avec COM, mais cela ressemble à un bug.

J'ai testé cela dans Windows 8.1, Windows 10 et Windows 10 Édition Anniversaire et il fonctionne parfaitement. Voici un exemple minimal en C qui manque évidemment de certains contrôles d'erreur.

#include <initguid.h>
#include <Objbase.h>
#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# ainsi:

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

Mise à jour: par @EugeneK commentaires, je crois qu' tabtip.exe est le serveur COM pour le composant COM en question, donc si votre code est REGDB_E_CLASSNOTREG, il devrait probablement fonctionner tabtip.exe et essayez de nouveau.

8voto

lama Points 59

J'ai aussi eu le même problème. 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 contrôle de la visibilité était la difficulté. Peut-être que l'OSKlib Nuget pourrait être mis à jour. Permettez-moi de résumer la sulotion complète (à coup sûr, mon code a maintenant des lignes inutiles):

 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;

    }
}
 

6voto

mikesl Points 983

La seule solution que j'ai trouvée fonctionne en envoyant PostMessage comme vous l'avez mentionné dans la réponse 1. Voici la version C # de celui-ci au cas où quelqu'un en aurait besoin.

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

6voto

Je détecte 4 situations lorsque vous essayez d'ouvrir le Clavier Tactile sur Windows 10 Anniversaire de mise à Jour

  1. Le clavier est Visible, lorsque les "IPTIP_Main_Window" est présent, PAS désactivé et EST visible
  2. Le clavier n'est pas visible lorsque la IPTIP_Main_Window" est présent mais désactivé
  3. Le clavier n'est pas visible lorsque la IPTIP_Main_Window" est présent, mais PAS désactivé et PAS visible
  4. Le clavier n'est pas visible lorsque la IPTIP_Main_Window" est PAS présent

1 - rien à faire

2+3 - activation via COM

4 - la plupart scénario intéressant. Dans certains dispositifs de départ TabTip processus ouvre le clavier tactile, sur certains - pas. Nous devons donc commencer TabTip processus, attendez que la fenêtre qui apparaît "IPTIP_Main_Window", cochez-la pour la visibilité et l'activer via COM si nessesary.

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

4voto

Usul Points 84

Il reste encore un peu de mystère sur la façon dont le clavier tactile est de le rendre visible par Windows 10 Anniversaire de mise à Jour. Je suis effectivement d'avoir exactement le même problème et voici les dernières infos que j'ai trouvé :

  • Windows 10 1607 fonctionne en deux modes : Desktop et Tablette. Alors que dans le mode Bureau, TabTip.exe peut être appelé, mais ne l'affiche pas. Alors qu'en mode Tablette, tout fonctionne bien : TabTip.exe montre lui-même lorsqu'il est appelé. Donc, 100% de travail solution de contournement est de mettre votre ordinateur en Mode Tablette, mais qui veut son ordinateur de bureau/ordinateur portable pour travailler en mode tablette ? Pas moi en tout cas !

  • Vous pouvez utiliser la fonction "EnableDesktopModeAutoInvoke" Clé (HKCU, DWORD à 1) et sur certains ordinateurs exécutant 1607 il a travaillé beaucoup alors que dans le Mode Bureau. Mais pour des raisons inconnues, il ne fonctionne pas sur mon HP touchpad.

Veuillez noter que cette valeur de registre est le "Afficher le clavier tactile sur le mode bureau si il n'y a pas de clavier branché" option dans les paramètres Windows > touch

  • Vous pouvez utiliser Torvin est le code pour afficher TabTip.exe (comme mentionné TabTip.exe doit être en cours d'exécution lorsque vous faites de la COM trucs), il fonctionne très bien sur certains ordinateurs exécutant 1607 (y compris mon HP touchpad ! yay!!!) Mais il ne fera rien, sur certains autres comps avec le même windows Construire.

Jusqu'à présent testé sur 4 ordinateurs différents et je n'arrive pas à obtenir quelque chose qui fonctionne correctement sur tous les...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X