Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1587
  • Last Modified:

speed up SetWindowsHookEx, or alternative?

Hello,

I have a program that runs in the background and uses Windows Hooks to look at the keyboard/mouse usage.

I use SetWindowsHookEx(), listening to WH_KEYBOARD_LL and WH_MOUSE_LL. However hooks tend to slow down systems pretty much, especially when playing games.

My question, is there a way to speed up processing these hooks, or are there better alternatives (besides DirectInput), I appriciate any feedback!
0
njitram
Asked:
njitram
1 Solution
 
grg99Commented:
The hook itself is mighty speedy;  it's waht you do in thehook procedure that can slow  things down.

How about you show us the code?
0
 
njitramAuthor Commented:
Alright, below is my code. It does quite alot when it's called, and everything works, it's just slow when playing games such as Half-life. I switched this part over from a DirectInput program, and in there it worked perfectly fast.

I hook it with:

g_hKbHook            = ::SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)kbProc, AfxGetApp()->m_hInstance, 0);


LRESULT CALLBACK
kbProc (int iCode, WPARAM wParam, LPARAM lParam)
{
    static HWND activeWnd = 0;

    if (iCode < 0) {
       return CallNextHookEx(g_hKbHook, iCode, wParam,lParam);
    }
    else {
        if(!pFrame->m_pAppWnd->state.bCountkeys)
        {
             return 0;
        }

        if (iCode == HC_ACTION)
        {
            KBDLLHOOKSTRUCT kbDllHookStruct = *(KBDLLHOOKSTRUCT*)lParam;
            if (wParam == WM_SYSKEYDOWN || wParam == WM_KEYDOWN)
            {
                if ((kbDllHookStruct.flags & LLKHF_INJECTED) != 0)
                {
                    return CallNextHookEx(g_hKbHook, iCode, wParam, lParam);
                }

                if ((GetKeyState(kbDllHookStruct.vkCode) & 0x8000) == 0)
                {
                    pFrame->KeyCount.getAccess();
                    pFrame->KeyCount.increment();
                    pFrame->KeyCount.releaseAccess();

                    pFrame->m_tray.SetIcon(IDI_TRAYICON_KEYDOWN);

                    pFrame->bKeyHitSinceSave = TRUE;

                    UINT tempkeys = 0;
                    CQuickCrypt crypt, crypto;
                    CString str;

                    str.Format("%s", gKeysHit);
                    crypt.SetCipher(str);
                    tempkeys = _ttoi(crypt.DeCipher1());
                    tempkeys++;
                              
                    str.Format("%ld", tempkeys);
                    crypto.SetPlain(str);
                    strcpy(gKeysHit, crypto.Cipher1());

                    gTotalKeys++;

                    if(pFrame->m_pAppWnd->state.bKeepFreq) {
                        Keys.IncrementHitCount(kbDllHookStruct.vkCode);
                        pFrame->m_pAppWnd->state.keysSinceLR++;
                    }
                }
            }
            if(wParam == WM_KEYUP)
            {
                pFrame->m_tray.SetIcon(IDI_TRAYICON);
                pFrame->SetTrayToolTip(TRUE);
            }
        }
    }

    return CallNextHookEx(g_hKbHook, iCode, wParam, lParam);
}
0
 
itsmeandnobodyelseCommented:
There is some code that might get improved:

>>>  pFrame->KeyCount.getAccess();
>>>  pFrame->KeyCount.increment();
>>>  pFrame->KeyCount.releaseAccess();

Maybe you can use InterlockedIncrement to have an atomic increment instead.

>>> pFrame->m_tray.SetIcon(IDI_TRAYICON_KEYDOWN);

That is a SendMessage to another window that shouldn't be done in a hook function. If the hook function is the only place where tray icons are going to be changed, you may hold the status of the tray in a static variable and call SetIcon only if there is a change. Or have a PostMessage instead of a SendMessage (get the internal call from afxcmn2.inl).

I don't know how much time the encrypting of the counter takes, but you may prove if you really need string encrypting for that. If you only need to hide a counter take an algorithm like that:

int hideNumber(int i)
{
    unsigned int x = i, y = 0;    
    for (int n = 0; n < 32; n++) if (x & (1<<(31-n))) y |= (1<<n);
    return (int)y;
}
int showNumber(int i)
{
    unsigned int x = 0, y = i;
    for (int n = 0; n < 32; n++) if (y & (1<<n)) x |= (1<<(31-n));
    return (int)x;
}

Regards, Alex
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
njitramAuthor Commented:
I think I know more about where the slowness comes from. I pasted the code for the keyboard calls above, only I also have mouse calls, registered with WH_MOUSE_LL.

I tried to remove the registering of the mouse handle, just for fun, but it turns out, removing this helped a great deal. So I'm kinda thinking something is wrong with the way I handle the mouse.

