Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extract the character from WM_KEYDOWN in PreTranslateMessage(MSG*pMsg)

In a MFC application within PreTranslateMessage(MSG *pMsg) inherited from a CView, I have this:

if (pMsg->message == WM_KEYDOWN) ...

The fields in a WM_KEYDOWN are documented here. The virtual key VK_ value is in pMsg->wParam and pMsg->lParam contains several field, of which bits 16-23 is the keyboard scan code.

So in my code I use:

const int virtualKey = pMsg->wParam;
const int hardwareScanCode = (pMsg->lParam >> 16) & 0x00ff; // bits 16-23

On my non-US keyboard for example, when I press the "#" character, I get the following:

virtualKey == 0xde --> VK_OEM_7 "Used for miscellaneous characters; it can vary by keyboard."
hardwareScanCode == 0x29 (41 decimal)

The character I'd like to "capture" or process differently is ASCII "#", 0x23 (35 decimal).

MY QUESTION

How do I translate the WM_KEYDOWN information to get something I can compare against, regardless of language or keyboard layout? I need to identify the # key whether the user has a standard US keyboard, or something different.

For example, I've been looking at the following functions such as:

MapVirtualKey(virtualkey, MAPVK_VSC_TO_VK);
// previous line is useless, the key VK_OEM_7 doesn't map to anything without the scan code

ToAscii(virtualKey, hardwareScanCode, nullptr, &word, 0);
// previous line returns zero, and zero is written to `word`

Edit:

Long story short: On a U.S. keyboard, SHIFT+3 = #, while on a French keyboard SHIFT+3 = /. So I don't want to look at individual keys, instead I want to know about the character.

When handling WM_KEYDOWN, how do I translate lParam and wParam (the "keys") to find out the character which the keyboard and Windows is about to generate?

like image 858
Stéphane Avatar asked Mar 09 '23 19:03

Stéphane


1 Answers

I believe this is a better solution. This one was tested with both the standard U.S. keyboard layout and the Canadian-French keyboard layout.

const int wParam = pMsg->wParam;
const int lParam = pMsg->lParam;
const int keyboardScanCode = (lParam >> 16) & 0x00ff;
const int virtualKey = wParam;

BYTE keyboardState[256];
GetKeyboardState(keyboardState);

WORD ascii = 0;
const int len = ToAscii(virtualKey, keyboardScanCode, keyboardState, &ascii, 0);
if (len == 1 && ascii == '#')
{
    // ...etc...
}

Even though the help page seems to hint that keyboardState is optional for the call to ToAscii(), I found that it was required with the character I was trying to detect.

like image 54
Stéphane Avatar answered Apr 08 '23 15:04

Stéphane