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> /// Get the process which the specified window belongs to, the value is cached into the ProcessId of the WindowInfo /// </summary> /// <param name="interopWindow">InteropWindow</param> /// <param name="forceUpdate">set to true to make sure the value is updated</param> /// <returns>int with process Id</returns> public static int GetProcessId(this IInteropWindow interopWindow, bool forceUpdate = false) { if (interopWindow.ProcessId.HasValue && !forceUpdate) { return(interopWindow.ProcessId.Value); } int processId; User32Api.GetWindowThreadProcessId(interopWindow.Handle, out processId); interopWindow.ProcessId = processId; return(interopWindow.ProcessId.Value); }
/// <summary> /// Set the window as foreground window /// </summary> /// <param name="interopWindow">The window to bring to the foreground</param> public static async ValueTask ToForegroundAsync(this IInteropWindow interopWindow) { // Nothing we can do if it's not visible! if (!interopWindow.IsVisible()) { return; } var foregroundWindow = User32Api.GetForegroundWindow(); // Window is already the foreground window if (foregroundWindow == 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 // It was advised to use the menu (ALT) key, but this was a solution which Jan Karger showed me var threadId1 = User32Api.GetWindowThreadProcessId(foregroundWindow, IntPtr.Zero); var threadId2 = User32Api.GetWindowThreadProcessId(interopWindow.Handle, IntPtr.Zero); // Show window in foreground. if (threadId1 != threadId2) { User32Api.AttachThreadInput(threadId1, threadId2, 1); User32Api.SetForegroundWindow(interopWindow.Handle); User32Api.AttachThreadInput(threadId1, threadId2, 0); } else { User32Api.SetForegroundWindow(interopWindow.Handle); } // Show window in foreground. User32Api.BringWindowToTop(interopWindow.Handle); User32Api.SetForegroundWindow(interopWindow.Handle); }
/// <summary> /// Get the current "ClipboardOwner" but only if it isn't us! /// </summary> /// <returns>current clipboard owner</returns> private static string GetClipboardOwner() { string owner = null; try { var hWnd = ClipboardNative.CurrentOwner; if (hWnd != IntPtr.Zero) { try { User32Api.GetWindowThreadProcessId(hWnd, out var pid); using (var me = Process.GetCurrentProcess()) using (var ownerProcess = Process.GetProcessById(pid)) { // Exclude myself if (me.Id != ownerProcess.Id) { // Get Process Name owner = ownerProcess.ProcessName; // Try to get the starting Process Filename, this might fail. try { owner = ownerProcess.Modules[0].FileName; } catch (Exception) { // Ignore } } } } catch (Exception e) { Log.Warn().WriteLine(e, "Non critical error: Couldn't get clipboard process, trying to use the title."); owner = User32Api.GetText(hWnd); } } } catch (Exception e) { Log.Warn().WriteLine(e, "Non critical error: Couldn't get clipboard owner."); } return(owner); }
/// <summary> /// Get the path for the real modern app process belonging to the window /// </summary> /// <param name="interopWindow">IInteropWindow</param> /// <returns></returns> private static string GetAppProcessPath(IInteropWindow interopWindow) { int pid; User32Api.GetWindowThreadProcessId(interopWindow.Handle, out pid); if (string.Equals(interopWindow.GetClassname(), AppQuery.AppFrameWindowClass)) { pid = interopWindow.GetChildren().FirstOrDefault(window => string.Equals(AppQuery.AppWindowClass, window.GetClassname()))?.GetProcessId() ?? 0; } if (pid <= 0) { return(null); } using (var process = Process.GetProcessById(pid)) { return(process.MainModule.FileName); } }
/// <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(); } }