기타

키보드 후킹을 이용한 바코드 읽기

카멜레온개발자 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);
	}));

}