39

In Windows 8 and Windows 10 before Anniversary update it was possible to show touch keyboard by starting

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

It no longer works in Windows 10 Anniversary update; the TabTip.exe process is running, but the keyboard is not shown.

Is there a way to show it programmatically?

UPDATE

I found a workaround - fake mouse click on touch keyboard icon in system tray. Here is code in 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;

UPDATE 2

Another thing I found is that setting this registry key restores old functionality when starting TabTip.exe shows touch keyboard

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\TabletTip\1.7\EnableDesktopModeAutoInvoke=1
EugeneK
  • 2,164
  • 1
  • 16
  • 21
  • 1
    With every question asking about TabTip.exe, I have to wonder: is there an API that brings up the touch keyboard in a supported fashion? – andlabs Aug 04 '16 at 18:45
  • I would prefer to use API if possible, but I could not find any. And all answers on SO refer to TabTip.exe – EugeneK Aug 04 '16 at 18:54
  • 1
    Searching for TabTip.exe on MSDN brings [this](https://msdn.microsoft.com/en-us/library/windows/desktop/ms701746(v=vs.85).aspx) up; is this correct? If not, is the input panel Raymond Chen talks about [here](https://blogs.msdn.microsoft.com/oldnewthing/20150601-00/?p=45481) the same as the one provided by TabTip.exe? I can't check either right now. – andlabs Aug 04 '16 at 18:57
  • Yes I think this is what I need, unfortunately according to [MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/jj126268(v=vs.85).aspx) this no longer works in Windows 10. – EugeneK Aug 04 '16 at 19:19
  • That MSDN link implies the OS opens the keyboard automatically for you, but this isn't happening for some reason? [Maybe the post from the week after, then?](https://blogs.msdn.microsoft.com/oldnewthing/20150608-00/?p=45431) What about the first MSDN link; is that the same interface? – andlabs Aug 04 '16 at 19:48
  • First MSDN link works up to Windows 7 only. This new post looks promising, I'll investigate it. Also I found a workaround by faking mouseclick on tray icon. – EugeneK Aug 04 '16 at 20:31
  • [You can’t simulate keyboard input with PostMessage](https://blogs.msdn.microsoft.com/oldnewthing/20050530-11/?p=35513/). – IInspectable Aug 05 '16 at 01:40
  • It is not keyboard, it is mouse click – EugeneK Aug 05 '16 at 16:33
  • It doesn't make a difference. The underlying issues are the same, irrespective of whether this is keyboard or mouse input. You'll wind up with an inconsistent system state, and depending on who you ask whether the left mouse button is pressed, the answer can be either "Yes" or "No". So, no, you cannot simulate mouse input with `PostMessage` either. – IInspectable Aug 06 '16 at 10:15
  • 3
    Your UPDATE 2 solution does not work for me. What type of key are you creating? – E-Bat Sep 04 '16 at 06:38
  • 1
    I created REG_DWORD key – EugeneK Sep 06 '16 at 22:50
  • 5
    @E-Bat Make sure you stop/start the tabletinputservice after adding the reg key (or reboot). – Mr. Bungle Oct 24 '16 at 23:45
  • (since you're still active on the site) If you have an answer to your own question, post it as an answer. Do **not** edit the question. Also see [When is EDIT/UPDATE appropriate in a post](https://meta.stackexchange.com/questions/127639/when-is-edit-update-appropriate-in-a-post) – user202729 Jul 30 '18 at 15:22

14 Answers14

33

OK, I reverse engineered what explorer does when the user presses that button in the system tray.

Basically it creates an instance of an undocumented interface ITipInvocation and calls its Toggle(HWND) method, passing desktop window as an argument. As the name suggests, the method either shows or hides the keyboard depending on its current state.

Please note that explorer creates an instance of ITipInvocation on every button click. So I believe the instance should not be cached. I also noticed that explorer never calls Release() on the obtained instance. I'm not too familiar with COM, but this looks like a bug.

I tested this in Windows 8.1, Windows 10 & Windows 10 Anniversary Edition and it works perfectly. Here's a minimal example in C that obviously lacks some error checks.

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

Here's the C# version as well:

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 comments, I believe that tabtip.exe is the COM server for the COM component in question, so if your code gets REGDB_E_CLASSNOTREG, it should probably run tabtip.exe and try again.

torvin
  • 6,515
  • 1
  • 37
  • 52
  • 1
    This only works for me if TabTip.exe is running, without this process running it fails with 'Class not registered' error. – EugeneK Dec 05 '16 at 19:36
  • Thanks, it works very well. Is there a way to control it's visibility nicely? – andrey.s Dec 28 '16 at 15:45
  • 2
    Thanks. I'm now trying to find a way to determine and control visibility also. The old "hwnd = FindWindow("IPTip_Main_Window", NULL)" Is no longer completely effective. Testing the returned HWND for null / visibility always returns true. However "PostMessage(hwnd, WM_SYSCOMMAND, (int)SC_CLOSE, 0)" will still hide the OSK. – Greg Jan 02 '17 at 07:52
  • 2
    @Greg, to test if the keyboard is open I read the window's style. The keyboard is open if all those three conditions are true: 1) `FindWindow` returned a non-null value, 2) `WS_VISIBLE` is set, and 3) `WS_DISABLED` is NOT set. I might add a code example later – torvin Jan 02 '17 at 21:39
  • 3
    The WS_DISABLED check was what I was missing. Now your solution provides a complete work around! To show, I spawn tabtip.exe, then check if not visible and call your ITipInvocation::Toggle if needed. – Greg Jan 02 '17 at 23:06
  • Hi! Thanks for the solution. Is there a way to switch keyboard layout aswell? How did you reengineer this solution? I'm trying to press the "&123" Button for numeric Layout.... – terix2k11 Mar 09 '17 at 15:17
  • @terix2k11 I reverse-engineered `explorer.exe`. I don't have a good solution for pressing buttons on the keyboard itself. Please let me know if you find a way of doing that – torvin Mar 09 '17 at 21:15
  • @torvin Based on the answer in https://stackoverflow.com/questions/5094398/how-to-programatically-mouse-move-click-right-click-and-keypress-etc-in-winfor I can spawn a click-event on the "&123" Button. Unfortunately this has two flaws 1) the obvious: my click coordinates are hard coded, but the onscreen keyboard could be moved 2) it only works if the click invoking runs on a process with elevated admin priviliges – terix2k11 Mar 10 '17 at 10:44
  • If I wanted to re-purpose this code sample to toggle one of the other virtual input devices that shows up on Explorer's Taskbar, what steps would I need to take/start at? If I understand it correctly, I would need the value for the equivalent interface of `ITipInvocation`, right? I'm happy to tackle this myself but knowing how to start would help me a lot! :) – kayleeFrye_onDeck Oct 10 '17 at 18:13
  • I want to say that after reading the documentation, my main challenge would be finding out the IID. I wasn't able to discern how I would go about doing that tho. – kayleeFrye_onDeck Oct 10 '17 at 20:32
  • 1
    @kayleeFrye_onDeck post a separate question – torvin Oct 10 '17 at 22:44
  • @torvin, seeing issue where I see the keyboard but IPTip_Main_Window's style is set to `84000000`. Did windows update change something? – mikesl Nov 07 '17 at 19:48
  • @mikesl hard to tell. post a new question with a _minimum_ code example that doesn't work. – torvin Nov 08 '17 at 02:15
  • Added question, how do you determine if windows virtual keyboard is visible: https://stackoverflow.com/questions/47187216/determine-if-windows-10-touch-keyboard-is-visible-or-hidden – mikesl Nov 08 '17 at 18:38
  • @torvin Can you explain how you reverse engineered explorer to find the Toggle command? I'm trying to do something similar but with the Dictation Toolbar that is opened with WIN+H and appears to be part of TextInputHost.exe "Text Input App". It also has identical window name and class name to the Touch Keyboard. – Brett Sanderson Sep 30 '20 at 05:19
  • @BrettSanderson this is a very broad topic. Usually reverse-engineering a complied program requires knowledge of x86 Assembly and WinAPI. If you're stuck somewhere, post a separate question. Otherwise I'm not sure how I can help, sorry – torvin Oct 01 '20 at 03:16
  • @torvin hi, my question is here: https://stackoverflow.com/questions/64084906/how-do-you-show-hide-the-dictation-toolbar-from-c-sharp the solution i have for the keyboard appears to work very well, it's just the dictation toolbar i do not like. Here's my current test application: https://cdn.discordapp.com/attachments/699577276571975760/762913256942993418/api.gif – Brett Sanderson Oct 07 '20 at 14:47
10

I had the same problem too. It took me much time and headache, but Thanks to Alexei and Torvin I finally got it working on Win 10 1709. Visibility check was the difficulty. Maybe The OSKlib Nuget could be updated. Let me sum up the complete sulotion (For sure my code has some unnecessary lines now):

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;

    }
}
Lama
  • 159
  • 1
  • 7
  • 1
    I tested and it did not detect that TapTip was open. Windows 10 Pro x64. ProcessExplorer: `C:\Windows\SystemApps\InputApp_cw5n1h2txyewy\WindowsInternal.ComposableShell.Experiences.TextInput.InputApp.exe` – Nasenbaer Feb 20 '19 at 18:28
  • I have the same problem like @Nasenbaer – Faeze Aug 19 '23 at 07:21
