3

I'm making form level shortcuts with form application.

First, it works with strip menus, however their shortcuts must be combination of any modifier and a word or decimal key. I need only a word or decimal key shortcut. Therefore it does not fit my needs.

And I tried a method that KeyDown and KeyUp events with form's KeyPreview set to true. If I handled the word or decimal keys with Handled and SuppressKeyPress set to true in those events, the child control cannot receive the input even though the control is TextBox or NumericUpDown that is a control that allows text input. Overriding ProcessCmdKey has the same issue.

And then, I tried to check the focusing control actually needs the input by calling focusing control's IsInputKey and IsInputChar. Yes, you cannot call them normally because these methods are protected. I used reflection. But I had no luck. These were not working as I expected.

Finally, I applied a branch that checks the focusing control is TextBox or something allowing input. I had no luck with this either. Because the NumericUpDown's real focus control is a private class called UpDownBase.UpDownEdit. It means that some other controls can have similar mechanism that cannot expect in build time. In short, it can cause bugs.

I think, I could solve this issue if there was a way to catch unhandled input in last key handling phase such like bubbling. But I couldn't find information about it for form applications.

Do I have to override ALL of child controls' ProcessCmdKeys?

Really isn't there a fancy way to solve this problem?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 1
    WinForms is designed in a way that it is easy to do usual things... So if something is hard to do, it is suspicious as your UI would not works the way most user expect it to work. – Phil1970 Dec 19 '17 at 01:03
  • Are you talking about system-wide key inputs? It is not really clear what you are trying to achieve? – bic Dec 19 '17 at 01:16
  • Here is my quick solution. I have changed searching focused control method. In previous, it searched to the depest control. The source was from [this](https://stackoverflow.com/a/439606/1655141). Currently, searching a type is exists in control tree to solve `NumericUpDown` case. It works fine but I don't think it's fast. –  Dec 19 '17 at 01:19
  • @bic As I wrote, form level. In other words, handle shorcut's routine when my form is foreground form and the currently focused control does not allow text input such as `Button`, `CheckBox`, `RadioButton` etc. –  Dec 19 '17 at 01:23
  • @donggas90: "I'm making form or global level shorcuts with form application." sorry, this is where my confusion came from. – bic Dec 19 '17 at 01:30
  • @bic My apologies. That sentence can cause confusion that you've done. –  Dec 19 '17 at 01:32
  • @donggas90: No problem, this seems to be what you're looking for. The key term is application-level keyboard hooks. https://stackoverflow.com/a/34384189/99804 – bic Dec 19 '17 at 01:35
  • @bic Thanks for link. I didn't test about it but it seems not filtering the situation that focusing control allow text input. In this case, the shortcut must not be fired. –  Dec 19 '17 at 01:40
  • @donggas90: Well you can add filtering to the event handler as you need. Thats all I've got at the moment. – bic Dec 19 '17 at 01:42
  • @bic Form application already can receive all of inputs in form level. Therefore need not hook. Filtering the case is real problem. I mentioned about `NumericUpDown` case in original question. In the end, I applied a temporary solution that worte it in above comment. –  Dec 19 '17 at 01:46
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/161487/discussion-between-bic-and-donggas90). – bic Dec 19 '17 at 01:48

1 Answers1

0

Here is my quick solution. I have changed searching focused control method.

In previous, it searching to the deepest active control. The source was from here. This way caused skipping NumericUpDown case because it is also a container, and returned its private control.

Therefore, I have changed it to searching a control type instead taking the deepest one in active control chain.

static bool IsFocusedControlType<T>(Control control, out T focused)
    where T : Control
{
    if (control is T t)
    {
        focused = t;
        return true;
    }
    var container = control as IContainerControl;
    while (container != null)
    {
        control = container.ActiveControl;
        if (control is T tt)
        {
            focused = tt;
            return true;
        }
        container = control as IContainerControl;
    }
    focused = null;
    return false;
}

static bool CanConsumeKey(Form sender, KeyEventArgs e)
{
    if (IsFocusedControlType(sender, out NumericUpDown ud))
    {
        return false;
    }
    if (IsFocusedControlType(sender, out TextBox tb) && !tb.ReadOnly)
    {
        return false;
    }
    if (IsFocusedControlType(sender, out ListView lv) && lv.LabelEdit)
    {
        return false;
    }
    if (IsFocusedControlType(sender, out TreeView tv) && tv.LabelEdit)
    {
        return false;
    }
    if (IsFocusedControlType(sender, out ComboBox cb) && 
        cb.DropDownStyle != ComboBoxStyle.DropDownList)
    {
        return false;
    }
    return true;
}

It works fine but I don't think it's fast.