VK_SNAPSHOT and KEYDOWN

Started by
11 comments, last by matt77hias 6 years, 5 months ago

I want to take a screenshot when the user presses "print screen" or ALT + "print screen". I succeed by listening for up keys:


case WM_KEYUP: {

	switch(wParam) {
	case VK_SNAPSHOT:
		SwapChain::Get()->TakeScreenShot();
    default:
    	return DefWindowProc(hWnd, msg, wParam, lParam);
	}
}
        
case WM_SYSKEYUP: {

	switch(wParam) {
	case VK_SNAPSHOT:
		SwapChain::Get()->TakeScreenShot();
	default:
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}
}

This does not work for down keys for VK_SNAPSHOT. Why is this the case?

🧙

Advertisement

I can't remember the exact reason, though I had this problem before (will search the forum-post that will hopefully contain the explanation). In the meanwhile, the solution for me was to install a hook, that checks for that specific keypress:


LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if(nCode >= 0 && nCode == HC_ACTION)
	{
		KBDLLHOOKSTRUCT* p = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
		switch(wParam)
		{
		case WM_KEYDOWN:
			if(p->vkCode == VK_SNAPSHOT)
				input::WindowProcHook::SetRawButtonState(input::Keys::PRINT, true, false); // your code goes here
			break;
		}
	}

	return CallNextHookEx(impl::hKeyboardHook, nCode, wParam, lParam);
}

// call this somewhere at program startup
void registerPrintKeyHook(void)
{
	impl::hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, lowLevelKeyboardProc, GetModuleHandle(NULL), 0);
}

EDIT: There you go:

this should hopefully explain it :)

I am going to give it a try. Thanks :)

🧙

13 hours ago, Juliean said:

if(nCode >= 0 && nCode == HC_ACTION)

Why not using if(HC_ACTION == nCode) ?

🧙

7 minutes ago, matt77hias said:

Why not using if(HC_ACTION == nCode) ?

You're right, makes much more sense. That code was pretty much copy paste, as I happen to do with most Win32-related code :D

14 hours ago, Juliean said:

return CallNextHookEx(impl::hKeyboardHook, nCode, wParam, lParam);

Since the first parameter is ignored according to MSDN, why also not providing nullptr?

The hook seems already nicer compared to other callbacks. I implemented the window callbacks as class methods. In order to support multiple instances, I always need to look for a way to smuggle the "this pointer" of the calling object into the function.

🧙

I added the registration of the hook but I never get inside the proc:

temp = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, GetModuleHandle(NULL), 0);

(temp is non-null)

🧙

Hm, not sure why it isn't being called for you, it definately worked for me. After looking through my code though, I noticed I wasn't even installing this hook anymore. From the commit that I wrote, there where some "responsiveness issues", so I just went with using WM_KEYUP for snapshots instead, oh well...

I am doing this the following way, seems a bit more standard WinAPI usage for me:

First, I have this enum:


enum Hotkeys{ UNUSED = 0, PRINTSCREEN = 1,};

Then in the InitInstance winapi function I call this after creating the window:


RegisterHotKey(hWnd, PRINTSCREEN, 0, VK_SNAPSHOT);

The last step is to handle the message in the message loop (WndProc function) like this:


switch (message)
{
	// ...
	case WM_HOTKEY:
		switch (wParam)
		{
		case PRINTSCREEN:
			{
				Helper::screenshot();
			}
			break;
		default:
			break;
		}
		break;
}

This one handles it on keydown. It also overrides the PrtScn key completely, so you cannot for example copy paste into Paint afterwards.

Cheers!

13 minutes ago, turanszkij said:

I am doing this the following way, seems a bit more standard WinAPI usage for me:

First, I have this enum:



enum Hotkeys{ UNUSED = 0, PRINTSCREEN = 1,};

Then in the InitInstance winapi function I call this after creating the window:



RegisterHotKey(hWnd, PRINTSCREEN, 0, VK_SNAPSHOT);

The last step is to handle the message in the message loop (WndProc function) like this:



switch (message)
{
	// ...
	case WM_HOTKEY:
		switch (wParam)
		{
		case PRINTSCREEN:
			{
				Helper::screenshot();
			}
			break;
		default:
			break;
		}
		break;
}

This one handles it on keydown. It also overrides the PrtScn key completely, so you cannot for example copy paste into Paint afterwards.

Cheers!

Nice and clean solution. I am going to give it a try as well :)

🧙

This topic is closed to new replies.

Advertisement