6

The only solution I've found to work is by sending PostMessage as you've mentioned in answer 1. Here's the C# version of it in case someone needs it.

[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,
}
mikesl
  • 2,133
  • 20
  • 25
  • Thanks mikesl, worked perfectly. Just missing declaration for nullIntPtr which I instantiated with var nullIntPtr = IntPtr.Zero; – Water Sep 26 '16 at 02:51
  • 2
    While this works, it requires the tray icon to be available. Unfortunately it can be hidden by the user. – JimmyBlu Sep 27 '16 at 10:46
  • @mikesl how can use it to show only telephone keypad – Rawat May 04 '18 at 08:51
  • This does not work on Windows 8.0. TIPBand is a child of ReBarWindow32, not TrayNotifyWnd. – Anders Sep 11 '20 at 21:57
6

I detect 4 situations when trying to open Touch Keyboard on Windows 10 Anniversary Update

  1. Keyboard is Visible - when "IPTIP_Main_Window" is present, NOT disabled and IS visible
  2. Keyboard is not visible - when "IPTIP_Main_Window" is present but disabled
  3. Keyboard is not visible - when "IPTIP_Main_Window" is present but NOT disabled and NOT visible
  4. Keyboard is not visible - when "IPTIP_Main_Window" is NOT present

1 - nothing to do

