在 Winforms 中捕获 WinKey+D 键序列
Catch WinKey+D key sequence in Winforms
我试图让我的应用程序始终显示在桌面级别。这意味着我的应用程序需要忽略 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 按钮。
我也曾尝试创建自己的邮件过滤器,但我迷失了方向。所有这些 messages 和按位:
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);
那么,我该如何申请 catch/ignore R/LWin+D?
尝试 How to detect when a windows form is being minimized? 中的解决方案,在事件触发之前捕获并处理它;它应该允许您忽略它。
此代码注册一个低级键盘钩子,并在按住 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;
}
}
}
另见 How to hook Win + Tab using LowLevelKeyboardHook
我知道这个问题太老了。但是,嘿,我最近不得不开发一个应用程序,它将像小部件一样保留在桌面上(为我公司的年度倒计时应用程序 bash)。
即使通过 windows 低级键盘钩子按下 WinKey+D 或 WinKey+M,我也设法让 window 留在后台(桌面 winform)。我使用了 dss539 的代码并对其进行了改进,以使我的 winforms 应用程序在桌面级别保持活跃。
诀窍是在遇到WinKey+D或WinKey+M时将TopMost 属性形式设置为true,其他键设置回false,交出windows句柄来处理.
下面是示例代码。
在 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;
}
我暴露了一个public 属性 for form,它在其代码中设置了最顶层的属性!
private bool topMost = false;
public bool SetTopMost
{
get
{
return topMost;
}
set
{
this.TopMost = topMost = value;
}
}
中提琴。现在,无论 windows 键组合如何,我的代码都在后台保持活动状态。但不会停留在其他应用程序之上,让用户做他们的正常工作!这就是要求!
它在 Windows 10 :)
中运行良好
我试图让我的应用程序始终显示在桌面级别。这意味着我的应用程序需要忽略 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 按钮。
我也曾尝试创建自己的邮件过滤器,但我迷失了方向。所有这些 messages 和按位:
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);
那么,我该如何申请 catch/ignore R/LWin+D?
尝试 How to detect when a windows form is being minimized? 中的解决方案,在事件触发之前捕获并处理它;它应该允许您忽略它。
此代码注册一个低级键盘钩子,并在按住 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;
}
}
}
另见 How to hook Win + Tab using LowLevelKeyboardHook
我知道这个问题太老了。但是,嘿,我最近不得不开发一个应用程序,它将像小部件一样保留在桌面上(为我公司的年度倒计时应用程序 bash)。
即使通过 windows 低级键盘钩子按下 WinKey+D 或 WinKey+M,我也设法让 window 留在后台(桌面 winform)。我使用了 dss539 的代码并对其进行了改进,以使我的 winforms 应用程序在桌面级别保持活跃。
诀窍是在遇到WinKey+D或WinKey+M时将TopMost 属性形式设置为true,其他键设置回false,交出windows句柄来处理.
下面是示例代码。
在 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;
}
我暴露了一个public 属性 for form,它在其代码中设置了最顶层的属性!
private bool topMost = false;
public bool SetTopMost
{
get
{
return topMost;
}
set
{
this.TopMost = topMost = value;
}
}
中提琴。现在,无论 windows 键组合如何,我的代码都在后台保持活动状态。但不会停留在其他应用程序之上,让用户做他们的正常工作!这就是要求!
它在 Windows 10 :)
中运行良好