none
Global Keyboard Hook (Captura global de teclas digitadas) - como implementar? RRS feed

  • Pergunta

  • Olá, pesquisando na net (já que não tinha a mínima ideia de como fazer), achei uma classe que captura as teclas digitadas pelo usuário em qualquer aplicação. Entretanto não sei como implementar ela no meu Form. Queria que elas fossem sendo exibidas num textbox à medida que forem sendo digitadas, claro, sem o foco no textbox. Alguém poderia ajudar? segue abaixo a classe que encontrei:

    public class KeyboardListener : IDisposable
        {
            /// <summary>
            /// Creates global keyboard listener.
            /// </summary>
            public KeyboardListener()
            {
                // We have to store the HookCallback, so that it is not garbage collected runtime
                hookedLowLevelKeyboardProc = (InterceptKeys.LowLevelKeyboardProc)LowLevelKeyboardProc;
    
                // Set the hook
                hookId = InterceptKeys.SetHook(hookedLowLevelKeyboardProc);
    
                // Assign the asynchronous callback event
                hookedKeyboardCallbackAsync = new KeyboardCallbackAsync(KeyboardListener_KeyboardCallbackAsync);
            }
    
            /// <summary>
            /// Destroys global keyboard listener.
            /// </summary>
            ~KeyboardListener()
            {
                Dispose();
            }
    
            /// <summary>
            /// Fired when any of the keys is pressed down.
            /// </summary>
            public event RawKeyEventHandler KeyDown;
    
            /// <summary>
            /// Fired when any of the keys is released.
            /// </summary>
            public event RawKeyEventHandler KeyUp;
    
            #region Inner workings
            /// <summary>
            /// Hook ID
            /// </summary>
            private IntPtr hookId = IntPtr.Zero;
    
            /// <summary>
            /// Asynchronous callback hook.
            /// </summary>
            /// <param name="nCode"></param>
            /// <param name="wParam"></param>
            /// <param name="lParam"></param>
            private delegate void KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode);
    
            /// <summary>
            /// Actual callback hook.
            /// 
            /// <remarks>Calls asynchronously the asyncCallback.</remarks>
            /// </summary>
            /// <param name="nCode"></param>
            /// <param name="wParam"></param>
            /// <param name="lParam"></param>
            /// <returns></returns>
            [MethodImpl(MethodImplOptions.NoInlining)]
            private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam)
            {
                if (nCode >= 0)
                    if (wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYDOWN ||
                        wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYUP ||
                        wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_SYSKEYDOWN ||
                        wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_SYSKEYUP)
                        hookedKeyboardCallbackAsync.BeginInvoke((InterceptKeys.KeyEvent)wParam.ToUInt32(), Marshal.ReadInt32(lParam), null, null);
    
                return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);
            }
    
            /// <summary>
            /// Event to be invoked asynchronously (BeginInvoke) each time key is pressed.
            /// </summary>
            private KeyboardCallbackAsync hookedKeyboardCallbackAsync;
    
            /// <summary>
            /// Contains the hooked callback in runtime.
            /// </summary>
            private InterceptKeys.LowLevelKeyboardProc hookedLowLevelKeyboardProc;
    
            /// <summary>
            /// HookCallbackAsync procedure that calls accordingly the KeyDown or KeyUp events.
            /// </summary>
            /// <param name="keyEvent">Keyboard event</param>
            /// <param name="vkCode">VKCode</param>
            void KeyboardListener_KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode)
            {
                switch (keyEvent)
                {
                    // KeyDown events
                    case InterceptKeys.KeyEvent.WM_KEYDOWN:
                        if (KeyDown != null)
                            KeyDown(this, new RawKeyEventArgs(vkCode, false));
                        break;
                    case InterceptKeys.KeyEvent.WM_SYSKEYDOWN:
                        if (KeyDown != null)
                            KeyDown(this, new RawKeyEventArgs(vkCode, true));
                        break;
    
                    // KeyUp events
                    case InterceptKeys.KeyEvent.WM_KEYUP:
                        if (KeyUp != null)
                            KeyUp(this, new RawKeyEventArgs(vkCode, false));
                        break;
                    case InterceptKeys.KeyEvent.WM_SYSKEYUP:
                        if (KeyUp != null)
                            KeyUp(this, new RawKeyEventArgs(vkCode, true));
                        break;
    
                    default:
                        break;
                }
            }
    
            #endregion
    
            #region IDisposable Members
    
            /// <summary>
            /// Disposes the hook.
            /// <remarks>This call is required as it calls the UnhookWindowsHookEx.</remarks>
            /// </summary>
            public void Dispose()
            {
                InterceptKeys.UnhookWindowsHookEx(hookId);
            }
    
            #endregion
        }
        /// <summary>
        /// Raw KeyEvent arguments.
        /// </summary>
        public class RawKeyEventArgs : EventArgs
        {
            /// <summary>
            /// VKCode of the key.
            /// </summary>
            public int VKCode;
    
            /// <summary>
            /// WPF Key of the key.
            /// </summary>
            public Key Key;
    
            /// <summary>
            /// Is the hitted key system key.
            /// </summary>
            public bool IsSysKey;
    
            /// <summary>
            /// Create raw keyevent arguments.
            /// </summary>
            /// <param name="VKCode"></param>
            /// <param name="isSysKey"></param>
            public RawKeyEventArgs(int VKCode, bool isSysKey)
            {
                this.VKCode = VKCode;
                this.IsSysKey = isSysKey;
                this.Key = System.Windows.Input.KeyInterop.KeyFromVirtualKey(VKCode);
            }
        }
    
        /// <summary>
        /// Raw keyevent handler.
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="args">raw keyevent arguments</param>
        public delegate void RawKeyEventHandler(object sender, RawKeyEventArgs args);
    
        #region WINAPI Helper class
        /// <summary>
        /// Winapi Key interception helper class.
        /// </summary>
        internal static class InterceptKeys
        {
            public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam);
            public static int WH_KEYBOARD_LL = 13;
    
            public enum KeyEvent : int
            {
                WM_KEYDOWN = 256,
                WM_KEYUP = 257,
                WM_SYSKEYUP = 261,
                WM_SYSKEYDOWN = 260
            }
    
            public static IntPtr SetHook(LowLevelKeyboardProc proc)
            {
                using (Process curProcess = Process.GetCurrentProcess())
                using (ProcessModule curModule = curProcess.MainModule)
                {
                    return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                        GetModuleHandle(curModule.ModuleName), 0);
                }
            }
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool UnhookWindowsHookEx(IntPtr hhk);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, UIntPtr wParam, IntPtr lParam);
    
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern IntPtr GetModuleHandle(string lpModuleName);
        }
        #endregion

    domingo, 18 de fevereiro de 2018 13:35

