【发布时间】:2016-11-14 22:49:36
【问题描述】:
所以,我一直在开发一个类来处理 VSTO 加载项中的 Kwyboard 输入,到目前为止,我一直在使用 Windows 挂钩来实现这一点,并取得了相对成功。
拥有此代码:
//.....
private const int WH_KEYBOARD = 2;
private const int WH_MOUSE = 7;
private enum WM : uint {
KEYDOWN = 0x0100,
KEYFIRST = 0x0100,
KEYLAST = 0x0108,
KEYUP = 0x0101,
MOUSELEFTDBLCLICK = 0x0203,
MOUSELEFTBTNDOWN = 0x0201,
MOUSELEFTBTNUP = 0x0202,
MOUSEMIDDBLCLICK = 0x0209,
MOUSEMIDBTNDOWN = 0x0207,
MOUSEMIDBTNUP = 0x0208,
MOUSERIGHTDBLCLK = 0x0206,
MOUSERIGHTBTNDOWN = 0x0204,
MOUSERIGHTBTNUP = 0x0205
}
private hookProcedure proc;
private static IntPtr hookID = IntPtr.Zero;
//Enganches
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr SetWindowsHookEx(int hookId, hookProcedure proc, IntPtr hInstance, uint thread);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern bool unHookWindowsHookEx(int hookId);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr CallNextHookEx(IntPtr hookId, int ncode, IntPtr wparam, IntPtr lparam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string name);
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetCurrentThreadId();
public CPInputListener() {
proc = keyBoardCallback;
hookID = setHook(proc);
}
private IntPtr setHook(hookProcedure procedure){
ProcessModule module = Process.GetCurrentProcess().MainModule;
uint threadId = (uint)GetCurrentThreadId();
return SetWindowsHookEx(WH_KEYBOARD, procedure, IntPtr.Zero, threadId);
}
public void stopListeningAll() {
unHookWindowsHookEx(WH_KEYBOARD);//For now
}
private IntPtr keyBoardCallback(int ncode, IntPtr wParam, IntPtr lParam) {
if (ncode >= 0) {
//LPARAM pretty useless
Keys key = (Keys)wParam;
KeyEventArgs args = new KeyEventArgs(key);
onKeyDown(args);//for now
}
return CallNextHookEx(hookID, ncode, wParam, lParam);
}
//....
我确实成功接收到键盘输入,但这是个大谜团;每次按下一个键,无论它有多快,事件 (onKeyDown) 都会准确调用 10 次,不多不少。
如果按键被长按,事件会继续被调用,但 10 x 10 次,而不是只调用一次。
到目前为止我已经尝试过
- 使用 wParam 在 Key Up 上调用所需事件:似乎不起作用,在我见过的所有处理 Key down 和 up 事件的代码中,使用了
IntPtr wParam,但我只能从该变量中检索没有帮助的键码。 - 使用
lParam或nCode:这些变量在这 10 次调用之间给出不一致的值,ncode倾向于检索 0 和 3,lParam某些值似乎是非托管内存地址...李>
我期待什么
我确实希望在按下键时只调用一次 onKeyDown,或者另一方面能够通过 on key up 调用该方法,我确实希望每次释放键时只调用一次。
如何绕过这个
如果我找不到合理的答案,我正在考虑使用定制的计时器来丢弃所有这些调用并只使用最后一个,如果其他一切都失败了,你会推荐这个吗?
非常感谢!要快乐,要善良! :D
【问题讨论】:
标签: c# windows ms-word vsto hook