R.Faladore
R.Faladore

Reputation: 33

C# Checking if more than one key is pressed (Global Keyboard Hook )

I'm making a C# form app that runs in the background and checking if you pressed CTRL + A + S. So I was checking forums on the internet and I already setup that the app runs in the background and now I'am trying to setup keyboard hook. I found a global keyboard hook code on the internet.

Here is this code:

    // GLOBAL HOOK
    [DllImport("user32.dll")]
    static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc callback, IntPtr hInstance, uint threadId);

    [DllImport("user32.dll")]
    static extern bool UnhookWindowsHookEx(IntPtr hInstance);

    [DllImport("user32.dll")]
    static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, int wParam, IntPtr lParam);

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

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

    const int WH_KEYBOARD_LL = 13; // Number of global LowLevel- hook on the keyboard
    const int WM_KEYDOWN = 0x100; // Messages pressing

    private LowLevelKeyboardProc _proc = hookProc;

    private static IntPtr hhook = IntPtr.Zero;

    public void SetHook()
    {
        IntPtr hInstance = LoadLibrary("User32");
        hhook = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, hInstance, 0);
    }

    public static void UnHook()
    {
        UnhookWindowsHookEx(hhook);
    }

    public static IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
    {
        if (code >= 0 && wParam == (IntPtr)WM_KEYDOWN)
        {
            int vkCode = Marshal.ReadInt32(lParam);

            if (vkCode.ToString() == "162") //162 is ASCI CTRL
            {
                MessageBox.Show("You pressed a CTRL");                    
            }
            return (IntPtr)1;
        }
        else
            return CallNextHookEx(hhook, code, (int)wParam, lParam);
    }

    private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        // Remove the hook
        UnHook();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        // Set the hook
        SetHook();
    }

}

My problem is that this hook is setup for 1 key and I can't figure it out how to check if 3 keys are pressed (CTRL + A + S).

I already tried this but didn't work.

if (vkCode.ToString() == "162" && vkCode.ToString() == "65" && vkCode.ToString() == "83") //162 is CTRL, 65 is A, 83 is S, ASCII CODE
            {
                MessageBox.Show("You pressed a CTRL + A + S");                    
            }

So my question is what I need to do that the program or this hook will allows me to checking 3 pressed keys (CTRL + A + S).

Upvotes: 3

Views: 2901

Answers (1)

Dan Field
Dan Field

Reputation: 21661

I believe you'd have to detect CTRL, A, and S separately, using flags to keep track of whether CTRL and A were the last keypresses, like so:

static bool ctrlPressed = false;
static bool ctrlAPressed = false;

public static IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
{
    if (code >= 0 && wParam == (IntPtr)WM_KEYDOWN)
    {
        int vkCode = Marshal.ReadInt32(lParam);

        if (vkCode == 162 || vkCode == 163) //162 is Left Ctrl, 163 is Right Ctrl
        {
            ctrlPressed = true;
        }
        else if (vkCode == 65 && ctrlPressed == true) // "A"
        {
            ctrlPressed = false;
            ctrlAPressed = true;
        }
        else if (vkCode == 83 && ctrlAPressed == true) // "S"
        {
            ctrlPressed = false;
            ctrlAPressed = false;
            MessageBox.Show("Bingo!");
        }
        else
        {
            ctrlPressed = false;
            ctrlAPressed = false;
        }

        // return (IntPtr)1; // note: this will interfere with keyboard processing for other apps
    }
//  else // don't interfere , always return callnexthookex
        return CallNextHookEx(hhook, code, (int)wParam, lParam);
}

If you want to make sure that all are pressed at the same time the logic is similar, you just have to add checks for whether the keypress was down or up. You might also come up with a more clever way of doing this using some kind of list or queue or something for the key presses.

Upvotes: 3

Related Questions