2+3 - activating via COM

4 - most interesting scenario. In some devices starting TabTip process opens touch keyboard, on some - not. So we must start TabTip process, wait for appearing window "IPTIP_Main_Window", check it for visibility and activate it via COM if nessesary.

I make small library for my project, you can use it - osklib

Alexei Shcherbakov
  • 1,125
  • 13
  • 10
  • I think the varied behaviour between not/opening the keyboard is connected to EnableDesktopModeAutoInvoke registy setting, too. Thanks for the research, and the library! – r618 Oct 06 '17 at 19:02
5

The following code will always work since it uses latest MS Api
I put it into a dll (Needed for a Delphi project) but it is a plain C
Also useful for obtaining the keyboard size and adjusting application layout

//*******************************************************************
//
// 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;
}
Sevast
  • 109
  • 1
  • 5
4

There is still some mystery about how the touch keyboard is set visible by Windows 10 Anniversary Update. I'm actually having the exact same issue and here are the lastest infos i've found :

  • Windows 10 1607 works in two modes : Desktop and Tablet. While in Desktop mode, TabTip.exe can be called but won't show. While in Tablet mode, everything works fine : TabTip.exe shows itself when called. So a 100% working workaround is to set your computer in Tablet Mode but who wants his desktop/laptop to work in tablet mode ? Not me anyway !

  • You can use the "EnableDesktopModeAutoInvoke" Key (HKCU, DWORD set to 1) and on some computers running 1607 it worked great while in Desktop Mode. But for some unknown reasons, it is not working on my HP touchpad.

