Thứ Năm, 28 tháng 6, 2012

C# – Chặn/vô hiệu hóa thông điệp keyboard bằng Hook


Như trong bài Giới thiệu kĩ thuật Hook và các khái niệm cơ bản đã trình bày, bạn có thể thấy rằng việc gọi CallNextHookEx() là việc cần thiết để tiếp tục gọi các hook procedure khác trong hook chain. Trường hợp bạn muốn chặn một thông điệp hay sự kiện nào đó, chỉ đơn giản là không gọi hàm CallNextHookEx() và trả về giá trị 1 trong hook procedure.
Trong ví dụ sau tôi sẽ chặn các phím Left Windows trên bàn phím, đồng thời cho Sendkey tên của phím đó để thay thế. Khi test bạn hãy mở một cửa sổ soạn thảo văn bản ra (như notepad) và focus nó. Sau đó hãy nhấn Left Windows, bạn sẽ không thấy Start Menu hiện ra và cửa sổ notepad sẽ được chèn vào dòng chữ LWin.
Tôi lấy lại ví dụ trong bài trước và sửa lại Hook procedure:
01private IntPtr KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
02{
03    if (nCode >= 0)
04    {
05        KeyboardHookStruct kbStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam,typeof(KeyboardHookStruct));
06 
07        if (wParam == (IntPtr)WM_KEYDOWN)
08        {
09            Keys k= (Keys)kbStruct.VirtualKeyCode;
10 
11            // disable Left Windows
12            if(k==Keys.LWin)
13            {
14                SendKeys.Send(k.ToString());
15                return (IntPtr)1;
16            }else if(k==Keys.Escape) // exit program
17                Application.Exit();
18        }
19    }
20 
21    return CallNextHookEx(_hookHandle, nCode, wParam, lParam);
22}
Để làm ví dụ trên bạn tạo một WindowsFormsApplication mới, xóa Form1 và thêm lớp Y2KeyboardHook sau:
001using System;
002using System.Runtime.InteropServices;
003using System.Diagnostics;
004using System.Windows.Forms;
005using System.Reflection;
006using System.ComponentModel;
007 
008namespace HookApp
009{
010 
011    class Y2KeyboardHook
012    {
013 
014        #region Win32 API Functions and Constants
015 
016        [DllImport("user32.dll", SetLastError = true)]
017        private static extern IntPtr SetWindowsHookEx(int idHook,
018            KeyboardHookDelegate lpfn, IntPtr hMod, int dwThreadId);
019 
020        [DllImport("user32.dll", SetLastError = true)]
021        private static extern bool UnhookWindowsHookEx(IntPtr hhk);
022 
023        [DllImport("user32.dll", SetLastError = true)]
024        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
025            IntPtr wParam, IntPtr lParam);
026 
027        [DllImport("kernel32.dll")]
028        private static extern IntPtr GetModuleHandle(string lpModuleName);
029 
030        private const int WH_KEYBOARD_LL = 13;
031 
032        private const int WM_KEYDOWN = 0x0100;
033        private const int WM_KEYUP = 0x101;
034 
035        #endregion
036 
037        private KeyboardHookDelegate _hookProc;
038        private IntPtr _hookHandle = IntPtr.Zero;
039 
040        public delegate IntPtr KeyboardHookDelegate(int nCode, IntPtr wParam, IntPtr lParam);
041 
042        [StructLayout(LayoutKind.Sequential)]
043        public struct KeyboardHookStruct
044        {
045            public int VirtualKeyCode;
046            public int ScanCode;
047            public int Flags;
048            public int Time;
049            public int ExtraInfo;
050        }
051 
052        // destructor
053        ~Y2KeyboardHook()
054        {
055            Uninstall();
056        }
057 
058        public void Install()
059        {
060            _hookProc = KeyboardHookProc;
061            _hookHandle = SetupHook(_hookProc);
062 
063            if (_hookHandle == IntPtr.Zero)
064                throw new Win32Exception(Marshal.GetLastWin32Error());
065        }
066        private IntPtr SetupHook(KeyboardHookDelegate hookProc)
067        {
068            IntPtr hInstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);
069 
070            return SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
071        }
072 
073        private IntPtr KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
074        {
075            if (nCode >= 0)
076            {
077                KeyboardHookStruct kbStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam,typeof(KeyboardHookStruct));
078 
079                if (wParam == (IntPtr)WM_KEYDOWN)
080                {
081                    Keys k= (Keys)kbStruct.VirtualKeyCode;
082 
083                    // disable Left Windows, Left Shift and Left Control keys
084                    if(k==Keys.LWin)
085                    {
086                        SendKeys.Send(k.ToString());
087                        return (IntPtr)1;
088                    }else if(k==(Keys.Escape)) // exit program
089                        Application.Exit();
090                }
091            }
092 
093            return CallNextHookEx(_hookHandle, nCode, wParam, lParam);
094        }
095 
096        public void Uninstall()
097        {
098            UnhookWindowsHookEx(_hookHandle);
099        }
100 
101    }
102}
Lớp Program:
01using System;
02using System.Windows.Forms;
03using HookApp;
04 
05namespace WindowsFormsApplication1
06{
07    internal sealed class Program
08    {
09 
10        [STAThread]
11        private static void Main(string[] args)
12        {
13            Y2KeyboardHook keyboardHook = new Y2KeyboardHook();
14            keyboardHook.Install();
15            Application.Run();
16        }
17 
18    }
19}
Muốn thoát ứng dụng bạn hãy nhấn Escape.

Không có nhận xét nào: