Fire Form KeyPress event - c#

I have a C# winform, on which I have 1 button.
Now, when I run my application, the button gets focus automatically.
The problem is KeyPress event of my form does not work because the button is focused.
I have tried this.Focus(); on FormLoad() event, but still the KeyPress event is not working.

You need to override the ProcessCmdKey method for your form. That's the only way you're going to be notified of key events that occur when child controls have the keyboard focus.
Sample code:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
// look for the expected key
if (keyData == Keys.A)
{
// take some action
MessageBox.Show("The A key was pressed");
// eat the message to prevent it from being passed on
return true;
// (alternatively, return FALSE to allow the key event to be passed on)
}
// call the base class to handle other key events
return base.ProcessCmdKey(ref msg, keyData);
}
As for why this.Focus() doesn't work, it's because a form can't have the focus by itself. A particular control has to have the focus, so when you set focus to the form, it actually sets the focus to the first control that can accept the focus that has the lowest TabIndex value. In this case, that's your button.

Try setting the Form's KeyPreview property to True.

Set keyPreview = true on main form

I would use one of the following:
Set the TabIndex property of the button to 0.
Set the IsDefault property of the button to true - So, It will be fired when pressing the ENTER key.

I had this same problem and I know this question was answered long ago, but my solution to this problem came from another stack overflow question in which my only button grabbed and kept focus. I accepted the users advice and created a button which couldn't get focus.
Maybe someone will find this useful:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace I2c_Programmer {
class NoSelectButton : Button{
public NoSelectButton() {
SetStyle(ControlStyles.Selectable, false);
}
}
}
Go into your designer, where the button is created and switch out the new System...button with your new class "new NoSelectButton();"

Related

Focus picturebox when entering form

I am creating a simple game for school in C#, where I am controlling a character using the WASD keys. The character is taken from a sprite sheet and put into an imagelist. The imagelist is in a picturebox.
Everything works fine when it's just the picturebox in the form, but when I add a button or something else, it's like it lose focus. It doesn't respond.
I have searched endless pages for a solution to set focus on the picturebox when the form opens, but I haven't found anything that works.
I would really appreciate some help.
Edit: It's WinForms.
The PictureBox cannot take the focus. It is intended as a way to show an image but not intended to allow user input such as via the keyboard.
A crude approach would be to intercept the OnKeyDown event on the Form itself and then test for the keys of interest. This will work as long as the control that has the focus, such as your Button, does not want to process those keys itself.
A better approach would be to override ProcessCmdKey() method of the Form. This method is called on the target control, such as your Button, to decide if the key is special. If the Button does not recognize it as special then it calls the parent control. In this way your Form level method will be called for each key press that is not a special key for the actual target. This allows the Button to still process a ENTER key which is used to press the Button but other keys will be processed by your Form.
Lastly, to intercept all keys before they are handled by any of the controls on the Form you would need to implement the IMessageFilter interface. Something like this...
public partial class MyWindow : Form, IMessageFilter
{
public MyWindow()
{
InitializeComponent();
Application.AddMessageFilter(this);
}
public bool PreFilterMessage(ref Message m)
{
// WM_KEYDOWN
if (m.Msg == 0x0100)
{
// Extract the keys being pressed
Keys keys = ((Keys)((int)m.WParam.ToInt64()));
// Test for the A key....
if (keys == Keys.A)
{
return true; // Prevent message reaching destination
}
}
}
return false;
}
I found event MouseHover with pictureBox1_Hover calling pictureBox1.Focus() worked. When the mouse was hovered over the PictureBox in question, it would gain focus. Other than that, it didn't seem that calling pictureBox1.Focus() during form load had any effect on the focus.
this.pictureBox1.MouseHover += new System.EventHandler(this.pictureBox1_Hover);
private void pictureBox1_Hover(object sender, EventArgs e)
{
pictureBox1.Focus();
}
It worked for me!

How do I capture Keys.F1 regardless of the focused control on a form?

I used KeyDown event and some simple code like if (e.KeyCode == Keys.F1) to capture F1 is pressed on a form BUT if there are some text boxes on the form or if there are some spreadsheets with Dock Fill on the form then the code above gets useless and does nothing. But I want to do something when user presses F1 on this form. so how do we capture a specific keydown event like F1 on the whole form..and I do not want to go to the route that capture the KeyDown of all other controls on the form and pass them to the Form for processing. is there any cleaner way to do this?
Yes, indeed there is. The correct way for the form to handle key events regardless of the control that currently has the input focus is to override the ProcessCmdKey method of your form class:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.F1)
{
MessageBox.Show("You pressed the F1 key");
return true; // indicate that you handled this keystroke
}
// Call the base class
return base.ProcessCmdKey(ref msg, keyData);
}
You return true to indicate that you handled the keystroke and don't want it to be passed on to other controls. If you do want it to be passed on to the event handlers for other controls, simply return false.
And you're best off ignoring the KeyPreview property. That's an anachronism from the VB 6 days and not really the preferred way of doing this in the .NET world. Further reading: Disadvantage of setting Form.KeyPreview = true?
Set the form's KeyPreview to true. This will make sure the form get the keypress messages first and if you handle it, you can set e.Handled = true so it doesn't passed down to the controls.
Turn on KeyPreview and every key press in the form will get routed through it's key event handlers first.
Another way is to Override the ProcessCmdKey function http://msdn.microsoft.com/en-us/library/system.windows.forms.control.processcmdkey(v=VS.100).aspx

Send Keyboard Events from one Form to another Form

