Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I have developed a custom dockable window with textboxes, comboboxes and buttons for use in ArcMap. After the user clicks on a button in the dockable window a function is invoked. How can I invoke the function/button_click-event using short cuts. Where do I have to wire the event?:

this.KeyDown +=new KeyEventHandler(MyDockableWindow_KeyDown);

Where do I have to impement the event?

private void MyDockableWindow_KeyDown(object sender, KeyEventArgs e)
    {
        switch (e.KeyCode)
        {
            case Keys.F1:
                button1.PerformClick();
                break;
            case Keys.F2:
                button2.PerformClick();
                break;
            case Keys.F3:
                button3.PerformClick();
                break;
            case Keys.F4:
                button4.PerformClick();
                break;
        }
    }
share|improve this question
add comment

2 Answers

If your Methods is capsulated to ArcMap Command, you could use AcceleratorTable.

IAcceleratorTable pAccTable = m_app.Document.Accelerators;
UID uid = new UIDClass();
//Some command uid
uid.Value = "{E1F29C6B-4E6B-11D2-AE2C-080009EC732A}";
bool addedAcc = pAccTable.Add(uid, System.Convert.ToInt32(System.Windows.Forms.Keys.A), true, false, false) ;

But, if other than the above like you want to execute your own methods, you need to use SetWindowsHookEx win32 api and global hooking keyboards event. This is the sample,

public class KeyEventsHooker {

    private const int WH_KEYBOARD_LL = 13;
    private const int WM_KEYDOWN = 0x0100;

    [StructLayout(LayoutKind.Sequential)]
    public struct KBDLLHOOKSTRUCT {
        public ushort KeyCode;
        public ushort Scan;
        public uint Flags;
        public uint Time;
        public IntPtr ExtraInfo;
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto,
     CallingConvention = CallingConvention.StdCall)]
    public static extern int SetWindowsHookEx(int idHook, HookProc lpfn,
    IntPtr hInstance, int threadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto,
     CallingConvention = CallingConvention.StdCall)]
    public static extern bool UnhookWindowsHookEx(int idHook);

    [DllImport("user32.dll", CharSet = CharSet.Auto,
     CallingConvention = CallingConvention.StdCall)]
    public static extern int CallNextHookEx(int idHook, int nCode,
    IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);

    private int hHook = 0;

    public delegate int HookProc(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
    public event Action<System.Windows.Forms.Keys> OnKeyDown;

    public void Hook() {

        hHook = SetWindowsHookEx(WH_KEYBOARD_LL, new HookProc(KeyHookProc), IntPtr.Zero, 0);
    }

    public void Unhook() {

        UnhookWindowsHookEx(hHook);
    }

    private int KeyHookProc(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam) {

        if (nCode < 0) {
            return CallNextHookEx(hHook, nCode, wParam, ref lParam);
        }
        else {

            switch (wParam.ToInt32()) {

                case WM_KEYDOWN:

                    if (OnKeyDown != null) {

                        OnKeyDown((System.Windows.Forms.Keys)lParam.KeyCode);
                    }

                    break;
            }

            return CallNextHookEx(hHook, nCode, wParam, ref lParam); 
        }
    }
}

And, you could hook in your DockableWindow Class like this,

public DockableWindow1(object hook) {
    InitializeComponent();
    this.Hook = hook;

    _keyEventsHooker = new KeyEventsHooker();
    _keyEventsHooker.Hook();
    _keyEventsHooker.OnKeyDown += new Action<Keys>(_keyEventsHooker_OnKeyDown);
}

You should consider that this sample is ignoring such as shift, alt and ctrl keys. But it is not a basis of GIS, so I will omit these parts.

share|improve this answer
    
Darksanta, thank you for your answer. Since the buttons are inside the dochable window (usercontrol), I can not use the ArcGIS shortcuts (IAcceleratorTable). I will give a try to your second solution, to see how it works You wrote that the sample is ignoring keys such as shift, alt and ctrl, which is a disadvantage. I found out an other way to get shortcuts working in the dockable window. I post it as an answer, since I have no possibility to add code blocks to a comment. –  Saleika Apr 26 '13 at 19:24
add comment
up vote 1 down vote accepted

I found two solutions for my question. The first one is to override the ProcessCmdKey method in my DockableWindow class e.g:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
    if (keyData == (Keys.Alt | Keys.A)) {
        button1.PerformClick();
        return true;
    }
    if (keyData == (Keys.Alt | Keys.B)) {
        button3.PerformClick();
        return true;
    }
    if (keyData == (Keys.Alt | Keys.C)) {
        button3.PerformClick();
        return true;
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

The second solution is to use the built-in support for mnemonics in the buttons. Considering a button with a text property like Set&A produces a self-documenting shortcut without needing any code. Operated by the user, in this example, by typing Alt+A.

In both cases the dockable window must have the focus or else it wouldn't work.

Both solutions are inspired by a post of Hans Passant on stackoverflow: http://stackoverflow.com/questions/10468200/key-events-processcmdkey

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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