glopes
glopes

Reputation: 4380

How to prevent context menu from closing when holding the Alt key?

I need to allow the Alt key to be used as a modifier when selecting certain menu entries in a ContextMenuStrip. This works fine with all other modifiers like Ctrl or Shift. However, for some reason Alt automatically closes the context menu.

I tried using the Closing event in the context menu, and the menu item AutoClose property, but this is proving to be more clunky than anticipated. Specifically, even though the context menu is kept open, the application MenuStrip is activated (which may explain why the context menu closes in the first place).

I've tried searching around but I found surprisingly few questions about this, and none on stack overflow, so I wonder whether there might be a better way to work around this that I have missed?

Example code showing that suppressing MenuStrip activation does not prevent context menu from closing:

class MainForm : Form
{
    MenuStrip menuStrip;
    ContextMenuStrip contextMenuStrip;

    public MainForm()
    {
        KeyPreview = true;
        menuStrip = new MenuStrip();
        menuStrip.Items.Add("&File");
        Controls.Add(menuStrip);

        contextMenuStrip = new ContextMenuStrip();
        contextMenuStrip.Items.Add("&OptionA");
        contextMenuStrip.Items.Add("&OptionB");
        ContextMenuStrip = contextMenuStrip;
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {
        if (e.Alt)
        {
            e.Handled = true;
            e.SuppressKeyPress = true;
        }
        else base.OnKeyDown(e);
    }
}

Upvotes: 1

Views: 597

Answers (1)

Zer0
Zer0

Reputation: 7354

This is by design, so you'll have to do the state tracking yourself. But this will definitely stop Alt from reaching the MenuStrip.

This is low level keyboard filtering, so you'll have to decide what to do when Alt is pressed entirely on your own, however.

You could also change the conditional to check for Alt plus some state.

In short, returning true from PreFilterMesssage will stop it from reaching your app.

static void Main()
{
    //...SNIP...
    Application.AddMessageFilter(new AltFilter());
    //...SNIP...
}

public class AltFilter : IMessageFilter
{
    private static ushort WM_SYSKEYDOWN = 0x0104;

    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg == WM_SYSKEYDOWN && Control.ModifierKeys == Keys.Alt)
        {
            //Do your own special thing instead
            return true;
        }
        return false;
    }
}

Upvotes: 1

Related Questions