Now that I had my Amazing Qwerty KeyBoard, I had to hook it up. BabySmash uses the OnKeyUp event in the MainScreen as its hook to the business logic:
public partial class MainWindow : Window
{
private readonly Controller controller;
public Controller Controller { get { return controller; } }
public MainWindow(Controller c)
{
this.controller = c;
this.DataContext = controller;
InitializeComponent();
}
....
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
e.Handled = true;
controller.ProcessKey(this, e);
}
...
}
Since I wanted to mimic the existing behavior as closely as possible, I had to create a corresponding event for my on-screen key board, and then have the MainWindow handle it in the same manner.
My keys are <Button/>s, so I used the "Click" event on all of my keys:
<Button Name="Q" Grid.Column="0" Grid.Row="0" Click="HandleKeyBoardClick" >
<Button Name="W" Grid.Column="1" Grid.Row="0" Click="HandleKeyBoardClick" >
...
<Button Name="M" Grid.Column="2" Grid.Row="6" Click="HandleKeyBoardClick" >
I then implemented the "HandleKeyBoardClick" class in the code behind:
protected void HandleKeyBoardClick(object sender, RoutedEventArgs e)
{
Button b = (Button) sender;
NewKeyBoardClick(b.Name);
}
I abstracted the actual logic of the event raising in case I ever wanted to raise the event in a different way. My NewKeyBoardClick method takes the desired key as a plain-text string (ie: "Q"). I chose not to convert back and forth from ascii codes because I really didn't see any value in doing so.
public void NewKeyBoardClick(string keyName)
{
//Raise a key click event for the specified key
}
Now I needed a KeyClick event. After much googling and pain (It was during this activity that my KeyBoard user control briefly became a custom control before it was reincarnated back in it's present form.) I not only needed a custom event, I needed a custom event argument (which key was clicked).
Here is what I came up with:
First, I created my custom argument:
public class KeyBoardClickArgs : EventArgs
{
public string KeyName { get; set; }
}
Then I created the delegate for my event:
public delegate void KeyboardClickHandler(Object sender, KeyBoardClickArgs args);
Then I created my event:
public event KeyboardClickHandler KeyBoardClick;
Now, I needed to raise the event with the proper argument in my NewKeyBoardClick class. First I instantiated my KeyClickArgs and set the keyName property. Then I check for any subscribers to my event, and if I find any, I raise my event:
public void NewKeyBoardClick(string keyName)
{
KeyBoardClickArgs e = new KeyBoardClickArgs();
e.KeyName = keyName;
if (KeyBoardClick != null)
{
KeyBoardClick(this, e);
}
}
Now my control is ready to go! (I know, I haven't implemented the size property yet - that came later.)
I added the KeyBoard control the the MainPage window:
xmlns:local="clr-namespace:BabySmash"
<Canvas Name="figuresCanvas"><local:Keyboard3 x:Name="KeyBoardC" Visibility="Hidden"/></Canvas>
I set it to "Hidden" because I only want to display it if we are in "drewbie mode".
Now I just needed to hook up the new event:
First I added it to the MainWindow constructor:
KeyBoardC.KeyBoardClick += new Keyboard3.KeyboardClickHandler(KeyBoardC_KeyBoardClick);
Then I used the event in the same way that MainScreen uses its OnKeyUp event:
void KeyBoardC_KeyBoardClick(object sender, KeyBoardClickArgs e)
{
controller.ProcessKey(this, e.KeyName);
}
Success!! The MainWindow is responding to keyboard clicks from either the real keyboard or my on-screen keyboard control in exactly the same way! Now I can go ahead with modifying BabySmash and implementing new "DrewbieSmash" features without thinking about the input mechanism.
I'll work on getting the source code available. Until then, email me.