예제 #1
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();
            }
        }
 public static bool IsKeyPressed(int key)
 {
     return((WinApi.GetAsyncKeyState(key) & 0x8000) != 0);
 }