Situation:
To PC connect 2 keyboards
a) User keyboard
b) Barcode scanner (emulates keyboard 0..9 and Return)

Task:
1. Block all input from scanner to user interface
2. On input from scanner activate specific window
3. Redirect all input from scanner to specific window

Solution:
1. For blocking 0..9 and Return used

SetWindowsHookEx(
                    WH_KEYBOARD_LL,
                    s_KeyboardDelegate,
                    Marshal.GetHINSTANCE(
                        Assembly.GetExecutingAssembly().GetModules()[0]),
                    0);

Full sample code
In SetWindowsHookEx we can block user input but can`t determine what is keyboard.
So we block all input 0..9 and return

 //Set hook
 private void Form1_Load(object sender, EventArgs e)
 {
  HookManager.KeyDown += HookManager_KeyDown;
 }
 //Block input
 void HookManager_KeyDown(object sender, KeyEventArgs e)
 {
  if (handle != IntPtr.Zero)
  {
   if ((e.KeyValue >= 48) & (e.KeyValue <= 57) 
      || (e.KeyValue >= 96) & (e.KeyValue <= 105) //NumPad
      || (e.KeyValue == 13))
   {
    e.Handled = true;
   }
 }
}

2. For determine what is keyboard use RawInput
Full sample code

 InputDevice id;
 IntPtr handleScanner = IntPtr.Zero;
 //Init
 public MainForm()
 {
  InitializeComponent();

  id = new InputDevice( Handle );
  id.KeyPressed += new InputDevice.DeviceEventHandler( m_KeyPressed );
  //Set barcode scanner handle
  //from id.deviceList
  //handleScanner = 
 }
 
 //Process input messages
 protected override void WndProc( ref Message message )
 {
  if( id != null )
   id.ProcessMessage(message);

   base.WndProc( ref message );
 }

 private void m_KeyPressed( object sender, InputDevice.KeyControlEventArgs e )
 {
  if (handleScanner != IntPtr.Zero)
  {
   if (e.Keyboard.deviceHandle != handleScanner )
   {
    //If input from user keyboard
    //repeat input to active window
    if ((e.Keyboard.key >= 48) & (e.Keyboard.key <= 57)
       || (e.Keyboard.key >= 96) & (e.Keyboard.key <= 105)
       || (e.Keyboard.key == 13))
    {
     DllImport.INPUT[] rec = new DllImport.INPUT[1];
     rec[0].type = 0x0001;
     rec[0].U.ki = new DllImport.KEYBDINPUT();
     rec[0].U.ki.wScan = (short)e.Keyboard.key;
     rec[0].U.ki.wVk = (short)e.Keyboard.key;
     DllImport.SendInput(1, rec, Marshal.SizeOf(typeof(DllImport.INPUT)));
    }
   }
   else
   {
    //If input from barcode scanner
    //Activate window for redirect
    IntPtr h = DllImport.FindWindow(null, "WindowFoRedirect");
    DllImport.SetForegroundWindow(h);
    //And send input to this window
    DllImport.INPUT[] rec = new DllImport.INPUT[1];
    rec[0].type = 0x0001;
    rec[0].U.ki = new DllImport.KEYBDINPUT();
    rec[0].U.ki.wScan = (short)e.Keyboard.key;
    rec[0].U.ki.wVk = (short)e.Keyboard.key;
    DllImport.SendInput(1, rec, Marshal.SizeOf(typeof(DllImport.INPUT)));
   }
  }
 }

For disable blocking resended input, need check KeyboardHookStruct.Flags on LLKHF_INJECTED
HookManager.Callbacks.cs in method KeyboardHookProc

//If nandled (in item 1) and Flag LLKHF_INJECTED
if ((handled) & (MyKeyboardHookStruct.Flags == 16))
{
 //unblock
 handled = false;
}
Posted in C#.

2 thoughts on “C#, Keyboard intercept, blocking, redirect

  1. Hi, I’ve the same issue as you with barcode scanners, I’m trying to make your code works, but I’m net to C#, can you post the full sourcecode?

    Thanks.

Leave a reply