Я нашел эту функцию, которая использует код 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)
Вот моя попытка, по крайней мере, должно быть место для начала. Некоторое время не делал никакого кода на С#, поэтому я не уверен, как именно его программировать, но, надеюсь, он должен принимать массив символов, нажимать клавиши в массиве и отправлять в виде структуры массива. Цикл 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;
}
Читая документ в MSDN ( docs.microsoft.com/en-us/windows/desktop/api/winuser/… ), кажется, что у вас может быть массив входных структур вместо указания только одной в вашей функции
SendKeyboard
. Если вы можете перегрузить (не слишком хорошо знакомы с C#), не могли бы вы сделать что-то вродеpublic static void SendKeyboard(char[] ch)
, у которого длинаKeyInputs
будет равна массиву символов?