Button prevents KeyDown event from triggering even with keypreview = true - c#

Steps to reproduce in VS Express 12:
Create a new Windows Forms Application project
Add a button
Set the Form KeyPreview to true
Add a keyDown event to the form
The event will not trigger as long as the button is present on the form
I have a project where I want to catch both keydown and keyup events, however, I can only seem to get the keyup event to work.
I have a form with a single panel, button and label on it. In the form the keyPreview property is set to true, and is linked to both the KeyDown and KeyUp events.
However, when I run the program, only the KeyUp event triggers.
I tried adding the event handlers manually by adding
this.KeyPreview = true;
this.KeyDown += new KeyEventHandler(Form1_KeyDown);
But it still does not work.
Any suggestions?
KeyUp event:
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
TriggerKey(e.KeyCode, false);
}
private void TriggerKey(Keys e, Boolean pKeyDown)
{
switch (e)
{
case Keys.Left:
mLeft = pKeyDown;
break;
case Keys.Right:
mRight = pKeyDown;
break;
case Keys.Down:
mDown = pKeyDown;
break;
case Keys.Up:
mUp = pKeyDown;
break;
}
}
My Form1_KeyDown event looks like this:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
TriggerKey(e.KeyCode, true);
}
Edit2:
I've tried removing the button from my form, and then both events trigger correctly. If I add it back in, the keyDown event stops working again. Why is the button interfering when the keypreview property is set?

KeyPreview is a VB6 compatibility feature, it isn't "native" Winforms. And it has a problem that exactly matches your issue. There are other Form methods that get a sniff at the keystroke first, before the code that looks at KeyPreview gets a chance to run and fire the KeyDown event. And they eat the navigation keystrokes first. Like the cursor keys that you are trying to see as well as the Tab key. This matches the VB6 behavior, it also couldn't see the cursor keys.
To stay ahead of that code, you'll need to override the ProcessDialogKey() method of the form. Like this:
protected override bool ProcessDialogKey(Keys keyData) {
switch (keyData) {
case Keys.Left:
//...
return true;
}
return base.ProcessDialogKey(keyData);
}

you're setting mUp on keyDown...? can you add all the related code context such as the mouse up event, also you may try to refresh, if you break does the even fire on key down?

Note that keyup is raised after keydown(if you want your mUp to remain true)

I saw in other similar posts that this could help
this.focus();
give it a try and let me know to keep looking for other ways

Related

WinForms ListBox intermittently changes the selection on CTRL+ENTER

I'm adding hotkey support to an app, and throughout, I use CTRL+ENTER as the hotkey for confirming dialogs.
I'm having a unique issue in the dialog below, which contains a ListBox. If the ListBox has the focus (it usually does) when the CTRL+ENTER hotkey is pressed, it intermittently shifts the ListBox selection down one position.
This creates a problem, since changing the selected item in the ListBox updates the New Customer Name field. What's happening is users choose the settings they want, hit CTRL+ENTER to execute the merge, and the settings suddenly change just before the merge occurs.
I'm not handling any key events on the ListBox, and the selection change is weirdly intermittent (perhaps 1 in 8 times). I also can't seem to get ENTER or CTRL+ENTER to cause selection changes intentionally.
What causes this behavior, and how do I suppress it?
Hotkey Handling
The approach I'm using to Form-level hotkey handling is to set Form.KeyPreview = true and to handle the KeyUp event. Based on this SO post, this is the cleanest way to support the handling of modifier keys, and it seems to work like a charm.
private void frmMerge_KeyUp(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Escape:
Close(); // Close Form
return;
case Keys.Enter:
if (e.Control) // CTRL+ENTER
ActionMerge(); // Merge Customer
return;
}
}
ListBox Use
The ListBox is setup very simply. It is populated once on Form Load;
private void frmMerge_Load(object sender, EventArgs e)
{
// Add all Customers to the list
foreach(Customer customer in Customers)
{
lbxNames.Items.Add(customer.Name);
}
// If there are items, select the first one
if (lbxNames.Items.Count > 0)
lbxNames.SelectedIndex = 0;
}
And it handles one event, SelectedIndexChanged, to update the New Customer Name TextBox
private void lbxNames_SelectedIndexChanged(object sender, EventArgs e)
{
txtName.Text = lbxNames.SelectedItem as string;
}
These are the only two places that the ListBox is touched in code.
I've found a workaround to the problem, but not determined the cause. My best guess is that I'm dealing with a keyboard hardware or driver issue, rather than a ListBox issue.
The intermittent nature of the problem was caused by the CTRL+M hotkey combination, which is used to open my Merge dialog. That M appears to stick in a key queue somewhere, perhaps in the hardware keyboard buffer or driver. On executing the CTRL+ENTER hotkey, that M fires a second time. In the ListBox, pressing M only shifts the selected record if there is a record beginning with M.
Workaround
I made two changes. First I suppress the M key in the ListBox. This works fine for me, since I only need arrow key and home/end navigation in the ListBox, and not alphabetic selection.
private void lbxNames_KeyDown(object sender, KeyEventArgs e)
{
// Suppress listbox hotkeys to prevent dialog hotkey conflicts
switch (e.KeyCode)
{
case Keys.M:
e.Handled = true;
e.SuppressKeyPress = true; // required
break;
}
}
Second, I changed my dialog-level hotkeys handler to use the ProcessCmdKey approach in place of KeyUp. The reason for this is that using KeyUp event handlers conflicted strangely between the Form level and the ListBox level. Many keys would get captured by the ListBox first, even with KeyPreview enabled.
protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, Keys keyData)
{
switch (keyData)
{
case Keys.Escape:
// Close the dialog
Close();
return true;
case Keys.Control | Keys.Enter:
// Perform the primary action
ActionMerge();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}

In winforms, on keydown event handler textbox event keypress is not working

In winform application, I am using a key down event to proceed to next field. It works properly but i want to handle an event of text box here as well like key press. If key down event on the form is available then key press event is not fired.
How can i resolve it.
Any suggestions?
Every KeyDown event receive a KeyEventArgs parameter.
Inside the KeyEventArgs parameter there is a property named SuppressKeyPress.
According to MSDN setting this property to true avoid the KeyPress event
If you set this property to false, the current control with focus will receive the keypress.
private void formMain_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
// Do your processing
....
e.Handled = true;
e.SuppressKeyPress = false;
}

