Keyboard input is passed onto a program’s window procedure in the form of messages. Each time a key is pressed a message is sent to the window with input focus. Since most applications will have more than one window, a particular window must have input focus in order to receive these messages. The window that has the keyboard focus receives all keyboard messages until the focus changes to a different window.
Pressing keys on the keyboard will generate both a keystroke and a character. Keystrokes are the physical keys you press on your keyboard and may or may not generate a character. Characters represent the display symbol or glyphs displayed as a result of the keypress.
When a key is pressed, a WM_KEYDOWN message is placed in the message queue by windows, and when that key is released a WM_KEYUP message is placed in the message queue. These keystroke messages indicate the pressed key using a virtual key code. The virtual key code is a device-independent integer code that uniquely identifies a key on the keyboard. The corresponding MFC message map macros are ON_WM_KEYDOWN, ON_WM_KEYUP. The prototype message handler is-
afx_msg void OnMsgName (UINT nChar, UINT nRepCnt, UINT nFlags)
where
nChar – virtual key code of the key that was pressed or released.
nRepCnt – repeat count—the number of keystrokes.
nFlags – contains the key’s scan code.
In addition to producing keystrokes, character messages are also produced as a result of translating keystroke messages into character codes. The most commonly used character message is WM_CHAR. A WM_CHAR message includes a character code that maps directly to a symbol in the current character set. The ON_WM_CHAR macro entry in a class’s message map routes WM_CHAR messages to the member function OnChar(). The prototype is prototype is as follows:
afx_msg void OnChar (UINT nChar, UINT nRepCnt, UINT nFlags)
where nChar holds the character code and nRepCnt and nFlags have the same meanings that they have in keystroke messages.
Some additional keyboard messages
SYSKEY messages
The WM_SYSKEYDOWN and WM_SYSKEYUP message is generated when the user presses the F10 key (menu bar) or holds down the ALT key and then presses another key. It also occurs when no window currently has the keyboard focus with the message being sent to the active window.
If other keys are pressed while the Alt key is held down will also generate WM_SYSKEYDOWN and WM_SYSKEYUP messages instead of WM_KEYDOWN and WM_KEYUP messages.
The window that receives the message can distinguish between these two contexts by checking the context code in the lParam parameter.
The corresponding message-map macros are ON_WM_KEYDOWN, ON_WM_KEYUP, ON_WM_SYSKEYDOWN, and ON_WM_SYSKEYUP.
Handling WM_SYSKEYDOWN and WM_SYSKEYUP messages is generally best left to the system since if these messages don’t find their way to ::DefWindowProc and get returned to windows then system keyboard commands such as Alt-Tab will stop working.
Dead keys
A dead key is a modifier key that does not generate a character on its own but modifies the character generated by the key pressed immediately after it. Dead keys are typically used to attach a specific diacritic to a base letter.
To process dead-key messages in an MFC application will need to include an ON_WM_DEADCHAR or ON_WM_SYSDEADCHAR entry in the message map in addition to supplying handling functions named OnDeadChar() and OnSysDeadChar().
Virtual key codes
Windows defines special constants for each key the user can press. These constants, known as virtual key codes, provide a hardware and language-independent method of identifying keyboard keys. These values are listed in the link below
https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
Retrieving a key state
The ::GetKeyState() API function retrieves the status of a specified virtual key. The status specifies whether the key is up, down, or toggled. Since information about the current states of keys such as Shift and Ctrl keys is not included in keyboard messages, the GetKeyState API function allows the developer to determine these key states before deciding on a course of action. The syntax for this function is –
#include <afxwin.h> class CSimpleApp : public CWinApp { public: BOOL InitInstance(); }; class CMainFrame : public CFrameWnd { public: CMainFrame(); afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnChar( UINT nChar, UINT nRepCnt, UINT nFlags ); afx_msg void OnPaint(); CString keycode; CString character; DECLARE_MESSAGE_MAP() }; BOOL CSimpleApp::InitInstance(){ m_pMainWnd = new CMainFrame(); m_pMainWnd->ShowWindow(m_nCmdShow); return TRUE; } CMainFrame::CMainFrame() { CRect rect(12,12,500,400); Create(NULL, "MFC KeyBoard Input",WS_CAPTION| WS_SYSMENU| WS_MAXIMIZEBOX| WS_MINIMIZEBOX); } BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd) ON_WM_KEYDOWN() ON_WM_CHAR() ON_WM_PAINT() END_MESSAGE_MAP() CSimpleApp MFCApp1; afx_msg void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags ) { CString converti; converti.Format("%d", nChar); keycode="keycode "+converti; } afx_msg void CMainFrame::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags ) { CRect clientRect; AfxGetMainWnd()->GetClientRect(&clientRect); CString converti; converti=(char)nChar; if (nChar>=32) { character="character "+converti; } AfxGetMainWnd()->InvalidateRect(clientRect,TRUE); } afx_msg void CMainFrame::OnPaint() { CPaintDC dc (this); dc.TextOut(0,0, keycode); dc.TextOut(0,20, character); }