Using a hardware key to tab through controls

The question of using a hardware button to tab through the controls on a form came up on the Compact Framework forum.  The answer, while simple, still had a couple of gotcha's, so I thought I'd give you the benefit of my experience. 

If you're not familiar with the HardwareButton control (Microsoft.WindowsCE.Forms.HardwareButton), it's a control that allows an application to override the functionality of Pocket PC directional pad (D-Pad) buttons by sending KeyUp and KeyDown events to the active control when one of the buttons is pressed.  The KeyDown/KeyUp events are the same as those used by the keyboard with the exception that the KeyEventArgs.KeyCode field may only contain one of five values:  Keys.Up, Keys.Down, Keys.Left, Keys.Right, or Keys.Enter.

To tab through the controls on a form, we need to set focus to the next control in the tab order when one of the D-Pad keys is pressed.  For this example we'll use the Enter button (usually the large button in the middle of the D-Pad).   First create a form with several controls and a HardwareButton control.  Add the following handler to the form:

        private void control_KeyUp(object sender, KeyEventArgs e)
            if ((e.KeyCode == System.Windows.Forms.Keys.Enter))
                Control control = sender as Control;
                if (null != control)
                    bool result = control.Parent.SelectNextControl(control, true, true, true, true);


Finally, set the KeyUp event of each control to the handler.  This was my first point of confusion.  I originally expected that the KeyUp events would be routed to the form.  That is not the case: they are routed to the active control.  My second point of confusion was the correct use of the SelectNextControl method.  I originally called it like this:

 bool result = control.SelectNextControl(control, true, true, true, true);


However, focus remained on the same control. I was confused until I found Subhag Oak's article. SelectNextControl does not find the next sibling of a control as I expected. Instead it finds the next child control in tab order of the control that calls it. (One could wish that it had been named SelectNextChildControl, but c'est la vie). In order to find the next sibling of the current control, SelectNextControl must be called by the current control's parent, using the current control as the starting point of the search. SelectNextControl's other parameters allow you to set the direction of the search, search all controls or only those with the TabStop property set to true, whether to search nested controls, and whether the search should wrap when the end of the Controls collection is reached.

I hope this saves someone out there some time.