3

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).

Dan Field
  • 20,885
  • 5
  • 55
  • 71
R.Faladore
  • 33
  • 1
  • 6
  • Why would you assume, that an expression like `x == 1 && x == 2` would ever evaluate to true? – IInspectable Jan 22 '16 at 12:32
  • I don't know. I just started learning C# and I want to make app which I mean is really useful but my programming skills are unclear so I appreciate all your answers and help. – R.Faladore Jan 22 '16 at 16:41

1 Answers1

3

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.

Sol
  • 21
  • 1
  • 5
Dan Field
  • 20,885
  • 5
  • 55
  • 71
  • Thanks a lot... just one more question – R.Faladore Jan 21 '16 at 19:19
  • It's working (the hook) but my problem is that when the program is running the keyboard layout don't working and I'm not able to typing the text so where is the problem. – R.Faladore Jan 21 '16 at 19:27
  • Take out the `return (IntPtr)1` part and your last `else` condition so that you always return the result of `CallNextHookEx`. Otherwise, your program is saying it's completely handled that event. – Dan Field Jan 21 '16 at 19:32
  • So what I need to return than? Just this – R.Faladore Jan 21 '16 at 19:59
  • I figure it out... So what were you thinking when you said I need to do some kind of list or queue? (Sorry for a lot of questions I'm 17 years old and my knowledge of programming and c# is so ununderstandable). – R.Faladore Jan 21 '16 at 20:16
  • You could try adding the key presses to some kind of data structure/custom class to track what keys were pressed and whether it's a sequence you're interested in. The proposed method is fine if you __only__ care about Ctrl+S+A, but if you have to start adding lots of flags and switches for other cases it will be come unmanageable. – Dan Field Jan 21 '16 at 20:17
  • So you mean something like KeyLogger? – R.Faladore Jan 21 '16 at 20:52