Reputation: 199
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
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
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
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
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