Click here to Skip to main content
15,884,298 members
Articles / Desktop Programming / WPF
Tip/Trick

Virtual Keyboard (TabTip) Integration in WPF on Win 8.1 and Win 10

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
23 Aug 2016CPOL 63K   5   29
Virtual Keyboard (TabTip) integration in WPF on Win 8.1 and Win 10

Introduction

I open-sourced my project to automate everything concerning TabTip integration in WPF app.

Simple to use

The easiest way to install the WPFTabTip is using the Package Manager Console in Visual Studio:

C#
PM> Install-Package WPFTabTip

One line of code in your startup logic, and you are good to go!

C#
TabTipAutomation.BindTo<TextBox>();

You can bind TabTip automation logic to any UIElement. Virtual Keyboard will open when any such element will get focus, and it will close when element will lose focus. Not only that, but TabTipAutomation will move UIElement (or Window) into view, so that TabTip will not block focused element.

Hardware Keyboard Detection

By default, TabTip automation will occur only if no hardware keyboard is detected.

You can change that behavior by setting TabTipAutomation.IgnoreHardwareKeyboard to any of the following values:

C#
public enum HardwareKeyboardIgnoreOptions
    {
        /// <summary>
        /// Do not ignore any keyboard.
        /// </summary>
        DoNotIgnore,

        /// <summary>
        /// Ignore keyboard, if there is only one, and it's description 
        /// can be found in ListOfHardwareKeyboardsToIgnoreIfSingleInstance.
        /// </summary>
        IgnoreIfSingleInstanceOnList,

        /// <summary>
        /// Ignore keyboard, if there is only one.
        /// </summary>
        IgnoreIfSingleInstance,

        /// <summary>
        /// Ignore all keyboards
        /// </summary>
        IgnoreAll
    }

If you want to ignore specific keyboard, you should set TabTipAutomation.IgnoreHardwareKeyboard to IgnoreIfSingleInstanceOnList, and add keyboard description to TabTipAutomation.ListOfHardwareKeyboardsToIgnoreIfSingleInstance.

To get description of keyboards connected to machine, you can use the following code:

C#
new ManagementObjectSearcher(new SelectQuery("Win32_Keyboard")).Get()
                .Cast<ManagementBaseObject>()
                .SelectMany(keyboard =>
                    keyboard.Properties
                        .Cast<PropertyData>()
                        .Where(k => k.Name == "Description")
                        .Select(k => k.Value as string))
                .ToList();

Change Keyboard Layout

To specify keyboard layout to be used with certain element, you can set InputScope property in XAML to one of the following:

  • Default
  • Url
  • EmailSmtpAddress
  • Number

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
Russian Federation Russian Federation
Max Fedotov is currently working in Moscow, Russia.
His set of skills include C#, XAML, Silverlight, WPF as well as Delphi and InterSystems Caché.

Comments and Discussions

 
QuestionRemove Emoji button Pin
themoscy3-Apr-20 1:10
themoscy3-Apr-20 1:10 
Suggestion5* but some issues Pin
Nasenbaaer13-Feb-19 22:35
Nasenbaaer13-Feb-19 22:35 
QuestionNon admin user Pin
Member 259687123-Mar-17 7:43
Member 259687123-Mar-17 7:43 
AnswerRe: Non admin user Pin
Max Fedotov24-Mar-17 5:48
Max Fedotov24-Mar-17 5:48 
QuestionUse InputScope="Number" with DataGridTextColumn? Pin
rburrough110-Oct-16 1:22
rburrough110-Oct-16 1:22 
AnswerRe: Use InputScope="Number" with DataGridTextColumn? Pin
Max Fedotov10-Oct-16 1:28
Max Fedotov10-Oct-16 1:28 
GeneralRe: Use InputScope="Number" with DataGridTextColumn? Pin
rburrough112-Oct-16 10:46
rburrough112-Oct-16 10:46 
GeneralRe: Use InputScope="Number" with DataGridTextColumn? Pin
Max Fedotov12-Oct-16 20:03
Max Fedotov12-Oct-16 20:03 
GeneralRe: Use InputScope="Number" with DataGridTextColumn? Pin
rburrough126-Oct-16 10:58
rburrough126-Oct-16 10:58 
GeneralRe: Use InputScope="Number" with DataGridTextColumn? Pin
Max Fedotov26-Oct-16 20:01
Max Fedotov26-Oct-16 20:01 
PraiseThanks Pin
rburrough110-Oct-16 1:13
rburrough110-Oct-16 1:13 
GeneralRe: Thanks Pin
Max Fedotov10-Oct-16 1:18
Max Fedotov10-Oct-16 1:18 
Questionhow to use Pin
Herilane25-Aug-16 19:22
professionalHerilane25-Aug-16 19:22 
AnswerRe: how to use Pin
Max Fedotov25-Aug-16 20:21
Max Fedotov25-Aug-16 20:21 
GeneralRe: how to use Pin
Herilane30-Aug-16 17:43
professionalHerilane30-Aug-16 17:43 
GeneralRe: how to use Pin
Max Fedotov30-Aug-16 18:03
Max Fedotov30-Aug-16 18:03 
GeneralRe: how to use Pin
Herilane31-Aug-16 1:03
professionalHerilane31-Aug-16 1:03 
Hi again Max

