How to pass key events from a control to a form?

advertisements

I am aware of the KeyPreview property of a Windows Form, and this allows the Form to receive the key events before they get passed to the focused control.

However, I want the Form to receive the event after it has been to the focused control.

As a test I have placed a TextBox on a Form. Upon typing in the TextBox it should perform it's default behavior, upon pressing certain key commands. Ctrl-S, F1, etc, I want those to bubble through the TextBox up to the Form to be handled at a higher level. These commands are those that the TextBox doesn't do by default.

I do need the events to go through the TextBox first though. The application this functionality is needed in is more complex than this simple example. For example, when the TextBox is the focused control it should perform the default Copy & Paste using Ctrl-C and Ctrl-V. However, when various other controls are focused these commands need to end up at the top-most Form-level to be processed there.

Edit: It seems that input events go from Form to Focused Control and not the other way around like I was expecting. If it went from Focus to Form I probably wouldn't be having the problem I have.

Edit2: Having read (briefly) though this article: http://www.codeproject.com/KB/WPF/BeginWPF3.aspx I am now assuming that the sort of 'bubbling' that I was expecting to just 'be there' is only available in WPF, and not standard C#. I think I'm going to have to re-think the way in which the users interact with my app as opposed to writing swathes of ugly code.

Big points to anyone who can reply on doing WPF-style bubbling in C# without ugly code.


You may still use KeyPreview property but check which control is focused, if it is a textbox then do nothing, else if it is another control - say RichTextBox - then handle the pressed keys. To get the currently focused control, you may need to access Win32 API. Example: Created a new Windows forms application, add a text box and a richtext box in the form, set the KeyPreview property of the form to true, add an event handler for the KeyDown event of the form, the textbox, and the richtextbox. Also the following using statement:

using System.Runtime.InteropServices;//for DllImport

then replace the code of the form by the following code:

public partial class Form1 : Form
{
    // Import GetFocus() from user32.dll
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
    internal static extern IntPtr GetFocus();

    protected Control GetFocusControl()
    {
        Control focusControl = null;
        IntPtr focusHandle = GetFocus();
        if (focusHandle != IntPtr.Zero)
            // returns null if handle is not to a .NET control
            focusControl = Control.FromHandle(focusHandle);
        return focusControl;
    } 

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        Control focusedControl = GetFocusControl();
        if (focusedControl != null && !(focusedControl is TextBox) && e.Control && e.KeyCode == Keys.C)//not a textbox and Copy
        {
            MessageBox.Show("@Form");
            e.Handled = true;
        }
    }

    private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
    {
        if(e.Control && e.KeyCode == Keys.C)
            MessageBox.Show("@Control");
    }

    private void textBox1_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.C)
            MessageBox.Show("@Control");
    }
}