/// <summary> /// Go to the previous "page" /// </summary> /// <returns>bool if this worked</returns> public bool Previous() { var result = false; var hasScrollInfo = TryRetrievePosition(out var scrollInfoBefore); switch (ScrollMode) { case ScrollModes.KeyboardPageUpDown: result = KeyboardInputGenerator.KeyPresses(VirtualKeyCode.Prior) == 2; break; case ScrollModes.WindowsMessage: result = SendScrollMessage(ScrollBarCommands.SB_PAGEUP); break; case ScrollModes.AbsoluteWindowMessage: if (!hasScrollInfo) { return(false); } // Calculate previous position, clone the scrollInfoBefore var scrollInfoForPrevious = scrollInfoBefore; scrollInfoForPrevious.Position = Math.Max(scrollInfoBefore.Minimum, scrollInfoBefore.Position - (int)scrollInfoBefore.PageSize); result = ApplyPosition(ref scrollInfoForPrevious); break; case ScrollModes.MouseWheel: var bounds = ScrollingWindow.GetInfo().Bounds; var middlePoint = new NativePoint(bounds.X + bounds.Width / 2, bounds.Y + bounds.Height / 2); result = MouseInputGenerator.MoveMouseWheel(WheelDelta, middlePoint) == 1; break; } return(result); }
private async Task TestInput() { // Start a process to test against using (var process = Process.Start("notepad.exe")) { // Make sure it's started Assert.NotNull(process); // Wait until the process started it's message pump (listening for input) process.WaitForInputIdle(); User32Api.SetWindowText(process.MainWindowHandle, "TestInput"); // Find the belonging window var notepadWindow = await WindowsEnumerator.EnumerateWindowsAsync() .Where(interopWindow => { User32Api.GetWindowThreadProcessId(interopWindow.Handle, out var processId); return(processId == process.Id); }) .FirstOrDefaultAsync(); Assert.NotNull(notepadWindow); // Send input var sentInputs = KeyboardInputGenerator.KeyPresses(VirtualKeyCode.KeyR, VirtualKeyCode.KeyO, VirtualKeyCode.KeyB, VirtualKeyCode.KeyI, VirtualKeyCode.KeyN); // Test if we indead sent 10 inputs (5 x down & up) Assert.Equal((uint)10, sentInputs); // Kill the process process.Kill(); } }
/// <summary> /// Set the window as foreground window /// </summary> /// <param name="interopWindow">The window to bring to the foreground</param> /// <param name="workaround">bool with true to use a trick (press Alt) to really bring the window to the foreground</param> public static async ValueTask ToForegroundAsync(this IInteropWindow interopWindow, bool workaround = true) { // Nothing we can do if it's not visible! if (!interopWindow.IsVisible()) { return; } // Window is already the foreground window if (User32Api.GetForegroundWindow() == interopWindow.Handle) { return; } if (interopWindow.IsMinimized()) { interopWindow.Restore(); while (interopWindow.IsMinimized()) { await Task.Delay(50).ConfigureAwait(false); } } // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms633539(v=vs.85).aspx if (workaround) { // Simulate an "ALT" key press, make it double to remove menu activation KeyboardInputGenerator.KeyPresses(VirtualKeyCode.Menu, VirtualKeyCode.Menu); } // Show window in foreground. User32Api.BringWindowToTop(interopWindow.Handle); User32Api.SetForegroundWindow(interopWindow.Handle); }
private async Task TestKeyHandler_Slow_Subscriber() { int pressCount = 0; const int pressHandlingTime = 500; // Wait 2x press plus overhead const int waitForPressHandling = (int)((pressHandlingTime * 2) * 1.1); var sequenceHandler = new KeyCombinationHandler(VirtualKeyCode.Shift, VirtualKeyCode.KeyA) { IgnoreInjected = false }; using (KeyboardHook.KeyboardEvents.Where(sequenceHandler).Subscribe(keyboardHookEventArgs => { Log.Info().WriteLine("Key combination was pressed, slow handling!", null); Thread.Sleep(pressHandlingTime); Log.Info().WriteLine("Key combination was pressed, finished!", null); pressCount++; })) { Log.Info().WriteLine("Pressing key combination", null); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Shift, VirtualKeyCode.KeyA); Log.Info().WriteLine("Pressed key combination", null); Log.Info().WriteLine("Pressing key combination", null); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Shift, VirtualKeyCode.KeyA); Log.Info().WriteLine("Pressed key combination", null); await Task.Delay(waitForPressHandling); Assert.Equal(2, pressCount); } }
private async Task TestKeyHandler_Sequence_InputGenerator() { int pressCount = 0; var sequenceHandler = new KeySequenceHandler( new KeyCombinationHandler(VirtualKeyCode.Print) { IgnoreInjected = false }, new KeyCombinationHandler(VirtualKeyCode.Shift, VirtualKeyCode.KeyA) { IgnoreInjected = false }); using (KeyboardHook.KeyboardEvents.Where(sequenceHandler).Subscribe(keyboardHookEventArgs => pressCount++)) { await Task.Delay(20); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Print); await Task.Delay(20); Assert.True(pressCount == 0); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Shift, VirtualKeyCode.KeyB); await Task.Delay(20); Assert.True(pressCount == 0); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Print); await Task.Delay(20); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Shift, VirtualKeyCode.KeyA); await Task.Delay(20); Assert.True(pressCount == 1); } }
private async Task TestKeyHandler_SingleCombination() { int pressCount = 0; var keyHandler = new KeyCombinationHandler(VirtualKeyCode.Back, VirtualKeyCode.RightShift) { IgnoreInjected = false, IsPassThrough = false }; using (KeyboardHook.KeyboardEvents.Where(keyHandler).Subscribe(keyboardHookEventArgs => pressCount++)) { await Task.Delay(20); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Back, VirtualKeyCode.RightShift); await Task.Delay(20); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Back, VirtualKeyCode.RightShift); await Task.Delay(20); } Assert.True(pressCount == 2); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Back, VirtualKeyCode.RightShift); await Task.Delay(20); Assert.True(pressCount == 2); }
private async Task TestKeyHandler_SequenceWithOptionalKeys_KeyboardInputGenerator() { int pressCount = 0; var sequenceHandler = new KeySequenceHandler( new KeyCombinationHandler(VirtualKeyCode.Print) { IgnoreInjected = false }, new KeyOrCombinationHandler( new KeyCombinationHandler(VirtualKeyCode.Shift, VirtualKeyCode.KeyA) { IgnoreInjected = false }, new KeyCombinationHandler(VirtualKeyCode.Shift, VirtualKeyCode.KeyB) { IgnoreInjected = false }) ) { // Timeout for test Timeout = TimeSpan.FromMilliseconds(200) }; using (KeyboardHook.KeyboardEvents.Where(sequenceHandler).Subscribe(keyboardHookEventArgs => pressCount++)) { await Task.Delay(20); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Print); await Task.Delay(20); Assert.Equal(0, pressCount); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Shift, VirtualKeyCode.KeyB); await Task.Delay(20); Assert.Equal(1, pressCount); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Print); await Task.Delay(20); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Shift, VirtualKeyCode.KeyA); await Task.Delay(20); Assert.Equal(2, pressCount); // Test with timeout, waiting to long KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Print); await Task.Delay(400); KeyboardInputGenerator.KeyCombinationPress(VirtualKeyCode.Shift, VirtualKeyCode.KeyA); await Task.Delay(20); Assert.Equal(2, pressCount); } }
/// <summary> /// Move to the start /// </summary> /// <returns>bool if this worked</returns> public bool Start() { var result = false; var hasScrollInfo = TryRetrievePosition(out var scrollInfoBefore); switch (ScrollMode) { case ScrollModes.KeyboardPageUpDown: KeyboardInputGenerator.KeyDown(VirtualKeyCode.Control); KeyboardInputGenerator.KeyPresses(VirtualKeyCode.Home); KeyboardInputGenerator.KeyUp(VirtualKeyCode.Control); result = true; break; case ScrollModes.WindowsMessage: result = SendScrollMessage(ScrollBarCommands.SB_TOP); break; case ScrollModes.AbsoluteWindowMessage: result = hasScrollInfo; if (hasScrollInfo) { // Calculate start position, clone the scrollInfoBefore var scrollInfoForStart = scrollInfoBefore; scrollInfoForStart.Position = scrollInfoBefore.Minimum; result = ApplyPosition(ref scrollInfoForStart); } break; case ScrollModes.MouseWheel: result = true; while (!IsAtStart) { if (!Previous()) { break; } } break; } return(result); }
/// <summary> /// Test scrolling a window /// </summary> /// <returns></returns> //[StaFact] private async Task TestScrollingAsync() { var breakScroll = false; IDisposable keyboardhook = null; try { keyboardhook = KeyboardHook.KeyboardEvents.Where(args => args.Key == VirtualKeyCode.Escape).Subscribe(args => breakScroll = true); // Start a process to test against using (var process = Process.Start("notepad.exe", "C:\\Windows\\setupact.log")) { // Make sure it's started Assert.NotNull(process); // Wait until the process started it's message pump (listening for input) process.WaitForInputIdle(); try { // Find the belonging window, by the process id var notepadWindow = WindowsEnumerator.EnumerateWindows() .FirstOrDefault(interopWindow => { User32Api.GetWindowThreadProcessId(interopWindow.Handle, out var processId); return(processId == process.Id); }); Assert.NotNull(notepadWindow); // Create a WindowScroller var scroller = notepadWindow.GetChildren().Select(window => window.GetWindowScroller()).FirstOrDefault(); Assert.NotNull(scroller); // Notepad should have ScrollBarInfo scroller.GetScrollbarInfo(); Assert.True(scroller.ScrollBar.HasValue); Log.Info().WriteLine("Scrollbar info: {0}", scroller.ScrollBar.Value); User32Api.SetForegroundWindow(scroller.ScrollingWindow.Handle); await Task.Delay(1000); // Just make sure the window is changed KeyboardInputGenerator.KeyPresses(VirtualKeyCode.Next, VirtualKeyCode.Down); await Task.Delay(2000); scroller.ScrollMode = ScrollModes.WindowsMessage; scroller.ShowChanges = false; // Move the window to the start Assert.True(scroller.Start()); // A delay to make the window move await Task.Delay(2000); // Check if it did move to the start Assert.True(scroller.IsAtStart); // Loop do { if (breakScroll) { break; } // Next "page" Assert.True(scroller.Next()); // Wait a bit, so the window can update await Task.Delay(300); // Loop as long as we are not at the end yet } while (!scroller.IsAtEnd); scroller.Reset(); } finally { // Kill the process process.Kill(); } } } finally { keyboardhook?.Dispose(); } }