I've got a form and am subscribing to the KeyUp event and handling the ALT key, this is working great but only when my form has the focus, if a control on the form has focus then this no longer works; what can I use to capture the keys when controls have focus? I'd rather not have to subscribe to every KeyUp event on every on the form controls...
Thanks.
Will setting the form's KeyPreview property to true work for you?
Try overriding ProcessCmdKey from your form. This will be raised regardless of which controls have focus, so long as the form is active. You will have to do a little more work checking the keydata. Ex:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if ((keyData & Keys.Alt) == Keys.Alt)
{
Debug.WriteLine("ALT");
}
return base.ProcessCmdKey(ref msg, keyData);
}
Related
I have an application with several forms and controls in a window. One of them is a custom control which has two member scrollbars, vertical and horizontal. Now when I press the arrow keys of the keyboard (with that custom control selected/in-focus) the scrollbars get the event Scrollbar.Scroll. But I need to handle the arrow keys for other purposes, only mouse to scroll.
The OnKeyDown of the custom control receives the event only after any of the two scrollbars are focused which is after the first key stroke. So, I don't get the first arrow press to handle, which is not good.
I also tried adding handler to Scrollbar.KeyDown event. Did not work.
How do I handle the arrows so that it does not scroll the view?
You could try overloading ProcessDialogKey in the intended component as follows:
protected override bool ProcessDialogKey(Keys keyData)
{
return true;
}
Works like a charm.
Try with the PreviewKeyDown event.
It check for it BEFORE the key is pressed.
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.
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.
I have a Data Grid View inside a control that is displayed in a certain area in an application.
I'd like this activity grid to refresh when F5 is pressed.
It's easy enough to do this when the Activity Grid View is the currently focused element on the screen by handling the Key Up event, but this obviously doesn't work when another element (e.g. the menu bar) was the last thing that was clicked on.
Is there a way to track key presses in this case as well? I don't have access to the code outside my data grid view/control.
The answer to this may be a clear no, but I wanted to make sure I wasn't missing something obvious in making this work.
No.
If you don't have access to the other controls that may have focus at the time, there's no way to pass the key up message from them to your control.
You can do some global keyboard event handling on the Form the controls are on.
If you add this to your form you can get the global key events before they are send to the control.
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
switch (keyData)
{
case Keys.F5:
// Send Refesh Event To Grid
return true; // Mark Key As Handled
// Add Any Extra Command Keys Here
}
return base.ProcessCmdKey(ref msg, keyData); // Resend To Base Function
}
Have you tried to capture the event on the Form itself and then call the event handler for the data grid? You'll have to set KeyPreview to true for the form to get notified of keyboard events.
The best way to handle this, is to get the main application form to handle all keypresses.
In order to do this, set the main Form property "KeyPreview" to True.
Then, handle all your KeyUp events on the main form.
More information on KeyPreview here: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview.aspx
I am using the webbrowser control in visual studio. I think it is a wrapper around internet explorer. Anyway all is going well I am using it in edit mode however I can't get he document's keydown event to fire (in order to catch ctrl+v) anyone had similar problems with it?
Anyone have a solution?
Indeed the webbrowser control is just a wrapper of the IE browser control.
Is your problem that the controls PreviewKeyDown not working? Seems to be working for me as long as the control has focus.
webBrowser1.PreviewKeyDown += new PreviewKeyDownEventHandler(webBrowser1_PreviewKeyDown);
....
private void webBrowser1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) {
Console.WriteLine(e.KeyCode.ToString() + " " + e.Modifiers.ToString());
if (e.Modifiers == Keys.Control && e.KeyCode == Keys.V) {
MessageBox.Show("ctrl-v pressed");
}
}
but perhaps I am not completely understanding?
You should override a "WndProc()" method in derived class from WebBrowser control or in form, which contains a webbrowser. Or you can catch the keys with custom message filter ( Application.AddMessageFilter ). With this way you can also filter a mouse actions.
I had same problems years ago, but I don't remember which way i used.
You mentioned the KeyDown event of the 'document'. If you are referring to the WebBrowser control's Document property (type HtmlDocument) it only has events for MouseUp, MouseDown, etc but not keyboard events. You want to register your event handler with the WebBrowser control's PreviewKeyDown delegate. You may also want to set the value of the WebBrowser control's WebBrowserShortcutsEnabled property to false if you don't want standard Internet Explorer shortcuts to have their usual effect. You should also make sure that the WebBrowser control is in focus by manually calling its Focus() method and setting the TabStop property of other controls on the form to false. If this is not possible because you have other controls on the form that need to accept focus, you also might want to add an event handler for the KeyDown event of the Form itself.
How to trap keystrokes in controls by using Visual C#
e.g.
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
const int WM_SYSKEYDOWN = 0x104;
if ((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN))
{
switch(keyData)
{
case Keys.Down:
this.Parent.Text="Down Arrow Captured";
break;
...
}
}
return base.ProcessCmdKey(ref msg,keyData);
}