Arrow key events not arriving

Basically, I have a form with a custom control on it (and nothing else). The custom control is completely empty, and the form has KeyPreview set to true.
With this setup, I am not receiving any KeyDown events for any arrow keys or Tab. Every other key that I have on my keyboard works. I have KeyDown event handlers hooked up to everything that has such events, so I'm sure I'm not missing anything.
Also of note is that if I remove the (completely empty) custom control, I DO get the arrow key events.
What on earth is going on here?
EDIT:
I added this to both the form and the control, but I'm STILL not getting arrow keys:
protected override void WndProc(ref Message m) {
switch (m.Msg) {
case 0x100: //WM_KEYDOWN
//this is the control's version. In the form, it's this.Text
ParentForm.Text = ((Keys)m.WParam).ToString();
break;
}
base.WndProc(ref m);
}
I also checked with Spy++, and determined that the form itself is not getting any WM_KEYDOWN messages, they're all going to the control. However, that said, the control IS getting the arrow key WM_KEYDOWN messages. Sigh.
Edit 2: I've also updated the ZIP file with this version. Please look at it, if you want to help...
Edit 3:
I've figured this out, sort of. The form is eating the arrow keys, probably in an attempt to maintain focus amongst its children. This is proven by the fact that I DO get the events if the form is empty.
Anyway, if I add this code to the form, I start getting the events again:
public override bool PreProcessMessage(ref Message msg) {
switch (msg.Msg) {
case 0x100: //WM_KEYDOWN
return false;
}
return base.PreProcessMessage(ref msg);
}
When I override this, the form doesn't get a chance to do its dirty work, and so I get my KeyDown events as I expect. I assume that a side effect of this is that I can no longer use my keyboard to navigate the form (not a big deal in this case, as it's a game, and the entire purpose of this exercise is to implement keyboard navigation!)
The question still remains about how to disable this "properly", if there is a way...
I've done some extensive testing, and I've figured everything out. I wrote a blog post detailing the solution.
In short, you want to override the ProcessDialogKey method in the form:
protected override bool ProcessDialogKey(Keys keyData) {
return false;
}
This will cause the arrow keys (and tab) to be delivered as normal KeyDown events. HOWEVER! This will also cause the normal dialogue key functionality (using Tab to navigate controls, etc) to fail. If you want to retain that, but still get the KeyDown event, use this instead:
protected override bool ProcessDialogKey(Keys keyData) {
OnKeyDown(new KeyEventArgs(keyData));
return base.ProcessDialogKey(keyData);
}
This will deliver a KeyDown message, while still doing normal dialogue navigation.
If focus is your issue, and you can't get your user control to take a focus and keep it, a simple work-around solution would be to echo the event to your user control on the key event you are concerned about. Subscribe your forms keydown or keypress events and then have that event raise an event to your user control.
So essentially, Form1_KeyPress would Call UserControl1_KeyPress with the sender and event args from Form1_KeyPress e.g.
protected void Form1_KeyPress(object sender, KeyEventArgs e)
{
UserControl1_KeyPress(sender, e);
}
Otherwise, you may have to take the long route and override your WndProc events to get the functionality you desire.

Forms not responding to KeyDown events

