【发布时间】:2010-12-10 23:49:56
【问题描述】:
我将自己在互联网上找到的代码拼接在一起 WH_KEYBOARD_LL 助手类:
将以下代码放入您的一些 utils 库中,让它成为 YourUtils.cs:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Windows.Input;
namespace MYCOMPANYHERE.WPF.KeyboardHelper
{
public class KeyboardListener : IDisposable
{
private static IntPtr hookId = IntPtr.Zero;
[MethodImpl(MethodImplOptions.NoInlining)]
private IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
try
{
return HookCallbackInner(nCode, wParam, lParam);
}
catch
{
Console.WriteLine("There was some error somewhere...");
}
return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);
}
private IntPtr HookCallbackInner(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
if (wParam == (IntPtr)InterceptKeys.WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (KeyDown != null)
KeyDown(this, new RawKeyEventArgs(vkCode, false));
}
else if (wParam == (IntPtr)InterceptKeys.WM_KEYUP)
{
int vkCode = Marshal.ReadInt32(lParam);
if (KeyUp != null)
KeyUp(this, new RawKeyEventArgs(vkCode, false));
}
}
return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);
}
public event RawKeyEventHandler KeyDown;
public event RawKeyEventHandler KeyUp;
public KeyboardListener()
{
hookId = InterceptKeys.SetHook((InterceptKeys.LowLevelKeyboardProc)HookCallback);
}
~KeyboardListener()
{
Dispose();
}
#region IDisposable Members
public void Dispose()
{
InterceptKeys.UnhookWindowsHookEx(hookId);
}
#endregion
}
internal static class InterceptKeys
{
public delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
public static int WH_KEYBOARD_LL = 13;
public static int WM_KEYDOWN = 0x0100;
public static int WM_KEYUP = 0x0101;
public static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
}
public class RawKeyEventArgs : EventArgs
{
public int VKCode;
public Key Key;
public bool IsSysKey;
public RawKeyEventArgs(int VKCode, bool isSysKey)
{
this.VKCode = VKCode;
this.IsSysKey = isSysKey;
this.Key = System.Windows.Input.KeyInterop.KeyFromVirtualKey(VKCode);
}
}
public delegate void RawKeyEventHandler(object sender, RawKeyEventArgs args);
}
我是这样使用的:
App.xaml:
<Application ...
Startup="Application_Startup"
Exit="Application_Exit">
...
App.xaml.cs:
public partial class App : Application
{
KeyboardListener KListener = new KeyboardListener();
private void Application_Startup(object sender, StartupEventArgs e)
{
KListener.KeyDown += new RawKeyEventHandler(KListener_KeyDown);
}
void KListener_KeyDown(object sender, RawKeyEventArgs args)
{
Console.WriteLine(args.Key.ToString());
// I tried writing the data in file here also, to make sure the problem is not in Console.WriteLine
}
private void Application_Exit(object sender, ExitEventArgs e)
{
KListener.Dispose();
}
}
问题在于它在按键一段时间后停止工作。从来没有引发任何错误,我只是在一段时间后没有得到任何输出。当它停止工作时,我找不到稳定的模式。
重现这个问题很简单,像疯子一样按一些键,通常在窗外。
我怀疑背后有一些邪恶的线程问题,有人知道如何保持这个工作吗?
我已经尝试过的:
- 用简单的东西替换
return HookCallbackInner(nCode, wParam, lParam);。 - 用异步调用替换它,尝试将睡眠 5000 毫秒(等)。
异步调用并没有让它更好地工作,当用户保持单个字母一段时间时,它似乎总是停止。
【问题讨论】:
-
我们可以截取密钥并发送一个不同的密钥而不是按下的那个吗?例如按 a 发送键 e 。
-
完整、可用并记录在案。这就是我喜欢 StackOverflow 的地方
-
是的,确实是新版本。我将添加到正文的链接。
-
我的代码和 USB 读卡器有问题。有时键没有右移。在同一会话中,我可以阅读一次 %WHATEVERò1234_ 和下一次 5WHAteVERò!"34_ (其中 ò 应该是 ; 和 _ 应该是?,但这取决于我的键盘)。在我编写自己的虚拟键解析器之前有什么帮助吗?
-
不确定这里发生了什么。 Matt 的修订已将其恢复为仍受垃圾回收影响的版本。检查早期的修订; 15 代表 Ciantic 的最后一个,或 16 代表 Matt 的第一个,我更喜欢命名。 17 和 18 是损坏的版本。