Last time, we clipped the focus item to the containing window so that we considered only the visible portion of the item. But we found that some programs use a dummy 0×0 window as their window for system focus, while visual focus remains elsewhere. How can we clip the focus item to the correct bounds?
It took a little thinking, but I realized that I can clip to the accessible parent of the focus item.
So first, a little more refactoring.
bool GetAccessibleBounds(IAccessible* acc, LONG childId, RECT* rc)
{
VARIANT vt;
vt.vt = VT_I4;
vt.lVal = childId;
if (acc->accLocation(&rc->left, &rc->top,
&rc->right, &rc->bottom, vt) == S_OK) {
rc->right += rc->left;
rc->bottom += rc->top;
return true;
} else {
*rc = {};
return false;
}
}
This obtains the bounds of an accessible item in the form of a RECT. We can now use the rectangle manipulation functions to intersect the object’s bounds with the bounds of its parent.
bool SetCursorPosToLocation(IAccessible* acc, LONG childId)
{
RECT rcObject;
if (GetAccessibleBounds(acc, childId, &rcObject)) {
RECT rcParent;
if (childId != CHILDID_SELF) {
if (GetAccessibleBounds(acc, CHILDID_SELF, &rcParent)) {
IntersectRect(&rcObject, &rcObject, &rcParent);
}
} else {
wil::com_ptr_nothrow<IDispatch> dispParent;
if (acc->get_accParent(dispParent.put()) == S_OK &&
dispParent) {
auto accParent = dispParent.try_query<IAccessible>();
if (accParent &&
GetAccessibleBounds(accParent.get(), CHILDID_SELF,
&rcParent)) {
IntersectRect(&rcObject, &rcObject, &rcParent);
}
}
}
SetCursorPos(rcObject.right - 1, rcObject.bottom - 1);
return true;
}
return false;
}
After getting the accessible bounds of the target, we also get the bounds of its parent. There are two ways to find the parent.
- If the
childIdis notCHILDID_SELF, then we are the parent element of the target, so we can ask for the accessible bounds of ourselves. - Otherwise, we are the target, so we cann
get_accParentto get our parent, and then get the bounds of that parent.
In either case, if the bounds were obtained successfully, then we intersect the target’s bounding rectangle with the parent’s bounding rectangle, and then position the cursor at the bottom right corner.
We got rid of the hwndClip parameter, so we can remove it from the call sites, returning the code to the version before we added the clip window.
I found that this didn’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.
We’ll investigate this next time.
> I found that this didn’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.
I imagine in that situation, assuming that item can fit into the parent, user would want parent window to scroll to position where that item is not clipped, as the goal of moving mouse cursor to something is usually to interact with that something.