D
D
Dmitry Shalimov2016-04-07 17:50:10
C++ / C#
Dmitry Shalimov, 2016-04-07 17:50:10

How to implement global KeyPress in C#?

For quite a long time I used the AutoHotKey program to automate a fairly large number of actions, and although the functionality of the program is sufficient, it is still not unlimited. In the end, I realized that this program is not the only solution and it's time to move on.
As a result, I started learning C# and now I'm trying to transfer one project to this platform, but I don't know how to work with WinApi, and more specifically, how to count keystrokes from the keyboard outside the form. Could you suggest how this is implemented?

Answer the question

In order to leave comments, you need to log in

3 answer(s)
D
dark_Kelvin, 2016-04-07
@Akui_Aru

If you need hotkeys, then use RegisterHotKey / UnregisterHotKey
If you need to catch KeyDown KeyPress KeyUp events, then use SetWindowsHookEx with the WH_KEYBOARD_LL / UnhookWindowsHookEx parameter

private bool hooked = false;
    private IntPtr hHook;
    private HookProc managedDelegate = InternalCallback;
    
    public event KeyEventHandler KeyDown;
        public event KeyEventHandler KeyUp;
    public event KeyPressEventHandler KeyPress;

    public void StartHook()
        {
            IntPtr delegt = Marshal.GetFunctionPointerForDelegate(managedDelegate);
      hHook = SetWindowsHookEx(HookType.WH_KEYBOARD_LL, delegt, getMainModuleHandle(), 0);
      if (hHook == IntPtr.Zero) throw new Win32Exception(Marshal.GetLastWin32Error());
    }
    
    public virtual void Unhook()
        {
      if (!UnhookWindowsHookEx(hHook)) throw new Win32Exception(Marshal.GetLastWin32Error());
    }
    
    protected int InternalCallback(int code, IntPtr wParam, IntPtr lParam)
        {
            if (code >= 0)
            {
                bool handled = false;
                KeyboardHookStruct keyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
        
        if (KeyDown != null && ((int)wParam == WM_KEYDOWN || (int)wParam == WM_SYSKEYDOWN))
        {
          Keys keyData = (Keys)keyboardHookStruct.VirtualKeyCode;
          KeyEventArgs e = new KeyEventArgs(keyData);
          KeyDown.Invoke(null, e);
          handled = e.Handled;
        }
        
        if (KeyPress != null && (int)wParam == WM_KEYDOWN)
        {
          //Перекодирование сканкодов в Ascii
        }
        
        if (KeyUp != null && ((int)wParam == WM_KEYUP || (int)wParam == WM_SYSKEYUP))
        {
          Keys keyData = (Keys)keyboardHookStruct.VirtualKeyCode;
          KeyEventArgs e = new KeyEventArgs(keyData);
          KeyUp.Invoke(null, e);
          handled = handled || e.Handled;
        }
        
                if (handled) return 1;
            }
            return CallNextHookEx(hHook, code, wParam, lParam);
        }
    
    
    
    private IntPtr getMainModuleHandle()
        {
            IntPtr hMod;
            using (Process process = Process.GetCurrentProcess())
            using (ProcessModule module = process.MainModule)
            {
                hMod = GetModuleHandle(module.ModuleName);
            }
            return hMod;
        }

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(HookType hook, IntPtr callback,
            IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", SetLastError = true)]
        internal static extern bool UnhookWindowsHookEx(IntPtr hhk);

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

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
    
     private const int
         WM_KEYDOWN = 0x100,
         WM_KEYUP = 0x101,
         WM_SYSKEYDOWN = 0x104,
         WM_SYSKEYUP = 0x105;
    
        [StructLayout(LayoutKind.Sequential)]
        private struct KeyboardHookStruct
        {
            /// <summary>
            /// Specifies a virtual-key code. The code must be a value in the range 1 to 254. 
            /// </summary>
            public int VirtualKeyCode;
            /// <summary>
            /// Specifies a hardware scan code for the key. 
            /// </summary>
            public int ScanCode;
            /// <summary>
            /// Specifies the extended-key flag, event-injected flag, context code, and transition-state flag.
            /// </summary>
            public int Flags;
            /// <summary>
            /// Specifies the Time stamp for this message.
            /// </summary>
            public int Time;
            /// <summary>
            /// Specifies extra information associated with the message. 
            /// </summary>
            public int ExtraInfo;
        }

    
    
  internal enum HookType : int
    {
        ///
        WH_JOURNALRECORD = 0,
        ///
        WH_JOURNALPLAYBACK = 1,
        ///
        WH_KEYBOARD = 2,
        ///
        WH_GETMESSAGE = 3,
        ///
        WH_CALLWNDPROC = 4,
        ///
        WH_CBT = 5,
        ///
        WH_SYSMSGFILTER = 6,
        ///
        WH_MOUSE = 7,
        ///
        WH_HARDWARE = 8,
        ///
        WH_DEBUG = 9,
        ///
        WH_SHELL = 10,
        ///
        WH_FOREGROUNDIDLE = 11,
        ///
        WH_CALLWNDPROCRET = 12,
        ///
        WH_KEYBOARD_LL = 13,
        ///
        WH_MOUSE_LL = 14
    }

B
bmforce, 2016-04-08
@bmforce

https://github.com/gmamaladze/globalmousekeyhook

A
APXAHGEL, 2016-04-09
@APXAHGEL

I am using this project

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question