An event driven Phone Keypad library. Includes KeyDown, KeyUp and KeyHoldling events to which event handlers can be attached in apps that use this library. Also includes a mechanism to fire those events from keypad scanning software. No hardware specific code though. These events mirror those events in the previous blog for the Arduino Keypad Event Scanning Sketch. The next blog hooks the two up.
This blog demonstrates exemplary code for for implementing event table mechanisms for custom events, particularly if the events are driven by custom hardware.
This project, a Universal Windows Platform library ( Windows 10) provides a generic interface and implementation for three keypad events for a phone matrix keypad:
These are defined as in the IKeypad interface:
namespace KeypadUWPLib { public interface IKeypad { event EventHandler<KeypadEventArgs> KeyDown; event EventHandler<KeypadEventArgs> KeyUp; event EventHandler<KeypadEventArgs> KeyHolding; } }
The Keypad Interface
The events require a tailored event args class KeypadEeventArgs. This is generated on an event and passed to the handler/s along with eth event source object. This is much the same as a XAML Command Button interface.
namespace KeypadUWPLib { public enum KeypadActions { Down, Up, Holding } public class KeypadEventArgs { /// Validation list List<char> validActions = new List<char>() { '+', '-', '@' }; public static List<char> ValidKeys = new List<char>() { '0', '1', '2', '3', '4', '5', '6', '7', '8','9', '#', '*' }; public KeypadEventArgs(KeypadActions action, char key) { if (!ValidKeys.Contains(key)) { } else { Key = key; Action = action; } } public char Key { get; internal set; } public KeypadActions Action { get; internal set; } }
The KeypadEventArgs class.
The two properties, the key that is pressed and the event (as an enum) are passed to the event handler. Some validation of the key character passed to the constructor is performed. An alternative constructor is also implemented that takes two characters and validates the first as a validAction character:
public KeypadEventArgs(char action, char key) { if (!ValidKeys.Contains(key)) { }else { Key = key; if (!validActions.Contains(action)) { } else { switch (action) { case '+': Action = KeypadActions.Down; break; case '-': Action = KeypadActions.Up; break; case '@': Action = KeypadActions.Holding; break; } } } }
The alternative event args constructor.
As the events are to be received as strings from the keypad hardware over the Bluetooth serial stream (next blog) it makes sense to encapsulate the conversion of the event character (+,- or @) into the event arg class.
The keypad class then implements the a table for each event. The KeyDown event mechanism is shown:
namespace KeypadUWPLib { public class Keypad : IKeypad { private EventRegistrationTokenTable<EventHandler<KeypadEventArgs>> m_KeyDownTokenTable = null; public event EventHandler<KeypadEventArgs> KeyDown { add { /*return*/ EventRegistrationTokenTable<EventHandler<KeypadEventArgs>> .GetOrCreateEventRegistrationTokenTable(ref m_KeyDownTokenTable) .AddEventHandler(value); } remove { EventRegistrationTokenTable<EventHandler<KeypadEventArgs>> .GetOrCreateEventRegistrationTokenTable(ref m_KeyDownTokenTable) .RemoveEventHandler(value); } } public event EventHandler<KeypadEventArgs> KeyUp { . . . . . } public event EventHandler<KeypadEventArgs> KeyHolding { . . . . . } }
The Keypad class.
For simplicity, function are prototypes only shown for KeyUp and KeyHolding. They are embellished in the same manner as the Down mechanism.
Note that each event MUST have an Add and Remove option (compiler error otherwise.Also, in Microsoft sample code (see Related MSDN Documentation above) the Add returns the table but the compiler rejects that. The code works without it.
When an event is received from the underlying hardware, a mechanism is needed to fire that event, whilst C++ and VB have explicit calls for raising or setting an event, C# does not. The handlers in the event table are actually just delegates, so its its just a matter to action this delegates.
The event table’s InvocationList (list of handlers that have been added) has an Invoke method that invokes all attached handlers to the event:
m_KeyDownTokenTable.InvocationList.Invoke(sender, e);
The RaiseEvent( ) method:
public void RaiseEvent(object sender, KeypadEventArgs e) { // Action relevant event switch (e.Action) { case KeypadActions.Down: if (m_KeyDownTokenTable == null) return; m_KeyDownTokenTable.InvocationList.Invoke(sender, e); break; case KeypadActions.Up: .... break; case KeypadActions.Holding: .... break; } }
The précised Keypad RaiseEvent( ) method.
An alternative method consumes a raw keypad string (as sent form the Arduino Keypad Sketch).:
public void RaiseEvent(object sender, string keyString) { //Validate keyString if (keyString.Length != 2) return; KeypadEventArgs e = null; char action = keyString[0]; char key = keyString[1]; e = new KeypadEventArgs(action, key); //Note: (char, char) constructor RaiseEvent(sender, e); }
The alternative RaiseEvent( ) method. Note: (char, char) constructor for event args.
The Keypad and related classes.
After adding the library to a UWP project (as a reference) the steps for using are summarised thus:
// Declare the class public KeypadUWPLib.Keypad Keypad { get; internal set; } // Instantiate it Keypad = new KeypadUWPLib.Keypad(); // Provide and hookup handlers Keypad.KeyDown += Keypad_KeyDown; Keypad.KeyUp += Keypad_KeyUp; Keypad.KeyHolding += Keypad_KeyHolding; // The KeyDown handler private void Keypad_KeyDown(object sender, KeypadUWPLib.KeypadEventArgs e) { System.Diagnostics.Debug.WriteLine("down " + e.Key + " " + e.Action.ToString()); }
Yes, the code could be simplified a by having a common event table for all three events given that the event args actually pass the event. I wanted the events separate as the KeyDown event is the only event I want in the end game of this activity. Reminder that the end game is a selfie stick for a phone.
You can of course use a common handler method for all three events as they have the same signature.
The KeyHolding event could launch a timer that periodically calls the delegates in its event table until KeyUp event occurs.
This event mechanism is not specific to an underlying Bluetooth Serial hardware and thus could be used by any keypad hardware, supplying events over a stream such as RS232 or TCPIP sockets or a client-server mechanism.