views:

2138

answers:

5

I want to create a component that allows us to have keyboard shortcut chords associated with an arbitrary command like the visual studio IDE does.

A: 

Use the form's OnKeyPressed event and check if the desired key combination was pressed in the eventArgs argument

Dror Helper
+1  A: 

Menu controls have property named ShortCut where you can assign a value. When you press that shortcut key, that menu item will be invoked. Use that property for the commands that has a corresponding menu.

If you need shortcuts that won't be available on the menus, then you'll have to handle that your self via the KeyUp or KeyDown events, either on the form or the control. A KeyEventArgs object will be passed to your handler, and you can check which key is pressed, and whether the Ctrl, Alt or Shift keys were also pressed.

Sample code from MSDN:

// Handle the KeyDown event to determine the type of character entered into the control.
private void textBox1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
    // Initialize the flag to false.
    nonNumberEntered = false;

    // Determine whether the keystroke is a number from the top of the keyboard.
    if (e.KeyCode < Keys.D0 || e.KeyCode > Keys.D9)
    {
        // Determine whether the keystroke is a number from the keypad.
        if (e.KeyCode < Keys.NumPad0 || e.KeyCode > Keys.NumPad9)
        {
            // Determine whether the keystroke is a backspace.
            if(e.KeyCode != Keys.Back)
            {
                // A non-numerical keystroke was pressed.
                // Set the flag to true and evaluate in KeyPress event.
                nonNumberEntered = true;
            }
        }
    }
    //If shift key was pressed, it's not a number.
    if (Control.ModifierKeys == Keys.Shift) {
        nonNumberEntered = true;
    }
}
jop
A: 

In addition to the above answers, using an ampersand in the caption of a button, or menu item, will cause it to be underlined, and accessible by using ALT + the letter you preceded by the ampersand &.

IOW, if you have a menu item captioned &File it will display with an underline under the F and the user can trigger the menu by clicking ALT+F.

hmcclungiii
A: 

Depends on the scope of the keyboard shortcut. If you want a keyboard shortcut to be used from any control on the Form without using a toolbar.

Set

Form.KeyPreview = true;

on the form. This will allow all keypress events to get filtered by the KeyPress, KeyDown and KeyUp events at the form level which will allow a single keyboard shortcut to be handled in one location instead of duplicating the functionality in all user controls.

MSDN: Form.KeyPreview Property

Richard R
+7  A: 

In answer to the question of keyboard chords specifically, I do not believe there is a ready-made option available to you at this point.

However, it should be simple enough to model. I would create a single class, perhaps KeyboardChordProvider. It will need to know about keyboard events at the form level. As stated elsewhere, the Form.KeyPreview property must be true. It may be enough for this provider to subscribe to the Form.KeyPress event. You could do all of this in the provider's constructor if you passed in the form.

You would need to register the potential keystrokes with the provider.

Internally this instance will track the current state. Whenever a keystroke is observed that represents the first key of the chord, you would update the provider's state and raise an event so that a subscriber could set text: (CTRL+W) was pressed. Waiting for second key of chord...

If the next keystroke matches a potential secondary option, then you have a match and could raise a ChordPressed event containing the details of the strokes entered. Alternatively, you might just call a particular callback that was given to the provider at the time the chord was registered (to avoid having a switch statement or some other dispatch in the ChordPressed event handler).

If, at any time, a keystroke does not match a potential next option, then you would reset the state of the provider.

Internal to the provider you might model the possible keystrokes using a tree structure. The current state of the provider is just a particular tree node. At the beginning, the root node would be active. If a child matches a keystroke then it becomes the current node in anticipation of the next stroke. If the child was a leaf node, then an entire chord has matched and you would raise ChordPressed event (passing the chain of strokes that got you to that point) or invoke the callback stored in the leaf. Whenever no keystroke matches a child, reset back to making the root node active.

I think this design would achieve what you want.

Drew Noakes
Thanks for the proposed solution Drew. More importantly. Thanks for not going half-way with a response.
JJS
Excellent instructions. I just used this in my own project.
Daniel Straight
Recording this interface here so I remember to implement my component later. http://msdn.microsoft.com/en-us/library/system.windows.forms.imessagefilter.aspx
JJS
Drew, thanks for the Form.KeyPreview info. That was the bit I was missing.
Stewbob