AdSense

Freitag, 6. September 2013

C# - Globale Hotkeys, welche wirklich global sind

(English version) Mein Musikplayer benutzt Hotkeys. Diese funktionieren auch relativ gut. Leider nur relativ. Bei einigen Spielen (z.B. League of Legends) funktionieren die Hotkeys nicht mehr und man kann z.B. kein Lied mehr weiterschalten. Um dieses Problem zu beheben habe ich nach einer neuen Möglichkeit gesucht, globale Hotkeys zu implementieren. Schlussendlich habe ich eine Implementierung von meinem Freund von http://csharp-tricks.blogspot.de/ übernommen und sie etwas weiter entwickelt. Die Hotkeys sind nun eine eigene Klasse, welche folgendermaßen benutzt wird:

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 ist einfach ein Integer, welcher Wert für welche Taste steht kann man hier nachlesen. Mehr gibt es zu diesen Hotkeys nicht zu sagen, die Events für KeyPressed und KeyReleased habe ich selber eingebaut, da es davor etwas unsauber gelöst wurde. Nun noch der Code der Klasse 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);
            }
        }
    }
}

Keine Kommentare:

Kommentar veröffentlichen