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;
        }
Example #2
0
        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);
            }
        }
Example #3
0
        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;
        }
Example #4
0
        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();
            }
        }