Respostas

  • Boa tarde, Denis Valjean.

    Nesse caso você deveria abrir essa questão como uma discussão, assim junto com a comunidade poderá encontrar a melhor maneira de implementar o que você deseja.

    Para abrir uma discussão, faça o mesmo processo de abrir uma pergunta, mas ao invés de marcar como pergunta, marque como discussão geral, assim:

    Atenciosamente,


    Filipe B de Castro

    Esse conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita

    MSDN Community Support

    Por favor, lembre-se de Marcar como Resposta as postagens que resolveram o seu problema. Essa é uma maneira comum de reconhecer aqueles que o ajudaram e fazer com que seja mais fácil para os outros visitantes encontrarem a resolução mais tarde.

    sexta-feira, 23 de fevereiro de 2018 17:04
    Moderador

Todas as Respostas

  • Boa tarde, Denis Valjean. Tudo bem?

    Obrigado por usar o fórum MSDN.

    Essa seria uma questão de "How to/Customização" ou "Break Fix/Erro"?

    Atenciosamente,

    Filipe B de Castro

    Esse conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita

    MSDN Community Support

    Por favor, lembre-se de Marcar como Resposta as postagens que resolveram o seu problema. Essa é uma maneira comum de reconhecer aqueles que o ajudaram e fazer com que seja mais fácil para os outros visitantes encontrarem a resolução mais tarde.

    segunda-feira, 19 de fevereiro de 2018 17:39
    Moderador
  • Boa tarde, Denis Valjean. Tudo bem?

    Obrigado por usar o fórum MSDN.

    Essa seria uma questão de "How to/Customização" ou "Break Fix/Erro"?

    Atenciosamente,

    Filipe B de Castro

    Esse conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita

    MSDN Community Support

    Por favor, lembre-se de Marcar como Resposta as postagens que resolveram o seu problema. Essa é uma maneira comum de reconhecer aqueles que o ajudaram e fazer com que seja mais fácil para os outros visitantes encontrarem a resolução mais tarde.

    Boa tarde. Questão de How to.
    segunda-feira, 19 de fevereiro de 2018 22:11
  • Boa tarde, Denis Valjean.

    Nesse caso você deveria abrir essa questão como uma discussão, assim junto com a comunidade poderá encontrar a melhor maneira de implementar o que você deseja.

    Para abrir uma discussão, faça o mesmo processo de abrir uma pergunta, mas ao invés de marcar como pergunta, marque como discussão geral, assim:

    Atenciosamente,


    Filipe B de Castro

    Esse conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita

    MSDN Community Support

    Por favor, lembre-se de Marcar como Resposta as postagens que resolveram o seu problema. Essa é uma maneira comum de reconhecer aqueles que o ajudaram e fazer com que seja mais fácil para os outros visitantes encontrarem a resolução mais tarde.

    sexta-feira, 23 de fevereiro de 2018 17:04
    Moderador