기타
키보드 후킹을 이용한 바코드 읽기
카멜레온개발자
2021. 5. 7. 10:21
급조해서 구글링 한 뒤 짠거라 코드가 허접하다..-_-;
정리도 안되어 있다. 그래도 돌아간다.
나중에 정리해야히 하면서 정리 안할듯...
public class KeyboardHook
{
public struct BarCodes
{
public int VirtKey; //Virtual Code
public int ScanCode; //Scan Code
public string KeyName; //Key Name
public uint AscII; //AscII
public char Chr; //character
public string BarCode; //Bar code information
public bool IsValid; //Is the bar code valid
public DateTime Time; //Scan time
}
private struct EventMsg
{
public int message;
public int paramL;
public int paramH;
public int Time;
public int hwnd;
}
static BarCodes barCode = new BarCodes();
public delegate void ProcessCode(string code);
public static ProcessCode ProcCode;
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc callback, IntPtr hInstance, uint threadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("user32.dll")]
static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, int wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("user32.dll")]
static extern uint MapVirtualKey(uint uCode, uint uMapType);
[DllImport("user32", EntryPoint = "GetKeyNameText")]
private static extern int GetKeyNameText(int lParam, 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[] lpKeyState, ref uint lpChar, int uFlags);
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x100;
private static LowLevelKeyboardProc _proc = hookProc;
private static IntPtr hhook = IntPtr.Zero;
static string strBarCode = "";
public static IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
{
if(code == 0)
{
EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg));
if(wParam == (IntPtr)WM_KEYDOWN)
{
barCode.VirtKey = msg.message & 0xff; //Virtual Code
barCode.ScanCode = msg.paramL & 0xff; //Scan Code
uint nonVirtualKey = MapVirtualKey((byte)barCode.VirtKey, 2);
if (nonVirtualKey != 0)
{
barCode.Chr = Convert.ToChar(nonVirtualKey);
if (DateTime.Now.Subtract(barCode.Time).TotalMilliseconds > 50)
{
strBarCode = barCode.Chr.ToString();
}
else
{
if ((msg.message & 0xff) == 13 && strBarCode.Length > 3) //Enter
{
barCode.BarCode = strBarCode;
barCode.IsValid = true;
ProcCode?.Invoke(strBarCode);
}
strBarCode += barCode.Chr.ToString();
}
barCode.Time = DateTime.Now;
barCode.IsValid = false;
}
}
}
//
return CallNextHookEx(hhook, code, (int)wParam, lParam);
}
public static void SetHook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, hInstance, 0);
}
public static void UnHook()
{
UnhookWindowsHookEx(hhook);
}
}
실제로 갖다 쓸때는 다음과 같이 하면 된다
//1. Form_Load같은 초기화 코드
KeyboardHook.SetHook();
KeyboardHook.ProcCode += ProcessCode;
//2. Form_Closing시
KeyboardHook.UnHook();
//3. 바코드가 읽어지면 호출되는 함수
private void ProcessCode(string code)
{
this.Invoke(new MethodInvoker(delegate ()
{
MessageBox.Show(code);
}));
}