CaseSensitive Keyboard Hook  
Author Message
EA512





PostPosted: Visual C++ General, CaseSensitive Keyboard Hook Top

Hi,

i made a programm. it displays the entered keys in a console window.

But all letters are in "caps lock"! How can i prevent that

eg. if i enter:
aBcDeFg

it displays:
ABCDEFG

[code]
__declspec(dllexport) LRESULT CALLBACK KeyEvent (int nCode,WPARAM wParam,LPARAM lParam)
{
if ((nCode == HC_ACTION) && ((wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN)))
{
KBDLLHOOKSTRUCT hooked =
*((KBDLLHOOKSTRUCT*)lParam);

DWORD dwMsg = 1;
dwMsg += hooked.scanCode << 16;
dwMsg += hooked.flags << 24;

char key[16];
GetKeyNameText(dwMsg,key,15);

std::cout << key;
}
return CallNextHookEx(hKeyHook,nCode,wParam,lParam);
}
[/code]


Visual C++16  
 
 
Peter Ritchie





PostPosted: Visual C++ General, CaseSensitive Keyboard Hook Top

You'll have to detect virtual key up/down of various keys (VK_LSHIFT VK_RSHIFT VK_CAPITAL) and keep track of whether the one of the Shift keys are down, or the CAPS lock key was pressed when you key a key-down message.

You can use GetKeyState to get the initial state of certain keys when you start up (i.e. they've been pressed before you added your hook).

 
 
EA512





PostPosted: Visual C++ General, CaseSensitive Keyboard Hook Top

uhmm... is there really no other way to do this
i mean: wont this produce a (noticable) latency between pressing the key and showing it in the console window :/

hmm... ok, and how can i make the captured letters lowercase

 
 
Peter Ritchie





PostPosted: Visual C++ General, CaseSensitive Keyboard Hook Top

How would that introduce a latency All the low-level keyboard messages are coming in regardless of whether you process them or not... WM_KEYDOWN doesn't provide case/shift-state/caps-state like WM_CHAR would; but, you can't get WM_CHAR in the keyboard hooks...

Example (aircode):

__declspec(dllexport) LRESULT CALLBACK KeyEvent (int nCode,WPARAM wParam,LPARAM lParam)
{
// TODO: more reliable if this is done right before the call to SetWindowsHookEx
static bool shiftPressed = GetKeyState(VK_SHIFT) < 0;
static bool capsLockOn = GetKeyState(VK_CAPITAL) < 0;

if (nCode == HC_ACTION)
{
if((wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN)))
{
KBDLLHOOKSTRUCT hooked =
*((KBDLLHOOKSTRUCT*)lParam);
if(hooked.vkCode == VK_LSHIFT || hooked.vkCode == VK_RSHIFT)
{
shiftPressed = true;
}
else if(hooked.vkCode == VK_CAPITAL)
{
capsLockOn = true;
}
else
{
char charPressed = hooked.vkCode;
if( (0 != isalpha(charPressed)) && (shiftPressed ^ capsLockOn) )
{
charPressed = tolower(charPressed);
}

DWORD dwMsg = 1;
dwMsg += hooked.scanCode << 16;
dwMsg += hooked.flags << 24;

char key[16];
GetKeyNameText(dwMsg,key,15);

std::cout << key;
}
}
else if((wParam == WM_SYSKEYUP) || (wParam == WM_KEYUP)))
{
if(hooked.vkCode == VK_LSHIFT || hooked.vkCode == VK_RSHIFT)
{
shiftPressed = false;
}
else if(hooked.vkCode == VK_CAPITAL)
{
capsLockOn = false;
}
}
}
return CallNextHookEx(hKeyHook,nCode,wParam,lParam);
}



 
 
Simple Samples





PostPosted: Visual C++ General, CaseSensitive Keyboard Hook Top

See The scope of this forum. Keyboard hooks are definitely a Windows thing, not a C++ thing. You will get more help in a more appropriate forum or newsgroup; for one reason, those people are more likely to have examples and such that they can find more conveniently. For this question specificly, I think you will get a better answer in another forum or newsgroup.

You mention performance, and for a keyboard hook, performance can be an important consideration. You should not do things such as std::cout in a hook. You can and should communicate the data to somewhere else, using a minimum of processing in the hook, so that the data can be processed outside the hook.

 



 
 
Simple Samples





PostPosted: Visual C++ General, CaseSensitive Keyboard Hook Top

You'll have to detect virtual key up/down of various keys (VK_LSHIFT VK_RSHIFT VK_CAPITAL) and keep track of whether the one of the Shift keys are down, or the CAPS lock key was pressed when you key a key-down message.

You can use GetKeyState to get the initial state of certain keys when you start up (i.e. they've been pressed before you added your hook).
Are you sure it is necessary to do that for a keyboard hook

 
 
Peter Ritchie





PostPosted: Visual C++ General, CaseSensitive Keyboard Hook Top

You are using the wParam incorrectly and you are not using the lParam. I think you will find the answers in the documentation. In particular, read the documentation of the KeyboardProc hook procedure.

I assumed he was using a low-level hook, where wParam is the message ID, not the virtual-key code...

 
 
Peter Ritchie





PostPosted: Visual C++ General, CaseSensitive Keyboard Hook Top

 
Are you sure it is necessary to do that for a keyboard hook
In case that part of one of my previous posts wasn't clear...  The keyboard hook functions are documented as only hooking WM_KEY{DOWN|UP} for KeyboardProc and WM_[SYS]KEY{DOWN|UP} for LowLevelKeyboardProc.  the KEY{UP|DOWN} messages don't include any scancode/virtual-key to ASCII code mapping or any shift-key/Caps-Lock state information at the time of the key action (you'd use the WM_CHAR message if you're interested in ASCII characters when not using a hook).  Querying the keyboard state at the time of the call to your KeyboardProc or your LowLevelKeyboardProc will do just that: give you the state of those keys when your procedure was called, not when the key action occurred.  The only way to reliably translate a keycode is to also watch the shift/caps key messages.
This is discussed in a few places, for example:

...all of which actually test the keyboard state (for shift/caps) at the time of the call; which is prone to error.



 
 
Simple Samples





PostPosted: Visual C++ General, CaseSensitive Keyboard Hook Top

If it is a low-level hook then I assume that I am the one that needs to read the documentation. If use of wParam and lParam is consistent with a low-level hook then it is safe to assume it is a low-level hook.