diff --git a/Sources/DesktopManager.Example/KeyboardInputExample.cs b/Sources/DesktopManager.Example/KeyboardInputExample.cs new file mode 100644 index 0000000..65ce13c --- /dev/null +++ b/Sources/DesktopManager.Example/KeyboardInputExample.cs @@ -0,0 +1,20 @@ +using System; +using System.Runtime.InteropServices; + +namespace DesktopManager.Example; + +/// +/// Demonstrates basic keyboard input using . +/// +internal static class KeyboardInputExample { + /// Runs the keyboard input example. + public static void Run() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { + Console.WriteLine("Keyboard input examples require Windows."); + return; + } + + Console.WriteLine("Pressing WIN+R to open Run dialog..."); + KeyboardInputService.PressShortcut(VirtualKey.VK_LWIN, VirtualKey.VK_R); + } +} diff --git a/Sources/DesktopManager.Example/Program.cs b/Sources/DesktopManager.Example/Program.cs index 1cdaefd..cb44d42 100644 --- a/Sources/DesktopManager.Example/Program.cs +++ b/Sources/DesktopManager.Example/Program.cs @@ -78,6 +78,9 @@ static void Main(string[] args) { // Demonstrate window keep-alive features WindowKeepAliveExample.Run(); + // Demonstrate keyboard input features + KeyboardInputExample.Run(); + // Run monitor watcher example for 30 seconds MonitorWatcherExample.RunAsync(TimeSpan.FromSeconds(30)).Wait(); diff --git a/Sources/DesktopManager.Tests/KeyboardInputServiceTests.cs b/Sources/DesktopManager.Tests/KeyboardInputServiceTests.cs new file mode 100644 index 0000000..97b3a2b --- /dev/null +++ b/Sources/DesktopManager.Tests/KeyboardInputServiceTests.cs @@ -0,0 +1,33 @@ +using System.Runtime.InteropServices; + +namespace DesktopManager.Tests; + +[TestClass] +/// +/// Tests for . +/// +public class KeyboardInputServiceTests { + [TestMethod] + /// + /// Test for PressKey_DoesNotThrow. + /// + public void PressKey_DoesNotThrow() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { + Assert.Inconclusive("Test requires Windows"); + } + + KeyboardInputService.PressKey(VirtualKey.VK_F24); + } + + [TestMethod] + /// + /// Test for PressShortcut_DoesNotThrow. + /// + public void PressShortcut_DoesNotThrow() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { + Assert.Inconclusive("Test requires Windows"); + } + + KeyboardInputService.PressShortcut(VirtualKey.VK_F23, VirtualKey.VK_F24); + } +} diff --git a/Sources/DesktopManager/DesktopManager.csproj b/Sources/DesktopManager/DesktopManager.csproj index c7083aa..c76512d 100644 --- a/Sources/DesktopManager/DesktopManager.csproj +++ b/Sources/DesktopManager/DesktopManager.csproj @@ -52,6 +52,8 @@ + + diff --git a/Sources/DesktopManager/KeyboardInputService.cs b/Sources/DesktopManager/KeyboardInputService.cs new file mode 100644 index 0000000..0e85227 --- /dev/null +++ b/Sources/DesktopManager/KeyboardInputService.cs @@ -0,0 +1,74 @@ +using System; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +namespace DesktopManager; + +/// +/// Provides methods for simulating keyboard input. +/// +[SupportedOSPlatform("windows")] +public static class KeyboardInputService { + /// + /// Presses a single key using SendInput. + /// + /// Key to press. + public static void PressKey(VirtualKey key) { + MonitorNativeMethods.INPUT[] inputs = new MonitorNativeMethods.INPUT[2]; + inputs[0].Type = MonitorNativeMethods.INPUT_KEYBOARD; + inputs[0].Data.Keyboard = new MonitorNativeMethods.KEYBDINPUT { + Vk = (ushort)key, + Scan = 0, + Flags = 0, + Time = 0, + ExtraInfo = IntPtr.Zero + }; + inputs[1].Type = MonitorNativeMethods.INPUT_KEYBOARD; + inputs[1].Data.Keyboard = new MonitorNativeMethods.KEYBDINPUT { + Vk = (ushort)key, + Scan = 0, + Flags = MonitorNativeMethods.KEYEVENTF_KEYUP, + Time = 0, + ExtraInfo = IntPtr.Zero + }; + MonitorNativeMethods.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf()); + } + + /// + /// Presses a shortcut combination of keys. + /// + /// Keys to press in order. + public static void PressShortcut(params VirtualKey[] keys) { + if (keys == null || keys.Length == 0) { + throw new ArgumentException("No keys specified", nameof(keys)); + } + + MonitorNativeMethods.INPUT[] inputs = new MonitorNativeMethods.INPUT[keys.Length * 2]; + int index = 0; + foreach (VirtualKey key in keys) { + inputs[index].Type = MonitorNativeMethods.INPUT_KEYBOARD; + inputs[index].Data.Keyboard = new MonitorNativeMethods.KEYBDINPUT { + Vk = (ushort)key, + Scan = 0, + Flags = 0, + Time = 0, + ExtraInfo = IntPtr.Zero + }; + index++; + } + + for (int i = keys.Length - 1; i >= 0; i--) { + inputs[index].Type = MonitorNativeMethods.INPUT_KEYBOARD; + inputs[index].Data.Keyboard = new MonitorNativeMethods.KEYBDINPUT { + Vk = (ushort)keys[i], + Scan = 0, + Flags = MonitorNativeMethods.KEYEVENTF_KEYUP, + Time = 0, + ExtraInfo = IntPtr.Zero + }; + index++; + } + + MonitorNativeMethods.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf()); + } +} diff --git a/Sources/DesktopManager/VirtualKey.cs b/Sources/DesktopManager/VirtualKey.cs new file mode 100644 index 0000000..096dd4a --- /dev/null +++ b/Sources/DesktopManager/VirtualKey.cs @@ -0,0 +1,311 @@ +namespace DesktopManager; + +/// +/// Virtual key codes used for keyboard input. +/// +public enum VirtualKey : ushort { + /// Left mouse button. + VK_LBUTTON = 0x01, + /// Right mouse button. + VK_RBUTTON = 0x02, + /// Cancel key. + VK_CANCEL = 0x03, + /// Middle mouse button. + VK_MBUTTON = 0x04, + /// Backspace key. + VK_BACK = 0x08, + /// Tab key. + VK_TAB = 0x09, + /// Enter key. + VK_RETURN = 0x0D, + /// Shift key. + VK_SHIFT = 0x10, + /// Control key. + VK_CONTROL = 0x11, + /// Alt key. + VK_MENU = 0x12, + /// Pause key. + VK_PAUSE = 0x13, + /// Caps Lock key. + VK_CAPITAL = 0x14, + /// Escape key. + VK_ESCAPE = 0x1B, + /// Spacebar. + VK_SPACE = 0x20, + /// Page Up key. + VK_PRIOR = 0x21, + /// Page Down key. + VK_NEXT = 0x22, + /// End key. + VK_END = 0x23, + /// Home key. + VK_HOME = 0x24, + /// Left Arrow key. + VK_LEFT = 0x25, + /// Up Arrow key. + VK_UP = 0x26, + /// Right Arrow key. + VK_RIGHT = 0x27, + /// Down Arrow key. + VK_DOWN = 0x28, + /// Insert key. + VK_INSERT = 0x2D, + /// Delete key. + VK_DELETE = 0x2E, + /// 0 key. + VK_0 = 0x30, + /// 1 key. + VK_1 = 0x31, + /// 2 key. + VK_2 = 0x32, + /// 3 key. + VK_3 = 0x33, + /// 4 key. + VK_4 = 0x34, + /// 5 key. + VK_5 = 0x35, + /// 6 key. + VK_6 = 0x36, + /// 7 key. + VK_7 = 0x37, + /// 8 key. + VK_8 = 0x38, + /// 9 key. + VK_9 = 0x39, + /// A key. + VK_A = 0x41, + /// B key. + VK_B = 0x42, + /// C key. + VK_C = 0x43, + /// D key. + VK_D = 0x44, + /// E key. + VK_E = 0x45, + /// F key. + VK_F = 0x46, + /// G key. + VK_G = 0x47, + /// H key. + VK_H = 0x48, + /// I key. + VK_I = 0x49, + /// J key. + VK_J = 0x4A, + /// K key. + VK_K = 0x4B, + /// L key. + VK_L = 0x4C, + /// M key. + VK_M = 0x4D, + /// N key. + VK_N = 0x4E, + /// O key. + VK_O = 0x4F, + /// P key. + VK_P = 0x50, + /// Q key. + VK_Q = 0x51, + /// R key. + VK_R = 0x52, + /// S key. + VK_S = 0x53, + /// T key. + VK_T = 0x54, + /// U key. + VK_U = 0x55, + /// V key. + VK_V = 0x56, + /// W key. + VK_W = 0x57, + /// X key. + VK_X = 0x58, + /// Y key. + VK_Y = 0x59, + /// Z key. + VK_Z = 0x5A, + /// Left Windows key. + VK_LWIN = 0x5B, + /// Right Windows key. + VK_RWIN = 0x5C, + /// Numpad 0 key. + VK_NUMPAD0 = 0x60, + /// Numpad 1 key. + VK_NUMPAD1 = 0x61, + /// Numpad 2 key. + VK_NUMPAD2 = 0x62, + /// Numpad 3 key. + VK_NUMPAD3 = 0x63, + /// Numpad 4 key. + VK_NUMPAD4 = 0x64, + /// Numpad 5 key. + VK_NUMPAD5 = 0x65, + /// Numpad 6 key. + VK_NUMPAD6 = 0x66, + /// Numpad 7 key. + VK_NUMPAD7 = 0x67, + /// Numpad 8 key. + VK_NUMPAD8 = 0x68, + /// Numpad 9 key. + VK_NUMPAD9 = 0x69, + /// Multiply key. + VK_MULTIPLY = 0x6A, + /// Add key. + VK_ADD = 0x6B, + /// Separator key. + VK_SEPARATOR = 0x6C, + /// Subtract key. + VK_SUBTRACT = 0x6D, + /// Decimal key. + VK_DECIMAL = 0x6E, + /// Divide key. + VK_DIVIDE = 0x6F, + /// F1 key. + VK_F1 = 0x70, + /// F2 key. + VK_F2 = 0x71, + /// F3 key. + VK_F3 = 0x72, + /// F4 key. + VK_F4 = 0x73, + /// F5 key. + VK_F5 = 0x74, + /// F6 key. + VK_F6 = 0x75, + /// F7 key. + VK_F7 = 0x76, + /// F8 key. + VK_F8 = 0x77, + /// F9 key. + VK_F9 = 0x78, + /// F10 key. + VK_F10 = 0x79, + /// F11 key. + VK_F11 = 0x7A, + /// F12 key. + VK_F12 = 0x7B, + /// F13 key. + VK_F13 = 0x7C, + /// F14 key. + VK_F14 = 0x7D, + /// F15 key. + VK_F15 = 0x7E, + /// F16 key. + VK_F16 = 0x7F, + /// F17 key. + VK_F17 = 0x80, + /// F18 key. + VK_F18 = 0x81, + /// F19 key. + VK_F19 = 0x82, + /// F20 key. + VK_F20 = 0x83, + /// F21 key. + VK_F21 = 0x84, + /// F22 key. + VK_F22 = 0x85, + /// F23 key. + VK_F23 = 0x86, + /// F24 key. + VK_F24 = 0x87, + /// Num Lock key. + VK_NUMLOCK = 0x90, + /// Scroll Lock key. + VK_SCROLL = 0x91, + /// Left Shift key. + VK_LSHIFT = 0xA0, + /// Right Shift key. + VK_RSHIFT = 0xA1, + /// Left Control key. + VK_LCONTROL = 0xA2, + /// Right Control key. + VK_RCONTROL = 0xA3, + /// Left Alt key. + VK_LMENU = 0xA4, + /// Right Alt key. + VK_RMENU = 0xA5, + /// Browser Back key. + VK_BROWSER_BACK = 0xA6, + /// Browser Forward key. + VK_BROWSER_FORWARD = 0xA7, + /// Browser Refresh key. + VK_BROWSER_REFRESH = 0xA8, + /// Browser Stop key. + VK_BROWSER_STOP = 0xA9, + /// Browser Search key. + VK_BROWSER_SEARCH = 0xAA, + /// Browser Favorites key. + VK_BROWSER_FAVORITES = 0xAB, + /// Browser Home key. + VK_BROWSER_HOME = 0xAC, + /// Volume Mute key. + VK_VOLUME_MUTE = 0xAD, + /// Volume Down key. + VK_VOLUME_DOWN = 0xAE, + /// Volume Up key. + VK_VOLUME_UP = 0xAF, + /// Next Track key. + VK_MEDIA_NEXT_TRACK = 0xB0, + /// Previous Track key. + VK_MEDIA_PREV_TRACK = 0xB1, + /// Stop Media key. + VK_MEDIA_STOP = 0xB2, + /// Play/Pause Media key. + VK_MEDIA_PLAY_PAUSE = 0xB3, + /// Launch Mail key. + VK_LAUNCH_MAIL = 0xB4, + /// Launch Media Select key. + VK_LAUNCH_MEDIA_SELECT = 0xB5, + /// Launch App1 key. + VK_LAUNCH_APP1 = 0xB6, + /// Launch App2 key. + VK_LAUNCH_APP2 = 0xB7, + /// OEM 1 key. + VK_OEM_1 = 0xBA, + /// OEM Plus key. + VK_OEM_PLUS = 0xBB, + /// OEM Comma key. + VK_OEM_COMMA = 0xBC, + /// OEM Minus key. + VK_OEM_MINUS = 0xBD, + /// OEM Period key. + VK_OEM_PERIOD = 0xBE, + /// OEM 2 key. + VK_OEM_2 = 0xBF, + /// OEM 3 key. + VK_OEM_3 = 0xC0, + /// OEM 4 key. + VK_OEM_4 = 0xDB, + /// OEM 5 key. + VK_OEM_5 = 0xDC, + /// OEM 6 key. + VK_OEM_6 = 0xDD, + /// OEM 7 key. + VK_OEM_7 = 0xDE, + /// OEM 8 key. + VK_OEM_8 = 0xDF, + /// OEM 102 key. + VK_OEM_102 = 0xE2, + /// Process key. + VK_PROCESSKEY = 0xE5, + /// Packet key. + VK_PACKET = 0xE7, + /// Attention key. + VK_ATTN = 0xF6, + /// CrSel key. + VK_CRSEL = 0xF7, + /// ExSel key. + VK_EXSEL = 0xF8, + /// Erase EOF key. + VK_EREOF = 0xF9, + /// Play key. + VK_PLAY = 0xFA, + /// Zoom key. + VK_ZOOM = 0xFB, + /// NoName key. + VK_NONAME = 0xFC, + /// PA1 key. + VK_PA1 = 0xFD, + /// Clear key. + VK_OEM_CLEAR = 0xFE +}