{"id":109951,"date":"2024-07-02T07:00:00","date_gmt":"2024-07-02T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109951"},"modified":"2024-06-24T09:11:08","modified_gmt":"2024-06-24T16:11:08","slug":"20240702-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240702-00\/?p=109951","title":{"rendered":"The history of <KBD>Alt<\/KBD>+number sequences, and why <KBD>Alt<\/KBD>+<KBD>9731<\/KBD> sometimes gives you a heart and sometimes a snowman"},"content":{"rendered":"<p>Once upon a time, the IBM PC was released.<\/p>\n<p>In the IBM PC BIOS, you could enter characters that weren&#8217;t present on the keyboard by holding the <kbd>Alt<\/kbd> key and typing the decimal value on the numeric keypad. For example, you could enter \u00f1 by holding <kbd>Alt<\/kbd> and typing <kbd>Numpad1<\/kbd> <kbd>Numpad6<\/kbd> <kbd>Numpad4<\/kbd>, then releasing the <kbd>Alt<\/kbd> key.<\/p>\n<p>For expository simplicity, I will henceforth use the notation <kbd>Alt<\/kbd>+<kbd>164<\/kbd> to indicate that you press the <kbd>Alt<\/kbd> key, then type the specified digits in sequence on the numeric keypad, then release the <kbd>Alt<\/kbd> key.<\/p>\n<p>Okay, so in the IBM PC BIOS, when you typed <kbd>Alt<\/kbd>+<kbd>\u2026<\/kbd>, the code numbers were treated as decimal byte values, and the result on the screen came from your video card&#8217;s character generator. In the United States, the character generator&#8217;s ROM showed what we today call <a href=\"https:\/\/en.wikipedia.org\/wiki\/Code_page_437\"> Code Page 437<\/a>.<\/p>\n<p>When it was introduced, Windows in the United States used <a href=\"https:\/\/en.wikipedia.org\/wiki\/Windows-1252\"> Code Page 1252<\/a> as its 8-bit character set, which it called the &#8220;ANSI character set&#8221;; the old BIOS character set was retroactively named the OEM character set. To preserve compatibility with MS-DOS, if you used the <kbd>Alt<\/kbd> key in conjunction with the numeric keypad, the number you typed was still looked up in OEM character set, so that your muscle-memory code numbers still worked. You could still type <kbd>Alt<\/kbd>+<kbd>164<\/kbd> to get your \u00f1, even though the code number for \u00f1 in Code Page 1252 is 241, not 164.<\/p>\n<p>If you wanted to type a character that had no OEM equivalent, you could prefix a numeric keypad <kbd>0<\/kbd> to indicate that you wanted the value looked up in the ANSI code page. Therefore, you could type <kbd>Alt<\/kbd>+<kbd>0169<\/kbd> to get a \u00a9, which did not exist in the OEM code page. You could also type <kbd>Alt<\/kbd>+<kbd>0241<\/kbd> to get your precious \u00f1, using the ANSI code point number rather than the OEM code point number.<\/p>\n<p>If you entered a number larger than 255, both Windows and the IBM PC BIOS took your value mod 256, so typing <kbd>Alt<\/kbd>+<kbd>259<\/kbd> was the same as typing <kbd>Alt<\/kbd>+<kbd>3<\/kbd>. Both gave you OEM code point 3, which for Code Page 437 is a heart \u2665.<\/p>\n<p>If you ask the Internet how to type some of these non-ASCII characters on Windows, you may see people (and large language models) that tell you to type, say, <kbd>Alt<\/kbd>+<kbd>9731<\/kbd> to get a Unicode snowman \u2603. Unfortunately, from what we&#8217;ve learned above, this doesn&#8217;t work. You instead get the OEM character whose value is 9731 mod 256 = 3, or the aforementioned heart \u2665.<\/p>\n<p>A customer reported that a recent Windows update broke their ability to type a snowman by using <kbd>Alt<\/kbd>+<kbd>9731<\/kbd>. We explained that the update was not at fault; rather, <kbd>Alt<\/kbd>+<kbd>9731<\/kbd> was never supposed to produce a snowman at all! But the customer insisted that it used to work.<\/p>\n<p>A closer investigation of the issue revealed the reason.<\/p>\n<p>You see, while it&#8217;s true that the <kbd>Alt<\/kbd>+<kbd>\u2026<\/kbd> decimal value is taken mod 256, that is just the default behavior of the Windows input system. But some controls (most notably the RichEdit control) override the default handling of the <kbd>Alt<\/kbd>+<kbd>\u2026<\/kbd> sequence and parse out the decimal value <i>mod 65536<\/i> rather than <i>mod 256<\/i>.<\/p>\n<p>This means that whether the <kbd>Alt<\/kbd>+<kbd>\u2026<\/kbd> value is taken mod 256 depends on what kind of control you are typing into.<\/p>\n<p>By default, the value is taken mod 256, and <kbd>Alt<\/kbd>+<kbd>9731<\/kbd> gives you a heart.<\/p>\n<p>But if you happen to be using a RichEdit control, then the <kbd>Alt<\/kbd>+<kbd>\u2026<\/kbd> value is taken mod 65536, and <kbd>Alt<\/kbd>+<kbd>9731<\/kbd> gives you a snowman.<\/p>\n<p>(I don&#8217;t know of anybody who takes the value mod 2097151, to support direct entry of code points outside the Basic Multilingual Plane.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Code pages and custom keyboard handling.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[104],"class_list":["post-109951","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-tipssupport"],"acf":[],"blog_post_summary":"<p>Code pages and custom keyboard handling.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109951","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=109951"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109951\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=109951"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109951"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109951"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}