my question is quite simple:
Our C# application has one MainForm with a menu and several keyboard shortcuts associated with the menu entries.
Now we need to trigger the menu entries from some child forms too. But since the MainForm is inactive when one of the child forms is active, the shortcuts do not work.
Is there a simple way to propagate all keyboard events from the child form to the 'Owner' form? Or just to another form in general?
Ah, and we cannot use some low level windows stuff, because we need to run the application on Mono/Linux too.
EDIT:
The exact problem i have is to trigger the menu items with the same shortcut from another form. Of course without updating code in the forms if the menu changes of new items are added.
This is what fixed it for me:
public class MainForm : Form
{
public bool ProcessCmdKeyFromChildForm(ref Message msg, Keys keyData)
{
Message messageCopy = msg;
messageCopy.HWnd = this.Handle; // We need to assign our own Handle, otherwise the message is rejected!
return ProcessCmdKey(ref messageCopy, keyData);
}
}
public class MyChildForm : Form
{
private MainForm mMainForm;
public MyChildForm(MainForm mainForm)
{
mMainForm = mainForm;
}
// This is meant to forward accelerator keys (eg. Ctrl-Z) to the MainForm
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (mMainForm.ProcessCmdKeyFromChildForm(ref msg, keyData))
{
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
Did you try something like this?
ParentForm : Form
{
public NotifyKeyPress(KeyPressEventArgs e)
{
OnKeyPress(e);
}
}
ChildForm : Form
{
ParentForm _parent;
public ChildForm(ParentForm parent)
{
_parent = parent;
KeyPress += KeyPressHandler;
}
public KeyPressHandler(object sender, KeyPressEventArgs e)
{
if (_parent != null)
{
_parent.NotifyKeyPress(e);
}
}
}
I think you want to set KeyPreview on the parent form to true
When this property is set to true, the form will receive all KeyPress, KeyDown, and KeyUp events. After the form's event handlers have completed processing the keystroke, the keystroke is then assigned to the control with focus. For example, if the KeyPreview property is set to true and the currently selected control is a TextBox, after the keystroke is handled by the event handlers of the form the TextBox control will receive the key that was pressed. To handle keyboard events only at the form level and not allow controls to receive keyboard events, set the KeyPressEventArgs.Handled property in your form's KeyPress event handler to true.
EDIT:
the answer in this question might be helpful:
The ToolStrip.AllowMerge property "gets or sets [...] whether multiple MenuStrip, ToolStripDropDownMenu, ToolStripMenuItem, and other types can be combined." (MSDN).
This means that you can:
"Use the AllowMerge property to enable multiple-document interface (MDI) children to combine their respective menus in the MDI parent." (AllowMerge property, Remark, MSDN)
See also:
MergeAction
MergeIndex
This, I hope, will help you get what you want. Now, I don't know if this is proper to Windows Forms or if it shall work on Linux too once built.
I presume by inactive you mean that it doesn't have focus?
The cleanest way to do this is to have each form expose events that relate to their menus being manipulated. When you create the forms, subscribe them to each other (or from child to MainForm or whatever way the flow needs to go). When the menu is clicked, execute your extra event and the other form will receive this.
Does that help? I believe that this is better than trying to force a message manually as it will be self-documenting code that the forms need to react to each other.
A more "away from the problem" approach, do you need two forms or can you refactor the UI design?
There is much simpler way to do this. Menu items should trigger appropriate method calls.
Then you can call these methods anywhere in application.
Instead of binding key shortcuts to menu items on the main form you can create a custom key-processing method that reacts to the key shortcuts. Put this method in the main form. Then invoke this method from all child forms on a key event. #Adam Driscoll's code is much compatible with this approach.

Adding an F5 Hotkey in C#

I'm making a windows app (WinForms) and would like my application to call a method when the user presses F5 - this should work no matter what the user is doing but they must be using the program - I don't want to use global hooks - any ideas?
Override the form's ProcessCmdKey on your main form and look for F5.
protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
{
bool bHandled = false;
// switch case is the easy way, a hash or map would be better,
// but more work to get set up.
switch (keyData)
{
case Keys.F5:
// do whatever
bHandled = true;
break;
}
return bHandled;
}
Check out the Form.KeyPreview property, it will allow you to trap all KeyDown, KeyUp and KeyPress events at the form level before allowing them to be processed by individual elements.
MSDN Form.KeyPreview page
If you have only one form that can have focus, you can set the KeyPreview property of that form to true and handle the KeyPress event.
The KeyPreview property will cause the form to receive all key presses, regardless which control on the form has the input focus.

C#: Trouble with Form.AcceptButton

I have a form with an button which is set as the AcceptButton of the form. The form has several other controls. Now when I press Enter on other controls the form gets closed because of the accept button on the form. Same goes for CancelButton. How do I handle this. I tried hooking on to keypress keydown event of the form and controls. None works. Any work around for this?
Thanks a ton,
Datte
That is how the AcceptButton property works. It specifies the button that is automatically clicked whenever you press <Enter>.
If you don't want this behaviour, don't set it as the AcceptButton. There is no other reason to do it.
Not exactly sure about how you expect your form to function, but you could do something like the following to have a little more control over things:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Enter)
{
// do something
}
if (keyData == Keys.Escape)
{
// do something else
}
return base.ProcessCmdKey(ref msg, keyData);
}
You can remove AcceptButton from form and set the KeyPreview property on the form that'll handle its KeyDown event. There you can check for the Enter key and take the action accordingly.
This is one of the feature of the form i.e.
if button does not have a focus if you still want desired code to be executed when user click Enter...
Set the AcceptButton property of a form to allow users to click a button by pressing the ENTER even if the button does not have focus.
Regards.
Try This One In VB>net
If CType(Me.ActiveControl, Button).Name = Button1.Name Then
End If

Categories