C#/Powershell 发送组合键
Posted
技术标签:
【中文标题】C#/Powershell 发送组合键【英文标题】:C# / Powershell send a combination of keys 【发布时间】:2019-10-08 04:01:54 【问题描述】:我发现这个函数利用 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)
【问题讨论】:
通读 MSDN (docs.microsoft.com/en-us/windows/desktop/api/winuser/…) 上的文档,看起来您可以拥有一组输入结构,而不是在SendKeyboard
函数中仅指定一个。如果您可以重载(不太熟悉 C#),您是否可以执行诸如 public static void SendKeyboard(char[] ch)
之类的操作,这将使 KeyInputs
长度等于字符数组?
【参考方案1】:
这是我的尝试,至少应该是一个开始的地方。有一段时间没有在 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;
【讨论】:
以上是关于C#/Powershell 发送组合键的主要内容,如果未能解决你的问题,请参考以下文章
Powershell:捕获组合输出,仅错误输出,将组合输出发送到控制台