첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.

728x90
반응형
728x170

TestProject.zip
0.01MB

▶ LowLevelKeyboardHook.cs

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 저수준 키보드 후킹
    /// </summary>
    public class LowLevelKeyboardHook
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Delegate
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 저수준 키보드 대리자 - LowLevelKeyboardDelegate(code, wordParameter, longParameter)

        /// <summary>
        /// 저수준 키보드 대리자
        /// </summary>
        /// <param name="code">코드</param>
        /// <param name="wordParameter">WORD 매개 변수</param>
        /// <param name="longParameter">LONG 매개 변수</param>
        /// <returns></returns>
        private delegate IntPtr LowLevelKeyboardDelegate(int code, IntPtr wordParameter, IntPtr longParameter);

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Import
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 모듈 핸들 구하기 - GetModuleHandle(moduleName)

        /// <summary>
        /// 모듈 핸들 구하기
        /// </summary>
        /// <param name="moduleName">모듈명</param>
        /// <returns>모듈 핸들</returns>
        [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string moduleName);

        #endregion
        #region 윈도우즈 후킹 설정하기 (확장) - SetWindowsHookEx(hookType, callback, moduleHandle, threadID)

        /// <summary>
        /// 윈도우즈 후킹 설정하기 (확장)
        /// </summary>
        /// <param name="hookType">후킹 타입</param>
        /// <param name="callback">콜백 함수</param>
        /// <param name="moduleHandle">모듈 핸들</param>
        /// <param name="threadID">쓰레드 ID</param>
        /// <returns>후킹 ID</returns>
        [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int hookType, LowLevelKeyboardDelegate callback, IntPtr moduleHandle, uint threadID);

        #endregion
        #region 다음 후킹 호출하기 (확장) - CallNextHookEx(hookID, code, wordParameter, longParameter)

        /// <summary>
        /// 다음 후킹 호출하기 (확장)
        /// </summary>
        /// <param name="hookID">후킹 ID</param>
        /// <param name="code">코드</param>
        /// <param name="wordParameter">WORD 매개 변수</param>
        /// <param name="longParameter">LONG 매개 변수</param>
        /// <returns>후킹 ID</returns>
        [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hookID, int code, IntPtr wordParameter, IntPtr longParameter);

        #endregion
        #region 윈도우즈 후킹 취소하기 (확장) - UnhookWindowsHookEx(hookID)

        /// <summary>
        /// 윈도우즈 후킹 취소하기 (확장)
        /// </summary>
        /// <param name="hookID">후킹 ID</param>
        /// <returns>처리 결과</returns>
        [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hookID);

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Event
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 키 PRESSED 이벤트 - KeyPressed

        /// <summary>
        /// 키 PRESSED 이벤트
        /// </summary>
        public event EventHandler<Keys> KeyPressed;

        #endregion
        #region 키 UNPRESSED 이벤트 - KeyUnpressed

        /// <summary>
        /// 키 UNPRESSED 이벤트
        /// </summary>
        public event EventHandler<Keys> KeyUnpressed;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// WH_KEYBOARD_LL
        /// </summary>
        private const int WH_KEYBOARD_LL = 13;

        /// <summary>
        /// WM_KEYDOWN
        /// </summary>
        private const int WM_KEYDOWN = 0x0100;

        /// <summary>
        /// WM_SYSKEYDOWN
        /// </summary>
        private const int WM_SYSKEYDOWN = 0x0104;

        /// <summary>
        /// WM_KEYUP
        /// </summary>
        private const int WM_KEYUP = 0x101;

        /// <summary>
        /// WM_SYSKEYUP
        /// </summary>
        private const int WM_SYSKEYUP = 0x105;

        /// <summary>
        /// 저수준 키보드 대리자
        /// </summary>
        private LowLevelKeyboardDelegate lowLevelKeyboardDelegate;

        /// <summary>
        /// 후킹 ID
        /// </summary>
        private IntPtr hookID = IntPtr.Zero;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - LowLevelKeyboardHook()

        /// <summary>
        /// 생성자
        /// </summary>
        public LowLevelKeyboardHook()
        {
            this.lowLevelKeyboardDelegate = ProcessLowLevelKeyboard;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 키보드 후킹하기 - HookKeyboard()

        /// <summary>
        /// 키보드 후킹하기
        /// </summary>
        public void HookKeyboard()
        {
            this.hookID = SetHook(this.lowLevelKeyboardDelegate);
        }

        #endregion
        #region 키보드 후킹 취소하기 - UnHookKeyboard()

        /// <summary>
        /// 키보드 후킹 취소하기
        /// </summary>
        public void UnHookKeyboard()
        {
            UnhookWindowsHookEx(this.hookID);
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 후킹 설정하기 - SetHook(lowLevelKeyboardDelegate)

        /// <summary>
        /// 후킹 설정하기
        /// </summary>
        /// <param name="lowLevelKeyboardDelegate">저수준 키보드 대리자</param>
        /// <returns>후킹 ID</returns>
        private IntPtr SetHook(LowLevelKeyboardDelegate lowLevelKeyboardDelegate)
        {
            using(Process process = Process.GetCurrentProcess())
            {
                using(ProcessModule processModule = process.MainModule)
                {
                    return SetWindowsHookEx
                    (
                        WH_KEYBOARD_LL,
                        lowLevelKeyboardDelegate,
                        GetModuleHandle(processModule.ModuleName),
                        0
                    );
                }
            }
        }

        #endregion
        #region 저수준 키보드 처리하기 - ProcessLowLevelKeyboard(code, wordParameter, longParameter)

        /// <summary>
        /// 저수준 키보드 처리하기
        /// </summary>
        /// <param name="code">코드</param>
        /// <param name="wordParameter">WORD 매개 변수</param>
        /// <param name="longParameter">LONG 매개 변수</param>
        /// <returns>처리 결과</returns>
        private IntPtr ProcessLowLevelKeyboard(int code, IntPtr wordParameter, IntPtr longParameter)
        {
            if(code >= 0 && wordParameter == (IntPtr)WM_KEYDOWN || wordParameter == (IntPtr)WM_SYSKEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(longParameter);

                KeyPressed?.Invoke(this, ((Keys)vkCode));
            }
            else if(code >= 0 && wordParameter == (IntPtr)WM_KEYUP || wordParameter == (IntPtr)WM_SYSKEYUP)
            {
                int vkCode = Marshal.ReadInt32(longParameter);

                KeyUnpressed?.Invoke(this, ((Keys)vkCode));
            }

            return CallNextHookEx(hookID, code, wordParameter, longParameter);
        }

        #endregion
    }
}

 

728x90

 

▶ MainForm.cs

using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 메인 폼
    /// </summary>
    public partial class MainForm : Form
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainForm()
        {
            InitializeComponent();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 메시지 표시하기 - DisplayMessage(keys)

        /// <summary>
        /// 메시지 표시하기
        /// </summary>
        /// <param name="keys">키</param>
        public void DisplayMessage(Keys keys)
        {
            this.messageLabel.Text = keys.ToString();
        }

        #endregion
    }
}

 

300x250

 

▶ Program.cs

using System;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 프로그램
    /// </summary>
    class Program
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 프로그램 시작하기 - Main()

        /// <summary>
        /// 프로그램 시작하기
        /// </summary>
        [STAThread]
        private static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            MainForm mainForm = new MainForm();

            LowLevelKeyboardHook keyboardHook = new LowLevelKeyboardHook();

            keyboardHook.KeyPressed += (sender, e) => mainForm.DisplayMessage(e);

            keyboardHook.HookKeyboard();

            Application.Run(mainForm);

            keyboardHook.UnHookKeyboard();
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요