C#/Powershell 发送组合键

C# / Powershell send a combination of keys

我发现这个函数使用 C# 代码通过 PowerShell 模拟按键。

我可以像这样模拟一个 WINDOWS 键:

[KBEmulator]::SendScanCode(0x5B)

但是我想发送组合 WINDOWS+CTRL+SHIFT+B

其中,就 ScanCode 而言是:

0x5B + 0x11 + 0x10 + 0x42 

不幸的是,我只精通 PowerShell 而对 C# 一无所知。

有没有一种方法可以修改此代码以使用组合键而不是一次只使用一个键?

功能按键:

Function KeyPress {

Param (
    [Parameter(position=0, mandatory=$true, parametersetname='key')]
    [char]$Key,
    [Parameter(position=0, mandatory=$true, parametersetname='scancode')]
    [int]$ScanCode
)

$code = @"
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

public static class KBEmulator {    
    public enum InputType : uint {
        INPUT_MOUSE = 0,
        INPUT_KEYBOARD = 1,
        INPUT_HARDWARE = 3
    }

    [Flags]
    internal enum KEYEVENTF : uint
    {
        KEYDOWN = 0x0,
        EXTENDEDKEY = 0x0001,
        KEYUP = 0x0002,
        SCANCODE = 0x0008,
        UNICODE = 0x0004
    }

    [Flags]
    internal enum MOUSEEVENTF : uint
    {
        ABSOLUTE = 0x8000,
        HWHEEL = 0x01000,
        MOVE = 0x0001,
        MOVE_NOCOALESCE = 0x2000,
        LEFTDOWN = 0x0002,
        LEFTUP = 0x0004,
        RIGHTDOWN = 0x0008,
        RIGHTUP = 0x0010,
        MIDDLEDOWN = 0x0020,
        MIDDLEUP = 0x0040,
        VIRTUALDESK = 0x4000,
        WHEEL = 0x0800,
        XDOWN = 0x0080,
        XUP = 0x0100
    }

    // Master Input structure
    [StructLayout(LayoutKind.Sequential)]
    public struct lpInput {
        internal InputType type;
        internal InputUnion Data;
        internal static int Size { get { return Marshal.SizeOf(typeof(lpInput)); } }            
    }

    // Union structure
    [StructLayout(LayoutKind.Explicit)]
    internal struct InputUnion {
        [FieldOffset(0)]
        internal MOUSEINPUT mi;
        [FieldOffset(0)]
        internal KEYBDINPUT ki;
        [FieldOffset(0)]
        internal HARDWAREINPUT hi;
    }

    // Input Types
    [StructLayout(LayoutKind.Sequential)]
    internal struct MOUSEINPUT
    {
        internal int dx;
        internal int dy;
        internal int mouseData;
        internal MOUSEEVENTF dwFlags;
        internal uint time;
        internal UIntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct KEYBDINPUT
    {
        internal short wVk;
        internal short wScan;
        internal KEYEVENTF dwFlags;
        internal int time;
        internal UIntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct HARDWAREINPUT
    {
        internal int uMsg;
        internal short wParamL;
        internal short wParamH;
    }

    private class unmanaged {
        [DllImport("user32.dll", SetLastError = true)]
        internal static extern uint SendInput (
            uint cInputs, 
            [MarshalAs(UnmanagedType.LPArray)]
            lpInput[] inputs,
            int cbSize
        );

        [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern short VkKeyScan(char ch);
    }

    internal static short VkKeyScan(char ch) {
        return unmanaged.VkKeyScan(ch);
    }

    internal static uint SendInput(uint cInputs, lpInput[] inputs, int cbSize) {
        return unmanaged.SendInput(cInputs, inputs, cbSize);
    }

    public static void SendScanCode(short scanCode) {
        lpInput[] KeyInputs = new lpInput[1];
        lpInput KeyInput = new lpInput();
        // Generic Keyboard Event
        KeyInput.type = InputType.INPUT_KEYBOARD;
        KeyInput.Data.ki.wScan = 0;
        KeyInput.Data.ki.time = 0;
        KeyInput.Data.ki.dwExtraInfo = UIntPtr.Zero;


        // Push the correct key
        KeyInput.Data.ki.wVk = scanCode;
        KeyInput.Data.ki.dwFlags = KEYEVENTF.KEYDOWN;
        KeyInputs[0] = KeyInput;
        SendInput(1, KeyInputs, lpInput.Size);

        // Release the key
        KeyInput.Data.ki.dwFlags = KEYEVENTF.KEYUP;
        KeyInputs[0] = KeyInput;
        SendInput(1, KeyInputs, lpInput.Size);

        return;
    }

    public static void SendKeyboard(char ch) {
        lpInput[] KeyInputs = new lpInput[1];
        lpInput KeyInput = new lpInput();
        // Generic Keyboard Event
        KeyInput.type = InputType.INPUT_KEYBOARD;
        KeyInput.Data.ki.wScan = 0;
        KeyInput.Data.ki.time = 0;
        KeyInput.Data.ki.dwExtraInfo = UIntPtr.Zero;


        // Push the correct key
        KeyInput.Data.ki.wVk = VkKeyScan(ch);
        KeyInput.Data.ki.dwFlags = KEYEVENTF.KEYDOWN;
        KeyInputs[0] = KeyInput;
        SendInput(1, KeyInputs, lpInput.Size);

        // Release the key
        KeyInput.Data.ki.dwFlags = KEYEVENTF.KEYUP;
        KeyInputs[0] = KeyInput;
        SendInput(1, KeyInputs, lpInput.Size);

        return;
    }
}
"@

if(([System.AppDomain]::CurrentDomain.GetAssemblies() | ?{$_ -match "KBEmulator"}) -eq $null) {
    Add-Type -TypeDefinition $code
}

switch($PSCmdlet.ParameterSetName){
    'key' { [KBEmulator]::SendKeyboard($Key) }
    'scancode' { [KBEmulator]::SendScanCode($ScanCode) }
}

}

[KBEmulator]::SendScanCode(0x5B)

这是我的尝试,至少应该是一个开始的地方。有一段时间没有在 C# 中编写任何代码,所以不确定如何在其中进行编程,但希望它应该接受字符数组并按下数组中的键并作为数组结构发送。 for 循环可能是索引关闭,但不确定,并且可能存在我在代码中没有意识到的随机错误,我什至不确定它是否会同时按下所有按键或一次按下一个按键,但希望这可以帮助您了解从哪里开始。

public static void SendKeyboard(char ch) {
    lpInput[] KeyInputs = new lpInput[1];
    lpInput KeyInput = new lpInput();
    // Generic Keyboard Event
    KeyInput.type = InputType.INPUT_KEYBOARD;
    KeyInput.Data.ki.wScan = 0;
    KeyInput.Data.ki.time = 0;
    KeyInput.Data.ki.dwExtraInfo = UIntPtr.Zero;


    // Push the correct key
    KeyInput.Data.ki.wVk = VkKeyScan(ch);
    KeyInput.Data.ki.dwFlags = KEYEVENTF.KEYDOWN;
    KeyInputs[0] = KeyInput;
    SendInput(1, KeyInputs, lpInput.Size);

    // Release the key
    KeyInput.Data.ki.dwFlags = KEYEVENTF.KEYUP;
    KeyInputs[0] = KeyInput;
    SendInput(1, KeyInputs, lpInput.Size);

    return;  
    }

 // Attempt at overloading for multiple key presses
 public static void SendKeyboard(char[] ch) {
    lpInput[] KeyInputs = new lpInput[ch.length];

    // Push the correct key
    for (int i = 0; i < ch.length; i++) {
    // Generate new memory address for KeyInput each time
    lpInput KeyInput = new lpInput();
    // Generic Keyboard Event
    KeyInput.type = InputType.INPUT_KEYBOARD;
    KeyInput.Data.ki.wScan = 0;
    KeyInput.Data.ki.time = 0;
    KeyInput.Data.ki.dwExtraInfo = UIntPtr.Zero;
    KeyInput.Data.ki.wVk = VkKeyScan(ch[i]);
    KeyInput.Data.ki.dwFlags = KEYEVENTF.KEYDOWN;
    KeyInputs[i] = KeyInput;
    }
    SendInput( ch.length, KeyInputs, ( lpInput.Size * ch.length ) );

    // Release the key
    for (int i = 0; i < ch.length; i++) {
    // Generate new memory address for KeyInput each time
    lpInput KeyInput = new lpInput();
    // Generic Keyboard Event
    KeyInput.type = InputType.INPUT_KEYBOARD;
    KeyInput.Data.ki.wScan = 0;
    KeyInput.Data.ki.time = 0;
    KeyInput.Data.ki.dwExtraInfo = UIntPtr.Zero;
    KeyInput.Data.ki.wVk = VkKeyScan(ch[i]);
    KeyInput.Data.ki.dwFlags = KEYEVENTF.KEYUP;
    KeyInputs[i] = KeyInput;
    }
    SendInput(ch.length, KeyInputs, ( lpInput.Size * ch.length ) );

    return;  
    }