1

I'm working on a large C# winforms project. After explaining thousands of times to my end users that they have to press tab instead of enter in textboxes, datagrids, and wherever, I decided to add a checkbox somewhere, so users can optionally set if they want to replace enter with tab. I don't like it myself, because I think weird stuff will happen, but I'd like to try it.

The thing is that I have lots of forms, and lots of places where I would have to set a keydown event or similar. I would like to put all of this in one place, on application level. Is there a way for this?

rvgiesen
  • 11
  • 3
  • Bad idea, If you replace enter key with tab, what will you do when user needs to press enter? – Sriram Sakthivel Sep 05 '13 at 12:31
  • I know, I've warned them lots of times about that. That's why they want the on/off switch, so whenever they need enter (which is almost never, apparently) they can switch it. Maybe I should start working for a different company. – rvgiesen Sep 05 '13 at 14:49

4 Answers4

0

I guess this is not possible, since some controls will expose the keydown event diverently (for example in cells of the gridview). You could iterate through all controls in a form recursively and assign the event for the basic controls though. The event itself then could be handled in a central place

DerApe
  • 3,097
  • 2
  • 35
  • 55
0

I'll advice you to create a separate class that the constructor accept the parameters you need (like the textbox), You create global variables and assign the parameters to the variables in the constructor.

Then Create the event handler in the class and then you can put your code in the event handler using the variables.

You can then call the class wherever you need the keydown event

0

Form level (you can implement the behaviour in the base form and inherit from it):

this.KeyPreview = true;
 protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
                PressedEnter();
            base.OnKeyDown(e);
        }
        private bool PressedEnter()
        {
           bool res = false; // true if handled
           Control ctr = GetFocusedControl();
           if (ctr != null && ctr is TextBox)
           {
               res = this.SelectNextControl(ctr, true, true, true, true);
           }
           return res;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
        internal static extern IntPtr GetFocus();
        private Control GetFocusedControl()
        {
            Control focusedControl = null;
            IntPtr focusedHandle = GetFocus();
            if (focusedHandle != IntPtr.Zero)
                // if control is not a .Net control will return null
                focusedControl = Control.FromHandle(focusedHandle);
            return focusedControl;
        }

It probably can be done on application level too: In your main form you'll have to prefilter messages from the message loop (using message filter: Application.AddMessageFilter(your filter)), check for message WM_KEYDOWN = 0x100, check if the pressed key was ENTER, then handle it same as above.You do it only once, in your main form, it'll work on all your child forms.

In your main form class:

protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.mouseMessageFilter = new MouseMoveMessageFilter();
            this.mouseMessageFilter.TargetForm = this;
            Application.AddMessageFilter(this.mouseMessageFilter);
        }

protected override void OnClosed(EventArgs e)
        {
            Application.RemoveMessageFilter(this.mouseMessageFilter);

            base.OnClosed(e);
        }

private class MouseMoveMessageFilter : IMessageFilter
        {
            public FormMain TargetForm { get; set; }

            public bool PreFilterMessage(ref Message m)
            {
                if (TargetForm.IsDisposed) return false;

                int numMsg = m.Msg;

                int VK_RETURN=0x0D;
                if (m.Msg == 0x100 &&(int)m.WParam == VK_RETURN) // WM_KEYDOWN and enter pressed
                {
                      if (TargetForm.PressedEnter()) return true;
                }

                return false;
            }
        }

sources:

https://stackoverflow.com/a/435510/891715

http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx

http://www.autohotkey.com/docs/misc/SendMessageList.htm

Community
  • 1
  • 1
Arie
  • 5,251
  • 2
  • 33
  • 54
0

It's much simpler to use a MessageFilter in combination with SendKeys:

public partial class Form1 : Form, IMessageFilter
{
    public Form1()
    {
        InitializeComponent();
        Application.AddMessageFilter(this);
    }        
    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg == 0x100)//WM_KEYDOWN
        {
            if (m.WParam.ToInt32() == 0xd)//VK_RETURN = 0xd
            {         
                SendKeys.Send("{TAB}");                                        
                return true; //Discard the Enter key
            }
        }
        return false;
    }
}
King King
  • 61,710
  • 16
  • 105
  • 130