Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataGrid PreviewTextInput event removing control characters from input

I have a WPF window with a data grid. I'm trying to capture, from a Symbol scanner, a string that is being sent through a virtual wedge. To the application it looks like the characters were typed. This string starts with ASCII 1 (SOH).

When the window has focus the window's PreviewTextInput receives the SOH along with all other human readable and non-human readable values. However, when the datagrid has focus the non-human readable characters are stripped away.

If I have a PreviewKeyDown or PreviewKeyUp on the window then the characters appear properly no matter what has focus. So somewhere along the way the data grid strips it out. Unfortunately because KeyDown/KeyUp do not show the ASCII characters I can't use these events without having to write some sort of parsing algorithm.

Can anyone tell me what I can do to get those non-human readable control characters to always be sent to the PreviewTextInput? Or how to parse all characters in the PreviewKeyDown?

Edited:

When the window has focus:

Window PreviewKeyDown - LeftCtrl
Window PreviewKeyDown - A
Window PreviewTextInput - <SOH>
Window PreviewKeyDown - Oem6
Window PreviewTextInput - ]
Window PreviewKeyDown - LeftShift
Window PreviewKeyDown - C
Window PreviewTextInput - C

When the data grid has focus:

Window PreviewKeyDown - LeftCtrl
DataGrid PreviewKeyDown - LeftCtrl
Window PreviewKeyDown - A
DataGrid PreviewKeyDown - A
Window PreviewKeyDown - Oem6
DataGrid PreviewKeyDown - Oem6
Window PreviewTextInput - ]
Window PreviewKeyDown - LeftShift
DataGrid PreviewKeyDown - LeftShift
Window PreviewKeyDown - C
DataGrid PreviewKeyDown - C
Window PreviewTextInput - C
like image 547
J Chapman Avatar asked Nov 12 '22 20:11

J Chapman


1 Answers

Alright, I know this may be not quite what you are expecting, but I have some experience writing software for some Symbol barcode scanners. In one application, we had users scan their badges to authenticate themselves to override certain conditions. We wanted the user to "scan" their badge and not be able to type in numbers with the keyboard. I remember we spent a long time trying to figure out how to make the input not come in as if it were typed by the keyboard. I believe we were able to scan some configuration codes from the Symbol barcode scanner's manual to configure it to be a USB device that we could open and handle its input however we wished. This approach was much better for us.

Have you considered trying something like that?

This post on the MSDN forums seems relevant (Converting Key To ASCII

Bar code readers usually can operate in two modes. One is where it acts as a keyboard wedge, generating keystrokes as though the user typed the code. Another is where an application program receives the scanned code directly, usually through a serial port. You've got the reader switched into a mode where it generates codes suitable for the latter way. Ctrl+B is a control code, SOH (Start Of Header). It is used to synchronize the program with the reader, SOH indicates the start of a scan, you'd use it to reset a buffer index.

You'll want to configure the reader for the keyboard wedge mode where it won't generate the control characters. You can still make it work if necessary by writing both a KeyDown event handler, to detect the SOH, and a KeyPressed event handler, to detect the scan codes. Avoid trying to convert key strokes you see in KeyDown to characters, KeyPressed already does this for you.

I believe this may work for you to convert to ASCII:

[DllImport("user32.dll")]
    static extern int ToAsciiEx(uint uVirtKey, uint uScanCode, byte[] lpKeyState, byte[] arr, uint uFlags, IntPtr hkl);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool GetKeyboardState(byte[] lpKeyState);


    private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        byte[] keyboardState = new byte[256];
        int keyCode = KeyInterop.VirtualKeyFromKey(e.Key);
        byte[] arr = new byte[4];
        GetKeyboardState(keyboardState );
        Debug.WriteLineIf(ToAsciiEx((uint)keyCode, 0, keyboardState, arr, 0, IntPtr.Zero) > 0, ASCIIEncoding.ASCII.GetString(arr));
    }
like image 79
Alan Avatar answered Nov 15 '22 09:11

Alan