Start TabTip with numpad view open

fac7orx picture fac7orx · Jan 15, 2014 · Viewed 11k times · Source

I basically have code that starts the keyboard, but it opens in alphanumeric portion and the box for editing is a NumericUpDown with numbers. So, I want to open tabtip.exe aka the onscreen keyboard in windows 8.1 with the numerpad focused. Here is my current code for opening tabtip, but again it does not open with numpad by default:

using System.Runtime.InteropServices; //added for keyboard closure
using System.Windows.Interop; //Keyboard closure - must add reference for WindowsBase

//Added for keyboard closure
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool PostMessage(int hWnd, uint Msg, int wParam, int lParam);

        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(String sClassName, String sAppName);

//open keyboard
void openKeyboard()
{
                ProcessStartInfo startInfo = new ProcessStartInfo(@"C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe");
                startInfo.WindowStyle = ProcessWindowStyle.Hidden;
                Process.Start(startInfo);
}

//close keyboard
void closeKeyboard()
{
uint WM_SYSCOMMAND = 274;
                uint SC_CLOSE = 61536;
                IntPtr KeyboardWnd = FindWindow("IPTip_Main_Window", null);
                PostMessage(KeyboardWnd.ToInt32(), WM_SYSCOMMAND, (int)SC_CLOSE, 0);
}

There's also seems to be some registry edit you can do, but I can't seem to get it to make the numpad portion of the taptip keyboard in windows 8.1 to show:

Windows 8 Desktop App: Open tabtip.exe to secondary keyboard (for numeric textbox)

Answer

Jon picture Jon · May 2, 2014

Currently with Windows 8.1, not much functionality seems to be programmatically exposed. The code below will cause the tabtip.exe to read the registry because the original process is killed. It is not completely reliable, but is a way to for it to respond to some registry values. The part about docking is optional, it forces it to dock each time via the registry change. The process.Kill(); should be in a try/catch since it occasionally doesn't have permission and can throw an exception.

    [DllImport("user32.dll")]
    public static extern IntPtr FindWindow(string sClassName, string sAppName);

    [DllImport("user32.dll")]
    public static extern IntPtr PostMessage(int hWnd, uint msg, int wParam, int lParam);

    private static void KillTabTip()
    {
        // Kill the previous process so the registry change will take effect.
        var processlist = Process.GetProcesses();

        foreach (var process in processlist.Where(process => process.ProcessName == "TabTip"))
        {
            process.Kill();
            break;
        }
    }

    public void ShowTouchKeyboard(bool isVisible, bool numericKeyboard)
    {
        if (isVisible)
        {
            const string keyName = "HKEY_CURRENT_USER\\Software\\Microsoft\\TabletTip\\1.7";

            var regValue = (int) Registry.GetValue(keyName, "KeyboardLayoutPreference", 0);
            var regShowNumericKeyboard = regValue == 1;

            // Note: Remove this if do not want to control docked state.
            var dockedRegValue = (int) Registry.GetValue(keyName, "EdgeTargetDockedState", 1);
            var restoreDockedState = dockedRegValue == 0;

            if (numericKeyboard && regShowNumericKeyboard == false)
            {
                // Set the registry so it will show the number pad via the thumb keyboard.
                Registry.SetValue(keyName, "KeyboardLayoutPreference", 1, RegistryValueKind.DWord);

                // Kill the previous process so the registry change will take effect.
                KillTabTip();
            }
            else if (numericKeyboard == false && regShowNumericKeyboard)
            {
                // Set the registry so it will NOT show the number pad via the thumb keyboard.
                Registry.SetValue(keyName, "KeyboardLayoutPreference", 0, RegistryValueKind.DWord);

                // Kill the previous process so the registry change will take effect.
                KillTabTip();
            }

            // Note: Remove this if do not want to control docked state.
            if (restoreDockedState)
            {
                // Set the registry so it will show as docked at the bottom rather than floating.
                Registry.SetValue(keyName, "EdgeTargetDockedState", 1, RegistryValueKind.DWord);

                // Kill the previous process so the registry change will take effect.
                KillTabTip();
            }

            Process.Start("c:\\Program Files\\Common Files\\Microsoft Shared\\ink\\TabTip.exe");
        }
        else
        {
            var win8Version = new Version(6, 2, 9200, 0);

            if (Environment.OSVersion.Version >= win8Version)
            {
                const uint wmSyscommand = 274;
                const uint scClose = 61536;
                var keyboardWnd = FindWindow("IPTip_Main_Window", null);
                PostMessage(keyboardWnd.ToInt32(), wmSyscommand, (int)scClose, 0);
            }
        }
    }

You can call the above method from a custom version of a TextBox where OnTouchDown is overridden and an additional DependencyProperty is created to indicate if the field uses the NumericKeyboard:

    #region NumericKeyboard
    public static readonly DependencyProperty NumericKeyboardProperty = DependencyProperty.Register("NumericKeyboard", typeof(bool), typeof(CustomTextBox), new FrameworkPropertyMetadata(false));

    /// <summary> Returns/set the "NumericKeyboard" state of the CustomTextBox. </summary>
    public bool NumericKeyboard
    {
        get { return (bool)GetValue(NumericKeyboardProperty); }
        set { SetValue(NumericKeyboardProperty, value); }
    }
    #endregion


    protected override void OnTouchDown(TouchEventArgs e)
    {
        base.OnTouchDown(e);
        Focus();

        if (IsReadOnly == false)
            ShowTouchKeyboard(true, NumericKeyboard);
    }

Currently, I have not had any success using similar techniques to position the TabTip window around the screen when in a floating (non-docked) state.