user1697111
user1697111

Reputation: 199

.NET Winforms Button KeyDown for Arrow keys

I have need for regulating program flow depending on Arrow pressing when Button is Active Control. Like this:

Private Sub btn_OK_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles btn_OK.KeyDown

    If e.KeyCode = Keys.Up Then
        If mode = mymodes.first Then
            firstcontrol.Focus()
        Else
            secondcontrol.Focus()
        End If
    End If
End Sub

As I can see KeyDown event is not fired at all with pressing any arrow key. Program instead do some his internal functionality and moves a focus by using form's tab order (as it seem's). KeyPreview is set to true on actual form.

Is here any way to get wanted functionality with arrow keys and without subclassing a button and using ProcessCmdKey?

Upvotes: 1

Views: 3355

Answers (4)

Martin Verjans
Martin Verjans

Reputation: 4796

Ok I did some research and effectively, the key_down event for the Arrow keys is captured before being processed...

Here is the source where it starts : http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs,7765d3efe64d5539

How it works

When a key is pressed, here is the list of what happens inside the control :

The function PreProcessControlMessageInternal is called.

This function will raise the event PreviewKeyDown on the control. Then it will call PreProcessMessage.

The function PreProcessMessage is called.

This function actually checks if anybody wants to use the key that has been pressed. In our case, (WM_KEYDOWN) :

  • The Control first calls ProcessCmdKey : if anyone want to decide this is a command key, return True and use that key. nobody else will see that key has been down

  • Then the Control calls IsInputKey() : If anyone decides this is an input key (TextBoxes for example), return True and process your key.

  • Then it calls ProcessDialogKey() : [Litterally from ReferenceSource]

is called to check for dialog keys such as TAB, arrow keys, and mnemonics

What to do

In your case, you have three possibilities, the last being the best (and easiest) :

Process the message when ProcessDialogKey() receives it :

Protected Overrides Function ProcessDialogKey(keyData As Keys) As Boolean
    If keyData = Keys.Up Or keyData = Keys.Down Or keyData = Keys.Left Or keyData = Keys.Right Then
        'Do whatever you want with the key
        Return True 'So the processing will stop
    End If
    Return MyBase.ProcessDialogKey(keyData)
End Function

Prevent the handling of this key so you can handle it in Button_keyDown()

Protected Overrides Function ProcessDialogKey(keyData As Keys) As Boolean
    If keyData = Keys.Up Or keyData = Keys.Down Or keyData = Keys.Left Or keyData = Keys.Right Then
        Return False
    End If
    Return MyBase.ProcessDialogKey(keyData)
End Function


Private Sub btn_OK_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles btn_OK.KeyDown

    If e.KeyCode = Keys.Up Then
        If mode = mymodes.first Then
            firstcontrol.Focus()
        Else
            secondcontrol.Focus()
        End If
    End If
End Sub

The Best Way

So actually (and based on the comment of Zohar Peled), the best way is to handle the PreviewKeyDown event, so you don't have to override any other method :

Private Sub Form1_PreviewKeyDown(sender As Object, e As PreviewKeyDownEventArgs) Handles MyBase.PreviewKeyDown
    'Do whatever here, all the keydown events will fall into this sub.
End Sub

Upvotes: 5

Zohar Peled
Zohar Peled

Reputation: 82474

Based on the answers to this question I came up with this (tested and working on my computer)

Private Sub Form1_PreviewKeyDown(sender As Object, e As PreviewKeyDownEventArgs) Handles MyBase.PreviewKeyDown
    If Me.Button1.Focused Then
        If e.KeyCode = Keys.Up Then
            If mode = mymodes.first Then
                firstcontrol.Focus()
            Else
                secondcontrol.Focus()
            End If
        End If
    End If
End Sub

Turns out that arrow keys are not handled by key_down event by default, but they are handled by the PreviewKeyDown event.

Upvotes: 0

Brandtware
Brandtware

Reputation: 483

I noticed that KeyUp works with Arrow-Keys on a Button while KeyDown does not. Would that help with your issue?

Upvotes: 0

Martin Verjans
Martin Verjans

Reputation: 4796

This code will only work if the focus is on the button.

Place this code at form level, so all controls that have the focus will pass up that event...

Private Sub myForm_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown

  If e.KeyCode = Keys.Up Then
      If mode = mymodes.first Then
          firstcontrol.Focus()
      Else
          secondcontrol.Focus()
      End If
  End If
End Sub

Upvotes: 0

Related Questions