我为自己编写了一个程序来简化工作。该程序的本质是启动,最小化到托盘并听键盘进行组合键
然后出现了一个bug:需要按下组合键时,系统其余部分忽略它,例如:我按了ctrl + n,程序运行,但系统响应按n,将其输入,例如,浏览器行,或打开一个新窗口
e.handled = true - 没有帮助,因为它阻止了任何 ctrl 或 n 按下
我尝试按条件处理 e.handled - 通常是魔法 - ctrl 会改变行为,但 n 继续工作实验表明,我的程序似乎远非 n 个单击处理程序队列中的第一个
老实说,我发现很难准确解释算法的行为方式,因为我测试了 e.handled = true 位置的一百万个选项,我已经很困惑了,但这里有一个例子:
e.handled = true,无条件放置在处理程序的最开始,完全关闭整个系统的 ctrl 和 n
e.handled = true,只要按下 n 和之前的所有键,它根本不起作用,如下所示:
private void gkh_KeyDown(object sender, KeyEventArgs e)
{
//e.Handled = true;
if (_combinaison.IndexOf(e.KeyCode) == _combinaison.Count - 1)
{
bool before_pressed = true;
for (int i = 0; i < _combinaison.IndexOf(e.KeyCode); i++)
{
if (_pressed[i] == false)
{
before_pressed = false;
}
}
if (before_pressed == true)
{
e.Handled = true;
_f(_combinaison);
}
}
else
{
_pressed[_combinaison.IndexOf(e.KeyCode)] = true;
}
}
这是我的代码:
class Combinaison
{
public delegate void EventFunction(List<Keys> keys);
private globalKeyboardHook _gkh = new globalKeyboardHook();
private EventFunction _f;
private List<Keys> _combinaison;
private List<bool> _pressed = new List<bool>();
public Combinaison(List<Keys> combinaison, EventFunction f)
{
_f = f;
_combinaison = combinaison;
foreach (Keys k in _combinaison)
{
_gkh.HookedKeys.Add(k);
_pressed.Add(false);
}
_gkh.KeyDown += new KeyEventHandler(gkh_KeyDown);
_gkh.KeyUp += new KeyEventHandler(gkh_KeyUp);
}
private void gkh_KeyUp(object sender, KeyEventArgs e)
{
if (_combinaison.IndexOf(e.KeyCode) == _combinaison.Count - 1)
{
e.Handled = true;
}
_pressed[_combinaison.IndexOf(e.KeyCode)] = false;
}
private void gkh_KeyDown(object sender, KeyEventArgs e)
{
if (_combinaison.IndexOf(e.KeyCode) == _combinaison.Count - 1)
{
bool before_pressed = true;
for (int i = 0; i < _combinaison.IndexOf(e.KeyCode); i++)
{
if (_pressed[i] == false)
{
before_pressed = false;
}
}
if (before_pressed == true)
{
_f(_combinaison);
}
}
else
{
_pressed[_combinaison.IndexOf(e.KeyCode)] = true;
}
}
}
class globalKeyboardHook
{
#region Constant, Structure and Delegate Definitions
/// <summary>
/// defines the callback type for the hook
/// </summary>
public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);
public struct keyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYDOWN = 0x104;
const int WM_SYSKEYUP = 0x105;
#endregion
#region Instance Variables
/// <summary>
/// The collections of keys to watch for
/// </summary>
public List<Keys> HookedKeys = new List<Keys>();
/// <summary>
/// Handle to the hook, need this to unhook and call the next hook
/// </summary>
IntPtr hhook = IntPtr.Zero;
#endregion
#region Events
/// <summary>
/// Occurs when one of the hooked keys is pressed
/// </summary>
public event KeyEventHandler KeyDown;
/// <summary>
/// Occurs when one of the hooked keys is released
/// </summary>
public event KeyEventHandler KeyUp;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="globalKeyboardHook"/> class and installs the keyboard hook.
/// </summary>
public globalKeyboardHook()
{
hook();
}
/// <summary>
/// Releases unmanaged resources and performs other cleanup operations before the
/// <see cref="globalKeyboardHook"/> is reclaimed by garbage collection and uninstalls the keyboard hook.
/// </summary>
~globalKeyboardHook()
{
unhook();
}
#endregion
#region Public Methods
/// <summary>
/// Installs the global hook
/// </summary>
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
}
/// <summary>
/// Uninstalls the global hook
/// </summary>
public void unhook()
{
UnhookWindowsHookEx(hhook);
}
/// <summary>
/// The callback for the keyboard hook
/// </summary>
/// <param name="code">The hook code, if it isn't >= 0, the function shouldn't do anyting</param>
/// <param name="wParam">The event type</param>
/// <param name="lParam">The keyhook event information</param>
/// <returns></returns>
public int hookProc(int code, int wParam, ref keyboardHookStruct lParam)
{
if (code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
KeyEventArgs kea = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
{
KeyDown(this, kea);
}
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
{
KeyUp(this, kea);
}
if (kea.Handled)
return 1;
}
}
return CallNextHookEx(hhook, code, wParam, ref lParam);
}
#endregion
#region DLL imports
/// <summary>
/// Sets the windows hook, do the desired event, one of hInstance or threadId must be non-null
/// </summary>
/// <param name="idHook">The id of the event you want to hook</param>
/// <param name="callback">The callback.</param>
/// <param name="hInstance">The handle you want to attach the event to, can be null</param>
/// <param name="threadId">The thread you want to attach the event to, can be null</param>
/// <returns>a handle to the desired hook</returns>
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);
/// <summary>
/// Unhooks the windows hook.
/// </summary>
/// <param name="hInstance">The hook handle that was returned from SetWindowsHookEx</param>
/// <returns>True if successful, false otherwise</returns>
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
/// <summary>
/// Calls the next hook.
/// </summary>
/// <param name="idHook">The hook id</param>
/// <param name="nCode">The hook code</param>
/// <param name="wParam">The wparam.</param>
/// <param name="lParam">The lparam.</param>
/// <returns></returns>
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam);
/// <summary>
/// Loads the library.
/// </summary>
/// <param name="lpFileName">Name of the library</param>
/// <returns>A handle to the library</returns>
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
#endregion
}
您需要在系统中注册全局热键,然后它们将被拦截,而不是监听。
在这里,我在旧档案中找到了这样一个类。
对不起,课程没有优化,但我写了这个差不多7年前,收集英语互联网上的信息。然后该项目在 WPF 下重写,这只是 Winforms 下的存档副本。现在我不会每次都
MessageFilter为每个热键注册,但我会注册一个,它会捕获所有内容(可能,我需要对其进行测试)。但是你可以检查和细化。用法
登记
取消注册
添加
По случаю, дописал класс для работы с горячими клавишами, обновленная версия здесь.