Win32: Alt+key beeps, a borrowed window class name, and one surrogate stash for every window #185

Open
opened 2026-10-31 17:22:46 +00:00 by jorijnvdgraaf · 0 comments

Three small problems in the Win32 window code, found while reviewing claude/win32-title. Line numbers refer to implementations/Crafter.Graphics-Window.cpp at 852ae8a.

Alt+key beeps

TranslateMessage turns Alt with a character key into WM_SYSCHAR, which reaches DefWindowProc through the default case (:339) and becomes SC_KEYMENU. The window has no menu, so WM_MENUCHAR gets its default answer, MNC_IGNORE, and Windows plays the error sound. An application that binds Alt+Enter or Alt+1 to 9 through onRawKeyDown gets its action and a beep on every press.

Fix: answer WM_MENUCHAR with MAKELRESULT(0, MNC_CLOSE). Alt+Space still opens the system menu.

The window class name can belong to someone else

The class is called "myWindowClass" (:128), registered under the executable's hInstance, and ERROR_CLASS_ALREADY_EXISTS (:410) is taken to mean an earlier window registered it. If the consumer's own window code uses the same name (it comes from a well-known Win32 tutorial), or a second copy of the library in a DLL registers it first, CreateWindowEx builds the HWND with that class's window procedure: no input, no resize, open never cleared.

Fix: a name only this library uses, such as L"Crafter.Graphics.Window", and on ERROR_CLASS_ALREADY_EXISTS a GetClassInfoExW check that its lpfnWndProc is WndProc.

One surrogate stash for every window

WM_CHAR keeps a pending high surrogate in a function-local static (:211) that every window shares, and only a low surrogate clears it. A high surrogate, then other characters, then a lone low surrogate are joined into a character neither unit belonged to: 0xD83D, 'a', 0xDE00 comes out as "a" and then U+1F600. Well-formed input never does this; malformed input from SendInput or PostMessageW can.

Fix: keep the stash in the Window, and drop a pending high surrogate when anything other than a low surrogate follows it.

Three small problems in the Win32 window code, found while reviewing `claude/win32-title`. Line numbers refer to `implementations/Crafter.Graphics-Window.cpp` at `852ae8a`. ## Alt+key beeps `TranslateMessage` turns Alt with a character key into `WM_SYSCHAR`, which reaches `DefWindowProc` through the default case (`:339`) and becomes `SC_KEYMENU`. The window has no menu, so `WM_MENUCHAR` gets its default answer, `MNC_IGNORE`, and Windows plays the error sound. An application that binds Alt+Enter or Alt+1 to 9 through `onRawKeyDown` gets its action and a beep on every press. Fix: answer `WM_MENUCHAR` with `MAKELRESULT(0, MNC_CLOSE)`. Alt+Space still opens the system menu. ## The window class name can belong to someone else The class is called `"myWindowClass"` (`:128`), registered under the executable's `hInstance`, and `ERROR_CLASS_ALREADY_EXISTS` (`:410`) is taken to mean an earlier window registered it. If the consumer's own window code uses the same name (it comes from a well-known Win32 tutorial), or a second copy of the library in a DLL registers it first, `CreateWindowEx` builds the HWND with that class's window procedure: no input, no resize, `open` never cleared. Fix: a name only this library uses, such as `L"Crafter.Graphics.Window"`, and on `ERROR_CLASS_ALREADY_EXISTS` a `GetClassInfoExW` check that its `lpfnWndProc` is `WndProc`. ## One surrogate stash for every window `WM_CHAR` keeps a pending high surrogate in a function-local `static` (`:211`) that every window shares, and only a low surrogate clears it. A high surrogate, then other characters, then a lone low surrogate are joined into a character neither unit belonged to: `0xD83D`, `'a'`, `0xDE00` comes out as `"a"` and then U+1F600. Well-formed input never does this; malformed input from `SendInput` or `PostMessageW` can. Fix: keep the stash in the `Window`, and drop a pending high surrogate when anything other than a low surrogate follows it.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Catcrafts/Crafter.Graphics#185
No description provided.