我将非常极端地解释,因为我的另一篇文章似乎并不是很清楚。
我正在开发一个应用程序,你可以添加一个自定义热键和触发的uppon,它会做一些事情(无关紧要)。你可以说" RegisterHotKey"从头顶开始,但不幸的是,这根本不能帮助我。 User32 dll的RegisterHotKey不允许多个非修改键进入热键,例如:
RegisterHotKey(someWindowHandle, someHotkeyId, MOD_SHIFT, K_A); // Shift + A: ok!
RegisterHotKey(someWindowHandle, someHotkeyId, MOD_SHIFT | MOD_ALT, K_A); // Shift + Alt + A: 2 modifiers, ok!
RegisterHotKey(someWindowHandle, someHotkeyId, MOD_SHIFT, K_A | K_B); // Shift + A + B: not possible!
还有一些其他系统热键不能覆盖"但事实并非如此。
为了实现这一点,我创建了一个C ++ DLL来挂钩键盘并使用SendNotifyMessage()调用将数据发送到我的C#Windows窗体应用程序。数据以我的形式WndProc完美地发送和接收。
按键类如下:
using System.Collections.Generic;
using System.Windows.Input;
// Usage: Keystroke k = new Keystroke(Key.LShift, Key.A, Key.B)
public class Keystroke
{
public List<Key> Keys { get; private set; };
public Keystroke(params Key[] keys)
{
Keys = new List<Key>(keys);
}
}
正如我们所看到的,这是一个非常简单的片段。基本上,热键/按键可以由任意组合键组成,即使只有修改键(例如Shift + Alt)。
键盘事件以下列方式在我的WndProc中调度:
public class MainForm : Form
{
List<Keystroke> customHotkeys;
protected override void WndProc(ref Message m)
{
if (m.Msg == LowLevelKeyboardHook.Message)
{
WinAPI.KBDLLHOOKSTRUCT keyboardHook = (WinAPI.KBDLLHOOKSTRUCT)Marshal.PtrToStructure(m.LParam, typeof(WinAPI.KBDLLHOOKSTRUCT));
switch (m.WParam.ToInt32())
{
case WinAPI.WM_KEYDOWN:
case WinAPI.WM_SYSKEYDOWN:
DispatchKeyDownMessage(keyboardHook);
break;
case WinAPI.WM_KEYUP:
case WinAPI.WM_SYSKEYUP:
// ...
break;
}
}
base.WndProc(ref m);
}
private void DispatchKeyDownMessage(WinAPI.KBDLLHOOKSTRUCT keyboardHook)
{
// Convert the key code into a System.Windows.Input.Key enum value
Key key = KeyInterop.KeyFromVirtualKey(keyboardHook.vkCode);
foreach (Keystroke keystroke in customHotkeys)
{
if (keystroke.Keys.Contains(key))
{
Console.WriteLine("Woot! Some hotkey wraps this key.");
}
}
}
}
上述方法确实有效,但是,这似乎没有最好的表现。由于我们正在处理全局系统挂钩,因此必须非常快速地发送消息。为此,我考虑在击键和&#34; keystroke.Keys.Contains(键)&#34;中添加某种按位标志技术。不再需要,加快速度。有点 LIKE 这个:
public class Keystroke
{
public List<Key> Keys { get; private set; }
public Key Flags { get; private set; }
public Keystroke(params Key[] keys)
{
Keys = new List<Key>(keys);
foreach (Key key in keys)
{
Flags |= key;
}
}
}
// Usage: bool containsK = (someKeystroke.Flags & Key.W) == Key.W;
正如我们所知,System.Windows.Input.Key枚举没有[Flags]属性。但是,我可以使用System.Windows.Forms.Keys枚举,但仍然如文档中所述,我们无法使用组合按位运算的值,因为它们不是互斥的:documentation。< / p>
为了解决标记问题,我创建了这个类:
public class Flagger<T> where T : struct
{
private static Dictionary<int, ulong> dictionary = new Dictionary<int, ulong>();
static Flagger()
{
int indexer = 0;
// Since values can be duplicated, we use names instead
foreach (String name in Enum.GetNames(typeof(T)))
{
ulong value = 1UL << indexer++; // 0, 1, 2, 4, 8, 16...
Console.WriteLine("{0} key now corresponds to the value {1}", name, value);
dictionary.Add(name.GetHashCode(), value);
}
}
private ulong flags;
public void Add(T value)
{
// Create hash only once for both checkup and storation
int hash = value.ToString().GetHashCode();
if (Check(hash))
{
ulong flag = dictionary[hash];
flags &= flag;
}
}
public void Remove(T value)
{
// Create hash only once for both checkup and storation
int hash = value.ToString().GetHashCode();
if (Check(hash))
{
ulong flag = dictionary[hash];
flags &= ~flag;
}
}
/// <summary>
/// Tests whether a value has already been added or not
/// </summary>
public bool Check(T value)
{
int hash = value.ToString().GetHashCode();
return Check(hash);
}
/// <summary>
/// Quick checkup because no hash needs to be computed
/// </summary>
private bool Check(int hash)
{
if (dictionary.ContainsKey(hash))
{
ulong flag = dictionary[hash];
return (flags & flag) == flag;
}
return false;
}
}
最后,我们现在停留在&#34; ulong值= 1UL&lt;&lt;索引++&#34;部分。由于Key枚举包含200个以上的值,因此我们会得到&#34; ulong value = 1UL&lt;&lt; 200&#34;对于第200次迭代,这会产生超出ulong限制的超巨长数,从而导致重复值。运行下面的代码,你会注意到它:
for (int i = 0; i < 200; i++)
{
Console.WriteLine("{0} generated {1}", i, 1UL << i);
}
我怎样才能解决上述问题?谢谢你的时间。