{"id":112080,"date":"2026-02-23T07:00:00","date_gmt":"2026-02-23T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=112080"},"modified":"2026-02-23T10:08:58","modified_gmt":"2026-02-23T18:08:58","slug":"20260223-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260223-00\/?p=112080","title":{"rendered":"Customizing the ways the dialog manager dismisses itself: Detecting the ESC key, second (failed) attempt"},"content":{"rendered":"<p>Last time, we saw that <a title=\"Customizing the ways the dialog manager dismisses itself: Detecting the ESC key, first (failed) attempt\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260220-00\/?p=112074\"> <code>Get\u00adAsync\u00adKey\u00adState<\/code> is not the way to detect whether the <kbd>ESC<\/kbd> key was down at the time the current input message was generated<\/a>. But what about if we switched to <code>Get\u00adKey\u00adState<\/code>? Would that allow us to distinguish between an <code>IDCANCEL<\/code> caused by the <kbd>ESC<\/kbd> and an <code>IDCANCEL<\/code> that come from the Close button?<\/p>\n<p>It helps, in that it tells you whether the <kbd>ESC<\/kbd> key was down when the event occurred, but just because the <kbd>ESC<\/kbd> is down doesn&#8217;t mean that the <kbd>ESC<\/kbd> key is why you got the message.<\/p>\n<p>For example, suppose your policy is to simply ignore the <kbd>ESC<\/kbd> key, but to close the dialog if the user clicks the Close button. If the user holds the <kbd>ESC<\/kbd> key and clicks the Close button, the initial press of the <kbd>ESC<\/kbd> will generate an <code>IDCANCEL<\/code>, and your call to <code>Get\u00adKey\u00adState<\/code> will report that the <kbd>ESC<\/kbd> is down, so you will ignore the message.<\/p>\n<p>And then the next <code>IDCANCEL<\/code> comes in due to the Close button, and your call to <code>Get\u00adKey\u00adState<\/code> will correctly report &#8220;The <kbd>ESC<\/kbd> key is still down.&#8221; So your function says, &#8220;Oh, this came from the <kbd>ESC<\/kbd> key, so ignore it.&#8221;<\/p>\n<p>Except that it didn&#8217;t come from the <kbd>ESC<\/kbd> key. It came from the Close button. It just so happens that the <kbd>ESC<\/kbd> is down, but that&#8217;s not the reason why you got the second <code>IDCANCEL<\/code>.<\/p>\n<p>Suppose you have a kiosk in a room with two entrances, a back entrance and a front entrance. If someone enters from the front door, you want to call the receptionist, but you don&#8217;t want to do it if they enter from the back door. What we&#8217;re doing by checking the <kbd>ESC<\/kbd> key is saying, &#8220;If the back door is open, then don&#8217;t call the receptionist.&#8221; But it&#8217;s possible that somebody is just standing in the back doorway, holding the door open, and during that time, somebody comes in the front door. Your logic sees that the back door is open and suppresses the call to the receptionist because you had assumed that only one door can be open at a time.<\/p>\n<p>Next time, we&#8217;ll look at distinguishing <kbd>ESC<\/kbd> from Close.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sniffing the synchronous keyboard state is still not precise enough.<\/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":[25],"class_list":["post-112080","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Sniffing the synchronous keyboard state is still not precise enough.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112080","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=112080"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112080\/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=112080"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=112080"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=112080"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}