Click here to Skip to main content
14,770,038 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
I'm working on a program that maps keystrokes to custom commands (for example Control+F2 executes a command. I want to allow my users to change the keystroke commands.

What I've done is in process command key captures the key and checks for a shortcut against a keys dictionary.

I need to figure out a way to display the stored keys enum. I've looked high and low for a solution, but having users see commands such as Control + oemkey1 is really ridiculous.

I've looked at MapVirtualKey, the keys converter, etc. Most solutions say to use the onkeypress event, but if I've stored a keys enum, there is no keypress event short of faking a hidden textbox which seems hacky.

anyone have any thoughts?
Posted
Comments
Sergey Alexandrovich Kryukov 20-Oct-11 19:48pm
   
Why do you think is hard? So far, you did not explain any real problem except that you did not find a solution.
--SA

This is a bit of a bodge, but it works...

Menu items can have shortcut keys, which are effective over the whole of the application. These keys can be changed by setting the ShortcutKeys property.

Interestingly, they work even if the menu item, or branch, or even the whole menu system is set to Visible=false. So the user doesn't have to be able to see the menu to use the shortcuts...:laugh:

As I say, it's a bit of a bodge, but it is maintainable, and it saves all the faff of adding the key handler to every control in the app which can have keyboard input.
   
But how do you convert the accelerator to a user friendly string? if you go to the accelerator property of a toolstrip menu item and try to set an accelerator to say Control + ?, you set Control + Shift + OEMQuestion, the shortcut will show Control + OEMQuestion.

There has to be a way to format a string to Control + ? without capturing the string in the keypress event of an editor and storing the keys state as well as a user string for this.
   
The Question Mark is named System.Windows.Forms.Keys.OemQuestion

Every Key in this Class is given an alphanumeric name.

I suggest you use if or switch to determine what character is pressed to get that symbol.

OR

You may just be talking about setting the ShortcutKeyDisplayString property to "Control + ?"?
   
v3
Right, the event KeyPress won't help you. You need to work with KeyDown. All you need is the key dictionary. Use System.Collections.Generic.Dictionary. For a value, use some appropriate delegate type. For a key, use a structure if two members: KeyCode and KeyModifiers, such as it is done here: http://msdn.microsoft.com/en-us/library/system.windows.forms.keyeventargs.keycode.aspx[^] (don't use this class for storage of key even if you use Forms, this is just for example). For this structure, override the method System.Object.ToString, to present the shortcut to the user. Let's say, you call this structure Shortcut.

Now, letting the user to select keys for a shortcut is easy. Create some focusable custom control, focus it and suggest the user press desired key combination. Yes, here is where a handler of KeyPress helps you. From the data of event arguments passed to the handler, pick up the Shortcut value, add to the dictionary or replace existing value. When a user selected shortcut keys, present the result in the same custom control. For goodness sake, don't use TextBox, make it a custom control. (The recipe for Forms: use overridden method OnPaint. When its shortcut is created/modified, call Invalidate on this control.)

Use this Shortcut for dual purpose: 1) to present shortcuts to the users, 2) to use it as a lookup dictionary to invoke the command delegates.

Many techniques are described in detail in my CodeProject article: Dynamic Method Dispatcher[^].

—SA
   
+5 Good question !

"I need to figure out a way to display the stored keys enum. I've looked high and low for a solution, but having users see commands such as Control + oemkey1 is really ridiculous."

I'd like to ask you what exactly you mean here when you say "users see commands:" does this mean:

1. at all times in your UI the key-command equivalents are visible to the user ?

2. or, do you wish to have some dynamic UI appear (pop-up?, modal window ?, etc.) at times when the user chooses to see the key-command mappings ? If this is the case, perhaps this display of the current-mappings is combined with an interface for editing them ?

Even before I noticed the word "Dictionary" in SAK's response (which I did not read), as I scrolled down the answers, the first thought in my mind was that the underlying data structure you will want to use is a Dictionary<ShortCut, string>, so that you can easily 'grab' a readable description of a 'Shortcut' to present to the user.

The question, then, is what type of class/structure is 'Shortcut' ? And, I'd have to think carefully about how you could differentiate complex shortcuts like control-alt-shift-f2: which is a very interesting question, and one I will pursue as I have time, but here's a quick 'sketch' of a ShortCuts collection (rendered as a static clas) and a ShortCut class: Hope these initial reactions are useful.
public static class ShortCuts
{
    public static Dictionary<ShortCut, string> CurrentShortCuts = new Dictionary<ShortCut, string>();

    public static void AddShortCut(string uDescription)
    {
        CurrentShortCuts.Add(new ShortCut(uDescription), uDescription);
    }
}

public class ShortCut
{
    // stub for constructor
    // other parameters to be determined
    public ShortCut(string uDescription)
    {
        UserDescription = uDescription;
    }

    public string UserDescription;

    // modifier keys
    public bool IsAltDown;
    public bool IsControlDown;
    public bool IsShiftDown;

    // all other required key downs
    public List<int> RequiredKeys;

    // should an instance of this class
    // contain an Action or Func
    // so the method can be directly executed
    // from the instance ?
    // Public Action PerformCommand ... ?
}
best, Bill
   
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900