How to capture global keystrokes with PowerShell?

后端 未结 2 1874
情书的邮戳
情书的邮戳 2021-01-14 22:46

Can Powershell listen for and capture key presses?

Is it possible to write a PowerShell script that, like AutoHotkey, sits in tray and waits until you press a predef

2条回答
  •  不思量自难忘°
    2021-01-14 23:23

    Not in PowerShell directly maybe, but as you can run pretty much any C# code, here is a basic working example based on an excellent solution by Peter Hinchley:

    Add-Type -TypeDefinition '
    using System;
    using System.IO;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace KeyLogger {
      public static class Program {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
    
        private static HookProc hookProc = HookCallback;
        private static IntPtr hookId = IntPtr.Zero;
        private static int keyCode = 0;
    
        [DllImport("user32.dll")]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
    
        [DllImport("user32.dll")]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);
    
        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
    
        [DllImport("kernel32.dll")]
        private static extern IntPtr GetModuleHandle(string lpModuleName);
    
        public static int WaitForKey() {
          hookId = SetHook(hookProc);
          Application.Run();
          UnhookWindowsHookEx(hookId);
          return keyCode;
        }
    
        private static IntPtr SetHook(HookProc hookProc) {
          IntPtr moduleHandle = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
          return SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, moduleHandle, 0);
        }
    
        private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
    
        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
          if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) {
            keyCode = Marshal.ReadInt32(lParam);
            Application.Exit();
          }
          return CallNextHookEx(hookId, nCode, wParam, lParam);
        }
      }
    }
    ' -ReferencedAssemblies System.Windows.Forms
    
    while ($true) {
        $key = [System.Windows.Forms.Keys][KeyLogger.Program]::WaitForKey()
        if ($key -eq "X") {
            Write-Host "Do something now."
        }
    }
    

    Version 2

    (using a callback):

    Add-Type -TypeDefinition '
      using System;
      using System.IO;
      using System.Diagnostics;
      using System.Runtime.InteropServices;
      using System.Windows.Forms;
    
      namespace PowerShell {
        public static class KeyLogger {
          private const int WH_KEYBOARD_LL = 13;
          private const int WM_KEYDOWN = 0x0100;
    
          private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
    
          private static Action keyCallback;
          private static IntPtr hookId = IntPtr.Zero;
    
          [DllImport("user32.dll")]
          private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
    
          [DllImport("user32.dll")]
          private static extern bool UnhookWindowsHookEx(IntPtr hhk);
    
          [DllImport("user32.dll")]
          private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
    
          [DllImport("kernel32.dll")]
          private static extern IntPtr GetModuleHandle(string lpModuleName);
    
          public static void Run(Action callback) {
            keyCallback = callback;
            hookId = SetHook();
            Application.Run();
            UnhookWindowsHookEx(hookId);
          }
    
          private static IntPtr SetHook() {
            IntPtr moduleHandle = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
            return SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, moduleHandle, 0);
          }
    
          private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) {
              var key = (Keys)Marshal.ReadInt32(lParam);
              keyCallback(key);
            }
            return CallNextHookEx(hookId, nCode, wParam, lParam);
          }
        }
      }
    ' -ReferencedAssemblies System.Windows.Forms
    
    [PowerShell.KeyLogger]::Run({
      param($key)
      if ($key -eq "X") {
        Write-Host "Do something now."
      }
    })
    

提交回复
热议问题