5

The standard Win + M keyboard shortcut minimizes open windows, but it does not minimize a borderless form.

I'm thinking of capturing key events of Win + M in KeyDown event but no luck, since it does not capture both but only captures the first key.

I can't programmatically minimize it using a keyboard shortcut

Any idea on how to minimize my for form by keyboard shortcut? or can I capture Win + M to trigger minimize function?

I'm using borderless form. To reproduce the problem, create a Form and set its BorderStyle to None and run the application. When you press Win + M, all the windows minimize, but my borderless form stays normal.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
myelxx
  • 314
  • 3
  • 11
  • 1
    Do you know why your form isn't minimized when WIN+M is pressed? Do you have some particular kind of form or do you have some particular event handling on minimization? – Matteo Umili Jan 26 '21 at 14:41
  • @MatteoUmili i'm using a borderless form – myelxx Jan 26 '21 at 14:42
  • @Zer0 can u give a more detailed view of your fix? – myelxx Jan 26 '21 at 14:43
  • thank you! will try to ask a new one @Zer0 – myelxx Jan 26 '21 at 14:58
  • 1
    I open the question as the suggested duplicate is not a proper answer for this question. None of the suggested solutions work when you press Win+M. – Reza Aghaei Jan 26 '21 at 15:37
  • @myelxx If normal keyboard shortcuts like Ctrl+M is acceptable for your case, then `ProcessCmdKey` is the way to go, otherwise if you want to make Win+M working for your borderless form (as expected to work for all forms) then `ProcessCmdKey` is not the way. – Reza Aghaei Jan 26 '21 at 15:43
  • Hope it's clearer now :) – Reza Aghaei Jan 26 '21 at 15:45
  • In case the OP wants to use another key combination for minimizing the form and don't want to fix the behavior when Win+M is pressed, the ProcessCmdKey would be the way to go, or if they want an app-side shortcut, then IMessageFilter. Both are addressed in the [suggested duplicate](https://stackoverflow.com/q/2790913/3110834). – Reza Aghaei Jan 26 '21 at 19:25

2 Answers2

3

As an option you can enable system menu (having minimize window style) for your borderless form, then while it doesn't show the control box, but the minimize command will work as expected.

Add the following piece of code to your Form and then Win + M will work as expected:

private const int WS_SYSMENU = 0x80000;
private const int WS_MINIMIZEBOX = 0x20000;
protected override CreateParams CreateParams
{
    get
    {
        CreateParams p = base.CreateParams;
        p.Style = WS_SYSMENU | WS_MINIMIZEBOX;
        return p;
    }
}
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
2

As a totally different option you can register a low level keyboard hook using SetWindowsHookEx and check if you received the Win + M, then minimize the window and let the key goes through other windows.

Add the following piece of code to your Form and then Win + M will work as expected:

private const int WH_KEYBOARD_LL = 13;
[StructLayout(LayoutKind.Sequential)]
private struct KBDLLHOOKSTRUCT
{
    public Keys vkCode;
    public int scanCode;
    public int flags;
    public int time;
    public IntPtr dwExtraInfo;
}
private delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(
    int idHook, HookProc lpfn, IntPtr hmod, uint dwThreadId);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(
    IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern short GetKeyState(int keyCode);
private const int KEY_PRESSED = 0x8000;
private static bool IsKeyDown(Keys key)
{
    return Convert.ToBoolean(GetKeyState((int)key) & KEY_PRESSED);
}

private IntPtr ptrHook;
private HookProc hookProc;
private IntPtr CaptureKeys(int code, IntPtr wParam, IntPtr lParam)
{
    if (code >= 0)
    {
        KBDLLHOOKSTRUCT objKeyInfo = 
            (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(
                lParam, typeof(KBDLLHOOKSTRUCT));
        if (objKeyInfo.vkCode == (Keys.M) &&
            (IsKeyDown(Keys.LWin) || IsKeyDown(Keys.RWin)))
        {
            this.WindowState = FormWindowState.Minimized;
            return (IntPtr)0;
        }
    }
    return CallNextHookEx(ptrHook, code, wParam, lParam);
}
bool HasAltModifier(int flags)
{
    return (flags & 0x20) == 0x20;
}
protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    var module = Process.GetCurrentProcess().MainModule;
    hookProc = new HookProc(CaptureKeys);
    ptrHook = SetWindowsHookEx(
        WH_KEYBOARD_LL, hookProc, GetModuleHandle(module.ModuleName), 0);
}
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • @Zer0 I tried `IMessageFilter` first but I couldn't get desired result. Maybe I had a mistake, I'll give it another try. – Reza Aghaei Jan 26 '21 at 16:45
  • I will give it a try, to be honest, I was biased to use hook so by first failure in IMessageFilter I gave up. – Reza Aghaei Jan 26 '21 at 16:47
  • @Zer0 I believe my attempts with IMessageFilter was right and Windows+M will not be trapped by IMessageFilter. I was able to trap a non-hotkey combination like Win+Z, when the application has focus, but the thing is Win+M is a standard windows hotkey, the other thing is the expected behavior is Win+M is also expected to work (minimize all windows) even if your application doesn't have focus. At least the message (if it's received by the application, is not a keydown/up/press message, it should be something else.) – Reza Aghaei Jan 26 '21 at 19:00
  • Both my solutions for this question can satisfy the requirement: Minimizing a borderless form when Win+M is pressed. My other answer is much convenient. – Reza Aghaei Jan 26 '21 at 19:01
  • 1
    Same here, I tried many combination. I even couldn't find anything useful using Spy++ - whatever message it is, I *guess*, since the borderless window doesn't have WS_SYSMENU and WS_MINIMIZEBOX styles, the window doesn't receive this message. – Reza Aghaei Jan 26 '21 at 19:20