Please note that this registry value is the "Show touch keyboard on desktop mode if there is no attached keyboard" option in Windows parameters > touch

  • You can use Torvin's code to show TabTip.exe (as mentioned TabTip.exe should be running when you do the COM stuff), it is working fine on some computers running 1607 (including my HP touchpad ! yay !) But it will do nothing on some others comps with the same windows Build.

So far tested on 4 different computers and i'm unable to get something working fine on all...

Usul
  • 129
  • 8
3

The problem seems to be with setting of Windows OS. I have faced same issue with the app I was developing. With Windows 8 and 10 (before update) code that called keyboard worked fine, but after update failed to work. After reading this article, I did following:

  1. Pressed Win+I to open the Settings app

  2. Clicked on Devices > Typing

  3. Turned "Automatically show the touch keyboard in windowed apps when there’s no keyboard attached to your device" ON.

    Right after that keyboard starting showing up in Windows 10 also.

Community
  • 1
  • 1
  • For me it was `Win+I` then click on `ease of access` (hotkey `Win+U`) under keyboard switch `Turns on the on-screen-keyboard` to on. – surfmuggle Apr 02 '17 at 07:13
  • the easy of access one seems to be a different touch keyboard from tabtip.exe ie without a working tabtip, I cannot use the emoji keyboard - they seem to be linked in some way... but ease of access kb is still available to me, just not tabtip or the button on my task bar which is what op is after – Hicsy Jan 09 '23 at 04:40
3

Implementing the IValueProvider/ITextProvider in your control is a correct way to achieve this, as described here: https://stackoverflow.com/a/43886052/1184950

Community
  • 1
  • 1
tombam
  • 168
  • 2
  • 5
3

I tried multiple things that did not work. But I discovered that I can use the Shortcut Keys Windows/Ctrl/O to open the On Screen Key Board.
Also there is a Nuget package: Input Simulator by Michael Noonan.

If you install the InputSimulator NuGet package in your Winforms project - then add code like this to an event, like a button:

private void button1_Click(object sender, EventArgs e)
{
    var simu = new InputSimulator();
    simu.Keyboard.ModifiedKeyStroke(new[] { VirtualKeyCode.LWIN, VirtualKeyCode.CONTROL }, VirtualKeyCode.VK_O);
}

You will also need to add these using statements:

using WindowsInput;
using WindowsInput.Native;

Run your app and the button will display the keyboard and also hit it again and it will remove it.

I am on Windows 10 and vs 2019.

entreprenerds
  • 957
  • 10
  • 20
1
Set oShell = CreateObject("WScript.Shell")
oShell.AppActivate "Program Manager"
oShell.Run "tabtip.exe", 0, true
oShell.SendKeys "%{TAB}"

[HKEY_CURRENT_USER\SOFTWARE\Microsoft\TabletTip\1.7] "EnableDesktopModeAutoInvoke"=dword:00000001

1

Following code works well on 21h1 version tablet and notebook,thanks for @torvin method

#include <dwmapi.h>
#include <windows.h>

#pragma comment(lib,"dwmapi.lib")

