Virtual Keyboard Example (C#)

August 7, 2010

Creating a virtual keyboard in WPF can be quite an obstacle. As far as I can tell, WPF does not directly support simulating keyboard strokes. This is an example of one way you can solve this problem.

Note: This is an evolution of the virtual keyboard code previously displayed on ascendedguard.com before the redesign.

Since WPF does not directly support simulating keyboard strokes, you have two options:

  • Import the SendInput function from a C++ DLL (User32.dll i believe it is)
  • Manually write the keyboard’s output using the built-in InputManager

In the example I’m showing here, the end result gives you a simple keyboard control that can be themed from within your DLL, and requires no code. You’ll notice the test program only contains a single line of code, to focus the cursor on the first text box at startup. There are two functions that really do all the work here. In reality, there are only two kind of keys: Normal and Special Function. Normal keys output some kind of text to the screen. Special function keys will do something special, like pressing shift, backspace, or caps lock, where you don’t expect the text on the key to be printed to the screen. The following function, WriteText, uses the current InputManager to write text:

1: /// <summary>
2: /// Handles standard (letter/number) virtual keyboard presses. 
3: /// </summary>
4: private void WriteText(object sender, RoutedEventArgs e)
5: {
6:     // For all normal letters and numbers, we can just grab the letter that was on the key.
7:     string text = ((Button )sender).Content.ToString();
8:
9:     if (this .IsShiftPressed)
10:     {
11:         // Unselect the shift key once a capital letter has been inserted.
12:         this .IsShiftPressed = false ;
13:     }
14:     else if (this .IsCapsLockPressed == false )
15:     {
16:         text = text.ToLower();
17:     }
18:
19:     var textEvent = new TextCompositionEventArgs (Keyboard .PrimaryDevice, new TextComposition (InputManager .Current, Keyboard .FocusedElement, text))
20:                         {
21:                             RoutedEvent = TextInputEvent
22:                         };
23:
24:     InputManager .Current.ProcessInput(textEvent);
25: }
26:

The special keys are, in some ways, simpler, but require special logic. For most keys, you can simply embed the Key that will be pressed within the Tag of each key, and send the appropriate RoutedEvent. For Shift and Caps Lock, though, since we’re handling logic about capitalization in our WriteText method, we simply set appropriate properties in our class:

 

1: /// <summary> Handles standard (letter/number) virtual keyboard presses. </summary>
2: /// <param name="sender"> Keyboard button sending the event. </param>
3: /// <param name="e"> Event arguments. </param>
4: private void PressSpecialKey(object sender, RoutedEventArgs e)
5: {
6:     Key key = (Key )((Button )sender).Tag;
7:
8:     KeyEventArgs keyEvent = new KeyEventArgs (Keyboard .PrimaryDevice, Keyboard .PrimaryDevice.ActiveSource, 0, key)
9:     {
10:         RoutedEvent = KeyDownEvent
11:     };
12:
13:     InputManager .Current.ProcessInput(keyEvent);
14: }
15:
16: /// <summary> Presses or depresses the shift key when caps lock is not pressed. </summary>
17: /// <param name="sender"> Object sending the event. </param>
18: /// <param name="e"> Event arguments. </param>
19: private void PressShift(object sender, RoutedEventArgs e)
20: {
21:     // No reason to change anything if caps is enabled.
22:     if (this .IsCapsLockPressed == false )
23:     {
24:         this .IsShiftPressed = !IsShiftPressed;
25:     }
26: }
27:
28: /// <summary> Presses or depresses the caps lock key. </summary>
29: /// <param name="sender"> Object sending the event. </param>
30: /// <param name="e"> Event arguments. </param>
31: private void PressCapsLock(object sender, RoutedEventArgs e)
32: {
33:     this .IsCapsLockPressed = !IsCapsLockPressed;
34:
35:     this .IsShiftPressed = false ;
36: }
37:

There are a few limitations with this implementation:

  • The virtual keyboard must be embedded on every form you intend to use it on. In some implementations, like single screen input kiosks, this may be desired even. However, it means you can’t just set a window as top-most and use it across your entire application.
  • Special characters aren’t included currently, which would be required for fields like “E-mail address”. You can treat this as an exercise to extend functionality of this keyboard.

Download the full source code, including a VS2010 project, here:
Virtual Keyboard Example v.1.0.0.0

You can download a pre-compiled version of the app here:
Pre-compiled VK Example Requires minimum .NET Framework 4.0 Client Profile

Revisions
1.0.0.0 – Initial Version


Comments are closed.