Share via


Capturing the Enter Key and Arrow Keys In a user control

Question

Thursday, November 20, 2014 4:33 PM

I have been researching for a while on this subject and I am getting a little bit here and there, but I can't seem to get this to work.  I have a base form in my project that Inherits the System.Windows.Forms.Form object.  This generic form has the KeyPreview property and I can set it to true when the form is create.  No problem there, however, I have a UserControl base object that is hosted in this window.  It Inherits Windows.Forms.UserControl.  From this base user control, I can create specific controls I need from this base user control.  So my form hosts one or more user controls.

Here is the problem.  I can set the keyPreview to true on the form, but not the user control.  I need to have the enter key act as a tab key until the control focus is a button, to which the enter button needs to act as normal and do a button click.  I also need the arrow keys to act as a tab to move focus through the controls where the up and back arrow moves the focus back to the previous control, and down and right move to the next control. 

I noticed there is no KeyPreview on the UserControl object and from what I read that is because the user control is a container to host other controls so I am stuck.

The reason for this behavior is the user entering data usually enter numeric data and only use the keypad of the keyboard and it slows up data entry to enter data then hit tab or mouseclick to the next field. 

Thanks.

All replies (3)

Friday, November 21, 2014 10:01 AM ✅Answered

I prefer using the way suggested in https://social.msdn.microsoft.com/Forums/vstudio/en-US/3f3bbba5-db71-4b91-9586-dbea57ed4d7f/net-usercontrol-keypress-event .

 

Write this bit of code in the user control and then drag the control to the form.Put in a 
debug statement in the line of code in the control and when you press a key on the user control
the debug statement will be hit.
Protected Overrides Function ProcessKeyPreview(ByRef m As Message) As Boolean
//Process the message to look for the key which was pressed.You will find lots of
//example by googling
 Return MyBase.ProcessKeyPreview(m)
End Function

remember make the reply as answer and vote the reply as helpful if it helps.


Monday, November 24, 2014 3:24 PM ✅Answered

Thanks all.  After more searching over the weekend, I ran across the ProcessCmdKey which I was able to override to get what I needed.  Here is the code:

Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
        'This is needed for the user control to capture the keys before bubbling them up.  This will allow the controls to act with key commands
        'first.  This will substitue the Enter and arrow keys for a tab or alt+tab functionality to move the cursor between tap stop controls in the user control.
        Select Case keyData
            Case ModifierKeys.Enter
                Windows.Forms.SendKeys.Send("{TAB}")

            Case ModifierKeys.Down
                Windows.Forms.SendKeys.Send("{TAB}")

            Case ModifierKeys.Up
                Windows.Forms.SendKeys.Send("+{TAB}")

            Case ModifierKeys.Right
                Windows.Forms.SendKeys.Send("{TAB}")

            Case ModifierKeys.Left
                Windows.Forms.SendKeys.Send("+{TAB}")

            Case Else 'ignore the keys and pass the message up
                MyBase.ProcessCmdKey(msg, keyData)
        End Select

        MyBase.ProcessCmdKey(msg, keyData)
        Return MyBase.ProcessCmdKey(msg, keyData)


    End Function
   

Saturday, November 22, 2014 1:44 AM

I didn't test this in the capacity that you want to use it. The code is for UserControl1. It has Buttons1 to 3 on it.

I placed one Button on the Form and two of the user controls on the Form.

If Button1 on the Form has focus and you select a left or right arrow key then immediately the focus goes to the first Button on the top user control (the first one added to the Form). Then selecting left or right arrow keys focuses only the Buttons in the top user control.

The tab key can be used to move from the Button on the Form to each UserControl then back to the Button on the Form.

If you tab to the second UserControl (the bottom one) then arrow keys will only focus its buttons.

I'm not sure that is what you want. Also I suppose better code could be provided in the UserControls code for doing whatever you desire.

There's a sub in the UserControl that is almost the same as the sub Risa displays in her post. I use that sub in a Form if I want to get any key selected on the keyboard regardless of the control that has focus when the key is selected. And I retrieved that sub from an app which in the Form Load event has KeyPreview set to true which maybe is not necessary. It doesn't seem necessary in the UserControl.

EDIT: It's also probable the logic for the If statements to reset the variable Counter are not in the correct location of the sub. Or prior to Counter += or -= 1 the next Nr should be known ahead of time to set the counter then so it can't go negative or more than the indexes in the List(Of Control). As it seems to me looking at the code that an error could occur if a certain Button was focused and you selected the arrow key that would move in the opposite direction perhaps. As I said I didn't really test this other than to focus the buttons but not forwarding and reversing direction at each location to see what may occur.

Option Strict On

Public Class UserControl1

    Dim MyControls As New List(Of Control)

    Private Sub UserControl1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For Each Ctl As Control In Me.Controls
            MyControls.Add(Ctl)
        Next
    End Sub

    Dim Counter As Integer = 0

    Protected Overrides Function ProcessCmdKey(ByRef msg As Message, ByVal keyData As Keys) As Boolean
        If Counter < 0 Then Counter = MyControls.Count - 1
        If Counter > MyControls.Count - 1 Then Counter = 0
        If keyData = Keys.Left Then
            GetNextControl(MyControls(Counter), False)
            Counter -= 1
        ElseIf keyData = Keys.Right Then
            GetNextControl(MyControls(Counter), True)
            Counter += 1
        End If
        Return Nothing
    End Function

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        MessageBox.Show("Btn1")
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        MessageBox.Show("Btn2")
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        MessageBox.Show("Btn3")
    End Sub

End Class

La vida loca