AdSense

Friday 6 September 2013

C# - Global hotkeys which are really global

(Deutsche Version) My music player uses hotkeys. Basically, the work fine. When playing several computer games (e.g. Leauge of Legends), the hotkeys do not work anymore. To solve this problem, I used an implementation from my friend from http://csharp-tricks-en.blogspot.de/ and adapted this implementation a bit. My hotkeys are now in a separate class which is used this way:

KeyHook MyHook = new KeyHook(this, KeyboardHookProcedure);
MyHook.Hook(KeyHook.KeyboardHookProc);

KeyHook.KeyPressed += KeyHook_KeyPressed;
KeyHook.KeyReleased += KeyHook_KeyReleased;


Die KeyHook_KeyPressed und KeyHook_KeyReleased Funktionen sehen folgendermaßen aus:

void KeyHook_KeyPressed(int keyCode, List<int> pressedKeys)
{}


keyCode is simply an integer, which value represents which key is listed here. I added the events KeyPressed and KeyReleased to have a clean solution. Now the code of the class KeyHook:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace anyNamespace
{
    public class KeyHook
    {
        public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

        //Declare hook handle as int.
        static int hHook = 0;

        //Declare keyboard hook constant.
        //For other hook types, you can obtain these values from Winuser.h in Microsoft SDK.
        const int WH_KEYBOARD_LL = 13;

        public delegate void KeyPressedEventHandler(int keyCode, List<int> pressedKeys);
        public static event KeyPressedEventHandler KeyPressed;

        public delegate void KeyReleasedEventHandler(int keyCode, List<int> pressedKeys);
        public static event KeyReleasedEventHandler KeyReleased;

        [StructLayout(LayoutKind.Sequential)]
        private class keyboardHookStruct
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }

        //Import for SetWindowsHookEx function.
        //Use this function to install thread-specific hook.
        [DllImport("user32.dll", CharSet = CharSet.Auto,
         CallingConvention = CallingConvention.StdCall)]
        private static extern int SetWindowsHookEx(int idHook, HookProc lpfn,
        IntPtr hInstance, int threadId);

        //Import for UnhookWindowsHookEx.
        //Call this function to uninstall the hook.
        [DllImport("user32.dll", CharSet = CharSet.Auto,
         CallingConvention = CallingConvention.StdCall)]
        private static extern bool UnhookWindowsHookEx(int idHook);

        //Import for CallNextHookEx.
        //Use this function to pass the hook information to next hook procedure in chain.
        [DllImport("user32.dll", CharSet = CharSet.Auto,
         CallingConvention = CallingConvention.StdCall)]
        private static extern int CallNextHookEx(int idHook, int nCode,
        IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll")]
        static extern IntPtr LoadLibrary(string lpFileName);

        //static Form1 View;
        static MainWindow mainWindow;

        const int MOD_SHIFT = 0x0004;

        IntPtr LL = (IntPtr)LoadLibrary("User32");

        public KeyHook(MainWindow _mainWindow, HookProc proc)
        {
            mainWindow = _mainWindow;
            Hook(proc);

        }

        ~KeyHook()
        {
            UnHook();
        }

        HookProc _proc;
        public int Hook(HookProc proc)
        {
            _proc = proc;
            hHook = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, LL, 0);
            return hHook;
        }

        public bool UnHook()
        {
            bool ret = UnhookWindowsHookEx(hHook);
            if (ret)
                hHook = 0;
            return ret;
        }

        public static List<int> pressedKeys = new List<int>();

        public static int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode < 0)
            {
                return CallNextHookEx(hHook, nCode, wParam, lParam);
            }
            else
            {
                keyboardHookStruct MyKeyboardHookStruct = (keyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(keyboardHookStruct));
                if ((MyKeyboardHookStruct.flags & 128) == 128)
                {
                    if (pressedKeys.Contains(MyKeyboardHookStruct.vkCode))
                    {
                        pressedKeys.Remove(MyKeyboardHookStruct.vkCode);
                        if (KeyReleased != null)
                        {
                            KeyReleased(MyKeyboardHookStruct.vkCode, pressedKeys);
                        }
                    }
                }
                if ((MyKeyboardHookStruct.flags & 128) == 0)
                {
                    if (!pressedKeys.Contains(MyKeyboardHookStruct.vkCode))
                    {
                        pressedKeys.Add(MyKeyboardHookStruct.vkCode);
                        if (KeyPressed != null)
                        {
                            KeyPressed(MyKeyboardHookStruct.vkCode, pressedKeys);
                        }
                    }
                }
                return CallNextHookEx(hHook, nCode, wParam, lParam);
            }
        }
    }
}

No comments:

Post a Comment