在Winforms中捕获WinKey+D键序列

本文关键字:WinKey+D Winforms | 更新日期: 2023-09-27 18:05:52

我正试图使我的应用程序始终呈现在桌面级别。这意味着我的应用程序需要忽略像LWin+D或RWin+D这样的键序列。我试着让它这样工作:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (prefixSeen)
    {
        if (keyData == Keys.D)
        {
            MessageBox.Show("Got it!");
        }
        prefixSeen = false;
        return true;
    }
    if (keyData == Keys.LWin)
    {
        prefixSeen = true;
        return true;
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

但是它只捕获RWin/LWin按钮,没有D按钮。

我也试着创建我自己的消息过滤器,但我迷失在其中。所有这些消息和Bitwise:

    public class KeystrokMessageFilter : System.Windows.Forms.IMessageFilter
    {
        public KeystrokMessageFilter() { }
        public bool PreFilterMessage(ref Message m)
        {
            if ((m.Msg == 256 /*0x0100*/))
            {
                switch (((int)m.WParam) | ((int)Control.ModifierKeys))
                {
                    case (int)(Keys.Control | Keys.Alt | Keys.K):
                        MessageBox.Show("You pressed ctrl + alt + k");
                        break;
                    case (int)(Keys.Control | Keys.C): MessageBox.Show("ctrl+c");
                        break;
                    case (int)(Keys.Control | Keys.V): MessageBox.Show("ctrl+v");
                        break;
                    case (int)Keys.Up: MessageBox.Show("You pressed up");
                        break;
                }
            }
            return false;
        }
}
Application.AddMessageFilter(keyStrokeMessageFilter);

那么,我如何让我的应用程序捕捉/忽略R/LWin+D?

在Winforms中捕获WinKey+D键序列

这段代码注册了一个低级键盘钩子,并在按住windows键时监听D按键。如果检测到这种情况,钩子就会忽略按下的键。否则,它将沿。

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace KbHook
{
    public static class Program
    {
        const int HC_ACTION = 0;
        const int WH_KEYBOARD_LL = 13;
        const int WM_KEYDOWN = 0x0100;
        static IntPtr HookHandle = IntPtr.Zero;
        static Form1 Form1;
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern IntPtr SetWindowsHookEx(int idHook, KbHook lpfn, IntPtr hMod, uint dwThreadId);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool UnhookWindowsHookEx(IntPtr hhk);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern IntPtr GetModuleHandle(string lpModuleName);
        [STAThread]
        static void Main()
        {
            try
            {
                using (var proc = Process.GetCurrentProcess())
                    using (var curModule = proc.MainModule)
                    {
                        var moduleHandle = GetModuleHandle(curModule.ModuleName);
                        HookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, IgnoreWin_D, moduleHandle, 0);
                    }
                Form1 = new Form1();
                Application.Run(Form1);
            }
            finally
            {
                UnhookWindowsHookEx(HookHandle);
            }
        }
        [DllImport("user32.dll")]
        static extern short GetAsyncKeyState(Keys vKey);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
        static IntPtr IgnoreWin_D(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode == HC_ACTION
                && IsWin_D(wParam, lParam))
                return (IntPtr) 1; //just ignore the key press
            return CallNextHookEx(HookHandle, nCode, wParam, lParam);
        }
        static bool IsWin_D(IntPtr wParam, IntPtr lParam)
        {
            if ((int) wParam != WM_KEYDOWN)
                return false;
            var keyInfo = (KbHookParam) Marshal.PtrToStructure(lParam, typeof (KbHookParam));
            if (keyInfo.VkCode != (int) Keys.D) return false;
            return GetAsyncKeyState(Keys.LWin) < 0
                   || GetAsyncKeyState(Keys.RWin) < 0;
        }
        delegate IntPtr KbHook(int nCode, IntPtr wParam, [In] IntPtr lParam);
        [StructLayout(LayoutKind.Sequential)]
        struct KbHookParam
        {
            public readonly int VkCode;
            public readonly int ScanCode;
            public readonly int Flags;
            public readonly int Time;
            public readonly IntPtr Extra;
        }
    }
}

参见如何使用LowLevelKeyboardHook钩住Win + Tab

我知道这个问题太老了。但是,嘿,我最近不得不开发一个应用程序,它将留在桌面上像一个小部件(倒计时应用程序为我们公司的年度盛会)。

我设法保持窗口留在后台(桌面winform),即使按下WinKey+D或WinKey+M通过windows低水平键盘挂钩。我使用了dss539的代码,并对其进行了改进,使我的winforms应用程序在桌面级别上保持活跃。

诀窍是当你遇到WinKey+D或WinKey+M时,将窗体的TopMost属性设置为true,并将其他键设置为false,并将句柄移交给窗口处理。

下面是示例代码:

In Program.cs - Main()

try
{
    using (var proc = Process.GetCurrentProcess())
    using (var curModule = proc.MainModule)
    {
        var moduleHandle = GetModuleHandle(curModule.ModuleName);
        HookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, IgnoreWin_DOrM, moduleHandle, 0);
    }
    frmForm1 = new frmIGS();
    Application.Run(frmForm1);
}
finally
{
    UnhookWindowsHookEx(HookHandle);
}

然后写你的键盘钩子方法:

static IntPtr IgnoreWin_DOrM(int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode == HC_ACTION
        && (IsWin_D(wParam, lParam) || IsWin_M(wParam, lParam)))
    {
        frmForm1.SetTopMost = true;
    }
    else
    {
        //if (frmForm1.SetTopMost)
        {
            frmForm1.SetTopMost = false;
        }
    }
    return CallNextHookEx(HookHandle, nCode, wParam, lParam);
}
static bool IsWin_D(IntPtr wParam, IntPtr lParam)
{
    if ((int)wParam != WM_KEYDOWN)
        return false;
    var keyInfo = (KbHookParam)Marshal.PtrToStructure(lParam, typeof(KbHookParam));
    if (keyInfo.VkCode != (int)Keys.D) return false;
    return GetAsyncKeyState(Keys.LWin) < 0
            || GetAsyncKeyState(Keys.RWin) < 0;
}
static bool IsWin_M(IntPtr wParam, IntPtr lParam)
{
    if ((int)wParam != WM_KEYDOWN)
        return false;
    var keyInfo = (KbHookParam)Marshal.PtrToStructure(lParam, typeof(KbHookParam));
    if (keyInfo.VkCode != (int)Keys.M) return false;
    return GetAsyncKeyState(Keys.LWin) < 0
            || GetAsyncKeyState(Keys.RWin) < 0;
}

我公开了form的公共属性,它在代码中设置了最顶层的属性!

private bool topMost = false;
public bool SetTopMost
{
    get
    {
        return topMost;
    }
    set
    {
        this.TopMost = topMost = value;
    }
}

中提琴。现在我的代码在后台保持活跃,不管windows的键组合。但不会停留在其他应用程序的顶部,允许用户做他们的正常工作!这就是要求!

在Windows 10中运行良好:)

尝试解决方案从如何检测何时窗口窗体被最小化?在事件触发之前捕获并处理它;它应该允许你忽略它