简体   繁体   English

keypress事件处理程序,但在没有表单的Windows应用程序上

[英]keypress event handler but on a windows app with no forms

I have an application that is tied to a card reader (magnetic strip). 我有一个与读卡器(磁条)相连的应用程序。 I've able to capture the data on the cards when I have a form that outputs my data or in a console application where I can output the data to the console. 当我有一个输出我的数据的表单时,或者在我可以将数据输出到控制台的控制台应用程序中时,我能够捕获卡上的数据。

But on the app I'm working on it has a Program class as its startup and just starts the program that way. 但是在我正在开发的应用程序上它有一个Program类作为它的启动,只是以这种方式启动程序。

What I think I need is a generic keypress listener to look for when the card reader is swiped. 我认为我需要的是一个通用的按键监听器,可以在读卡器时查找。

Windows Forms App Ex Console App Ex KeyPressEventHandler Delegate Windows窗体应用程序Ex 控制台应用程序Ex KeyPressEventHandler委托

I think I want something like the KeyPressEventHandler but I can't seem to get that to work in my application. 我想我想要像KeyPressEventHandler这样的东西,但我似乎无法在我的应用程序中使用它。

I've created the following Extention method: 我创建了以下Extention方法:

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;
    }
}

But I'm unsure of how to reference it in my Main() method. 但我不确定如何在我的Main()方法中引用它。 I don't see a keypress method. 我没有看到按键方法。

Depending on the version of the CLR and Windows, you will have some specific problems using Windows Hooks. 根据CLR和Windows的版本,使用Windows Hook会遇到一些特定问题。

  1. A WH_KEYBOARD/WH_KEYBOARD_LL keyboard hooks require a message loop to operate correctly. WH_KEYBOARD / WH_KEYBOARD_LL键盘挂钩需要消息循环才能正常运行。 The keyboard event is posted to the installing thread's message queue before generating the call to hook delegate. 在生成对钩子委托的调用之前,键盘事件将发布到安装线程的消息队列。
  2. Windows Vista and later will not allow hooks from lower privilege processes to see activity in higher privilege process. Windows Vista及更高版本不允许来自较低权限进程的挂钩在较高权限进程中查看活动。 So you may or may not get the keyboard event depending on what process currently has the input focus. 因此,您可能会或可能不会获取键盘事件,具体取决于当前具有输入焦点的进程。
  3. Once you have hooked keyboard events, you will need to have a start and stop sentinel generated by the card reader to indicate that you should capture the remaining input. 连接键盘事件后,您需要有一个由读卡器生成的开始和停止标记,以指示您应该捕获剩余的输入。 Whether or not this is achievable is going to depend on the ability to configure the card reader. 这是否可实现取决于配置读卡器的能力。

Having said all of that, it is certainly possible to achieve the desired result using WH_KEYBOARD or WH_KEYBOARD_LL hooks. 说完所有这些之后,使用WH_KEYBOARD或WH_KEYBOARD_LL挂钩肯定可以实现所需的结果。 If you decide to go that route, I suggest that you use alternating Left-Ctrl and Right-Control keypresses as start and stop sentinels from the reader (assuming it is capable of doing so). 如果您决定走这条路线,我建议您使用交替的Left-Ctrl和Right-Control按键作为读取器的开始和停止标记(假设它能够这样做)。

Also, if you do end up with a Windows Hook, you will need to install the hook from a background thread rather than your application's main thread as you are required to process keyboard events within a certain amount of time. 此外,如果您最终使用Windows Hook,则需要从后台线程而不是应用程序的主线程安装钩子,因为您需要在一定时间内处理键盘事件。 If you take longer than Windows allows, the hook will be ignored. 如果您花费的时间比Windows允许的时间长,则会忽略该挂钩。

As an alternate to Windows Hooks, you may use DirectInput. 作为Windows Hooks的替代,您可以使用DirectInput。 Honestly, I've never tried this approach but the concept seems reasonable and eliminates some of the uncertainty of Windows Hooks. 老实说,我从来没有尝试过这种方法,但这个概念似乎是合理的,并消除了Windows Hooks的一些不确定性。

I'm assuming that since you are asking for global keyboard events, that your card reader is some variety of USB HID device. 我假设你要求全球键盘事件,你的读卡器是各种各样的USB HID设备。 You can validate that your card reader shows up as a DirectInput device by running DxDiag. 您可以通过运行DxDiag验证您的读卡器是否显示为DirectInput设备。 The device should appear on the Input tab if it will be accessible. 如果设备可以访问,则该设备应出现在“输入”选项卡上。 There appear to be various managed assemblies for DirectX available. 似乎有各种可用的DirectX托管程序集。

If you are not limited to the type of card reader that you have, you might be better off with a serial based reader. 如果您不仅限于所使用的读卡器类型,那么使用基于串行的读卡器可能会更好。 With it you would not be completing with other applications for the device's output. 有了它,您将无法完成设备输出的其他应用程序。

I realize I didn't actually answer your question, so feel free to down vote or ignore this answer. 我意识到我实际上并没有回答你的问题,所以请随意投票或忽略这个答案。 Hopefully, this did give you some information about what issues you may face. 希望这确实能为您提供有关您可能面临的问题的一些信息。

After some further thought, I considered that you may be able to access the HID device directly and perform the keyboard translations using standard Win32 API. 经过深思熟虑后,我认为您可以直接访问HID设备并使用标准Win32 API执行键盘翻译。 In looking along that route, I came across the Raw Input API. 在查看该路线时,我遇到了Raw Input API。 Using this you should be able to register for raw input for all keyboard devices, then determine at input time what device actually generated the event. 使用此功能,您应该能够为所有键盘设备注册原始输入,然后在输入时确定实际生成事件的设备。 Eliminating the need for start and stop sentinels from the reader. 消除了读者启动和停止哨兵的需要。

Even better, the API send messages to distinguish between input generated when the window is the foreground window and when it is not. 更好的是,API发送消息以区分窗口是前景窗口时生成的输入和不是窗口时生成的输入。 With this API you will still need to create a window and message loop on a background thread, but it should be much cleaner than the Windows Hook method. 使用此API,您仍然需要在后台线程上创建窗口和消息循环,但它应该比Windows Hook方法更清晰。

See Using Raw Input from C# to handle multiple keyboards on CodeProject for an example application reading raw input in C#. 有关在C#中读取原始输入的示例应用程序,请参阅使用C#中的原始输入来处理 CodeProject上的多个键盘

An example (thought I didn't updated the code since .net framework 1.1) to have an event when any key is pressed : 一个例子(我以为自.net框架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); 
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM