William Thomas
William Thomas

Reputation: 2126

Stripping modifiers from Windows Form Keys

I'm currently working on a project that deals with setting hotkeys to perform actions. I have the hotkey functionality working, but I don't want to allow hotkeys to be set if the key is composed only of modifiers. For example, Ctrl + F is a valid hotkey but Ctrl + Alt is not.

I've tried several methods to strip the modifier keys off of the actual Keys enumeration object, then check it against Keys.None to determine whether or not it is composed of only modifier keys. However, in practice, this is not working out so well.

I tried this method first:

private Keys StripModifiers(Keys Key)
{
    return Key & ~Keys.Modifiers;
}

That didn't work, as my Ctrl key seems to be invoking the PreviewKeypress method with a KeyData property of LButton | ShiftKey | Control, which the Keys.Modifiers bitmask apparently does not fully catch.

I tried writing my own, more complex one:

private Keys StripModifiers(Keys Key)
{
    return Key &
        ~Keys.Alt &
        ~Keys.CapsLock &
        ~Keys.Control &
        ~Keys.ControlKey &
        ~Keys.LControlKey &
        ~Keys.LMenu &
        ~Keys.LShiftKey &
        ~Keys.LWin &
        ~Keys.MButton &
        ~Keys.Menu &
        ~Keys.NumLock &
        ~Keys.RButton &
        ~Keys.RControlKey &
        ~Keys.RMenu &
        ~Keys.RShiftKey &
        ~Keys.RWin &
        ~Keys.Scroll &
        ~Keys.Shift &
        ~Keys.ShiftKey;
}

However that didn't work either because pressing the A key, which simply invoked the event with the KeyData property of 65, reduces it to Keys.None, so it's too restrictive.

I'm pretty much at a loss at this point, has anybody ever encountered or solved this issue before?

Upvotes: 3

Views: 1721

Answers (1)

Hans Passant
Hans Passant

Reputation: 941990

Your original code is correct. You can make it a bit more legible with Key & Keys.KeyCode but that produces the same result. So you need to use this method in an Options window:

private static IsValidShortcutKey(Keys key) {
    return (key & Keys.KeyCode) != Keys.None;
}

You are then getting a little lost at talking about ProcessKeyPreview(). You should be using ProcessCmdKey() instead btw. That's later, long after the user picked a key that was deemed valid by IsValidShortcutKey(). And yes, any key will make that method run, regardless of whether it matches a shortcut you selected. With an extra dollup of confusion because the Keys.ToString() method does a lousy job of displaying the real keystroke, caused by the Keys enumeration having the [Flags] attribute. Cast to int to see the real value.

So you should have two very distinct chunks of code. One chunk in your Options menu that checks if a requested key stroke is valid. It should use IsValidShortcutKey().

And another chunks that checks if the key is pressed. Which should resemble something like this:

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
        if (keyData == keySelectedInConfig) {
            RunOperationSelectedInConfig();
            return true;
        }
        return base.ProcessCmdKey(ref msg, keyData);
    }

Upvotes: 2

Related Questions