Department of InformatiX
Microsoft .NET Micro Framework Tools & Resources

Yesterday I have released a control named ButtonTextBox, which allows you to enter any text input. But as you know, button is not a key...

IButtonTranslator

...so we have to translate a button press into actual input data, be it a character, word, number or whatever. One way would be to define hundreds of buttons and assign a character to each (you could for example use actual character values for the enum to be able to just cast the button to the character as shown here), but I wouldn't like you very much because you would force buttons to be like keys!

But most of you have already seen a device which uses reasonably small amount of keys (yes I know) to enter all the letters: the cell phone. I was inspired a bit by that idea and created this very simple interface:

public interface IButtonTranslator { bool GetText(Button button, int pressedCount, out string text); bool GetNumber(Button button, out int number); }

Using such class you could take any button, number of how many times it was pressed, and translate this info into any letter. This is what GetText method is supposed to do, returning a value of true if it was able to find any corresponding letter to the button, or false otherwise. In fact we had used out char in the project, but to keep pace with Windows Presentation Foundation system, I've changed it to string and adjusted the text box as well for you (in WPF it is possible to get whole text as an input at once, e.g. from speech or handwriting recognition, or some IME input method).

The GetNumber method is then some sugar for the case you want to switch to number mode (the text box uses it when AllowNumbersOnly is set to true).

SequentialButtonTranslator

Okay, let's look into some practical implementation. Usually you give your buttons successive values. Like here:

public enum Numpad { Button0 = 1, // we can't start at 0 since this is Button.None, which is not a valid button Button1, Button2, Button3, Button4, Button5, Button6, Button7, Button8, Button9 }

So why not to have a translator which would take advantage of the button values? For example, the GetNumber method could be really easy:

public bool GetNumber(Button button, out int number) { number = (int)button - 1; return (number > 0) && (number < 10); }

Okay, and what about the letters? We will keep the string option aside and focus on characters only. Looking on the cell phone you can see that each button represents up to four letters - characters. So we can join the characters in a string and pack them into array. And to keep things sequential, let's sort it in the same order as we have our buttons:

string[] CharacterData = new string[] { "+0", // characters for Button0 " .?!,1", // Button1 "abc2", // Button2 "def3", // Button3 "ghi4", // Button4 etc. ... }

The GetText can then conceptually work like this one:

public bool GetText(Button button, int pressedCount, out string text) { try { text = CharacterData[(int)button - 1].Substring(pressedCount, 1); return true; } catch { return false; } }

This is not a very good style by the way, we should do some error checking instead of using try catch block to control the program flow (and throwing an exception is time expensive). If you now add a configurable first button (instead of the - 1 coefficient) and circular letter retrieval (treating the string as abc2abc2abc2abc2...), you have the SequentialButtonTranslator! This implementation is available in the text box demo project or you can download it right here.

Multiple buttons example

To see a bit more complicated example than the one in the demo, here is a sample set-up for multiple buttons:

SequentialButtonTranslator ButtonTranslator = new SequentialButtonTranslator(); ButtonTranslator.FirstCharacterButton = (Button)Numpad.Button0; // cast our enum value to the Button ButtonTranslator.CharacterData = new string[] { // you can use resources and make the keys localizable Resources.GetString(LetterData.Button0), // +-()0 Resources.GetString(LetterData.Button1), // .:,-1?!/@ Resources.GetString(LetterData.Button2), // abcáč2 Resources.GetString(LetterData.Button3), // defďéě3 Resources.GetString(LetterData.Button4), // ghií4 Resources.GetString(LetterData.Button5), // jkl5 Resources.GetString(LetterData.Button6), // mnoňó6 Resources.GetString(LetterData.Button7), // pqrsřš7 Resources.GetString(LetterData.Button8), // tuvťůú8 Resources.GetString(LetterData.Button9) // wxyzýž9 }; ButtonTranslator.FirstNumberButton = (Button)KeypadButton.NumPad0; ButtonTranslator.NumberData = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

That's all you need to use the SequentialButtonTranslator with phone-like oriented buttons. Oh and if you want to use it together with the ButtonTextBox, be aware of the control buttons (like left/right arrow assigned to VK_LEFT/VK_RIGHT button) and choose some free sequence of numbers for your buttons.

Comments
Sign in using Live ID to be able to post comments.