Hi everyone!

I am using a dll to hook keyboard strokes for my application.
The hook works fine, but now i want to disable some keystrokes while my application is running.

So i did the following :

_declspec(dllexport) LRESULT CALLBACK KBHookProc(int Code, WPARAM wParam, LPARAM lParam)
{
	
	if (Code < 0) return(CallNextHookEx(hhook, Code, wParam, lParam));

		if (lParam & (1 << 31)) 
		{
			if(wParam==VK_F2)
			{
				keystrokes = 2;
				keytime=GetTickCount();
				return(CallNextHookEx(hhook, Code, wParam, lParam));
			}
			else if (wParam == VK_F3)
			{
				keystrokes = 3;
				keytime=GetTickCount();
				return(CallNextHookEx(hhook, Code, wParam, lParam));
			}
			else if (wParam == VK_F4)
			{
				keystrokes = 4;
				keytime=GetTickCount();
				return(CallNextHookEx(hhook, Code, wParam, lParam));
			}
			else if (wParam == VK_F5)
			{
				keystrokes = 5;
				keytime=GetTickCount(); //I WANT TO BLOCK F5 so i do not return callnexthookex
				return -1;
			}
//... OTHER KEYS I WANT TO BE PROCESSED

//....

			else 
                        {   
                            keystrokes = 0;
                            return(CallNextHookEx(hhook, Code, wParam, lParam));
                        }
		}
	return -1; // If i keep this line ALL keys are blocked
	//return(CallNextHookEx(hhook, Code, wParam, lParam)); // if i keep this line all keystrokes pass including F5 i am trying to block.
}

So as you see on the comments above i try for example to block F5 keystroke by "breaking" the hook chain.
The last to lines as stated above, both produce unwanted effects.

Is there anyway i could sort this out? Has anyone done this before? I searched really thorougly through the net and couldn't find anything. Using another technique (such as other applications or registry tweaks) is not an option.

Thanks in advance!

Recommended Answers

All 9 Replies

If that last line is executed instead of any of those if statements then the line 6 is the obvious problem. have you checked the value of lparam and lparam & 0x80000000 ? And why don't you just simplify that line by using 0x80000000 instead of 1 << 31 ? The compiler could care less one way or the other but it would help you and others to know that mask you are trying to use.

And there's no bigger help than inserting printf/cout statements to show you exactly which blocks of code are executing (and the values of variables too). They're easy to insert and easy to remove. If you want to get fancy you can define your own "logging system" so that you can print out information at various levels of importance, and set the importance level(s) you're interested in.

Thanks both for the answers.

Bit 31 in lparam tells whether a key is down.
And as for the logging i used printfs and i am quite sure that both return statements (in lines : 30 and 43) are executed when line 43 is not commented.

You made me think that maybe the callback function is executed twice when a key press occurs. Once on the keydown event and once more on keyup event.

But changing my code to the following had the same results :

_declspec(dllexport) LRESULT CALLBACK KBHookProc(int Code, WPARAM wParam, LPARAM lParam)
{
	
	if (Code < 0) return(CallNextHookEx(hhook, Code, wParam, lParam));

		if (lParam & (1 << 31)) 
		{
			if(wParam==VK_F2)
			{
				keystrokes = 2;
				keytime=GetTickCount();
				return(CallNextHookEx(hhook, Code, wParam, lParam));
			}
			else if (wParam == VK_F3)
			{
				keystrokes = 3;
				keytime=GetTickCount();
				return(CallNextHookEx(hhook, Code, wParam, lParam));
			}
			else if (wParam == VK_F4)
			{
				keystrokes = 4;
				keytime=GetTickCount();
				return(CallNextHookEx(hhook, Code, wParam, lParam));
			}
			else if (wParam == VK_F5)
			{
				keystrokes = 5;
				keytime=GetTickCount(); //I WANT TO BLOCK F5 so i do not return callnexthookex
				return -1;
			}
//... OTHER KEYS I WANT TO BE PROCESSED

//....

			else 
                        {   
                            keystrokes = 0;
                            return(CallNextHookEx(hhook, Code, wParam, lParam));
                        }
		}
// EDIT HERE: 
        else  //Any other event such as keyup won't be passed to the hook chain
        {
	    return -1; // If i keep this line ALL keys are blocked
	//return(CallNextHookEx(hhook, Code, wParam, lParam)); // if i keep this line all keystrokes pass including F5 i am trying to block.
        }
}

