{"id":110272,"date":"2024-09-16T07:00:00","date_gmt":"2024-09-16T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110272"},"modified":"2024-09-16T09:12:55","modified_gmt":"2024-09-16T16:12:55","slug":"20240916-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240916-00\/?p=110272","title":{"rendered":"Some notes on Win32 carets"},"content":{"rendered":"<p>In Win32, the <i>caret<\/i> is a visual indication of where the next typed character will be inserted. It is traditionally a thin vertical bar.<\/p>\n<p>Note that all defaults listed below are as of this writing. The values are not contractual, but I&#8217;m just providing them for illustration.<\/p>\n<p>You can ask for the caret blink rate by calling the <code>Get\u00adCaret\u00adBlink\u00adTime<\/code> function (default: 500ms). Note that the caret will stop blinking after a while (default: 5 seconds) to avoid running timers indefinitely if they have a period shorter than one minute. Furthermore, on Remote Desktop connections, caret blinking might be disable entirely. This avoids long-running timers on systems that may be hosting multiple simultaneous interactive users. When you have 100 users signed in, each with a blinking caret, even a timer that fires only once every 500ms is running at a high enough frequency to cause measurable energy consumption.<\/p>\n<p>The caret blink rate also controls the default blink rate used by the <code>Flash\u00adWindow\u00adEx<\/code> function, and when the system flashes the title bar of a window when you click on its disabled owner, it does so (today) at 8 times the caret blink rate.<\/p>\n<p>When you create a caret, you can let the system choose the dimensions by setting the width and height to zero. Today, this uses the system-defined window border width and height. Unfortunately, the window manager lets you down here: The recommended width is not the window border width but the caret width, which comes from <code>System\u00adParameters\u00adInfo<\/code> with <code>SPI_<wbr \/>GET\u00adCARET\u00adWIDTH<\/code>. So those defaults don&#8217;t help you much; they&#8217;re the wrong values.<\/p>\n<p>Another way to create a caret is to use a bitmap. In that case, it is your responsibility to keep the bitmap handle valid for as long as the bitmap caret is in use, <i>viz<\/i>. until the caret is destroyed, or it is replaced by another caret.<\/p>\n<p>In all cases, the system draws the caret by the classic algorithm of XOR. This works okay if the background is white or black (or close to it). Not so great if the background is some other color, and definitely not so great if the background is gray (because inverted gray is still gray).<\/p>\n<p>In the case where you set the caret to a bitmap, the system will still use XOR to draw it. If your bitmap is not a monochrome bitmap, then things will probably look kind of weird because XOR&#8217;ing two colors together tends to produce non-intuitive results.<\/p>\n<p>I guess what you could do is XOR the background color with your desired caret color, and use that color as the color in your caret bitmap. Through the magic of XOR, when the caret bitmap is XOR&#8217;d with the background color, your desired caret color pops out.<\/p>\n<p>background ^ (background ^ foreground) = foreground<\/p>\n<p>This is really more of a hack based on a mathematical quirk than an intended design behavior. Bitmap carets were intended to be used with monochrome bitmaps.<\/p>\n<p>There you go, a bunch of loosely-connected paragraphs on Win32 carets.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Assorted notes and musings.<\/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-110272","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Assorted notes and musings.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110272","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=110272"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110272\/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=110272"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110272"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110272"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}