Bar code readers in general act as if they were a normal keyboard.
Once your application loses focus, keyboard events (logically) are not passed to it (why would they happen?) So your application would want to receive what you are writing in a word document for example).
But if there is a solution. To achieve this, you must use the global keyboard hooks (global keyboard hooks), which basically subscribe to the OS system to capture the keystrokes.
Here is a code taken from this answer in which I have translated the comments, which can help you what do you want:
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace SnagFree.TrayApp.Core
{
class GlobalKeyboardHookEventArgs : HandledEventArgs
{
public GlobalKeyboardHook.KeyboardState KeyboardState { get; private set; }
public GlobalKeyboardHook.LowLevelKeyboardInputEvent KeyboardData { get; private set; }
public GlobalKeyboardHookEventArgs(
GlobalKeyboardHook.LowLevelKeyboardInputEvent keyboardData,
GlobalKeyboardHook.KeyboardState keyboardState)
{
KeyboardData = keyboardData;
KeyboardState = keyboardState;
}
}
//Basado en https://gist.github.com/Stasonix
class GlobalKeyboardHook : IDisposable
{
public event EventHandler<GlobalKeyboardHookEventArgs> KeyboardPressed;
public GlobalKeyboardHook()
{
_windowsHookHandle = IntPtr.Zero;
_user32LibraryHandle = IntPtr.Zero;
_hookProc = LowLevelKeyboardProc; // debemos mantener vivo _hookProc, proque el RB(GC) no es consciente del comportamiento de SetWindowsHookEx.
_user32LibraryHandle = LoadLibrary("User32");
if (_user32LibraryHandle == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode, $"Fallo al cargar la biblioteca 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
}
_windowsHookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, _hookProc, _user32LibraryHandle, 0);
if (_windowsHookHandle == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode, $"Fallo al ajustar los ganchos de teclado para '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// proque solo podemos "desengancharnos" en el mismo hilo, no en el recolector de basura
if (_windowsHookHandle != IntPtr.Zero)
{
if (!UnhookWindowsHookEx(_windowsHookHandle))
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode, $"Fallo al desenganchar los ganchos de teclado para '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
}
_windowsHookHandle = IntPtr.Zero;
_hookProc -= LowLevelKeyboardProc;
}
}
if (_user32LibraryHandle != IntPtr.Zero)
{
if (!FreeLibrary(_user32LibraryHandle)) /
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode, $"Fallo al descargar biblioteca 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
}
_user32LibraryHandle = IntPtr.Zero;
}
}
~GlobalKeyboardHook()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private IntPtr _windowsHookHandle;
private IntPtr _user32LibraryHandle;
private HookProc _hookProc;
delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool FreeLibrary(IntPtr hModule);
/// <summary>
/// La función SetWindowsHookEx instala un gancho (hook) de aplicación en una cadena de ganchos.
/// Los ganchos se instalan para monitorizar el sistema en busca de ciertos tipos de eventos.
/// Estos eventos estan asociados o bien con un hilo específico o bien con todos los hilo en el mismo escritorio como el hilo que llamaThese events are
/// </summary>
/// <param name="idHook">tipo de gancho</param>
/// <param name="lpfn">procedimiento de gancho</param>
/// <param name="hMod">handle a la instancia de la aplicación</param>
/// <param name="dwThreadId">identificador del hilo</param>
/// <returns>Si la función lo consigue, el valor de retorno es un handle a procedimiento de gancho.</returns>
[DllImport("USER32", SetLastError = true)]
static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
/// <summary>
/// La función UnhookWindowsHookEx elimina un procedimiento de enganche instalado en una cadena de enganches por la función SetWindowsHookEx.
/// </summary>
/// <param name="hhk">handle al procedimiento de enganche</param>
/// <returns>Si la función lo consigue, el valor de retorno es true.</returns>
[DllImport("USER32", SetLastError = true)]
public static extern bool UnhookWindowsHookEx(IntPtr hHook);
/// <summary>
/// La función CallNextHookEx pasa la información del gancho al siguiente procedimiento de enganche en la cadena de enganches actual.
/// Un procedimiento de enganche pueda llamar a esta función antes o despues de procesar la información.
/// </summary>
/// <param name="hHook">handle del enganche actual</param>
/// <param name="code">código del gancho pasado al procedimiento del gnacho</param>
/// <param name="wParam">valor pasado al procedimiento de enganche</param>
/// <param name="lParam">valor pasado al procedimiento de enganche</param>
/// <returns>Si la función lo consigue, el valor de retorno es true.</returns>
[DllImport("USER32", SetLastError = true)]
static extern IntPtr CallNextHookEx(IntPtr hHook, int code, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
public struct LowLevelKeyboardInputEvent
{
/// <summary>
/// Código de tecla virtual. El código debe ser un valor en el rango 1-254.
/// </summary>
public int VirtualCode;
/// <summary>
/// Código de hardware para la tecla.
/// </summary>
public int HardwareScanCode;
/// <summary>
/// La bandera de tecla extendida, banderas de inyección de evento, código de contexto, y bandera de estado de transición. Este miembro está especificado de la manera siguiente: Una aplicación puede usar los valores siguientes para comprobar las banderas de pulsación de teclado. Comprobar LLKHF_INJECTED (bit 4) te dirá si el ebento fue inyectado. Si lo fue, comprobar LLKHF_LOWER_IL_INJECTED (bit 1) te dirá si el evento fué inyectado desde un proceso que corre en un nivel mas bajo de integridad.
/// </summary>
public int Flags;
/// <summary>
/// La marca de tiempo para este mensaje, equivalente a lo que GetMessageTime devolvería para este mensaje.
/// </summary>
public int TimeStamp;
/// <summary>
/// Información adicional asociada al mensaje.
/// </summary>
public IntPtr AdditionalInformation;
}
public const int WH_KEYBOARD_LL = 13;
//const int HC_ACTION = 0;
public enum KeyboardState
{
KeyDown = 0x0100,
KeyUp = 0x0101,
SysKeyDown = 0x0104,
SysKeyUp = 0x0105
}
public const int VkSnapshot = 0x2c;
//const int VkLwin = 0x5b;
//const int VkRwin = 0x5c;
//const int VkTab = 0x09;
//const int VkEscape = 0x18;
//const int VkControl = 0x11;
const int KfAltdown = 0x2000;
public const int LlkhfAltdown = (KfAltdown >> 8);
public IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
{
bool fEatKeyStroke = false;
var wparamTyped = wParam.ToInt32();
if (Enum.IsDefined(typeof(KeyboardState), wparamTyped))
{
object o = Marshal.PtrToStructure(lParam, typeof(LowLevelKeyboardInputEvent));
LowLevelKeyboardInputEvent p = (LowLevelKeyboardInputEvent)o;
var eventArguments = new GlobalKeyboardHookEventArgs(p, (KeyboardState)wparamTyped);
EventHandler<GlobalKeyboardHookEventArgs> handler = KeyboardPressed;
handler?.Invoke(this, eventArguments);
fEatKeyStroke = eventArguments.Handled;
}
return fEatKeyStroke ? (IntPtr)1 : CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
}
}
}
Usage:
using System;
using System.Windows.Forms;
namespace SnagFree.TrayApp.Core
{
internal class Controller : IDisposable
{
private GlobalKeyboardHook _globalKeyboardHook;
public void SetupKeyboardHooks()
{
_globalKeyboardHook = new GlobalKeyboardHook();
_globalKeyboardHook.KeyboardPressed += OnKeyPressed;
}
private void OnKeyPressed(object sender, GlobalKeyboardHookEventArgs e)
{
//Debug.WriteLine(e.KeyboardData.VirtualCode);
if (e.KeyboardData.VirtualCode != GlobalKeyboardHook.VkSnapshot)
return;
// seems, not needed in the life.
//if (e.KeyboardState == GlobalKeyboardHook.KeyboardState.SysKeyDown &&
// e.KeyboardData.Flags == GlobalKeyboardHook.LlkhfAltdown)
//{
// MessageBox.Show("Alt + Print Screen");
// e.Handled = true;
//}
//else
if (e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyDown)
{
MessageBox.Show("Print Screen");
e.Handled = true;
}
}
public void Dispose()
{
_globalKeyboardHook?.Dispose();
}
}
}
Another option is to use an existing library, such as CodeProject .
Edit:
After thinking about it, you have another problem with this solution. How do you distinguish that what arrives comes from the barcode reader? If I'm not mistaken, some allow you to configure a "chain of control" prior to the barcode itself. If not, the solution is complicated enough.
I have translated hook as hook , in the absence of another more accurate synonym