Touch Screen Keyboard in Login Form
Introduction
For a touch screen project, the user needed a touch screen keyboard to enter information in a textbox, password box etc. So, a keyboard layout was to be implemented in WPF. Here, a custom keyboard layout is implemented using StackPanel
s and Button
s.
Touch Screen Keyboard is a WPF window with no style. Considerable work has to be done to make sync the keyboard window and the application window for resizing, out of screen, minimize, maximize, and window activate and deactivate issues. Ctrl, Alt, Function, and Arrow key functionalities are not given, but basic keys including Enter, BackSpace, Shift, TAB, CapsLock functionalities are implemented. Some features of this Touch Screen Keyboard are:
- Window state sync: it synchronizes itself with window maximize, minimize.
- It never goes out of screen in x-axis.
- It always keeps itself in sync with the application window size.
- It keeps itself in sync with window move.
- No hooking: it does not use any sort of hooking (no interoperability).
Keyboard layout
Keyboard layout is created using StackPanel
s and Button
. If you look at the keyboard layout, you will see that there are five rows. For these five rows, five StackPanel
s with horizontal orientation are taken. Each of these StackPanel
s contain the keys (Button
s) for its corresponding row. A parent StackPanel
with vertical orientation contains these five StackPanel
s.
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal" >
//ALL the keys(Buttons) of the first row of the keyboard layout.
</StackPanel>
<StackPanel Orientation="Horizontal" >
//ALL the keys(Buttons) of the Second row of the keyboard layout.
</StackPanel>
<StackPanel Orientation="Horizontal" >
//ALL the keys(Buttons) of the third row of the keyboard layout.
</StackPanel>
<StackPanel Orientation="Horizontal" >
//ALL the keys(Buttons) of the fourth row of the keyboard layout.
</StackPanel>
<StackPanel Orientation="Horizontal" >
//ALL the keys(Buttons) of the fifth row of the keyboard layout.
</StackPanel>
</StackPanel>
Here, all the keys are Button
s with a certain look and feel. I would like to give special thanks to Mark Heath for his article "Creating a Custom WPF Button Template in XAML". The button style is taken from there, and full credits for the buttons go to him. All the key strokes are handled using WPF commands.
Remora Pattern by Ben Constable
According to Ben Constable, Remora Pattern allows you to attach a chunk of logic to any existing element that you have. This pattern can be implemented using an Attached Dependency Property in WPF, which is shown in Ben Constable's blog. You can take a look at it here.
Here, an Attached Dependency Property is attached with an object. When the object is initiated, it goes to set the value of the Attached Dependency Property, which results in calling an Attached Dependency Property Change event. In the event handler, you can add your intended functionality, which is the additional functionality of the object.
<PasswordBox k:TouchScreenKeyboard.TouchScreenKeyboard="true" x:Name="txtPassword" />
The code:
public static readonly DependencyProperty TouchScreenKeyboardProperty =
DependencyProperty.RegisterAttached("TouchScreenKeyboard", typeof(bool),
typeof(TouchScreenKeyboard), new UIPropertyMetadata(default(bool),
TouchScreenKeyboardPropertyChanged));
Here, a TouchScreenKeyboard
attached property is exposed form the Touch Screen custom control. To get the touch screen keyboard functionality, you have to set the TouchScreenKeyboard
attached property to a textbox or a password box. When this textbox or password box is initiated, it sets the value of the TouchScreenKeyboard
attached property which in turn calls the TouchScreenKeyboardPropertyChanged
event.
static void TouchScreenKeyboardPropertyChanged(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
FrameworkElement host = sender as FrameworkElement;
if (host != null)
{
host.GotFocus += new RoutedEventHandler(OnGotFocus);
host.LostFocus += new RoutedEventHandler(OnLostFocus);
}
}
In TouchScreenKeyboardPropertyChanged
, we add functionality in the focus and lost focus events. Here, host
is a textbox or password box in which you are setting the TouchScreenKeyboard
attached property. In the ONGOTFocus
event handler, you will show the touch screen keyboard to enter keys, and in the UNFocus
event handler, the keyboard will disappaer.
The code
How does it move a parent window and a keyboard window together?
When a WPF window moves , it fires the LocationChanged
event. In the code to find the parent window of the virtual keyboard window, the following code is written in the focus event of host
:
FrameworkElement ct = host;
while (true)
{
if (ct is Window)
{
((Window)ct).LocationChanged +=
new EventHandler(TouchScreenKeyboard_LocationChanged);
break;
}
ct = (FrameworkElement)ct.Parent;
}
After getting the parent window, the LocationChanged
event of the parent window is subscribed to. Now, whenever the parent window moves, it will invoke the LocationChanged
event handler method and the location of the TouchScreenWindow
will be updated accordingly.
How does it synchronize the keyboard window with the parent window maximize?
When the parent window is maximized, the LayoutUpdate
event is fired by each of the child controls. So, the LayoutUpdate
event of the textbox or the password box which is host
is subscribed in the following code in the focus
event:
host.LayoutUpdated += new EventHandler(tb_LayoutUpdated);
Now, whenever the parent window is maximized, it will invoke the LayoutUpdated
event handler method and the location of the TouchScreenWindow
will be updated accordingly.
How does it synchronize keyboard window with the parent window resize?
When the parent window is resized, the LayoutUpdate
event is fired by each of the child controls. So, the LayoutUpdate
event of the textbox or password box which is host
is subscribed in the following code in the focus
event:
host.LayoutUpdated += new EventHandler(tb_LayoutUpdated);
Now, whenever the parent window is resized, it will invoke the LayoutUpdated
event handler method and the location of the TouchScreenWindow
will be updated accordingly.
How does it make the host control's border red and background yellow?
The host control's border is made red when it gets focus. So, in the focus
event of host
, the following code is written:
_PreviousTextBoxBackgroundBrush = host.Background;
_PreviousTextBoxBorderBrush = host.BorderBrush;
_PreviousTextBoxBorderThickness = host.BorderThickness;
host.Background = Brushes.Yellow;
host.BorderBrush = Brushes.Red;
host.BorderThickness = new Thickness(4);
The border color, background, and thickness is changed in this event. Before making changes, the border’s property values are saved so that at a later time it can restore its original look. In the unfocused event, it restores its original look.
How does it restrict the touch screen keyboard WPF window to go outside of the screen in x-axis?
SystemParameters.VirtualScreenWidth
returns the width of the virtual screen in pixels. Now we know the lower boundary is 0 and the upper boundary is SystemParameters.VirtualScreenWidth
. So, all it has to do is to go through some logic. The logic is written in the following code:
if (WidthTouchKeyboard + Actualpoint.X > SystemParameters.VirtualScreenWidth)
{
double difference = WidthTouchKeyboard + Actualpoint.X -
SystemParameters.VirtualScreenWidth;
_InstanceObject.Left = Actualpoint.X - difference;
}
else if (!(Actualpoint.X > 1))
{
_InstanceObject.Left = 1;
}
else
_InstanceObject.Left = Actualpoint.X;
What the code does here is it checks whether the leftmost x-axis vale and the rightmost x-axis value of the touch screen keyboard are out of the screen or not. If it is out of the screen, then it resets it to appropriate value. Otherwise, it does nothing.
How do I position the child window to the exact position of the host control?
When the host control is focused, it fires the focus
event. In the focus
event, we get the location of the host control. Then, we set the touch screen keyboard window's location accordingly.
How the touch screen keyboard window is always on top of the host window and does not make problems with other windows?
Setting the touch screen keyboard window to the topmost will not work. Because in that case, the touch screen keyboard will always remain on top of all the other windows in the machine. To solve the problem, we take the help of the Activatewindow
and Deactivatewindow
events of the host window. When he host window is activated, it fires the Activated
event, and when the host window is deactivated, it fires the Deactivated
event.
FrameworkElement ct = host;
while (true)
{
if (ct is Window)
{
((Window)ct).Activated += new EventHandler(TouchScreenKeyboard_Activated);
((Window)ct).Deactivated += new EventHandler(TouchScreenKeyboard_Deactivated);
break;
}
ct = (FrameworkElement)ct.Parent;
}
It subscribes to the Activated
and Deactivated
events of the parent window. In the Activated
event, the touch screen keyboard is made topmost, and in the Deactivated
event, it resets it. Here is the code for this functionality:
static void TouchScreenKeyboard_Deactivated(object sender, EventArgs e)
{
if (_InstanceObject != null)
{
_InstanceObject.Topmost = false;
}
}
static void TouchScreenKeyboard_Activated(object sender, EventArgs e)
{
if (_InstanceObject != null)
{
_InstanceObject.Topmost = true;
}
}
Sample code
Here, a project has been attached which shows the touch screen keyboard control in action.
Conclusion
Thanks for reading this write up. I hope that this write up will be helpful for some people. If you guys have any questions, I would love to answer.
References
History
- Initial release – 16/01/09.