February 13th, 2026
heartintriguinglike4 reactions

How can I distinguish between the numeric keypad 0 and the top-row 0 in the WM_CHAR message?

Last time, we looked at how to distinguish the numeric keypad 0 and the top-row 0 in the WM_KEY­DOWN message. We may as well look at the analogous table for WM_CHAR.

Event wParam Extended?
Numpad0 with NumLock on VK_0 0
Numpad0 with NumLock off (no WM_CHAR)
Ins key (no WM_CHAR)
0 on top row VK_0 0

I got the name VK_0 from this comment block in winuser.h.

/*
 * VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39)
 * 0x3A - 0x40 : unassigned
 * VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A)
 */

Uh-oh. The extended bit doesn’t distinguish between the two. They both show up as VK_0, non-extended.

What changes is something not in the above table: The scan code.

So let’s convert the scan code back to a virtual key.

auto vk_from_scan = MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK);
Event wParam Extended? vk_from_scan
Numpad0 with NumLock on VK_0 0 VK_INSERT
Numpad0 with NumLock off (no WM_CHAR)
Ins key (no WM_CHAR)
0 on top row VK_0 0 VK_0

So we can infer which zero was pressed by taking the scan code, mapping it to a virtual key, and seeing whether it’s the Ins key (from the numeric keypad) or the 0 key (from the top row).

But wait, we’re not done yet.

There are ways to type the character 0 without using the numeric keypad or the top row. For example, you can hold the Alt key and then type 4,8 on the numeric keypad, and that will type a 0. I tried it out, and the vk_from_scan was VK_MENU, which is the virtual key code for the Alt key. Another way of entering a 0 is by using an input method editor (IME). Or there might be a custom keyboard layout that generates a 0 through some wacky chord sequence.

Therefore, if the vk_from_scan is neither VK_INSERT nor VK_0, you have to conclude that the 0 was entered by some means other than the numeric keypad or the top row.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

10 comments

Discussion is closed. Login to edit/delete existing comments.

Sort by :
  • Nathan Phillip Brink (Binki)

    Shouldn’t games be using WM_KEYUP then?

    • Danielix Klimax

      Games should be using proper API meant for their usage model in the first place. Be it old DirectInput or newer XInput. Those who don’t will get hit with very “interesting” bugs.

      • Kevin Norris

        Seconding Krzysztof’s comment: The complexity they describe is before you consider things like Steam Input remapping. Steam allows users to remap their controller buttons to any controller, keyboard, or mouse input, and mix and match those inputs freely in the same control scheme. So you can have the user rapidly switching between input methods in the heat of gameplay, and they probably expect you to “just handle it.”

      • Krzysztof Kawa

        Yeah, except sometimes games need a standard boring text input box and cursor navigation alongside the typical game stuff. XInput only works with the Xbox controllers (and stuff that pretends to be them) and doesn't handle keyboards. DirectInput is old and really cumbersome. There's newer GameInput that has keyboard support, but even the docs state explicitly it's meant for mapping keys to typical game actions and not suited for text input. Same goes for DirectInput actually. You'd end up reimplementing stuff like autorepeat, cursor navigation etc.
        Yeah, you can do a virtual keyboard in some cases, but some games really...

        Read more
  • HXO

    I have a sort of related question.

    On at least two PCs, from different manufacturers, when three finger taps are enabled for middleclick, I find it works locally, but not in Remote Desktop sessions. There it works as Win+P and brings op Projection settings (which does not work in RD).

    When I look at local keyboard and mouse events (not WindowsMessages, my little .NET application just uses Forms events), I see this when three finger tapping:

    LWin down
    ControlKey down
    ShiftKey down
    F22 up
    ShiftKey up
    ControlKey up
    LWin up
    Middle down
    Middle - 1 click
    Middle up

    How did it come to this?Read more

  • Neil Rashbrook · Edited

    Or perhaps what you should conclude is that you shouldn’t be trying to work out how the user entered a 0 character.

    (I’m assuming the VK_MENU comes from the WM_KEYUP message that indicates the end of the Alt, 4, 8 sequence.)

    (Sadly we don’t get to use those nice <kbd>s in comments.)

    • Jan RingoÅ¡

      Games. Games do need to distinguish these. I remember RTS that used the top row numbers to select unit groups, but numpad numbers to enter comm codes.

      • Antonio Rodríguez

        Kile: Right. Good argument. Following it, we should get rid of multi monitor support (most laptop users never ever connect an external monitor). Then, the command line (most users do no need to use it, ever). And perhaps even that outdated mouse/touchpad support (touch screens made it redundant).
        Windows is what it is because of choice. It has the largest software library of any OS, period. But it is also the one which supports most form factors and user scenarios. "It just works", which was once the slogan of certain fruit-named company, is actually fulfilled in the Windows ecosystem. I...

        Read more
      • anonymous

        this comment has been deleted.

      • Danielix Klimax

        Games should use proper API for their usage in the first place. DirectInput or XInput. Problem becomes trivial then…