Jump to content

Plugins and Accept User Keyboard Input


Recommended Posts

I've looked into it, you need to run the hook on its own context via "Application.Run();" to get it working:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
using robotManager.Helpful;
using wManager.Plugin;

public class Main : IPlugin
{
    public void Initialize()
    {
        KeyBoardHook.Initialize();
        KeyBoardHook.OnKeyDown += KeyDown;
    }
    
    public void Dispose()
    {
        KeyBoardHook.OnKeyDown -= KeyDown;
        KeyBoardHook.Dispose();
    }

    public void Settings()
    {
    }
    
    private static void KeyDown(object sender, KeyBoardHook.KeyArgs keyArgs)
    {
        Logging.Write(keyArgs.Key.ToString());
    }


    public class KeyBoardHook
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_KEYUP = 0x101;
        private static readonly LowLevelKeyboardProc Proc = HookCallback;
        private static IntPtr _hookId = IntPtr.Zero;
        private static Keys _lastKeyDown = Keys.None;
        public delegate void KeyBoardHookEventHandler(object sender, KeyArgs e);
        public static event KeyBoardHookEventHandler OnKeyDown = delegate{};
        public static event KeyBoardHookEventHandler OnKeyUp = delegate{};

        internal static void Initialize()
        {
            Task.Factory.StartNew(() =>//avoid thread blocking from Application.Run();
            {
                _hookId = SetHook(Proc);
                Application.Run(); //important! need to run in its own "context"
            });
        }

        internal static void Dispose()
        {
            UnhookWindowsHookEx(_hookId);
            Application.Exit();
        }
        
        private static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (var curProcess = Process.GetCurrentProcess())
            using (var curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
            }
        }
        
        private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
        
        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode < 0)
                return CallNextHookEx(_hookId, nCode, wParam, lParam);
            if (wParam == (IntPtr) WM_KEYDOWN)
            {
                var vkCode = (Keys) Marshal.ReadInt32(lParam);
                if (_lastKeyDown == vkCode)
                    return CallNextHookEx(_hookId, nCode, wParam, lParam);
                OnKeyDown(null, new KeyArgs(vkCode));
                _lastKeyDown = vkCode;
            }
            else if (wParam == (IntPtr) WM_KEYUP)
            {
                var vkCode = (Keys) Marshal.ReadInt32(lParam);
                OnKeyUp(null, new KeyArgs(vkCode));
                if (_lastKeyDown == vkCode)
                    _lastKeyDown = Keys.None;
            }
            return CallNextHookEx(_hookId, nCode, wParam, lParam);
        }
        
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
        
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);
        
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
        
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        public class KeyArgs : EventArgs 
        {
            public Keys Key { get; private set; }

            public KeyArgs(Keys key) 
            {
                this.Key = key;
            }
        }
    }
}

So far it worked well.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...