powershell - 如何使用 PowerShell 捕获全局击键?

标签 powershell hotkeys keystroke keylogger

Powershell 可以监听和捕获按键吗?

是否可以编写一个 PowerShell 脚本,例如 AutoHotkey ,坐在托盘中并等待直到您按下预定义的键盘键开始执行?每次按下所述键时可能不会返回但会开火?

我想要实现的是 - 仅在启动脚本后按按钮执行预定义的脚本操作,因此将其放在桌面上并定义快捷键不起作用。

例如:
我希望每次按“x”键时输入 3 次文本“TEST”,但我希望只有在执行此操作的脚本正在运行时才会发生这种情况。因此,当脚本未运行时 - 按“x”将无济于事。

基本上,AutoHotkey 可以做到这一点,但如果可能的话,我想在 PowerShell 中做到这一点,而无需编写大量 C# 代码,因为那时我只需为此编写一个小型 C# 托盘应用程序。

最佳答案

可能不是直接在 PowerShell 中,但您几乎可以运行任何 C# 代码,这里是一个基于 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."
    }
}

版本 2

(使用回调):
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<Keys> 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<Keys> 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."
  }
})

关于powershell - 如何使用 PowerShell 捕获全局击键?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54236696/

相关文章:

powershell - PowerShell 可以编写 SQL Server Reporting Services RDL 文件的脚本吗?

powershell - PowerShell 中是否有字符串连接快捷方式?

powershell - 将哈希表值属性导出到 CSV 文件

c - 有没有更好的方法来分析在 C 的屏幕上没有打印的情况下按下的键(例如箭头键和 Return)?

java - 将组合键绑定(bind)到 JFrame

powershell - 通过 powershell 脚本使 ms-edge 窗口全屏显示(通常是 F11)

c# - 如何在 C# 中使用热键启动程序?

intellij-idea - Intellij IDEA 向左/向右移动元素(Ctrl+Alt+Shift+Left/Right)在 Ubuntu 18.01 上不起作用

c# - 使用全局热键 : Get key that was actually pressed

c++ - C/C++ 中击键的 Prettyprint ascii 值