Skip to content

Instantly share code, notes, and snippets.

@JoeRobich
Created March 4, 2015 23:37
Show Gist options
  • Save JoeRobich/81ae679ee2d29efa3fa5 to your computer and use it in GitHub Desktop.
Save JoeRobich/81ae679ee2d29efa3fa5 to your computer and use it in GitHub Desktop.
WPF AttachedProperty to show the on-screen keyboard when the control get focused by touch then hide it when the control loses focus. Code in this Gist is MIT Licensed.
<Window x:Class="TouchKeyboardTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TouchKeyboardTest"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Touch Keyboard Test"
Height="350"
Width="525">
<Grid Margin="25">
<StackPanel>
<TextBox Margin="0 5" local:TabletHelper.ShowInputPanelOnTouch="True" />
<DatePicker Margin="0 5" local:TabletHelper.ShowInputPanelOnTouch="True" />
<RichTextBox Margin="0 5" local:TabletHelper.ShowInputPanelOnTouch="True" />
<Button Content="Clear Focus" HorizontalAlignment="Right" />
</StackPanel>
</Grid>
</Window>
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace TouchKeyboardTest
{
public class TabletHelper
{
public static readonly DependencyProperty ShowInputPanelOnTouchProperty =
DependencyProperty.RegisterAttached("ShowInputPanelOnTouch", typeof(bool), typeof(TabletHelper), new FrameworkPropertyMetadata(false, ShowInputPanelOnTouchChanged));
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_CLOSE = 0xF060;
private const string TabTipPath = @"microsoft shared\ink\tabtip.exe";
private const string OskPath = @"osk.exe";
readonly static string _expandedTabTipPath;
readonly static string _expandedOskPath;
static CancellationTokenSource _cancelCloseInputPanel;
static TabletHelper()
{
var programFilesPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles).Replace(" (x86)", "");
_expandedTabTipPath = Path.Combine(programFilesPath, TabTipPath);
var system32Path = Environment.GetFolderPath(Environment.SpecialFolder.System);
_expandedOskPath = Path.Combine(system32Path, OskPath);
}
public static void ShowInputPanel()
{
if (_cancelCloseInputPanel != null)
_cancelCloseInputPanel.Cancel();
if (File.Exists(_expandedTabTipPath))
Process.Start(_expandedTabTipPath);
else if (File.Exists(_expandedOskPath))
Process.Start(_expandedOskPath);
}
public static void HideInputPanel()
{
_cancelCloseInputPanel = new CancellationTokenSource();
Task.Delay(100, _cancelCloseInputPanel.Token)
.ContinueWith(t =>
{
_cancelCloseInputPanel = null;
if (t.IsCanceled)
return;
CloseInputPanelWindow();
});
}
private static void CloseInputPanelWindow()
{
int inputPanelHandle = FindWindow("OSKMainClass", null);
if (inputPanelHandle <= 0)
inputPanelHandle = FindWindow("IPTIP_Main_Window", null);
if (inputPanelHandle > 0)
SendMessage(inputPanelHandle, WM_SYSCOMMAND, SC_CLOSE, 0);
}
public static bool GetShowInputPanelOnTouch(DependencyObject obj)
{
return (bool)obj.GetValue(ShowInputPanelOnTouchProperty);
}
public static void SetShowInputPanelOnTouch(DependencyObject obj, bool value)
{
obj.SetValue(ShowInputPanelOnTouchProperty, value);
}
private static void ShowInputPanelOnTouchChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var uiElement = (UIElement)obj;
uiElement.GotKeyboardFocus -= UIElement_GotKeyboardFocus;
uiElement.TouchDown -= UIElement_TouchDown;
if ((bool)e.NewValue)
{
uiElement.GotKeyboardFocus += UIElement_GotKeyboardFocus;
uiElement.TouchDown += UIElement_TouchDown;
}
}
private static void UIElement_TouchDown(object sender, TouchEventArgs e)
{
var uiElement = (UIElement)sender;
uiElement.TouchLeave -= UIElement_TouchLeave;
uiElement.TouchUp -= UIElement_TouchUp;
if (!uiElement.IsFocused)
return;
uiElement.TouchLeave += UIElement_TouchLeave;
uiElement.TouchUp += UIElement_TouchUp;
}
private static void UIElement_TouchLeave(object sender, TouchEventArgs e)
{
var uiElement = (UIElement)sender;
uiElement.TouchLeave -= UIElement_TouchLeave;
uiElement.TouchUp -= UIElement_TouchUp;
}
private static void UIElement_TouchUp(object sender, TouchEventArgs e)
{
var uiElement = (UIElement)sender;
uiElement.TouchLeave -= UIElement_TouchLeave;
uiElement.TouchUp -= UIElement_TouchUp;
ShowInputPanel();
uiElement.LostKeyboardFocus += UIElement_LostKeyboardFocus;
}
private static void UIElement_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
var uiElement = (UIElement)sender;
uiElement.LostKeyboardFocus -= UIElement_LostKeyboardFocus;
if (!uiElement.AreAnyTouchesOver)
return;
ShowInputPanel();
uiElement.LostKeyboardFocus += UIElement_LostKeyboardFocus;
}
private static void UIElement_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
var uiElement = (UIElement)sender;
uiElement.LostKeyboardFocus -= UIElement_LostKeyboardFocus;
HideInputPanel();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment