private AttachedThreadInputScope() { s_current.Value?.Dispose(); s_current.Value = this; _foregroundWindow = WinApi.GetForegroundWindow(); _currentThreadId = WinApi.GetCurrentThreadId(); _foregroundThreadId = WinApi.GetWindowThreadProcessId(_foregroundWindow, out var _); if (_currentThreadId != _foregroundThreadId) { // attach to the foreground thread if (!WinApi.AttachThreadInput(_currentThreadId, _foregroundThreadId, true)) { // unable to attach, see if the window is a Win10 Console Window var className = new StringBuilder(capacity: 256); WinApi.GetClassName(_foregroundWindow, className, className.Capacity - 1); if (String.CompareOrdinal("ConsoleWindowClass", className.ToString()) != 0) { return; } // consider attached to a console window } } _attached = true; }
public static bool TryGetThirdPartyForgroundWindow(out IntPtr hwnd) { hwnd = IntPtr.Zero; var foregroundWindow = WinApi.GetForegroundWindow(); var currentThreadId = WinApi.GetCurrentThreadId(); var foregroundThread = WinApi.GetWindowThreadProcessId(foregroundWindow, out var _); if (currentThreadId == foregroundThread) { return(false); } else { var hwndRoot = WinApi.GetAncestor(foregroundWindow, WinApi.GA_ROOT); if (hwndRoot != IntPtr.Zero) { foregroundWindow = hwndRoot; } var className = new StringBuilder(capacity: 256); WinApi.GetClassName(foregroundWindow, className, className.Capacity - 1); if (className.ToString().CompareTo("Shell_TrayWnd") == 0) { return(false); } hwnd = foregroundWindow; return(true); } }
public static async Task <bool> FeedTextAsync(string text, CancellationToken token) { await s_asyncLock.WaitAsync(token); try { var foregroundWindow = WinApi.GetForegroundWindow(); WinApi.BlockInput(true); try { var size = Marshal.SizeOf <WinApi.INPUT>(); var input = new WinApi.INPUT[1]; // feed each character individually and asynchronously foreach (var c in text) { token.ThrowIfCancellationRequested(); if (WinApi.GetForegroundWindow() != foregroundWindow || IsAnyKeyPressed()) { break; } if (c == '\n' || c == '\r') { // we need this for correctly handling line breaks // when pasting into Chromium's <textarea> SimulateKeyDown(WinApi.VK_RETURN); SimulateKeyUp(WinApi.VK_RETURN); } else { CharToKeyboardInput(c, ref input[0]); if (WinApi.SendInput((uint)input.Length, input, size) == 0) { break; } } if (InputHelpers.AnyInputMessage(WinApi.QS_ALLINPUT)) { await InputHelpers.TimerYield(token : token); } } return(true); } finally { WinApi.BlockInput(false); } } finally { s_asyncLock.Release(); } }
public static async Task <bool> FeedTextAsync(string text, CancellationToken token) { await s_asyncLock.WaitAsync(token); try { var foregroundWindow = WinApi.GetForegroundWindow(); WinApi.BlockInput(true); try { var size = Marshal.SizeOf <WinApi.INPUT>(); var input = new WinApi.INPUT[1]; // feed each character individually and asynchronously foreach (var c in text) { token.ThrowIfCancellationRequested(); if (WinApi.GetForegroundWindow() != foregroundWindow || IsAnyKeyPressed()) { break; } CharToKeyboardInput(c, ref input[0]); if (WinApi.SendInput((uint)input.Length, input, size) == 0) { break; } if (InputHelpers.AnyInputMessage(WinApi.QS_ALLINPUT)) { await InputHelpers.TimerYield(token : token); } } return(true); } finally { WinApi.BlockInput(false); } } finally { s_asyncLock.Release(); } }
private AttachedThreadInputScope() { s_current.Value?.Dispose(); s_current.Value = this; _foregroundWindow = WinApi.GetForegroundWindow(); _currentThreadId = WinApi.GetCurrentThreadId(); _foregroundThreadId = WinApi.GetWindowThreadProcessId(_foregroundWindow, out var _); if (_currentThreadId != _foregroundThreadId) { // attach to the foreground thread if (!WinApi.AttachThreadInput(_foregroundThreadId, _currentThreadId, true)) { return; } } _attached = true; }
public static IntPtr GetPrevActiveWindow() { var foregroundWindow = WinApi.GetAncestor(WinApi.GetForegroundWindow(), WinApi.GA_ROOT); var hwndPrev = IntPtr.Zero; var hwndFound = IntPtr.Zero; bool enumWindowsProc(IntPtr hwnd, IntPtr lparam) { if (WinApi.IsWindowVisible(hwnd)) { if (hwndPrev == foregroundWindow) { hwndFound = hwnd; return(false); } hwndPrev = hwnd; } return(true); } WinApi.EnumDesktopWindows(IntPtr.Zero, enumWindowsProc, IntPtr.Zero); return(hwndFound); }
private async static ValueTask <(bool left, bool right)> GetLeftRightCtrlStateAsync(uint delay, CancellationToken token) { // this is used purely for debugging and so we utilize // native CreateTimerQueueTimer with WT_EXECUTEINPERSISTENTTHREAD // for keyboard polling here, because we don't want // to pollute ThreadPool threads with AttachThreadInput other user32 calls var tcs = new TaskCompletionSource <(bool, bool)>(TaskCreationOptions.RunContinuationsAsynchronously); using var rego = token.Register(() => tcs.SetCanceled(), useSynchronizationContext: false); WinApi.WaitOrTimerCallbackProc timerCallback = delegate { try { // attach the to the foreground thread to read the keyboard status var currentThread = WinApi.GetCurrentThreadId(); var foregroundWindow = WinApi.GetForegroundWindow(); var foregroundThread = WinApi.GetWindowThreadProcessId(foregroundWindow, out uint foregroundProcess); var attached = WinApi.AttachThreadInput(foregroundThread, currentThread, true); try { var leftCtrl = (WinApi.GetAsyncKeyState(WinApi.VK_LCONTROL) & 0x8000) != 0; var rightCtrl = (WinApi.GetAsyncKeyState(WinApi.VK_RCONTROL) & 0x8000) != 0; tcs.TrySetResult((leftCtrl, rightCtrl)); } finally { if (attached) { WinApi.AttachThreadInput(foregroundThread, currentThread, false); } } } catch (Exception ex) { tcs.TrySetException(ex); } }; var gcHandle = GCHandle.Alloc(timerCallback); IntPtr timerHandle = IntPtr.Zero; try { if (!WinApi.CreateTimerQueueTimer( out timerHandle, IntPtr.Zero, timerCallback, IntPtr.Zero, delay, 0, (UIntPtr)(WinApi.WT_EXECUTEINPERSISTENTTHREAD | WinApi.WT_EXECUTEONLYONCE))) { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } return(await tcs.Task); } finally { if (timerHandle != IntPtr.Zero) { WinApi.DeleteTimerQueueTimer(IntPtr.Zero, timerHandle, IntPtr.Zero); } gcHandle.Free(); } }