Question

I am using a global keyboard hook in order to work with a barcode reader. The barcode reader sends an STX character ahead of the barcode and an ETX character after the barcode.

Sometimes the ToAscii function results in the proper STX and ETX codes (0x02 or 0x03), but most of the time it becomes 0x62 (b) or 0x63 (c).

Can this be explained and preferably resolved?

I have added the hook callback below for clarity:

    private IntPtr HookCallback(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam)
    {
        if (nCode >= 0)
        {
            // Prepare the characters and retrieve the keyboard state.
            char[] characters = new char[2];
            byte[] keyState = GetKeyboardState();


            if (KeyPressed != null && WinAPI.ToAscii(lParam.vkCode, lParam.scanCode, keyState, characters, 0) == 1)
            {
                // Initialize the event arguments and fire the KeyPressed event.
                GlobalKeyboardHookEventArgs e = new GlobalKeyboardHookEventArgs(characters, (int)wParam);
                KeyPressed(null, e);

                // Do not call the next hook if the event has been handled.
                if (e.Handled)
                {
                    return (IntPtr)1;
                }
            }
        }

        // Call the next hook.
        return WinAPI.CallNextHookEx(hook, nCode, wParam, ref lParam);
    }
}
Was it helpful?

Solution

Since the scanner is and must be configured as a USB keyboard, I am forced to capture the input using a low level keyboard hook. However, instead of using STX/ETX characters as prefix/suffix, I have now set up the scanner to send a keyboard command (Alt + Shift + Backspace) as prefix and suffix.

This allows me to determine when a barcode is coming and when it has finished. To prevent users from accidentally (or intentionally) oerforming the keyboard command I have implemented a timer. The timer makes sure that barcode parsing is cancelled if no barcode is received after 100 milliseconds.

The keyboard command is caught using the RegisterHotKey and UnregisterHotKey Windows API calls.

When swallowing input during barcode processing it is very important not to swallow the backspace character. The low level keyboard hook is called prior to the hot key callback and swallowing the backspace character will prevent the hot key callback from ever occuring.

OTHER TIPS

The scanner acts as a keyboard but isn't.

By calling the WinApi.ToAscii() windows translates the input to a "valid" keymapping. ToAscii() interprets 0x02 as the key mapped to 'b'. But that will depend on the current active installed/configured keyboard. So just relying on 'b' & 'c' can cause problems on a... Russian keyboard :-)

Just use the raw input data, extract the data between STX/ETX and map that part to Ascii. That keycode should be in lParam.vkCode or lParam.scanCode. KBDLLHOOKSTRUCT

Result might by like the following, but I'm unable to verify it right now

private bool _isScanningCode;

private IntPtr HookCallback(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam)
    {
        if (nCode >= 0)
        {
            // Prepare the characters and retrieve the keyboard state.
            char[] characters = new char[2];
            byte[] keyState = GetKeyboardState();

            if (lParam.scanCode == 0x02)
            {
                _isScanningCode == true;
                return (IntPtr)1; // act like key is handled
            }
            if (lParam.scanCode == 0x03)
            {
                _isScanningCode == false;
                return (IntPtr)1; //act like key is handled
            }

            if (_isScanningCode)
            {

                if (KeyPressed != null &&
                    WinAPI.ToAscii(lParam.vkCode, lParam.scanCode, keyState, characters, 0) == 1)
                {
                    // Initialize the event arguments and fire the KeyPressed event.
                    GlobalKeyboardHookEventArgs e = new GlobalKeyboardHookEventArgs(characters, (int) wParam);
                    KeyPressed(null, e);

                    // Do not call the next hook if the event has been handled.
                    if (e.Handled)
                    {
                        return (IntPtr) 1;
                    }
                }
            }
        }

        // Call the next hook.
        return WinAPI.CallNextHookEx(hook, nCode, wParam, ref lParam);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top