Welcome back to System Events and Integration. We are now in Lesson 3, so we already know how to react to timer events and mouse input; now, we are adding another major part of event-driven programming: the keyboard.
In this lesson, we will process hardware key input by handling WM_KEYDOWN. Our goal is simple and useful: when the user presses Esc, the window will treat it like a shortcut, show a confirmation dialog, and close only if the user agrees. This gives us a clean first example of turning a raw key press into real application logic.
As you may recall from previous units, WinAPI messages carry different kinds of data depending on the event. Mouse clicks gave us coordinates through lParam. Keyboard key presses work differently: WM_KEYDOWN places the important value in wParam.
Here is the key idea:
WM_KEYDOWNtells us that a key was pressed.wParamcontains a virtual key code, such asVK_ESCAPEorVK_F1.- Virtual key codes are great for shortcuts because they describe the logical key, not typed text.
It is important to note that keyboard messages are sent only to the window that currently has input focus. If the user clicks away to another application, your window will stop receiving these messages. This ensures that only the active window processes the user's typing.
That is why this message is a better fit for keys like Esc, arrows, and function keys than character-based input.
Before we react to the keyboard, it helps to show a clear instruction in the window. We do that in WM_PAINT, which is the proper place for drawing. This keeps the visual part of the program separate from the input part, a pattern that should feel familiar after the mouse lesson.
This code starts a paint cycle with BeginPaint, draws a wide string with TextOutW, then ends the cycle with EndPaint. Using lstrlenW(msg) means we let WinAPI compute the string length for us instead of hardcoding it. The result is a small prompt inside the client area:
Now we can listen for the actual key press. This is the heart of the lesson: when Windows sends WM_KEYDOWN, we inspect wParam and compare it with a virtual key constant. In this case, we are looking for VK_ESCAPE.
This comparison is simple, but it is very powerful. Instead of dealing with text, we are reacting to a specific key at the hardware-event level. That makes this pattern useful for shortcut handling, menu triggers, and keys that do not produce normal characters. Notice the contrast with the mouse lesson: there, lParam held packed position data; here, wParam tells us which key went down.
Pressing Esc should not immediately close the program. Instead, we pause and ask the user what to do. A message box is a good fit here because it is modal, which means the program waits for an answer before continuing.
There are two important parts here. First, MessageBoxW shows a Yes-or-No dialog with a question icon, and it returns the button the user clicked. Second, we only call DestroyWindow(hwnd) when the result is IDYES. That gives us a clean shortcut flow: Esc triggers the dialog, and the dialog decides whether the close action should continue.
Calling DestroyWindow does not end the program by itself. Instead, it starts the normal window shutdown process. As part of that process, Windows sends WM_DESTROY, and that is where we post the quit message for the message loop.
This step is worth understanding clearly. DestroyWindow closes the window; PostQuitMessage(0) tells the application loop to stop. Keeping these responsibilities separate is good WinAPI style because shutdown still flows through the same message system we have been using all course long. It also means unhandled messages can still fall through to DefWindowProcW in the normal way.
In this lesson, we built a full WinAPI keyboard input flow. We displayed a prompt during WM_PAINT, listened for WM_KEYDOWN, checked wParam for VK_ESCAPE, asked for confirmation with MessageBoxW, and closed the window through the standard DestroyWindow then WM_DESTROY path.
Just as importantly, we reinforced a pattern that has been growing across the course: input, drawing, and shutdown all move through the same message system. Timers gave us time-based events, mouse messages gave us coordinates, and now keyboard messages give us shortcut-style control through virtual key codes. In the practice section coming up, we will turn this into hands-on work so we can start recognizing keyboard triggers with confidence and speed.