Anyway i should mention that i test the above this way:
I run my application, i open notepad, i type stuff...and see what's going on there..

As i mentioned it seems that i can only block ALL keystrokes only.
I ve done some extra debugging and it looks like the hooks work fine on my application (meaning that if my application window has focus, the keys i want to be blocked are blocked - and others work as before.)
But also on another application which is a directx fullscreen one ALL keys work and NONE is blocked.

So : My application blocks ALL keys on some apps. Blocks only the keys i want on its window. Blocks NONE of the keys on a fullscreen directx application.

Obviously i come to realize that i cannot manipulate fully system wide hooks.
I don't know what else to think.

Any other suggestion would be great.
Thanks.

> Bit 31 in lparam tells whether a key is down.

What gives you such idea?

Try an experiment: set a breakpoint at line 6. Press buttons few times. Pay attention to lparam. Be surprised that it doesn't change. Then read documentation, and realize that lParam is a pointer is disguise, and that wParam is press/release info.

It's generally considered bad form for one application to steal events from all other applications. I'm betting (with good cause) that you can do what you need, which means making sure that the keyboard events are passed to your application -before- they're passed to the application that currently has focus ... if you don't want to (or can't) tell the system that your application should keep focus until it says otherwise (or terminates). Depending on why you need the F5 keypress event sent only to your special application, there may be some other way to achieve the same end. I'm not going to pry, but if this were easy to do, the solution would be ubiquitous and well-documented, and probably none of your applications would work correctly because some other application would be stealing the events it wants. :)

>well-documented

As a matter of fact, it is. See a link in my post. As for applications working correctly, MSDN specifies that
For a specified hook type, thread hooks are called first, then global hooks. which means that an application is still able to receive all events, and also warns that

The global hooks are a shared resource, and installing one affects all applications in the same desktop as the calling thread. ... Global hooks should be restricted to special-purpose applications or to use as a development aid during application debugging. Libraries that no longer need a hook should remove its hook procedure.

> Bit 31 in lparam tells whether a key is down.

What gives you such idea?

Try an experiment: set a breakpoint at line 6. Press buttons few times. Pay attention to lparam. Be surprised that it doesn't change. Then read documentation, and realize that lParam is a pointer is disguise, and that wParam is press/release info.

Aahhhh shhoooot... well that's what you get when you're tired of reading proper documentation and start reading users' documentation.. It's seems so easy in the beginning but always hides most of the truth.
:)

It's generally considered bad form for one application to steal events from all other applications. I'm betting (with good cause) that you can do what you need, which means making sure that the keyboard events are passed to your application -before- they're passed to the application that currently has focus ... if you don't want to (or can't) tell the system that your application should keep focus until it says otherwise (or terminates). Depending on why you need the F5 keypress event sent only to your special application, there may be some other way to achieve the same end. I'm not going to pry, but if this were easy to do, the solution would be ubiquitous and well-documented, and probably none of your applications would work correctly because some other application would be stealing the events it wants. :)

I totally understand what you're trying to say.
But having to work with kiosk machines means that you always have to "hack" a certain aspect of the os, to create transparency for your application. Add old applications that noone knows how they work but have to cooperate with your's to the equation and you 'll have a nice picture of it..
I know another couple of ways to do what i want (done it before ) but the one is really hard, and the other really stupid and not stable at all..
So i just thought i should give this a try.

>well-documented

As a matter of fact, it is. See a link in my post. As for applications working correctly, MSDN specifies that
For a specified hook type, thread hooks are called first, then global hooks. which means that an application is still able to receive all events, and also warns that

