Search code examples
c#consolelistenerkeypress

Deployment of C# console application for Keyboard Listener


I have a C# console application that is designed to run in the background and capture key press events and if it matches my hotkey I want to do some action and NOT pass that key on to the active application.

On my development machine I can run the build exe file without visual studio and my program works as expected. When I type my hotkey, (f11 or f12), anywhere, in any application, that key event is captured and not passed on to the active application. When I deploy the exe to another machine, same OS, (Windows 8.1 Pro), the key press is detected and I can "do something", (see code), but then it is passed on to the active application. This is not the desired operation nor what I am experiencing on my development machine. My specific question, is there something else I need to do in order to deploy this application to other machines so that they key press event is not only captured but ALSO not passed on to the active application?

    public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

    public static IntPtr SetHook(LowLevelKeyboardProc proc)
    {
        using (Process curProcess = Process.GetCurrentProcess())
        using (ProcessModule curModule = curProcess.MainModule)
        {
            return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
        }
    }

    public static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
        {
            Keys pressedKey = (Keys)Marshal.ReadInt32(lParam);

            if (pressedKey == Keys.F11 || pressedKey == Keys.F12)
            {
                // Do something...

                // Don't pass the key press on to the system
                return (System.IntPtr)1;
            }
        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool UnhookWindowsHookEx(IntPtr hhk);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

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

Solution

  • Have you tried setting lParam to null? It's been a while since i've done key handling, so not sure if it's better to set to null or IntPtr.Zero. One of the two should work:

    public static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
        {
            Keys pressedKey = (Keys)Marshal.ReadInt32(lParam);
    
            if (pressedKey == Keys.F11 || pressedKey == Keys.F12)
            {
                // Do something...
    
                // Don't pass the key press on to the system
                lParam = null;
            }
        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }