Feedback

Globale KeyHook

Sprache: C#

Mit dieser Klasse kann man eine systemweite KeyboardHook setzen. Dabei werden alle Tasten in die List KeyCodes geschrieben.
public class KeyHook
    {
        private delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

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

        public static List<Keys> KeyCodes = new List<Keys>();

        //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;

        HookProc KeyboardHookProcedure;

        [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);

        public KeyHook()
        {
            Hook();
        }

        ~KeyHook()
        {
            UnHook();
        }

        public int Hook()
        {
            KeyboardHookProcedure = new HookProc(KeyHook.KeyboardHookProc);

            hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, (IntPtr)LoadLibrary("User32"), 0);
            return hHook;
        }

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

        private static int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode < 0)
            {
                return CallNextHookEx(hHook, nCode, wParam, lParam);
            }
            else
            {

                if (((int)wParam == 256) || ((int)wParam == 260))
                {
                    keyboardHookStruct MyKeyboardHookStruct = (keyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(keyboardHookStruct));
                    KeyCodes.Add((Keys)MyKeyboardHookStruct.vkCode);
                }
                return 1;
            }
        }

    }
public class KeyHook
    {
        private delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

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

        public static List<Keys> KeyCodes = new List<Keys>();

        //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;

        HookProc KeyboardHookProcedure;

        [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);

        public KeyHook()
        {
            Hook();
        }

        ~KeyHook()
        {
            UnHook();
        }

        public int Hook()
        {
            KeyboardHookProcedure = new HookProc(KeyHook.KeyboardHookProc);

            hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, (IntPtr)LoadLibrary("User32"), 0);
            return hHook;
        }

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

        private static int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode < 0)
            {
                return CallNextHookEx(hHook, nCode, wParam, lParam);
            }
            else
            {

                if (((int)wParam == 256) || ((int)wParam == 260))
                {
                    keyboardHookStruct MyKeyboardHookStruct = (keyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(keyboardHookStruct));
                    KeyCodes.Add((Keys)MyKeyboardHookStruct.vkCode);
                }
                return 1;
            }
        }

    }

5 Kommentare

  1. Wenn ich die Keys mitprotokolliere, indem ich bei KeyCodes.Add((Keys)MyKeyboardHookStruct.vkCode); die KeyCodes in eine Listbox schreibe, bemerke ich gerade, dass die Tasten zwar abgefangen, aber nicht normal geschrieben werden. D.h. wenn ich im Editor „Hallo“ schreibe, steht in meiner Listbox zwar H A L L O, aber im Editor nichts…

    Kann man das irgendwie verändern, dass die Tasten auch wirklich von Windows „ausgeführt“ und nicht nur protokolliert werden?

    PS: Die einzigen Tasten, die protokolliert und ausgeführt werden, sind die Power und die Sleep-Tasten, durch die mein PC in den Standby bzw. Ruhezustand versetzt werden.

  2. ersetz das „return 1“ durch „return CallNextHookEx(hHook, nCode, wParam, lParam);“
    in der methode: private static int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
    das return 1 sorgt dafür, dass der hook abgefangen wird und windows ihn nicht mehr verarbeitet.

  3. Achja, hab ich vergessen zu sagen:
    Das hab ich schon probiert!
    Es trat allerdings, als ich eine Taste drückte folgender Fehler bei obigem Befehlssatz auf:
    „Für den von der Garbage Collection gesammelten Delegaten vom Typ „WindowsChiiks!WindowsChiiks.KeyHook+HookProc::Invoke“ wurde ein Rückruf durchgeführt. Dies kann Anwendungsabstürze, Datenbeschädigung und -verlust zur Folge haben. Beim Übergeben von Delegaten an nicht verwalteten Code müssen die Delegaten von der verwalteten Anwendung beibehalten werden, bis sichergestellt ist, dass sie nie aufgerufen werden.“

    Kenn mich mit Delegaten nicht so aus… Was muss ich verändern?

  4. Hallo, im Forum habe ich keinen Thread darüber gefunden und wollte wegen einer Frage auch nichts anlegen. Es funktioniert alles perfekt, ich würde nun aber gern für eine abgefangene Taste mehrere andere Tastendrücke simulieren. Ist das irgendwie machbar? Danke!

  5. entschuldigt mich bitte, wenn ich dieses alte Thema wieder hochpushe, aber ich habe grade glaub ich ein Brett vorm Kopf: Wenn ich obenstehenden code im release ausführe und tasten drücke, werden diese manchmal doppelt oder dreifach ausgewertet.
    „NumPad1
    NumPad2
    NumPad1
    NumPad3
    NumPad2
    NumPad4
    NumPad3
    NumPad5
    NumPad4
    NumPad6
    NumPad5
    NumPad6
    NumPad7
    NumPad8
    NumPad7
    NumPad9
    NumPad8
    NumPad9“
    kommt da z.B. raus wenn ich 123456789 auf dem Numpad eingebe.
    Was kann ich tun, um die auswertung auf eins zu begrenzen?