How to listen for keyboard input and modify it to specific input?

54890279 0 Reputation points
2023-03-13T09:05:11.4566667+00:00

Hi everyone,

I have a barcode scanner that acts as a keyboard input. I need it to only input "def" when I scan "abc,def" in any input field such as webpages, applications, etc.

Below is my attempt.

public struct BarCodes
{
	public int VirtKey;
	public int ScanCode;
	public string KeyName;
	public uint Ascll;
	public char Chr;
	public string BarCode;
	public bool IsValid;
	public DateTime Time;
}

private struct EventMsg
{
	public int message;
	public int paramL;
	public int paramH;
	public int Time;
	public int hwnd;
}

delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
BarCodes barCode = new BarCodes();
int hKeyboardHook = 0;
string strBarCode = "";

//install hook
public bool KeyboardStart()
{
	if (hKeyboardHook == 0)
	{
		hookproc = new HookProc(KeyboardHookProc);

		IntPtr moduleptr = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);

		hKeyboardHook = SetWindowsHookEx(13, hookproc, moduleptr, 0);


		//WH_KEYBOARD_LL=13
		//hKeyboardHook = SetWindowsHookEx(13, new HookProc(KeyboardHookProc), Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
	}
	return (hKeyboardHook != 0);
}

//uninstall hook
public bool KeyboardStop()
{
	if (hKeyboardHook != 0)
	{
		return UnhookWindowsHookEx(hKeyboardHook);
	}
	return true;
}

private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
	if (nCode == 0)
	{
		EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg));
		if (wParam == 0x100)//WM_KEYDOWN=0x100
		{
			barCode.VirtKey = msg.message & 0xff;
			barCode.ScanCode = msg.paramL & 0xff;
			StringBuilder strKeyName = new StringBuilder(225);
			if (GetKeyNameText(barCode.ScanCode * 65536, strKeyName, 255) > 0)
			{
				barCode.KeyName = strKeyName.ToString().Trim(new char[] { ' ', '\0' });
			}
			else
			{
				barCode.KeyName = "";
			}
			byte[] kbArray = new byte[256];
			uint uKey = 0;
			GetKeyboardState(kbArray);


			if (ToAscii(barCode.VirtKey, barCode.ScanCode, kbArray, ref uKey, 0))
			{
				barCode.Ascll = uKey;
				barCode.Chr = Convert.ToChar(uKey);
			}

			TimeSpan ts = DateTime.Now.Subtract(barCode.Time);

			if (ts.TotalMilliseconds > 50)
			{
				strBarCode = barCode.Chr.ToString();
			}
			else
			{
				if ((msg.message & 0xff) == 13 && strBarCode.Length > 3)
				{

					barCode.BarCode = strBarCode;
					barCode.IsValid = true;


					//methods 1
					//it can run on button click event and hook,but can not run on webpages.
					//------------------------------------------------
					IntPtr foregroundWindow = GetForegroundWindow();
					int foregroundWindowProcessId;
					GetWindowThreadProcessId(foregroundWindow, out foregroundWindowProcessId);
					Process foregroundProcess = Process.GetProcessById(foregroundWindowProcessId);

					List<IntPtr> result = new List<IntPtr>();
					int ct = 0;
					IntPtr prevChild = IntPtr.Zero;
					IntPtr currChild = IntPtr.Zero;

					while (true && ct < 100)
					{
						currChild = FindWindowEx(foregroundProcess.MainWindowHandle, prevChild, null, null);
						if (currChild == IntPtr.Zero) break;
						result.Add(currChild);
						prevChild = currChild;
						++ct;
					}

					Point caretPos = Cursor.Position;
					IntPtr target = IntPtr.Zero;
					target = WindowFromPoint(caretPos);

					foreach (IntPtr hWnd in result)
					{
						if (hWnd == target)
						{
							Clipboard.SetText(BarcodeSplit(strBarCode) + "\r");
							SendMessage(hWnd, WM_PASTE, 0, "");
						}
					}

					private string BarcodeSplit(string str)
					{
						string[] BarcodeArray = str.Split(',');
						if (LimitCode.Contains(BarcodeArray[2]))
						{
							return BarcodeArray[0];
						}
						else
						{
							return BarcodeArray[1];
						}
					}
					//------------------------------------------------

					//methods 2
					//it can not run on hook
					//------------------------------------------------
					IntPtr foregroundWindow = GetForegroundWindow();
					//set windows focus
					SetForegroundWindow(foregroundWindow);

					INPUT Input = new INPUT();
					Input.type = 1; //keyboard_input
					Input.ki.wVk = 0x42; //CAPS_Lock
					Input.ki.dwFlags = 0;
					SendInput(1, ref Input, Marshal.SizeOf(Input));

					//放開Caps Lock
					Input = new INPUT();
					Input.type = 1;
					Input.ki.wVk = 0x42;
					Input.ki.dwFlags = 2;//key_up
					SendInput(1, ref Input, Marshal.SizeOf(Input));

					//------------------------------------------------

					//methods 3
					//it can not run on hook
					//------------------------------------------------
					IntPtr foregroundWindow = GetForegroundWindow();
					//set windows focus
					SetForegroundWindow(foregroundWindow);
					SendKeys.Send(barCode.BarCode);
					//------------------------------------------------
				}
				strBarCode += barCode.Chr.ToString();
			}
			barCode.Time = DateTime.Now;
			if (BarCodeEvent != null) BarCodeEvent(barCode);//觸發事件
			barCode.IsValid = false;
		}
	}
	//stop keyboard key in
	return 1;
}