The global hooks are a shared resource, and installing one affects all applications in the same desktop as the calling thread. ... Global hooks should be restricted to special-purpose applications or to use as a development aid during application debugging. Libraries that no longer need a hook should remove its hook procedure.

I'm going to try something else and post back results.
Thanks for the feedback.
:)

Well i just figured it out.

The callback function is executed twice on every keypress.
One for keyboard down (WM_KEYDOWN) message and one for keyboard up message (WM_KEYUP).

I wanted to execute my code ONLY once in a keypress. So i distinguished those with the help of the lParam bitmask calculation.
Eventually, bit 31 of lParam DOES tell you wether you have a keyup or keydown event. I don't know if it this is a workaround or the real thing, but it works because lParam looks like this:

The lParam is = 0x1f0001   //KEY DOWN
The lParam is = 0xc01f0001 //KEY UP

On every Key Up callback the lParam has c0 as the two msbits. The other part is the same and contains probably scancode information.

So applying the bitmask :

//KEY_DOWN
(00000000000)111110000000000000001 //values on parentheses are implied
AND (bitwise)
  10000000000000000000000000000000 (FALSE)
=
  00000000000000000000000000000000


//KEY UP
11000000000111110000000000000001
AND (bitwise)
10000000000000000000000000000000
=
10000000000000000000000000000000 (TRUE)

So if i change my dll code to the following :

_declspec(dllexport) LRESULT CALLBACK KBHookProc(int Code, WPARAM wParam, LPARAM lParam)
{
	
	if (Code < 0) return(CallNextHookEx(hhook, Code, wParam, lParam));

			if((wParam==VK_F2) && (lParam & (1 << 31)))
			{
				keystrokes = 2;
				keytime=GetTickCount();
				return(CallNextHookEx(hhook, Code, wParam, lParam));
			}
			else if ((wParam == VK_F3) && (lParam & (1 << 31)))
			{
				keystrokes = 3;
				keytime=GetTickCount();
				return(CallNextHookEx(hhook, Code, wParam, lParam));
			}
			else if ((wParam == VK_F4) && (lParam & (1 << 31)))
			{
				keystrokes = 4;
				keytime=GetTickCount();
				return(CallNextHookEx(hhook, Code, wParam, lParam));
			}
			else if (wParam == VK_F5) //F5 keyup AND keydown are blocked
			{
				return -1;
			}
//... OTHER KEYS I WANT TO BE PROCESSED

//....

			else 
                        {
                            return(CallNextHookEx(hhook, Code, wParam, lParam));
                        }

}

I finally manage to block F5 and let all other keys function correctly.
:)

BUT : This seems to work only to applications that have thread hooks (virtually almost every common application) and of course my own application. The fullscreen application i wanted to intercept, does not work. All keystrokes there are working. Maybe because it uses global hooks too. I don't know...

So the only workaround is the following (done it before and works):

1) Block the keys you want using windows registry and scancode mappings (or MSKLC tool from microsoft) (this means the key will be ALWAYS blocked for ALL operating system functions and only the reverse proccess and a reboot can bring it back)

2) Use another key with your hook and keybd_event function to emulate the blocked key on your favor. (or use autohotkey http://www.autohotkey.com/)

Or if you like it hardcore, write your own keyboard driver...
:)

In order to mark this thread as solved i add the following.

I didn't manage to understand why the application i want to block isn't working.
But i concluded to 2 possible answers :
1) Either it loads it's own keyboard driver (or filter driver)
2) Or it's a directx's feature to manage hooks in a way that they are not affected by the technique i applied

In the end it turns out that i will have to write my own low level keyboard filter driver because neither scancode mappings through registry works!
:)

This is possible using the WDK (Windows driver Kit), which has sample code for keyboard filter drivers among others.
Never written a driver before so i'm reading documentation atm..

For what it's worth, thanks to everyone that helped.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.