{"id":111984,"date":"2026-01-13T07:00:00","date_gmt":"2026-01-13T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111984"},"modified":"2026-01-13T09:08:32","modified_gmt":"2026-01-13T17:08:32","slug":"20260113-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260113-00\/?p=111984","title":{"rendered":"Clipping the focus item when looking for its on-screen location, part 2"},"content":{"rendered":"<p>Last time, <a title=\"Clipping the focus item when looking for its on-screen location\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260112-00\/?p=111980\"> we clipped the focus item to the containing window<\/a> so that we considered only the visible portion of the item. But we found that some programs use a dummy 0\u00d70 window as their window for system focus, while visual focus remains elsewhere. How can we clip the focus item to the correct bounds?<\/p>\n<p>It took a little thinking, but I realized that I can clip to the accessible parent of the focus item.<\/p>\n<p>So first, a little more refactoring.<\/p>\n<pre>bool GetAccessibleBounds(IAccessible* acc, LONG childId, RECT* rc)\r\n{\r\n    VARIANT vt;\r\n    vt.vt = VT_I4;\r\n    vt.lVal = childId;\r\n\r\n    if (acc-&gt;accLocation(&amp;rc-&gt;left, &amp;rc-&gt;top,\r\n                         &amp;rc-&gt;right, &amp;rc-&gt;bottom, vt) == S_OK) {\r\n        rc-&gt;right += rc-&gt;left;\r\n        rc-&gt;bottom += rc-&gt;top;\r\n        return true;\r\n    } else {\r\n        *rc = {};\r\n        return false;\r\n    }\r\n}\r\n<\/pre>\n<p>This obtains the bounds of an accessible item in the form of a <code>RECT<\/code>. We can now use the rectangle manipulation functions to intersect the object&#8217;s bounds with the bounds of its parent.<\/p>\n<pre>bool SetCursorPosToLocation(IAccessible* acc, LONG childId)\r\n{\r\n    RECT rcObject;\r\n    if (GetAccessibleBounds(acc, childId, &amp;rcObject)) {\r\n        RECT rcParent;\r\n        if (childId != CHILDID_SELF) {\r\n            if (GetAccessibleBounds(acc, CHILDID_SELF, &amp;rcParent)) {\r\n                IntersectRect(&amp;rcObject, &amp;rcObject, &amp;rcParent);\r\n            }\r\n        } else {\r\n            wil::com_ptr_nothrow&lt;IDispatch&gt; dispParent;\r\n            if (acc-&gt;get_accParent(dispParent.put()) == S_OK &amp;&amp;\r\n                dispParent) {\r\n                auto accParent = dispParent.try_query&lt;IAccessible&gt;();\r\n                if (accParent &amp;&amp;\r\n                    GetAccessibleBounds(accParent.get(), CHILDID_SELF,\r\n                                        &amp;rcParent)) {\r\n                    IntersectRect(&amp;rcObject, &amp;rcObject, &amp;rcParent);\r\n                }\r\n            }\r\n        }\r\n        SetCursorPos(rcObject.right - 1, rcObject.bottom - 1);\r\n        return true;\r\n    }\r\n    return false;\r\n}\r\n<\/pre>\n<p>After getting the accessible bounds of the target, we also get the bounds of its parent. There are two ways to find the parent.<\/p>\n<ul>\n<li>If the <code>childId<\/code> is not <code>CHILDID_SELF<\/code>, then we are the parent element of the target, so we can ask for the accessible bounds of ourselves.<\/li>\n<li>Otherwise, we are the target, so we cann <code>get_accParent<\/code> to get our parent, and then get the bounds of that parent.<\/li>\n<\/ul>\n<p>In either case, if the bounds were obtained successfully, then we intersect the target&#8217;s bounding rectangle with the parent&#8217;s bounding rectangle, and then position the cursor at the bottom right corner.<\/p>\n<p>We got rid of the <code>hwndClip<\/code> parameter, so we can remove it from the call sites, returning the code to the version before we added the clip window.<\/p>\n<p>I found that this didn&#8217;t always succeed in clipping the item to the parent. For example, if you highlight a clipped item in File Explorer in Tiles view, the cursor still moves to the invisible bottom right corner of the unclipped tile.<\/p>\n<p>We&#8217;ll investigate this next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Finding the correct clipping parent.<\/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-111984","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Finding the correct clipping parent.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111984","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=111984"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111984\/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=111984"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111984"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111984"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}