Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/client.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/dlls/oleacc/client.c b/dlls/oleacc/client.c index 0c2215fe62e..4c6dc0ab18b 100644 --- a/dlls/oleacc/client.c +++ b/dlls/oleacc/client.c @@ -306,8 +306,26 @@ static HRESULT WINAPI Client_get_accKeyboardShortcut(IAccessible *iface, static HRESULT WINAPI Client_get_accFocus(IAccessible *iface, VARIANT *pvarID) { Client *This = impl_from_Client(iface); - FIXME("(%p)->(%p)\n", This, pvarID); - return E_NOTIMPL; + GUITHREADINFO info; + + TRACE("(%p)->(%p)\n", This, pvarID); + + V_VT(pvarID) = VT_EMPTY; + info.cbSize = sizeof(info); + if(GetGUIThreadInfo(0, &info) && info.hwndFocus) { + if(info.hwndFocus == This->hwnd) { + V_VT(pvarID) = VT_I4; + V_I4(pvarID) = CHILDID_SELF; + } + else if(IsChild(This->hwnd, info.hwndFocus)) { + V_VT(pvarID) = VT_DISPATCH; + if(FAILED(AccessibleObjectFromWindow(info.hwndFocus, OBJID_WINDOW, + &IID_IDispatch, (void**)&V_DISPATCH(pvarID)))) + V_VT(pvarID) = VT_EMPTY; + } + } + + return S_OK; }
static HRESULT WINAPI Client_get_accSelection(IAccessible *iface, VARIANT *pvarID)
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/tests/main.c | 47 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-)
diff --git a/dlls/oleacc/tests/main.c b/dlls/oleacc/tests/main.c index 97fc625ac8b..86abe17b2a5 100644 --- a/dlls/oleacc/tests/main.c +++ b/dlls/oleacc/tests/main.c @@ -920,7 +920,7 @@ static void test_default_client_accessible_object(void) IDispatch *disp; IOleWindow *ow; IEnumVARIANT *ev; - HWND chld, btn, hwnd, hwnd2; + HWND chld, chld2, btn, hwnd, hwnd2; HRESULT hr; VARIANT vid, v; BSTR str; @@ -939,6 +939,9 @@ static void test_default_client_accessible_object(void) btn = CreateWindowA("BUTTON", "btn &t &junk", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 50, 0, 50, 50, hwnd, NULL, NULL, NULL); ok(btn != NULL, "CreateWindow failed\n"); + chld2 = CreateWindowA("static", "static &t &junk", WS_CHILD | WS_VISIBLE, + 0, 0, 50, 50, chld, NULL, NULL, NULL); + ok(chld != NULL, "CreateWindow failed\n");
hr = CreateStdAccessibleObject(NULL, OBJID_CLIENT, &IID_IAccessible, (void**)&acc); ok(hr == E_FAIL, "got %x\n", hr); @@ -1013,6 +1016,44 @@ static void test_default_client_accessible_object(void) ok(hr == E_INVALIDARG, "get_accChild returned %x\n", hr); ok(disp == NULL, "disp = %p\n", disp);
+ /* Neither the parent nor any child windows have focus, VT_EMPTY. */ + hr = IAccessible_get_accFocus(acc, &v); + ok(hr == S_OK, "hr %#x\n", hr); + ok(V_VT(&v) == VT_EMPTY, "V_VT(&v) = %d\n", V_VT(&v)); + + /* Set the focus to the parent window. */ + ShowWindow(hwnd, SW_SHOW); + SetFocus(hwnd); + hr = IAccessible_get_accFocus(acc, &v); + ok(hr == S_OK, "hr %#x\n", hr); + ok(V_VT(&v) == VT_I4, "V_VT(&v) = %d\n", V_VT(&v)); + ok(V_I4(&v) == CHILDID_SELF, "V_I4(&v) = %d\n", V_I4(&v)); + + /* Set focus to each child window. */ + SetFocus(btn); + hr = IAccessible_get_accFocus(acc, &v); + ok(hr == S_OK, "hr %#x\n", hr); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(&v) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(&v) = %p\n", V_DISPATCH(&v)); + if (!!V_DISPATCH(&v)) IDispatch_Release(V_DISPATCH(&v)); + + SetFocus(chld); + hr = IAccessible_get_accFocus(acc, &v); + ok(hr == S_OK, "hr %#x\n", hr); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(&v) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(&v) = %p\n", V_DISPATCH(&v)); + if (!!V_DISPATCH(&v)) IDispatch_Release(V_DISPATCH(&v)); + + /* Child of a child, still works on parent HWND. */ + SetFocus(chld2); + hr = IAccessible_get_accFocus(acc, &v); + ok(hr == S_OK, "hr %#x\n", hr); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(&v) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(&v) = %p\n", V_DISPATCH(&v)); + if (!!V_DISPATCH(&v)) IDispatch_Release(V_DISPATCH(&v)); + + ShowWindow(hwnd, SW_HIDE); + hr = IAccessible_QueryInterface(acc, &IID_IEnumVARIANT, (void**)&ev); ok(hr == S_OK, "got %x\n", hr);
@@ -1195,6 +1236,10 @@ static void test_default_client_accessible_object(void) ok(V_VT(&v) == VT_I4, "V_VT(&v) = %d\n", V_VT(&v)); ok(V_I4(&v) == STATE_SYSTEM_INVISIBLE, "V_I4(&v) = %x\n", V_I4(&v));
+ hr = IAccessible_get_accFocus(acc, &v); + ok(hr == S_OK, "hr %#x\n", hr); + ok(V_VT(&v) == VT_EMPTY, "V_VT(&v) = %d\n", V_VT(&v)); + hr = IAccessible_accHitTest(acc, 200, 200, &v); ok(hr == S_OK, "got %x\n", hr); ok(V_VT(&v) == VT_I4, "V_VT(&v) = %d\n", V_VT(&v));
On 9/17/21 6:37 PM, Connor McAdams wrote:
@@ -939,6 +939,9 @@ static void test_default_client_accessible_object(void) btn = CreateWindowA("BUTTON", "btn &t &junk", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 50, 0, 50, 50, hwnd, NULL, NULL, NULL); ok(btn != NULL, "CreateWindow failed\n");
- chld2 = CreateWindowA("static", "static &t &junk", WS_CHILD | WS_VISIBLE,
0, 0, 50, 50, chld, NULL, NULL, NULL);
- ok(chld != NULL, "CreateWindow failed\n");
typo: chld2
- /* Set focus to each child window. */
- SetFocus(btn);
- hr = IAccessible_get_accFocus(acc, &v);
- ok(hr == S_OK, "hr %#x\n", hr);
- ok(V_VT(&v) == VT_DISPATCH, "V_VT(&v) = %d\n", V_VT(&v));
- ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(&v) = %p\n", V_DISPATCH(&v));
- if (!!V_DISPATCH(&v)) IDispatch_Release(V_DISPATCH(&v));
There's no need to check if V_DISPATCH(&v) != NULL. It's already done by earlier ok call.
This test is also not checking what is actually returned. I don't know if it's important in this case but you can get the hwnd from dispatch (query for IOleWindow and call IOleWindow_GetWindow) and compare it with btn.
Thanks, Piotr
Hi Connor,
On 9/17/21 6:37 PM, Connor McAdams wrote:
@@ -306,8 +306,26 @@ static HRESULT WINAPI Client_get_accKeyboardShortcut(IAccessible *iface, static HRESULT WINAPI Client_get_accFocus(IAccessible *iface, VARIANT *pvarID) { Client *This = impl_from_Client(iface);
- FIXME("(%p)->(%p)\n", This, pvarID);
- return E_NOTIMPL;
- GUITHREADINFO info;
- TRACE("(%p)->(%p)\n", This, pvarID);
- V_VT(pvarID) = VT_EMPTY;
- info.cbSize = sizeof(info);
- if(GetGUIThreadInfo(0, &info) && info.hwndFocus) {
if(info.hwndFocus == This->hwnd) {
V_VT(pvarID) = VT_I4;
V_I4(pvarID) = CHILDID_SELF;
}
else if(IsChild(This->hwnd, info.hwndFocus)) {
V_VT(pvarID) = VT_DISPATCH;
if(FAILED(AccessibleObjectFromWindow(info.hwndFocus, OBJID_WINDOW,
&IID_IDispatch, (void**)&V_DISPATCH(pvarID))))
V_VT(pvarID) = VT_EMPTY;
The child case seems to be not right. You should propagate error from AccessibleObjectFromWindow and check if returned interface pointer is not NULL. It should probably look like this: hr = AccessibleObjectFromWindow(info.hwndFocus, OBJID_WINDOW, &IID_IDispatch, (void**)&disp); if (FAILED(hr)) return hr; if (!disp) return E_FAIL;
V_VT(pvarID) = VT_DISPATCH; V_DISPATCH(pvarID) = disp;
It would be also nice to rename the pvarID argument to e.g. focus.
Thanks, Piotr