Win Api Как узнать повторный ли это эвент нажатия клавиши

Пишу сейчас обработчик клавиатурного ввода. Сейчас имеется такой код.

 public class LowLevlHook : CriticalFinalizerObject, IDisposable
    {
        private bool _disposed = false;

        public void Dispose()
        {
            if (_disposed is true) return;
            UninstallHook();
            _disposed = true;
            GC.SuppressFinalize(this);
        }

        private delegate IntPtr KeyboardHookHandler(int nCode, WMEvent wParam, TagKBDLLHOOKSTRUCT lParam);
        private KeyboardHookHandler? hookHandler;

        private IntPtr hookID = IntPtr.Zero;

        public void InstallHook()
        {
            CheckDisposed();
            hookHandler = HookFunc;
            hookID = SetHook(hookHandler);
        }

        ~LowLevlHook()
        {
            try
            {
                if (_disposed is true) return;
                UnhookWindowsHookEx(hookID);
                Marshal.FreeHGlobal(hookID);
            }
            catch { }
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void CheckDisposed() { if (_disposed is true) throw new ObjectDisposedException("You cannot use an instance of a class after it has been disposed of."); }


        public void UninstallHook() { CheckDisposed(); UnhookWindowsHookEx(hookID); }


        private const int WH_KEYBOARD_LL = 13;
        private const int WH_KEYBOARD = 2;

        private IntPtr SetHook(KeyboardHookHandler proc) =>
                        SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                         GetModuleHandleW(Process.GetCurrentProcess().MainModule is not ProcessModule module2 ?
                          throw new NullReferenceException() : module2.ModuleName ?? throw new NullReferenceException()), 0);



        internal delegate void KeyboardHookCallback(VKeys key, SettingHook setting);
        internal event KeyboardHookCallback? KeyDown;


        internal SettingHook Settings = new SettingHook();



        private IntPtr HookFunc(int nCode, WMEvent wParam, TagKBDLLHOOKSTRUCT lParam)
        {
            if (nCode is 0) 
            {
                if (wParam is WMEvent.WM_KEYDOWN || wParam is WMEvent.WM_SYSKEYDOWN)
                {
                    // Необходимо отбросить повторные эвенты когда клавиша зажата
                    KeyDown?.Invoke(lParam.Vkcode, Settings);
                    if (Settings.Break is true)
                    {
                        Settings.Break = false;
                        return (System.IntPtr)1;
                    }
                }
            }
            return CallNextHookEx(hookID, nCode, wParam, lParam);
        }
        enum WMEvent: uint
        {
            WM_KEYDOWN = 256,
            WM_SYSKEYDOWN = 260,
            WM_KEYUP = 257,
            WM_SYSKEYUP = 261
        }

[StructLayout(LayoutKind.Sequential)]
struct TagKBDLLHOOKSTRUCT
        {
            internal readonly VKeys Vkcode;
            internal readonly uint ScanCode;
            internal readonly uint Flags;
            internal readonly uint Time; // Милисикунды между сообщениями. Обнуляются при переполнинии.
            internal readonly UIntPtr DwExtraInfo;   //??
        }
        #region WinAPI
        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowsHookEx(int idHook, KeyboardHookHandler lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll")]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll")]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, WMEvent wParam, TagKBDLLHOOKSTRUCT lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        private static extern IntPtr GetModuleHandleW([MarshalAs(UnmanagedType.LPWStr)] string lpModuleName);
        #endregion
}

Мне необходимо определить была ли нажата клавиша до. Имеется ввиду отбросить ивенты повторные, когда клавиша уже была зажата и вызвала повторный эвент.
Я пытался расшифровать в структуре TagKBDLLHOOKSTRUCT Flags (Скорей всего не правильно), но даже если правильно, вроде там нет информации о том была ли нажата клавиша. Это информация вроде как есть в WH_KEYBOARD, но не пойму как указать окно (или что-то еще), эвенты не приходят, и не понятно подходит ли это для моей задачи.

Обновление: Мне удается привязать WH_KEYBOARD только к потоку в последним аргументе метода CallNextHookEx(), и это работает только если окно имеет фокус.


Ответы (0 шт):