Question

Code:

Private Sub KeyHandling(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
    Select Case e.KeyCode
      Case Keys.Left
        btnPrev.PerformClick()
      Case Keys.Right
        btnNext.PerformClick()
      Case Keys.Up
        btnFirst.PerformClick()
      Case Keys.Down
        btnLast.PerformClick()
    End Select
End Sub

The KeyPreview property of my form is enabled.

Problem:

This code won't do anything, except when I hold the control key. Can anyone explain this? :)

Was it helpful?

Solution

This is because the cursor keys get intercepted early, before the KeyDown event fires. Winforms uses it to move the focus, just like Tab. When you hold down the Ctrl key, it is no longer a navigating key and your KeyDown event can see it.

You'd normally fix that by overriding IsInputKey() but that won't work if the form has any controls. They probably do if you set KeyPreview to true. The form never gets the focus, the controls do. You need to give up on KeyPreview, it's an old VB6 anachronism anyway, you catch the cursor keys by overriding ProcessCmdKey(). Like this:

Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
    If keyData = Keys.Left Then
        Console.WriteLine("left")
        Return True
    End If
    Return MyBase.ProcessCmdKey(msg, keyData)
End Function

OTHER TIPS

I assume you have Buttons on your form. When a button has the focus the user can change the focus by navigate with the arrow buttons between the buttons on the form. That is the reason why buttons don't receive the KeyDown event when an arrow key is pressed.

Following trick will help you to avoid this. For every button on your form set the PreviewKeyDown event to the following:

Private Sub Button1_PreviewKeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PreviewKeyDownEventArgs) Handles Button1.PreviewKeyDown
        e.IsInputKey = True
End Sub

What's happening is that the arrow keys are navigating the controls on the form, much like the Tab key. Each press of an arrow key is moving the focus from the currently active control to the next control in the same relative direction as that arrow key.

This interpretation of arrow keys is implemented at a higher level than the form's KeyDown event that you're handling. Each key press is actually being consumed by the ProcessDialogKey function, which is preventing that key event from ever being passed down to your KeyHandling method for any further processing.

The reason that everything works as you expect when the Ctrl key is held down is that the ProcessDialogKey function doesn't consume those events, allowing them to be passed on to your event handler method. The method's documentation tells us:

The method performs no processing on keystrokes that include the ALT or CONTROL modifiers.


If you don't want the arrow keys to navigate between your controls and only to "click" the aptly-named buttons, the solution should be obvious: You need to override the ProcessDialogKey method, add your custom key handling logic, and return a value of "True" to indicate that you processed the key yourself. Otherwise, you'll go ahead and call through to the base class so as not to disrupt the standard handling of things like Tab and Enter. Again, the documentation is refreshingly clear here:

When overriding the ProcessDialogKey method in a derived class, a control should return true to indicate that it has processed the key. For keys that are not processed by the control, the result of calling the base class's ProcessDialogChar method should be returned.

Simply add the following code to your form, and remove the KeyHandling method you have now:

Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean
    Select Case keyData
        Case Keys.Left
            btnPrev.PerformClick()
            Return True
        Case Keys.Right
            btnNext.PerformClick()
            Return True
        Case Keys.Up
            btnFirst.PerformClick()
            Return True
        Case Keys.Down
            btnLast.PerformClick()
            Return True
    End Select

    Return MyBase.ProcessDialogKey(keyData)
End Function

You need to provide a lot more information.

For starters, which form event are you handling. You show a handler with a non-standard handler name, but you don't show which event it is associated with. How are you associating it with an event?

In the form designer, look at the events tab in the Properties window. Do you have anything under KeyDown or KeyPress? That's where it needs to be.

Second, is it not doing anything because you don't have it hooked up to form keyboard events or because it runs but just doesn't do what you want? Set a breakpoint. Does the code ever get called?

Depending on the answer to the questions above, you may need to switch between handling the KeyDown or KeyPress event, depending on which characters you are trying to detect.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top