Good news and bad news ;- {

I made that change and it is doing something at least. But that something is an exception.

It involves WPFTabTip. This is thrown when I move the cursor onto any textbox. The only event behind any textbox I use is mouseLeave. But the error occurs when the mouse is still over the textbox .

Null reference exception in System.reactive.platformservices.dll

C#
System.NullReferenceException was unhandled
  HResult=-2147467261
  Message=Object reference not set to an instance of an object.
  Source=WPFTabTip
  StackTrace:
       at WPFTabTip.TabTip.OpenUndocked()
       at WPFTabTip.TabTip.OpenUndockedAndStartPoolingForClosedEvent()
       at WPFTabTip.TabTipAutomation.<>c.<AutomateTabTipOpen>b__10_2(Tuple`2 _)
       at System.Reactive.Linq.ObservableImpl.Do`1._.OnNext(TSource value)
    --- End of stack trace from previous location where exception was thrown ---
       at System.Reactive.PlatformServices.ExceptionServicesImpl.Rethrow(Exception exception)
       at System.Reactive.Stubs.<>c.<.cctor>b__2_1(Exception ex)
       at System.Reactive.AnonymousSafeObserver`1.OnError(Exception error)
       at System.Reactive.Concurrency.ObserveOn`1.ObserveOnSink.OnErrorPosted(Object error)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
       at System.Windows.Threading.DispatcherOperation.InvokeImpl()
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Windows.Threading.DispatcherOperation.Invoke()
       at System.Windows.Threading.Dispatcher.ProcessQueue()
       at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
       at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
       at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
       at System.Windows.Application.RunDispatcher(Object ignore)
       at System.Windows.Application.RunInternal(Window window)
       at touch3.App.Main() in C:\Users\eps2\Documents\Visual Studio 2015\Projects\touch3\touch3\obj\Debug\App.g.cs:line 0
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 


For some reason it's not showing the Inner Exception info - maybe there is none? If you need to know more I can drill down to any part of the exception detail - and transcribe it. I can't see a way to print it out from the exception dialog box that VS shows.

One thing I noticed in the error detail which I'm guessing is in the WPFTabTip.dll is 'Target: {Void OpenUndocked()}'

I hope this has highlighted a possible simple error that you haven't trapped yet and isn't going to cause a headache.
GeneralRe: how to use Pin
Max Fedotov31-Aug-16 1:35
Max Fedotov31-Aug-16 1:35 
GeneralRe: how to use Pin
Herilane31-Aug-16 1:52
professionalHerilane31-Aug-16 1:52 
GeneralRe: how to use Pin
Max Fedotov31-Aug-16 2:20
Max Fedotov31-Aug-16 2:20 
GeneralRe: how to use Pin
Herilane31-Aug-16 2:46
professionalHerilane31-Aug-16 2:46 
GeneralRe: how to use Pin
Max Fedotov31-Aug-16 2:35
Max Fedotov31-Aug-16 2:35 
GeneralRe: how to use Pin
Herilane31-Aug-16 3:22
professionalHerilane31-Aug-16 3:22 
GeneralRe: how to use Pin
Max Fedotov31-Aug-16 4:54
Max Fedotov31-Aug-16 4:54 
GeneralRe: how to use Pin
Herilane31-Aug-16 17:55
professionalHerilane31-Aug-16 17:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.