
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. As a result, you have two options:
- Import the SendInput function from a C++ DLL (User32.dll i believe it is)
- Manually write the output in the cases you want to.
The 2nd option isn't too bad to handle. This way also prevents you from having to handle each button separately, but I'm sure you could work around that in a way similar to what I've done here.
Basically, create your keyboard layout within it's own panel or grid, with each key being a button. Once you've done this, you can do a foreach loop on each button, where if it's a letter (usually the Button.Content.Length == 1), send it to one event handler, otherwise, send the button to a special event handler. Also, make sure every button is not focusable (Button.IsFocusable = false).
1foreach (Button b in KeyboardPanel.Children)
2{
3 b.Focusable = false;
4
5 if (b.Content.ToString().Length <= 1)
6 {
7 b.Click += new RoutedEventHandler(keyboardButton_Click);
8 }
9 else
10 {
11 b.Click += new RoutedEventHandler(keyboardButtonSpecial_Click);
12 }
13}
Once you've done this, the implementation is similiar to this:
662
663
664
665 void keyboardButtonSpecial_Click(object sender, RoutedEventArgs e)
666 {
669 switch (((Button)sender).Content.ToString())
670 {
671 case "Space":
672 if (System.Windows.Input.Keyboard.FocusedElement.GetType() == typeof(TextBox))
673 {
674 TextBox box = ((TextBox)System.Windows.Input.Keyboard.FocusedElement);
675 int newIndex = box.CaretIndex + 1;
676 box.Text = box.Text.Insert(box.CaretIndex, " ");
677 box.CaretIndex = newIndex;
678 }
679 break;
680 case "Shift":
681 if (isKeyboardUppercase())
682 setKeyboardUppercase(false);
683 else
684 setKeyboardUppercase(true);
685 break;
686 case "Tab":
687 ((UIElement)System.Windows.Input.Keyboard.FocusedElement).MoveFocus(new System.Windows.Input.TraversalRequest(System.Windows.Input.FocusNavigationDirection.Next));
688 break;
689 case "Delete":
690 if (System.Windows.Input.Keyboard.FocusedElement.GetType() == typeof(TextBox))
691 {
692 System.Windows.Forms.SendKeys.SendWait("{BACKSPACE}");
693 }
694 break;
695 case "Enter":
696 if (System.Windows.Input.Keyboard.FocusedElement.GetType() == typeof(TextBox))
697 {
698 TextBox box = ((TextBox)System.Windows.Input.Keyboard.FocusedElement);
699 if (box.AcceptsReturn)
700 {
701 int nIndex = box.CaretIndex + 1;
702 box.Text = box.Text.Insert(box.CaretIndex, Environment.NewLine);
703 box.CaretIndex = nIndex;
704 }
705 }
706 break;
707 }
708 }
709
710 bool isKeyboardUppercase()
711 {
712 if (Char.IsUpper((keyboardLetterA.Content.ToString().ToCharArray())[0]))
713 return true;
714 else
715 return false;
716 }
717
718 void setKeyboardUppercase(bool upper)
719 {
720 foreach (Button b in KeyboardPanel.Children)
721 {
722 if (b.Content.ToString().Length <= 1
723 {
724 if (upper)
725 b.Content = b.Content.ToString().ToUpper();
726 else
727 b.Content = b.Content.ToString().ToLower();
728 }
729 }
730 }
731
732 void keyboardButton_Click(object sender, RoutedEventArgs e)
733 {
735 if (System.Windows.Input.Keyboard.FocusedElement.GetType() == typeof(TextBox))
736 {
737 TextBox box = ((TextBox)System.Windows.Input.Keyboard.FocusedElement);
738 int newIndex = box.CaretIndex + 1;
739 box.Text = box.Text.Insert(box.CaretIndex, ((Button)sender).Content.ToString());
740 box.CaretIndex = newIndex;
741
742 if (Char.IsUpper((((Button)sender).Content.ToString().ToCharArray())[0]))
743 {
744 setKeyboardUppercase(false);
745 }
746
747 }
748 }
749 #endregion
In here, you can see I've got several things going on. If you push Shift on my keyboard, it'll change the content of the letters to uppercase or lowercase, based on what they already were. (I test this by looking at the letter A key's content).
I also only type if we're currently focused into a TextBox. For the program I was using this in, I had no need for typing unless we're focused in a TextBox. Since i know I'm in a TextBox, i can look for the Caret and type at that point.
Look at the "DELETE" Key (it's actually Backspace, it was just improperly named). I've left this bad code "as-is" to show the other way you could handle some input. If I'm in WPF, obviously I would like to keep Windows Forms out of my application if possible. After looking at this, the answer seemed somewhat obvious (and similiar to all the other methods of input):
1 case "Delete":
2 if (System.Windows.Input.Keyboard.FocusedElement.GetType() == typeof(TextBox))
3 {
4 TextBox box = ((TextBox)System.Windows.Input.Keyboard.FocusedElement);
5 int newIndex = box.CaretIndex - 1;
6 if (newIndex >= 0)
7 {
8 box.Text = box.Text.Remove(box.CaretIndex - 1, 1);
9 box.CaretIndex = newIndex;
10 }
11 }
12 break;
This method handles deleting characters in logic, and now eliminates the need for System.Windows.Forms.
The applications for a virtual keyboard like this? I'd say for added accessibility, and touch-screen applications where users may not want to move their fingers from the monitor to a keyboard for typing small things.
29 comments:
Chould you send me your whole project?tks.
my e-mail:xielingsen @ gmail.com
Hello !
Your keyboard control is so cool ! Could you please send me your source project ? Thanks a lot.
My Email : frederic.poindron@gmail.com
Hello this is exactly what I need for a project for work for touchscreens. Can you send me the source code?
Thanks,
Wade.Beasley@insightbb.com
hello
it's exactly what i'm searching for a touchscreen project. If possible i would enjoy if you can send me the project:
philippe.staedler@gmail.com
Unfortunately, as this is embedded within an application I'm doing for someone, I'm unable to send out the actual source. Sorry about that guys.
Overall, undertaking this project isn't too complicated. Create the interface using Blend or VS, and use a method for interfacing with the buttons similar to what I've done above.
hi,
Great project! Can You Please(Please!!) send it to me?
It will be great!
my mail is john.maymon@gmail.com
Can you publish virtual keyboard as usercontrol?
private void keyboardButtonSpecial_Click(object sender, RoutedEventArgs e)
{
switch (((Button)sender).Content.ToString())
{
case "Space":
if (System.Windows.Input.Keyboard.FocusedElement.GetType() == typeof(TextBox))
{
TextBox box = ((TextBox)System.Windows.Input.Keyboard.FocusedElement);
int newIndex = box.CaretIndex + 1;
box.Text = box.Text.Insert(box.CaretIndex, " ");
box.CaretIndex = newIndex;
}
break;
case "Shift":
if (isKeyboardUppercase())
setKeyboardUppercase(false);
else
setKeyboardUppercase(true);
break;
case "Tab":
((UIElement)System.Windows.Input.Keyboard.FocusedElement).MoveFocus(new System.Windows.Input.TraversalRequest(System.Windows.Input.FocusNavigationDirection.Next));
break;
case "Delete":
if (System.Windows.Input.Keyboard.FocusedElement.GetType() == typeof(TextBox))
{
System.Windows.Forms.SendKeys.SendWait("{BACKSPACE}");
}
break;
case "Enter":
if (System.Windows.Input.Keyboard.FocusedElement.GetType() == typeof(TextBox))
{
TextBox box = ((TextBox)System.Windows.Input.Keyboard.FocusedElement);
if (box.AcceptsReturn)
{
int nIndex = box.CaretIndex + 1;
box.Text = box.Text.Insert(box.CaretIndex, Environment.NewLine);
box.CaretIndex = nIndex;
}
}
break;
}
}
bool isKeyboardUppercase()
{
if (Char.IsUpper((keyboardLetterA.Content.ToString().ToCharArray())[0]))
return true;
else
return false;
}
void setKeyboardUppercase(bool upper)
{
foreach (Button b in KeyboardPanel.Children)
{
if (b.Content.ToString().Length <= 1)
{
if (upper)
b.Content = b.Content.ToString().ToUpper();
else
b.Content = b.Content.ToString().ToLower();
}
}
}
void keyboardButton_Click(object sender, RoutedEventArgs e)
{
if (System.Windows.Input.Keyboard.FocusedElement.GetType() == typeof(TextBox))
{
TextBox box = ((TextBox)System.Windows.Input.Keyboard.FocusedElement);
int newIndex = box.CaretIndex + 1;
box.Text = box.Text.Insert(box.CaretIndex, ((Button)sender).Tag.ToString());
box.CaretIndex = newIndex;
}
}
It can help someone to copy and paste...
not function for filds PasswordBox. the BackSpace no contains CaretIndex. tks
It looks like you're right. I've never dealt with the PasswordBox in WPF, but it looks like the control does not support any kind of CaretIndex, and the TextBox no longer supports character masking as was the case in .NET 2.0
I was looking at this for a reference.
So in this case the keyboard isn't going to work at all for password fields. For the example I've posted though, I assumed all fields were TextBox's anyways, which went around this issue. For this issue, you'd need to create a custom Textbox control that does indeed mask characters similar to a PasswordBox similar to the way .NET 2 handled these, unless someone else has a better idea?
We have implemented a keyboard similar to this and have issues with two way binding when we manipulate the textbox from code. Have you had any issues with this?
Are you binding the textbox to the keyboard specifically somehow, or is this an issue with a Textbox completely outside your keyboard?
I'm not sure what exactly is involved in your two-way binding to help out.
Nice. I'm doing something similar, and I've been using the Tag property on the button to identify the special cases, since I have images rather than string content in some (like the back and return buttons.)
If it has a tag, it's a special case; if the tag is null, I get the content as a string.
Hi Again.
I ran into a wall with PasswordBox controls, which don't have a caretindex property, which sent me back looking for a way to simulate keystrokes.
Check out:
characters and keystrokes
Hi! It's really what I'm searching so long..Could you please send me your source code? It's so wonderful!!!!
Thanks a lot and best regards from Ukraine!!!
Katya
e-mail: any.retake@gmail.com
I am looking for this kind of keybaord for a touchscreen application. Can you please send me the whole project??? Tks my email is ramu.attelli@gmail.com
Hi,
Fucusable is "false" but still getting focus if i am writing google search bar or another textbox which textbox is not on Virtual Keyboard application.. All my elements are not focusable. any clue?
I am looking for this kind of keybaord for a touchscreen application. Can you please send me the whole project??? Tks my email is srikanth2k8@gmail.com
could you please send me the whole project. This something we are trying to implement and this would really make it easy.
tiggerhorton@gmail.com
Thanks
Due to this code being a part of another project I worked on for someone, I can't release the original code or project, so no point in asking. Sorry.
hi Gaurd,
i can understand, but i new to wpf, and the dead lin is aproaching. so need to complete in order to continue the job.
SendKey command do not work..
Ray Akkanson
Can you please send me the whole project ?
Thanks.
geochatz[at]yahoo.com
Would you please send me the project?
Send to chr1986(at)hotmail(dot)com
Great code!
Would you please send me the project?
ciro.cesar@gmail.com
Great code!
Would you please send me the project?
Thanks !
51FALLINLOVE@giga.net.tw
Can you please send me the whole project ?
Thanks.
51FALLINLOVE@giga.net.tw
Post a Comment