void toggleKeyboardShowState()
{
    if(FindWindowEx(nullptr,nullptr,L"IPTip_Main_Window",nullptr)!=nullptr)
    {
        ITipInvocation *tip_invocation_;
        if(CoCreateInstance(CLSID_UIHostNoLaunch,nullptr,CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER,IID_ITipInvocation,(void **)&tip_invocation_)==S_OK)
            tip_invocation_->Toggle(GetDesktopWindow());
        return;
    }
    PVOID OldValue=nullptr;
    BOOL bRet=Wow64DisableWow64FsRedirection(&OldValue);
    ShellExecute(nullptr,L"open",L"C:\\Program Files\\Common Files\\microsoft shared\\ink\\TabTip.exe",nullptr,nullptr,SW_SHOWNORMAL);
    if(bRet)
        Wow64RevertWow64FsRedirection(OldValue);
}

bool keyboardIsShow()
{
    int cloaked=0;
    return DwmGetWindowAttribute(FindWindowExW(FindWindowExW(nullptr,nullptr,L"ApplicationFrameWindow",nullptr),nullptr,L"Windows.UI.Core.CoreWindow",L"Microsoft Text Input Application"),DWMWA_CLOAKED,&cloaked,DWM_CLOAKED_INHERITED)==S_OK?0==cloaked:false;
}

start tabtip process or hide->show

if(!keyboardIsShow())
    toggleKeyboardShowState();

show->hide

if(keyboardIsShow())
    toggleKeyboardShowState();

The keyboard show state can be switched even without if judgment.

Chidori
  • 11
  • 2
0

Use this method:

  1. Create osk.bat file and save it under your program folder ie. C:\My Software\osk.bat

  2. Type in this osk.bat the following cmd:

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

  3. Use Windows Script to run this bat file

    oWSH = CREATEOBJECT("wscript.shell")

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

Alex Butenko
  • 3,664
  • 3
  • 35
  • 54
Vinny
  • 1
0

Innovation of Touch Keyboard via TabTip.exe requires the addition of a few values in the registry

Before we invoke TapTip via CMD

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

Ensure the below values are present in Windows Registry and set to 1 :

  1. SOFTWARE\Microsoft\TabletTip\1.7 - EnableDesktopModeAutoInvoke
  2. SOFTWARE\Microsoft\TabletTip\1.7 - DisableNewKeyboardExperience
  3. HKCU\Software\Microsoft\windows\CurrentVersion\ImmersiveShell - TabletMode

Implementation in JAVA, refer : OnScreenTabletKeyboardInvocation

Leo Ka
  • 1
  • 3
-1

In Win10 Ver 1803, DesktopMode, there is no reliable way to
toggle the "Touch Keyboard" on|off [ ITipInvocation.Toggle() ];
nor can you reliably discover if it's "up" ( on screen )
[ IFrameworkInputPane.Location() ]; both routines fail randomly.

Instead, ensure that "TabTIP.EXE" and "....InputApp.EXE"
only run when the keyboard is "up" ( on screen ).

To toggle the keyboard on and off ( from 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_ ( i.e. its processes were running ), 
    //  so it was "turned _Off_" (killed); and we're done.

    goto Done ;

  //  The keyboard was _Off_ ( i.e. 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 <tlhelp32.H>

      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);
Jeff Relf
  • 55
  • 3
  • 3
    When posting an answer that contains code, please include an explanation of what the code does and how it answers the user's question. Answers consisting of nothing but code are strongly discouraged. – Jim Garrison Jul 26 '18 at 23:12
  • The problem, asked at least three times, on three different pages, is that the keyboard toggle ( ITipInvocation.Toggle() ) does _NOT_ ( N O T ) always work ( Win10 desktop Ver 1803 ). I, and only I, have provided the soltion. My solution is well tested, it works. I commented the code... did you read the comments, Jim ? ! – Jeff Relf Jul 26 '18 at 23:27
  • 5
    Rather than getting snippy, you should learn to accept constructive criticism from users that are experienced with the site. Code comments are not a substitute for providing a textual explanation. Your experience here will be vastly improved if you learn to accept advice that is intended to help you. – Ken White Jul 27 '18 at 00:48
  • This is temporarily locked while it's being discussed on meta. –  Jul 30 '18 at 16:02