From e9d0e595633ec26b98f45da91dbaafa3dedfac86 Mon Sep 17 00:00:00 2001 From: Marcos Diez Date: Tue, 27 May 2025 17:54:41 -0300 Subject: [PATCH 1/2] CITRIXKeyUp CITRIXKeyDown CITRIXKeyPress --- WindowsInput/IKeyboardSimulator.cs | 19 +++++ WindowsInput/KeyboardSimulator.cs | 108 +++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/WindowsInput/IKeyboardSimulator.cs b/WindowsInput/IKeyboardSimulator.cs index dbfb2dc..83dc06b 100644 --- a/WindowsInput/IKeyboardSimulator.cs +++ b/WindowsInput/IKeyboardSimulator.cs @@ -27,6 +27,25 @@ public interface IKeyboardSimulator /// The for the key. IKeyboardSimulator KeyPress(VirtualKeyCode keyCode); + /// + /// Simulates the key press gesture for the specified key. + /// + /// The for the key. + IKeyboardSimulator CITRIXKeyPress(VirtualKeyCode keyCode); + + + /// + /// Simulates the key press gesture for the specified key. + /// + /// The VirtualKeyCode to release + IKeyboardSimulator CITRIXKeyUp(VirtualKeyCode keyCode); + + /// + /// Simulates the key press gesture for the specified key. + /// + /// The VirtualKeyCode to press and hold + IKeyboardSimulator CITRIXKeyDown(VirtualKeyCode keyCode); + /// /// Simulates a key press for each of the specified key codes in the order they are specified. /// diff --git a/WindowsInput/KeyboardSimulator.cs b/WindowsInput/KeyboardSimulator.cs index 1c397eb..ea88bdd 100644 --- a/WindowsInput/KeyboardSimulator.cs +++ b/WindowsInput/KeyboardSimulator.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading; using WindowsInput.Native; +using System.Runtime.InteropServices; namespace WindowsInput { @@ -224,5 +225,112 @@ public IKeyboardSimulator Sleep(TimeSpan timeout) Thread.Sleep(timeout); return this; } + + + // source: https://stackoverflow.com/a/5029069 + // CITRIX HACK + // Function used to get the scan code + [DllImport("user32.dll")] + static extern uint MapVirtualKey(uint uCode, uint uMapType); + + [DllImport("User32.dll")] + private static extern uint SendInput(uint numberOfInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] input, int structSize); + + + /// + /// Calls the Win32 SendInput method ... + /// + /// The VirtualKeyCode to press + public IKeyboardSimulator CITRIXKeyPress(VirtualKeyCode keyCode) //prev public static void + { + var down = new INPUT(); + down.Type = (UInt32)InputType.Keyboard; + down.Data.Keyboard = new KEYBDINPUT(); + down.Data.Keyboard.KeyCode = (UInt16)keyCode; //prev .Keyboard.Vk + // Scan Code here, was 0 + down.Data.Keyboard.Scan = (ushort)MapVirtualKey((UInt16)keyCode, 0); + down.Data.Keyboard.Flags = 0; + down.Data.Keyboard.Time = 0; + down.Data.Keyboard.ExtraInfo = IntPtr.Zero; + + var up = new INPUT(); + up.Type = (UInt32)InputType.Keyboard; + up.Data.Keyboard = new KEYBDINPUT(); + up.Data.Keyboard.KeyCode = (UInt16)keyCode; + // Scan Code here, was 0 + up.Data.Keyboard.Scan = (ushort)MapVirtualKey((UInt16)keyCode, 0); + up.Data.Keyboard.Flags = (UInt32)KeyboardFlag.KeyUp; + up.Data.Keyboard.Time = 0; + up.Data.Keyboard.ExtraInfo = IntPtr.Zero; + + INPUT[] inputList = new INPUT[2]; + inputList[0] = down; + inputList[1] = up; + + var numberOfSuccessfulSimulatedInputs = SendInput(2, + inputList, Marshal.SizeOf(typeof(INPUT))); + if (numberOfSuccessfulSimulatedInputs == 0) + throw new Exception( + string.Format("The key press simulation for {0} was not successful.", + keyCode)); + return this; + } + + /// + /// Calls the Win32 SendInput method ... + /// + /// The VirtualKeyCode to press and hold + public IKeyboardSimulator CITRIXKeyDown(VirtualKeyCode keyCode) //prev public static void + { + var down = new INPUT(); + down.Type = (UInt32)InputType.Keyboard; + down.Data.Keyboard = new KEYBDINPUT(); + down.Data.Keyboard.KeyCode = (UInt16)keyCode; //prev .Keyboard.Vk + // Scan Code here, was 0 + down.Data.Keyboard.Scan = (ushort)MapVirtualKey((UInt16)keyCode, 0); + down.Data.Keyboard.Flags = 0; + down.Data.Keyboard.Time = 0; + down.Data.Keyboard.ExtraInfo = IntPtr.Zero; + + INPUT[] inputList = new INPUT[1]; + inputList[0] = down; + + var numberOfSuccessfulSimulatedInputs = SendInput(1, + inputList, Marshal.SizeOf(typeof(INPUT))); + if (numberOfSuccessfulSimulatedInputs == 0) + throw new Exception( + string.Format("The key press simulation for {0} was not successful.", + keyCode)); + return this; + } + + + /// + /// Calls the Win32 SendInput method ... + /// + /// The VirtualKeyCode to release + public IKeyboardSimulator CITRIXKeyUp(VirtualKeyCode keyCode) //prev public static void + { + var up = new INPUT(); + up.Type = (UInt32)InputType.Keyboard; + up.Data.Keyboard = new KEYBDINPUT(); + up.Data.Keyboard.KeyCode = (UInt16)keyCode; + // Scan Code here, was 0 + up.Data.Keyboard.Scan = (ushort)MapVirtualKey((UInt16)keyCode, 0); + up.Data.Keyboard.Flags = (UInt32)KeyboardFlag.KeyUp; + up.Data.Keyboard.Time = 0; + up.Data.Keyboard.ExtraInfo = IntPtr.Zero; + + INPUT[] inputList = new INPUT[1]; + inputList[0] = up; + + var numberOfSuccessfulSimulatedInputs = SendInput(1, + inputList, Marshal.SizeOf(typeof(INPUT))); + if (numberOfSuccessfulSimulatedInputs == 0) + throw new Exception( + string.Format("The key press simulation for {0} was not successful.", + keyCode)); + return this; + } } } \ No newline at end of file From 450662f41b935cb19c30930b09cfd496e3456f82 Mon Sep 17 00:00:00 2001 From: Marcos Diez Date: Tue, 27 May 2025 23:00:13 -0300 Subject: [PATCH 2/2] cleanup --- WindowsInput/KeyboardSimulator.cs | 40 +++++++++++++------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/WindowsInput/KeyboardSimulator.cs b/WindowsInput/KeyboardSimulator.cs index ea88bdd..d9cdd68 100644 --- a/WindowsInput/KeyboardSimulator.cs +++ b/WindowsInput/KeyboardSimulator.cs @@ -227,9 +227,9 @@ public IKeyboardSimulator Sleep(TimeSpan timeout) } - // source: https://stackoverflow.com/a/5029069 // CITRIX HACK // Function used to get the scan code + // source: https://stackoverflow.com/a/5029069 [DllImport("user32.dll")] static extern uint MapVirtualKey(uint uCode, uint uMapType); @@ -276,11 +276,13 @@ public IKeyboardSimulator CITRIXKeyPress(VirtualKeyCode keyCode) //prev public s return this; } + /// /// Calls the Win32 SendInput method ... /// /// The VirtualKeyCode to press and hold - public IKeyboardSimulator CITRIXKeyDown(VirtualKeyCode keyCode) //prev public static void + /// a WindowsInput.Native.KeyboardFlag + private IKeyboardSimulator CITRIXKey(VirtualKeyCode keyCode, UInt32 keyFlag = 0) //prev public static void { var down = new INPUT(); down.Type = (UInt32)InputType.Keyboard; @@ -288,7 +290,7 @@ public IKeyboardSimulator CITRIXKeyDown(VirtualKeyCode keyCode) //prev public st down.Data.Keyboard.KeyCode = (UInt16)keyCode; //prev .Keyboard.Vk // Scan Code here, was 0 down.Data.Keyboard.Scan = (ushort)MapVirtualKey((UInt16)keyCode, 0); - down.Data.Keyboard.Flags = 0; + down.Data.Keyboard.Flags = keyFlag; down.Data.Keyboard.Time = 0; down.Data.Keyboard.ExtraInfo = IntPtr.Zero; @@ -305,32 +307,22 @@ public IKeyboardSimulator CITRIXKeyDown(VirtualKeyCode keyCode) //prev public st } + /// + /// Calls the Win32 SendInput method ... + /// + /// The VirtualKeyCode to press and hold + public IKeyboardSimulator CITRIXKeyDown(VirtualKeyCode keyCode) //prev public static void + { + return CITRIXKey(keyCode); + } + /// /// Calls the Win32 SendInput method ... /// /// The VirtualKeyCode to release public IKeyboardSimulator CITRIXKeyUp(VirtualKeyCode keyCode) //prev public static void { - var up = new INPUT(); - up.Type = (UInt32)InputType.Keyboard; - up.Data.Keyboard = new KEYBDINPUT(); - up.Data.Keyboard.KeyCode = (UInt16)keyCode; - // Scan Code here, was 0 - up.Data.Keyboard.Scan = (ushort)MapVirtualKey((UInt16)keyCode, 0); - up.Data.Keyboard.Flags = (UInt32)KeyboardFlag.KeyUp; - up.Data.Keyboard.Time = 0; - up.Data.Keyboard.ExtraInfo = IntPtr.Zero; - - INPUT[] inputList = new INPUT[1]; - inputList[0] = up; - - var numberOfSuccessfulSimulatedInputs = SendInput(1, - inputList, Marshal.SizeOf(typeof(INPUT))); - if (numberOfSuccessfulSimulatedInputs == 0) - throw new Exception( - string.Format("The key press simulation for {0} was not successful.", - keyCode)); - return this; + return CITRIXKey(keyCode, (UInt32)KeyboardFlag.KeyUp); } } -} \ No newline at end of file +}