I've been working for a while on my Windows Forms project, and I decided to experiment with keyboard shortcuts. After a bit of reading, I figured I had to just write an event handler and bind it to the form's KeyDown event:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.Alt && e.KeyCode == Keys.O)
{
MessageBox.Show("Ctrl+Alt+O: magic!");
}
}
I did that the good ol' way of opening the Properties panel of the Visual Studio designer, then double-clicking on the KeyDown event of my form to generate the Form1_KeyDown event handler. But on testing my application, the form doesn't respond at all to the Ctrl+Alt+O keyboard shortcut. The Visual Studio designer did generate the code to bind the event handler to the form though:
private void InitializeComponent()
{
// ...
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
// ...
}
So I tried adding a Console.WriteLine() call to the handler to check that it was being called at all, but no luck on that either.
Also, I tried to set a breakpoint on the event binding call (shown just above) and found that the program reaches that breakpoint just fine. But any breakpoints I set within the method definition itself are never reached.
To make sure I was doing the first few steps correctly, I tried repeating them with:
A new form in the same solution.
Same issue: the form doesn't respond when I press my Ctrl+Alt+O keyboard shortcut and the debugger isn't even stepping into the event handler. Tried this again and it works.
A brand new WinForms solution.
It works perfectly: the message dialog appears (the Console.WriteLine() call also works).
So I'm quite lost here. What's preventing all the forms in this one project from receiving KeyDown events?
Does your form have KeyPreview property set to true?
Form.KeyPreview Property
Gets or sets a value indicating whether the form will receive key
events before the event is passed to the control that has focus.
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview.aspx
The most common piece of advice for this problem on StackOverflow and the MSDN1, 2 (including the accepted answer here) is quick and easy:
KeyDown events are triggered on a Form as long as its KeyPreview property is set to true
That's adequate for most purposes, but it's risky for two reasons:
KeyDown handlers do not see all keys. Specifically, "you can't see the kind of keystrokes that are used for navigation. Like the cursor keys and Tab, Escape and Enter for a dialog."
There are a few different ways to intercept key events, and they all happen in sequence. KeyDown is handled last. Hence, KeyPreview isn't much of a preview, and the event could be silenced at a few stops on the way.
(Credit to #HansPassant for those points.)
Instead, override ProcessCmdKey in your Form:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == Keys.Up)
{
// Handle key at form level.
// Do not send event to focused control by returning true.
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
That way, all keys are visible to the method, and the method is first in line to see the event.
Note that you still have control over whether or not focused controls see the KeyDown event. Just return true to block the subsequent KeyDown event, rather than setting KeyPressEventArgs.Handled to true as you would in a KeyDown event handler. Here is an article with more details.
Try setting the KeyPreview property on your form to true. This worked for me for registering key presses.

Press Escape key to call method

Is there a way to start a method in C# if a key is pressed? For example, Esc?
use the OnKeyPress Event of your textbox and in the event
if(e.KeyCode==Keys.Escape)
{
yourTextBox.Text = string.Empty;
}
As others have mentioned, handle the KeyDown or KeyUp event of the appropriate control. The KeyPress event would work for the Escape key as well, though it will not trigger for some keys, such as Shift, Ctrl or ALt.
If you want to execute this function anytime the user presses the Escape key, then you probably want to handle the event on the Form. If you do this, you will probably also want to set the Form's KeyPreview property to true. This will allow the Form control to receive the event even if the focus is currently inside of one of the child controls.
If you want the behavior to be specific to a control, such as clearing the text within a textbox that currently has focus, then you should handle the KeyDown or KeyUp event of the TextBox control. This way, your event handler will not be triggered if the user presses the escape key outside of the textbox.
In some situations you might want to prevent child controls from handling the same event that you've just handled. You can use the SuppressKeyPress property on the KeyEventArgs class to control this behavior:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
MessageBox.Show("Escape key pressed");
// prevent child controls from handling this event as well
e.SuppressKeyPress = true;
}
}
In case someone is looking for how to do this in a console application
if (Console.ReadKey().Key == ConsoleKey.Escape)
{
return;
}
I am writing WinForms application. User fills the textbox and if he wants to delete everything, he just clicks esc key on keyboard
I think you need to handle the KeyDown event.
You have to switch the form property "KeyPreview" to true or your events will not be fired. Handling these events alone will not do anything even though the events are correct. It will look to you like nothing really happens even though you have subscribed the proper event handlers.
First in Properties do > KeyPreview : True
Then :
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
//call your method here
}
}
Are you writing a Console application, a WinForms application or something else? Are you trying to capture the ESC key at all times (regardless of the focused window/application) or something else?
More context required.
If you're writing a Console app, then you should start looking at things like Console.ReadKey...
http://msdn.microsoft.com/en-us/library/system.console.readkey.aspx
With Event KeyPress...
//Escape
if (e.KeyChar == '')
{
this.DialogResult = DialogResult.Cancel;
e.Handled = true;
}
You can use KeyUp event too. I prefer it though.
private void Window_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) {
if (e.Key == Key.Escape) {
//WHAT WILL HAPPEN INSERT HERE
}
}
The basic answer is listed here several time
Implement Form_KeyDown
Private Sub frmCustomerSearch_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
Try
If e.KeyCode = Keys.Escape Then
ClearFindForm()
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Set form.keyPreview
form.KeyPreview = true
The additional thing you need to check is whether you have a button capturing ESC so it can be the form.cancelButton
to be sure ...
form.CancelButton = nothing
This is sneaky. If you have set that and forgot about it, the Escape key will not trigger the KeyDown event.
I was led to this because a button set to be the form.CancelButton does not seem to fire if it is invisible or on a non visible tab,so KEYDOWN is your only option.

Categories

Resources