The ES_NUMBER edit control style limits typed input to digits, but what if you also want to accept negative numbers? How can we extend¹ ES_NUMBER to accept the minus sign?
The ES_NUMBER edit control style works by altering the behavior of the edit control when it receives a WM_CHAR. You can do that too!
Subclass the edit control and handle the WM_CHAR message by checking whether the character is a digit or a minus sign. If not, then beep and return. Otherwise, let the message through.
LRESULT CALLBACK SignedIntegerSubclassProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
UINT_PTR uIdSubclass,
DWORD_PTR dwRefData)
{
switch (uMsg) {
case WM_NCDESTROY:
RemoveWindowSubclass(hwnd, SignedIntegerSubclassProc, uIdSubclass);
break;
case WM_CHAR:
{
wchar_t ch = (wchar_t)wParam;
if (ch < L' ') break; // let control character through
else if (ch == L'-') break; // let hyphen-minus through
else if (ch == L'\x2212') break; // let Unicode minus sign through
else if (IsUnicodeDigit(ch)) break; // let digit through
MessageBeep(0); // otherwise invalid
return 0;
}
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
BOOL EnforceSignedIntegerEdit(HWND hwnd)
{
return SetWindowSubclass(hwnd, SignedIntegerSubclassProc, 0, 0);
}
If the user entered a character, then we let it through if it is one of the following:
- A control character, to permit Ctrl+A, Ctrl+C, Bksp, Tab, and so on.
- Unicode character U+002D HYPHEN-MINUS, which is what most people think of as a minus sign.
- Unicode character U+2212 MINUS SIGN, which is a true minus sign.
¹ As noted in the documentation, the ES_NUMBER edit control style doesn’t prevent the user from putting non-digits into the edit control by other means, like pasting with Ctrl+V. The exercise is to extend the existing behavior of the ES_NUMBER style, not to fix it to cover all the other scenarios. Our technique has the same defects as ES_NUMBER, but at least it’s the same defects.
0 comments