按键事件处理程序,但在没有窗体的 Windows 应用上



>我有一个与读卡器(磁条(相关的应用程序。 当我有一个输出数据的表单时,或者在控制台应用程序中,我可以将数据输出到控制台,从而能够捕获卡上的数据。

但是在我正在处理的应用程序中,它有一个程序类作为其启动,并以这种方式启动程序。

我认为我需要的是一个通用的按键侦听器,以便在刷卡器时查找。

Windows Forms App Ex控制台应用前KeyPressEventHandler Delegate

我想我想要类似KeyPressEventHandler的东西,但我似乎无法在我的应用程序中使用它。

我创建了以下扩展方法:

public static class Utilities
{
    private static KeyPressEventHandler handler = KeyPressed;
    public static void KeyPressed(Object sender, KeyPressEventArgs e)
    {
        while (true)
        {
            dataReceived.Append(e.KeyChar);
        }
    }
    public static KeyPressEventHandler getKeyPressHandler()
    {
        return handler;
    }
}

但我不确定如何在我的Main()方法中引用它。 我没有看到按键方法。

根据CLR和Windows的版本,使用Windows Hooks会遇到一些特定的问题。

  1. WH_KEYBOARD/WH_KEYBOARD_LL键盘挂钩需要消息循环才能正常运行。键盘事件在生成对挂钩委托的调用之前发布到安装线程的消息队列。
  2. Windows Vista 及更高版本将不允许来自较低权限进程的挂钩查看较高权限进程中的活动。因此,您可能会也可能不会获得键盘事件,具体取决于当前具有输入焦点的进程。
  3. 挂钩键盘事件后,您需要由读卡器生成启动和停止哨兵,以指示应捕获剩余输入。这是否可实现将取决于配置读卡器的能力。

说了这么多,使用WH_KEYBOARD或WH_KEYBOARD_LL钩子当然有可能达到预期的结果。如果您决定走这条路,我建议您使用交替的左按和右控制按键作为阅读器的开始和停止哨兵(假设它能够这样做(。

此外,如果您最终获得了 Windows 挂钩,则需要从后台线程而不是应用程序的主线程安装挂钩,因为您需要在一定时间内处理键盘事件。如果您花费的时间超过 Windows 允许的时间,则挂钩将被忽略。

作为 Windows Hooks 的替代方案,您可以使用 DirectInput。老实说,我从未尝试过这种方法,但这个概念似乎是合理的,并且消除了 Windows Hooks 的一些不确定性。

我假设由于您要求全局键盘事件,那么您的读卡器是某种USB HID设备。可以通过运行 DxDiag 来验证读卡器是否显示为直接输入设备。如果设备可访问,则设备应显示在"输入"选项卡上。似乎有各种可用于 DirectX 的托管程序集。

如果您不限于您拥有的读卡器类型,则最好使用基于串行的读卡器。有了它,您将无法完成设备输出的其他应用程序。

经过进一步思考,我认为您可以直接访问 HID 设备并使用标准 Win32 API 执行键盘转换。在沿着这条路线查看时,我遇到了原始输入 API。使用此功能,您应该能够注册所有键盘设备的原始输入,然后在输入时确定实际生成事件的设备。无需从阅读器开始和停止哨兵。

更好的是,API 发送消息以区分窗口是前台窗口时生成的输入和不是前台窗口时生成的输入。使用此 API,您仍然需要在后台线程上创建窗口和消息循环,但它应该比 Windows Hook 方法干净得多。

有关在 C# 中读取原始输入的示例应用程序,请参阅使用 C# 中的原始输入处理 CodeProject 上的多个键盘。

一个例子(以为我从 .net Framework 1.1 开始就没有更新代码(在按下任何键时有一个事件:

public class Hook
{
    [DllImport("user32.dll",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
    private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
    [DllImport("user32.dll",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
    private static extern bool UnhookWindowsHookEx(int idHook);
    [DllImport("user32.dll",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
    private static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
    [DllImport("kernel32.dll")]
    public static extern int GetCurrentThreadId();
    public static event Action Event = null;
    private const int WH_KEYBOARD = 2;
    private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
    static int _hookKeyboard = 0;
    private static HookProc _hookKeyboardProc;
    public static bool Install() 
    {
        _hookKeyboardProc = new HookProc(KeyboardHook);
        _hookKeyboard = SetWindowsHookEx(WH_KEYBOARD, _hookKeyboardProc, IntPtr.Zero, GetCurrentThreadId());
        return _hookKeyboard != 0;
    }
    public static bool Uninstall()
    {
        // uninstall keyboard hook
        if(!UnhookWindowsHookEx(_hookKeyboard))
            return false;
        _hookMouseProc = null;
        return true;
    }
    private static int KeyboardHook(int nCode, IntPtr wParam, IntPtr lParam)
    {
        // if any message - fire event
        if(nCode >= 0 && Event != null) 
            Event();
        return CallNextHookEx(_hookKeyboard, nCode, wParam, lParam); 
    }
}