//Below are relevant quotes.
[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, Int32 wParam, IntPtr lParam);

[DllImport("user32", EntryPoint = "GetKeyNameText")]
private static extern int GetKeyNameText(int IParam, StringBuilder lpBuffer, int nSize);

[DllImport("user32", EntryPoint = "GetKeyboardState")]
private static extern int GetKeyboardState(byte[] pbKeyState);

[DllImport("user32", EntryPoint = "ToAscii")]
private static extern bool ToAscii(int VirtualKey, int ScanCode, byte[] lpKeySate, ref uint lpChar, int uFlags);

[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string name);

// Get a handle to an application window.
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

// Activate an application window.
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, uint wParam, string lParam);

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

private const int WM_SETTEXT = 0x000C;

private const int WM_PASTE = 0x0302;

[DllImport("User32.dll")]
public static extern int SendMessageW(IntPtr hWnd, int uMsg, int wParam, int lParam);

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId);

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern IntPtr GetFocus();

[DllImport("user32.dll")]
private static extern IntPtr GetAncestor(IntPtr hWnd, uint flags);

private const uint GA_ROOT = 2;

[DllImport("user32.dll")]
static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);

[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
internal static extern int AttachThreadInput(int idAttach, int idAttachTo, bool fAttach);

[DllImport("kernel32.dll")]
internal static extern int GetCurrentThreadId();

[DllImport("user32.dll")]
public static extern bool GetGUIThreadInfo(int idThread, ref GUITHREADINFO lpgui);

[StructLayout(LayoutKind.Sequential)]
public struct GUITHREADINFO
{
	public int cbSize;
	public uint flags;
	public IntPtr hwndActive;
	public IntPtr hwndFocus;
	public IntPtr hwndCapture;
	public IntPtr hwndMenuOwner;
	public IntPtr hwndMoveSize;
	public IntPtr hwndCaret;
	public RECT rcCaret;
}

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
	public int Left;
	public int Top;
	public int Right;
	public int Bottom;
}

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

[DllImport("user32.dll", EntryPoint = "ChildWindowFromPointEx")]//指定坐标处窗体句柄
private static extern IntPtr ChildWindowFromPointEx(IntPtr hwnd, Point pt, uint flags);

[DllImport("user32.dll")]
public static extern bool GetCaretPos(out Point lpPoint);

[StructLayout(LayoutKind.Explicit)]
internal struct INPUT
{
	[FieldOffset(0)]
	internal int type;//0:mouse event;1:keyboard event;2:hardware event
	[FieldOffset(4)]
	internal MOUSEINPUT mi;
	[FieldOffset(4)]
	internal KEYBDINPUT ki;
	[FieldOffset(4)]
	internal HARDWAREINPUT hi;
}

[StructLayout(LayoutKind.Sequential)]
internal struct HARDWAREINPUT
{
	internal int uMsg;
	internal short wParamL;
	internal short wParamH;
}

[StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT
{
	internal ushort wVk;
	internal ushort wScan;
	internal uint dwFlags;
	internal uint time;
	internal IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
internal struct MOUSEINPUT
{
	internal int dx;
	internal int dy;
	internal int mouseData;
	internal int dwFlags;
	internal int time;
	internal IntPtr dwExtraInfo;
}

How can I modify it to achieve my desired goal?

If there are any missing parameters provided, please let me know.

Developer technologies Windows Forms
Developer technologies C#
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.