PsychoMantis
PsychoMantis

Reputation: 1015

low level keyboard hook repeat keystrokes (unwanted)

my laptop space bar is broken and so I went on a venture to write a low level keyboard hook to disable it (As it insisted it was being pressed all the time) and change my full stop/period key into a new space bar.. that works fine but I have 2 issues.

1) The new space bar keystroke is sent twice, always - I don't know why

2) I'm trying to rewrite this hook to read alternative input and when I output that input to verify, it's doubled up in the output.

I'm not a strong c++ programmer nor am I a master if the Windows API so would love for a spot of guidance from you guys, if I may!

Code follows:-

#include<Windows.h>
#include <stdio.h>
#include <iostream>

using namespace std;

HHOOK hHook = NULL;
INPUT space[2];
bool sendingSpace=false;

void sendSpace()
{
            cout << "Sending space\n";

        space[0].type=INPUT_KEYBOARD;
        space[0].ki.wVk=VK_SPACE;
        space[0].ki.time=0;

        space[1].type=INPUT_KEYBOARD;
        space[1].ki.wVk=VK_SPACE;
        space[1].ki.time=0;
        space[1].ki.dwFlags=KEYEVENTF_KEYUP;

        SendInput(2,space,sizeof(INPUT));


}

LRESULT CALLBACK MyLowLevelHook ( int nCode , WPARAM wParam , LPARAM lParam)
{
    KBDLLHOOKSTRUCT* hs = (KBDLLHOOKSTRUCT*)lParam;
    if(nCode <0)
    return CallNextHookEx(hHook , nCode ,wParam , lParam);

    switch(hs->vkCode)
    {
    case VK_SPACE:
        if(!sendingSpace)
        {
        cout << "Ignoring space bar\n";
            return 1;
        }
        else
        {
            return CallNextHookEx(hHook , nCode ,wParam , lParam);
        }
        break;

        case VK_OEM_PERIOD:
        sendingSpace=true;
        sendSpace();
        sendingSpace=false;

        return 1;


        break;

        default:
            cout << hs->vkCode << " ( " << (char)(hs->vkCode) << ")" << endl;
            break;
    }

        return CallNextHookEx(hHook , nCode ,wParam , lParam);
}

int main()
{
    //FreeConsole();

    MSG msg;
    hHook = SetWindowsHookEx(WH_KEYBOARD_LL, MyLowLevelHook , NULL,NULL);

    while(!PeekMessage(&msg, NULL, 0, 0,PM_REMOVE)>0)
    {

            TranslateMessage(&msg);
            DispatchMessage(&msg);
    }

    UnhookWindowsHookEx(hHook);
    return 0;
} 

P.S Im only using PeekMessage as a trial and error attempt to solve my issue!

Thanks in advance for any guidance, help or fingers pointing in the right direction!

Upvotes: 1

Views: 2614

Answers (1)

Anya Shenanigans
Anya Shenanigans

Reputation: 94594

The keyboard hook sees an event for a key being pressed and a key being released. The wParam argument of the hook callback contains WM_KEYDOWN on a key down, and WM_KEYUP on a key up.

In this case, you're not separating them both out, and are sending a space character every time the key is pressed and then released.

What you should really do is SendInput a KEYEVENTF_KEYDOWN when you see a WM_KEYDOWN and to a SendInput of a KEYEVENTF_KEYUP on seeing a WM_KEYUP.

The easiest way to accomplish this is to add a parameter to the sendSpace() function, so that it looks like:

void sendSpace(WPARAM param)
{
  INPUT space;

  cout << "Sending space " << (param == WM_KEYDOWN ? "Down" : "Up") << endl;

  space.type = INPUT_KEYBOARD;
  space.ki.wVk = VK_SPACE;
  space.ki.time = 0;
  space.ki.dwFlags = (param == WM_KEYDOWN) ? KEYEVENTF_KEYDOWN : KEYEVENTF_KEYUP;

  SendInput(1, &space, sizeof INPUT);
}

Upvotes: 1

Related Questions