312

I'm looking for a best way to implement common Windows keyboard shortcuts (for example Ctrl+F, Ctrl+N) in my Windows Forms application in C#.

The application has a main form which hosts many child forms (one at a time). When a user hits Ctrl+F, I'd like to show a custom search form. The search form would depend on the current open child form in the application.

I was thinking of using something like this in the ChildForm_KeyDown event:

   if (e.KeyCode == Keys.F && Control.ModifierKeys == Keys.Control)
        // Show search form

But this doesn't work. The event doesn't even fire when you press a key. What is the solution?

1
  • It's really strange that Winforms doesn't seem to have specific functionality for this like the native Windows API does.
    – Stewart
    Commented Aug 19, 2019 at 11:02

9 Answers 9

509

You probably forgot to set the form's KeyPreview property to True. Overriding the ProcessCmdKey() method is the generic solution:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
  if (keyData == (Keys.Control | Keys.F)) {
    MessageBox.Show("What the Ctrl+F?");
    return true;
  }
  return base.ProcessCmdKey(ref msg, keyData);
}
4
  • 3
    This works well, but only detects it for me if the form is the active window. Anyone know how to bind it so in any window view it is possible?
    – Gaʀʀʏ
    Commented Jul 18, 2012 at 3:41
  • In some situations KeyPreview is quite indispensable. For example, when pressing a shortcut is required to suppress input but nevertheless to allow a separate MenuStrip event to fire. ProcessCmdKey approach would force the duplication of event firing logic.
    – Saul
    Commented Jun 10, 2014 at 11:13
  • 1
    Hmm, no, the Form's KeyDown event handler is quite distinct from a menu item's Click event handler. You still do the exact same way, either call the event handler method directly (no need for it to be exclusively called by an event) or refactor the common logic into a separate method. Commented Jun 10, 2014 at 11:26
  • 30
    "What the Ctrl+F?" LOL
    – kchad
    Commented May 19, 2018 at 20:11
83

On your Main form

  1. Set KeyPreview to True
  2. Add KeyDown event handler with the following code

    private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.N)
        {
            SearchForm searchForm = new SearchForm();
            searchForm.Show();
        }
    }
    
1
  • 6
    + for , Set KeyPreview to True .. was missing that Commented Oct 30, 2013 at 12:01
21

The best way is to use menu mnemonics, i.e. to have menu entries in your main form that get assigned the keyboard shortcut you want. Then everything else is handled internally and all you have to do is to implement the appropriate action that gets executed in the Click event handler of that menu entry.

5
  • 1
    The problem is that main form doesn't use common windows menus. It uses custom navigation panel that is used to show child forms. The search forms are invoked by click on the ToolStripButton on the child form.
    – Rockcoder
    Commented Dec 30, 2008 at 12:16
  • menu mnemonics real sample?
    – Kiquenet
    Commented Feb 6, 2019 at 9:33
  • 1
    @Kiquenet learn.microsoft.com/en-us/dotnet/api/… Commented Feb 6, 2019 at 13:11
  • 1
    Mnemonics are a distinct concept from shortcut keys, and there are important differences in how they operate. In short, mnemonics are the underlined characters used to access menus, menu commands and dialog controls using the keyboard. OTOH, shortcut keys are a way to access commands without going through the menus, and moreover they can be arbitrary keystrokes like Ctrl+F or F5, not restricted to character keys.
    – Stewart
    Commented Aug 15, 2019 at 8:49
  • 1
    @Stewart That is correct! My answer wasn’t trying to imply that all keyboard shortcuts are mnemonics, merely that menu mnemonics is the easiest way of getting this functionality. Unfortunately, as Rockcoder’s comment clarifies, this solution doesn’t seem appropriate here. I still recommend it as the preferable solution, where possible. For a general solution, Hans’ accepted answer is the way forward. Commented Aug 15, 2019 at 10:03
12

You can even try this example:

public class MDIParent : System.Windows.Forms.Form
{
    public bool NextTab()
    {
         // some code
    }

    public bool PreviousTab()
    {
         // some code
    }

    protected override bool ProcessCmdKey(ref Message message, Keys keys)
    {
        switch (keys)
        {
            case Keys.Control | Keys.Tab:
              {
                NextTab();
                return true;
              }
            case Keys.Control | Keys.Shift | Keys.Tab:
              {
                PreviousTab();
                return true;
              }
        }
        return base.ProcessCmdKey(ref message, keys);
    }
}

public class mySecondForm : System.Windows.Forms.Form
{
    // some code...
}
8

If you have a menu then changing ShortcutKeys property of the ToolStripMenuItem should do the trick.

If not, you could create one and set its visible property to false.

1
  • No I do't have a menu. ToolStripButton for search is actually located on the BindingNavigator control, so adding a menu is probably not an option.
    – Rockcoder
    Commented Dec 30, 2008 at 16:06
6

From the main Form, you have to:

  • Be sure you set KeyPreview to true( TRUE by default)
  • Add MainForm_KeyDown(..) - by which you can set here any shortcuts you want.

Additionally,I have found this on google and I wanted to share this to those who are still searching for answers. (for global)

I think you have to be using user32.dll

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);

    if (m.Msg == 0x0312)
    {
        /* Note that the three lines below are not needed if you only want to register one hotkey.
         * The below lines are useful in case you want to register multiple keys, which you can use a switch with the id as argument, or if you want to know which key/modifier was pressed for some particular reason. */

        Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);                  // The key of the hotkey that was pressed.
        KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF);       // The modifier of the hotkey that was pressed.
        int id = m.WParam.ToInt32();                                        // The id of the hotkey that was pressed.


        MessageBox.Show("Hotkey has been pressed!");
        // do something
    }
}

Further read this http://www.fluxbytes.com/csharp/how-to-register-a-global-hotkey-for-your-application-in-c/

0
4

Hans's answer could be made a little easier for someone new to this, so here is my version.

You do not need to fool with KeyPreview, leave it set to false. To use the code below, just paste it below your form1_load and run with F5 to see it work:

protected override void OnKeyPress(KeyPressEventArgs ex)
{
    string xo = ex.KeyChar.ToString();

    if (xo == "q") //You pressed "q" key on the keyboard
    {
        Form2 f2 = new Form2();
        f2.Show();
    }
}
1
  • 8
    First, overriding ProcessCmdKey is the recommended way of handling a keystroke intended to do some command-like operation, which is what the OP was asking about. Second, you've misunderstood Hans' comment about setting KeyPreview to true; he was just telling the OP why his technique wasn't working. Setting KeyPreview to true is not needed for using ProcessCmdKey.
    – RenniePet
    Commented Jul 12, 2014 at 5:58
2

In WinForm, we can always get the Control Key status by:

bool IsCtrlPressed = (Control.ModifierKeys & Keys.Control) != 0;
0

The VB.NET version of Hans' answer.

(There's a ProcessCmdKey function template in Visual Studio.)

  Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean

    If (keyData = (Keys.Control Or Keys.F)) Then
      ' call your sub here, like
      SearchDialog()
      Return True
    End If

    Return MyBase.ProcessCmdKey(msg, keyData)
  End Function

End Class

Not the answer you're looking for? Browse other questions tagged or ask your own question.