From: Connor McAdams conmanx360@gmail.com
Check for window focus against the current foreground window's thread GUI data rather than the currently executing thread's GUI data.
Signed-off-by: Connor McAdams conmanx360@gmail.com ---
-v4: Switch from checking the GUI thread data of the HWND we're checking to the foreground window's GUI thread data. dlls/oleacc/client.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/dlls/oleacc/client.c b/dlls/oleacc/client.c index 3b33be55a21..0c2215fe62e 100644 --- a/dlls/oleacc/client.c +++ b/dlls/oleacc/client.c @@ -227,6 +227,7 @@ static HRESULT WINAPI Client_get_accRole(IAccessible *iface, VARIANT varID, VARI static HRESULT WINAPI Client_get_accState(IAccessible *iface, VARIANT varID, VARIANT *pvarState) { Client *This = impl_from_Client(iface); + GUITHREADINFO info; LONG style;
TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pvarState); @@ -244,7 +245,9 @@ static HRESULT WINAPI Client_get_accState(IAccessible *iface, VARIANT varID, VAR V_I4(pvarState) |= STATE_SYSTEM_UNAVAILABLE; else if(IsWindow(This->hwnd)) V_I4(pvarState) |= STATE_SYSTEM_FOCUSABLE; - if(GetFocus() == This->hwnd) + + info.cbSize = sizeof(info); + if(GetGUIThreadInfo(0, &info) && info.hwndFocus == This->hwnd) V_I4(pvarState) |= STATE_SYSTEM_FOCUSED; if(!(style & WS_VISIBLE)) V_I4(pvarState) |= STATE_SYSTEM_INVISIBLE;
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/tests/main.c | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+)
diff --git a/dlls/oleacc/tests/main.c b/dlls/oleacc/tests/main.c index ce44e06abe4..0419b862459 100644 --- a/dlls/oleacc/tests/main.c +++ b/dlls/oleacc/tests/main.c @@ -729,6 +729,36 @@ static void test_AccessibleChildren(IAccessible *acc) ok(V_VT(children+2) == VT_EMPTY, "V_VT(children+2) = %d\n", V_VT(children+2)); }
+static void check_accessible_state(IAccessible *acc, INT state_flags, BOOL todo) +{ + VARIANT vid, v; + HRESULT hr; + + V_VT(&vid) = VT_I4; + V_I4(&vid) = CHILDID_SELF; + hr = IAccessible_get_accState(acc, vid, &v); + ok(hr == S_OK, "got %x\n", hr); + ok(V_VT(&v) == VT_I4, "V_VT(&v) = %d\n", V_VT(&v)); + if (todo) + todo_wine ok(V_I4(&v) == state_flags, "V_I4(&v) = %x\n", V_I4(&v)); + else + ok(V_I4(&v) == state_flags, "V_I4(&v) = %x\n", V_I4(&v)); +} + +static DWORD WINAPI acc_focus_test_invisible_thread(LPVOID param) +{ + check_accessible_state((IAccessible *)param, STATE_SYSTEM_FOCUSABLE | + STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_FOCUSED, TRUE); + return 0; +} + +static DWORD WINAPI acc_focus_test_visible_thread(LPVOID param) +{ + check_accessible_state((IAccessible *)param, STATE_SYSTEM_FOCUSABLE | + STATE_SYSTEM_FOCUSED, FALSE); + return 0; +} + static void test_default_client_accessible_object(void) { IAccessible *acc; @@ -743,6 +773,7 @@ static void test_default_client_accessible_object(void) RECT rect; LONG l, left, top, width, height; ULONG fetched; + HANDLE hthread;
hwnd = CreateWindowA("oleacc_test", "wnd &t &junk", WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, NULL, NULL); @@ -901,6 +932,40 @@ static void test_default_client_accessible_object(void) ok(V_I4(&v) == (STATE_SYSTEM_FOCUSABLE|STATE_SYSTEM_INVISIBLE), "V_I4(&v) = %x\n", V_I4(&v));
+ /* + * Currently, Wine's SetForegroundWindow behavior doesn't match Windows, + * so calling SetFocus on an invisible HWND doesn't set it as the + * foreground window. Until this is fixed, our STATE_SYSTEM_FOCUSED + * behavior will be broken. + */ + SetFocus(hwnd); + hr = IAccessible_get_accState(acc, vid, &v); + ok(hr == S_OK, "got %x\n", hr); + ok(V_VT(&v) == VT_I4, "V_VT(&v) = %d\n", V_VT(&v)); + todo_wine ok(V_I4(&v) == (STATE_SYSTEM_FOCUSABLE|STATE_SYSTEM_INVISIBLE|STATE_SYSTEM_FOCUSED), + "V_I4(&v) = %x\n", V_I4(&v)); + + /* + * Show that STATE_SYSTEM_FOCUSED is set properly even when queried in a + * thread separate from the provided HWND's GUI thread. + */ + hthread = CreateThread(NULL, 0, acc_focus_test_invisible_thread, (void *)acc, 0, NULL); + ok(!WaitForSingleObject(hthread, 10000), "Focus thread failed to return!\n"); + CloseHandle(hthread); + + ShowWindow(hwnd, SW_SHOW); + SetFocus(hwnd); + hr = IAccessible_get_accState(acc, vid, &v); + ok(hr == S_OK, "got %x\n", hr); + ok(V_VT(&v) == VT_I4, "V_VT(&v) = %d\n", V_VT(&v)); + ok(V_I4(&v) == (STATE_SYSTEM_FOCUSABLE|STATE_SYSTEM_FOCUSED), + "V_I4(&v) = %x\n", V_I4(&v)); + + hthread = CreateThread(NULL, 0, acc_focus_test_visible_thread, (void *)acc, 0, NULL); + ok(!WaitForSingleObject(hthread, 10000), "Focus thread failed to return!\n"); + CloseHandle(hthread); + ShowWindow(hwnd, SW_HIDE); + str = (void*)0xdeadbeef; hr = IAccessible_get_accHelp(acc, vid, &str); ok(hr == S_FALSE, "got %x\n", hr);