Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

keypress event handler but on a windows app with no forms

Tags:

c#

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.

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

I think I want something like the KeyPressEventHandler but I can't seem to get that to work in my application.

I've created the following Extention method:

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. I don't see a keypress method.

like image 575
webdad3 Avatar asked Oct 21 '22 23:10

webdad3


2 Answers

Depending on the version of the CLR and Windows, you will have some specific problems using Windows Hooks.

  1. A WH_KEYBOARD/WH_KEYBOARD_LL keyboard hooks require a message loop to operate correctly. 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. 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. 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).

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. If you take longer than Windows allows, the hook will be ignored.

As an alternate to Windows Hooks, you may use DirectInput. Honestly, I've never tried this approach but the concept seems reasonable and eliminates some of the uncertainty of 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. You can validate that your card reader shows up as a DirectInput device by running DxDiag. The device should appear on the Input tab if it will be accessible. There appear to be various managed assemblies for DirectX available.

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.

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. In looking along that route, I came across the 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. 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.

See Using Raw Input from C# to handle multiple keyboards on CodeProject for an example application reading raw input in C#.

like image 97
William Avatar answered Nov 02 '22 08:11

William


An example (thought I didn't updated the code since .net framework 1.1) to have an event when any key is pressed:

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); 
    }
}
like image 24
Sinatr Avatar answered Nov 02 '22 07:11

Sinatr