Below is the code for the mouse handling. This is only supposed to catch mouse buttons.

// Registering the mouse hook
g_hMouseHook      = ::SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)mouseProc, AfxGetApp()->m_hInstance, 0);

// mouse handling
LRESULT CALLBACK
kbProc (int iCode, WPARAM wParam, LPARAM lParam)
{
        if (iCode < 0) {
              return CallNextHookEx(g_hKbHook, iCode, wParam,lParam);
        }
        else {
                if (iCode == HC_ACTION)
                {
                      KBDLLHOOKSTRUCT kbDllHookStruct = *(KBDLLHOOKSTRUCT*)lParam;
                     if (wParam == WM_SYSKEYDOWN || wParam == WM_KEYDOWN)
                     {
                           if ((kbDllHookStruct.flags & LLKHF_INJECTED) != 0)
                           {
                                  return CallNextHookEx(g_hKbHook, iCode, wParam, lParam);
                           }

                           if ((GetKeyState(kbDllHookStruct.vkCode) & 0x8000) == 0)
                           {
                                   // handle a clicked mouse button
                            }
                     }
                     if(wParam == WM_KEYUP)
                     {
                            // when the button goes up
                     }
               }
        }

        return CallNextHookEx(g_hKbHook, iCode, wParam, lParam);
}

Is there anything wrong with this?
0
 
itsmeandnobodyelseCommented:
Looks like a mismatch. Please post mouseProc and not kbProc.

Regards, Alex
0
 
njitramAuthor Commented:
Woops, sorry, no idea where that came from...below the mouseProc;

LRESULT CALLBACK
mouseProc(int iCode, WPARAM wParam, LPARAM lParam)
{
    if (iCode < 0) {
        return CallNextHookEx(g_hMouseHook, iCode, wParam, lParam);
    }
    else {
        if (iCode == HC_ACTION)
        {
            MSLLHOOKSTRUCT msllHookStruct = *(MSLLHOOKSTRUCT*)lParam;
            if (wParam == WM_LBUTTONDOWN || wParam == WM_RBUTTONDOWN || wParam == WM_XBUTTONDOWN ||
                wParam == WM_MBUTTONDOWN)
            {
                if ((msllHookStruct.flags & LLMHF_INJECTED) != 0)
                {
                    return CallNextHookEx(g_hKbHook, iCode, wParam, lParam);
                }

                // handle mouse down
            }
            if (wParam == WM_LBUTTONUP || wParam == WM_RBUTTONUP || wParam == WM_XBUTTONUP ||
                wParam == WM_MBUTTONUP)
            {
                 // handle mouse up
            }
        }
    }
    return CallNextHookEx(g_hMouseHook, iCode, wParam, lParam);
}

The functions inside the handling are about the same as the keyboard, but considering those work perfectly fast in the keyboard proc now..I thought I'd save some room...
0
 
itsmeandnobodyelseCommented:
No, that code couldn't be slow as it handles only mouse button clicks (and not mouse moves as i guessed before your post).

However, it will be called for any mouse move message as well. So little times may add to something that is measurable, though i don't believe it. But you may use a static counter to find out, how often it is called.

Is there another mouse hook somewhere?

Regards, Alex
0
 
itsmeandnobodyelseCommented:
You also could comment the handling of the mouse clicks, to see whether the mouse hook itself or your mouse handling slows down.

Regards, Alex
0
 
njitramAuthor Commented:
There is not a second mouse hook somewhere, I'm only using 2 hooks, one for the keyboard and one for the mouse.

I tried putting a small counter which counted the times mouseProc was called, well, that was alot. ;) So I figure it gets called everytime the mouse moves/clicks.

I also tried to empty the code that handles the mouse clicks to a single 'clicks++;', but it still continued to go slow.
0
 
itsmeandnobodyelseCommented:
>> that was alot. ;)

How often a second? And do you have to move the mouse for that?

You could try to return not calling CallNextHookEx. Only to see if these calls are the reason for the slowness.

Regards, Alex


0
 
njitramAuthor Commented:
I'd say every pixel, inch, or whatever is used to measure mouse distances to see when another message is posted.

And when I remove the return's, the mouse stops responding totally (Including in Windows).
0
 
itsmeandnobodyelseCommented:
>>> the mouse stops responding totally

You *have* to call CallNextHookEx if nCode < 0. Return 0 all other returns, as a non-zero return means you've processed the message, thus the message will not get processed by the target window.

Regards, Alex

0
 
njitramAuthor Commented:
No change when I put the returns to 0, I'm really out of ideas...do you have any left?
0
 
moduloCommented:
PAQed with points refunded (500)

modulo
Community Support Moderator
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now