uiautomationcore: Add WinEvent hook on the UIA event thread.
Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
parent
336503f3c9
commit
2a2c4cd7b9
1 changed files with 105 additions and 16 deletions
|
@ -50,6 +50,20 @@ static SAFEARRAY *uia_get_desktop_rt_id(void)
|
|||
return uia_desktop_node_rt_id;
|
||||
}
|
||||
|
||||
static int win_event_to_uia_event_id(int win_event)
|
||||
{
|
||||
switch (win_event)
|
||||
{
|
||||
case EVENT_OBJECT_FOCUS: return UIA_AutomationFocusChangedEventId;
|
||||
case EVENT_SYSTEM_ALERT: return UIA_SystemAlertEventId;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* UI Automation event map.
|
||||
*/
|
||||
|
@ -247,6 +261,7 @@ struct uia_event_thread
|
|||
LONG ref;
|
||||
|
||||
struct list *event_queue;
|
||||
HWINEVENTHOOK hook;
|
||||
};
|
||||
|
||||
#define WM_UIA_EVENT_THREAD_STOP (WM_USER + 1)
|
||||
|
@ -264,12 +279,18 @@ static CRITICAL_SECTION event_thread_cs = { &event_thread_cs_debug, -1, 0, 0, 0,
|
|||
enum uia_queue_event_type {
|
||||
QUEUE_EVENT_TYPE_SERVERSIDE,
|
||||
QUEUE_EVENT_TYPE_CLIENTSIDE,
|
||||
QUEUE_EVENT_TYPE_WIN_EVENT,
|
||||
};
|
||||
|
||||
struct uia_queue_event
|
||||
{
|
||||
struct list event_queue_entry;
|
||||
int queue_event_type;
|
||||
};
|
||||
|
||||
struct uia_queue_uia_event
|
||||
{
|
||||
struct uia_queue_event queue_entry;
|
||||
|
||||
struct uia_event_args *args;
|
||||
struct uia_event *event;
|
||||
|
@ -285,14 +306,40 @@ struct uia_queue_event
|
|||
} u;
|
||||
};
|
||||
|
||||
static void uia_event_queue_push(struct uia_queue_event *event)
|
||||
struct uia_queue_win_event
|
||||
{
|
||||
struct uia_queue_event queue_entry;
|
||||
|
||||
HWINEVENTHOOK hook;
|
||||
DWORD event_id;
|
||||
HWND hwnd;
|
||||
LONG obj_id;
|
||||
LONG child_id;
|
||||
DWORD thread_id;
|
||||
DWORD event_time;
|
||||
};
|
||||
|
||||
static void uia_event_queue_push(struct uia_queue_event *event, int queue_event_type)
|
||||
{
|
||||
event->queue_event_type = queue_event_type;
|
||||
EnterCriticalSection(&event_thread_cs);
|
||||
|
||||
if (queue_event_type == QUEUE_EVENT_TYPE_WIN_EVENT)
|
||||
{
|
||||
struct uia_queue_win_event *win_event = (struct uia_queue_win_event *)event;
|
||||
|
||||
if (win_event->hook != event_thread.hook)
|
||||
{
|
||||
free(event);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
assert(event_thread.event_queue);
|
||||
list_add_tail(event_thread.event_queue, &event->event_queue_entry);
|
||||
PostMessageW(event_thread.hwnd, WM_UIA_EVENT_THREAD_PROCESS_QUEUE, 0, 0);
|
||||
|
||||
exit:
|
||||
LeaveCriticalSection(&event_thread_cs);
|
||||
}
|
||||
|
||||
|
@ -322,7 +369,7 @@ static void uia_node_lresult_release(LRESULT lr)
|
|||
|
||||
static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct uia_event_args *args,
|
||||
struct uia_event *event);
|
||||
static HRESULT uia_raise_clientside_event(struct uia_queue_event *event)
|
||||
static HRESULT uia_raise_clientside_event(struct uia_queue_uia_event *event)
|
||||
{
|
||||
HUIANODE node, nav_start_node;
|
||||
HRESULT hr;
|
||||
|
@ -354,7 +401,7 @@ static HRESULT uia_raise_clientside_event(struct uia_queue_event *event)
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT uia_raise_serverside_event(struct uia_queue_event *event)
|
||||
static HRESULT uia_raise_serverside_event(struct uia_queue_uia_event *event)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
LRESULT lr, lr2;
|
||||
|
@ -397,29 +444,70 @@ static void uia_event_thread_process_queue(struct list *event_queue)
|
|||
while (1)
|
||||
{
|
||||
struct uia_queue_event *event;
|
||||
HRESULT hr;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (!(event = uia_event_queue_pop(event_queue)))
|
||||
break;
|
||||
|
||||
if (event->queue_event_type == QUEUE_EVENT_TYPE_SERVERSIDE)
|
||||
hr = uia_raise_serverside_event(event);
|
||||
else
|
||||
hr = uia_raise_clientside_event(event);
|
||||
switch (event->queue_event_type)
|
||||
{
|
||||
case QUEUE_EVENT_TYPE_SERVERSIDE:
|
||||
case QUEUE_EVENT_TYPE_CLIENTSIDE:
|
||||
{
|
||||
struct uia_queue_uia_event *uia_event = (struct uia_queue_uia_event *)event;
|
||||
|
||||
if (event->queue_event_type == QUEUE_EVENT_TYPE_SERVERSIDE)
|
||||
hr = uia_raise_serverside_event(uia_event);
|
||||
else
|
||||
hr = uia_raise_clientside_event(uia_event);
|
||||
|
||||
uia_event_args_release(uia_event->args);
|
||||
IWineUiaEvent_Release(&uia_event->event->IWineUiaEvent_iface);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
WARN("Failed to raise event type %d with hr %#lx\n", event->queue_event_type, hr);
|
||||
|
||||
uia_event_args_release(event->args);
|
||||
IWineUiaEvent_Release(&event->event->IWineUiaEvent_iface);
|
||||
free(event);
|
||||
}
|
||||
}
|
||||
|
||||
static void CALLBACK uia_event_thread_win_event_proc(HWINEVENTHOOK hook, DWORD event_id, HWND hwnd, LONG obj_id,
|
||||
LONG child_id, DWORD thread_id, DWORD event_time)
|
||||
{
|
||||
struct uia_queue_win_event *win_event;
|
||||
|
||||
TRACE("%p, %ld, %p, %ld, %ld, %ld, %ld\n", hook, event_id, hwnd, obj_id, child_id, thread_id, event_time);
|
||||
|
||||
if (!win_event_to_uia_event_id(event_id))
|
||||
return;
|
||||
|
||||
if (!(win_event = calloc(1, sizeof(*win_event))))
|
||||
{
|
||||
ERR("Failed to allocate uia_queue_win_event structure\n");
|
||||
return;
|
||||
}
|
||||
|
||||
win_event->hook = hook;
|
||||
win_event->event_id = event_id;
|
||||
win_event->hwnd = hwnd;
|
||||
win_event->obj_id = obj_id;
|
||||
win_event->child_id = child_id;
|
||||
win_event->thread_id = thread_id;
|
||||
win_event->event_time = event_time;
|
||||
uia_event_queue_push(&win_event->queue_entry, QUEUE_EVENT_TYPE_WIN_EVENT);
|
||||
}
|
||||
|
||||
static DWORD WINAPI uia_event_thread_proc(void *arg)
|
||||
{
|
||||
HANDLE initialized_event = arg;
|
||||
struct list event_queue;
|
||||
HWINEVENTHOOK hook;
|
||||
HWND hwnd;
|
||||
MSG msg;
|
||||
|
||||
|
@ -435,6 +523,8 @@ static DWORD WINAPI uia_event_thread_proc(void *arg)
|
|||
|
||||
event_thread.hwnd = hwnd;
|
||||
event_thread.event_queue = &event_queue;
|
||||
event_thread.hook = hook = SetWinEventHook(EVENT_MIN, EVENT_MAX, 0, uia_event_thread_win_event_proc, 0, 0,
|
||||
WINEVENT_OUTOFCONTEXT);
|
||||
|
||||
/* Initialization complete, thread can now process window messages. */
|
||||
SetEvent(initialized_event);
|
||||
|
@ -455,6 +545,7 @@ static DWORD WINAPI uia_event_thread_proc(void *arg)
|
|||
|
||||
TRACE("Shutting down UI Automation event thread.\n");
|
||||
|
||||
UnhookWinEvent(hook);
|
||||
DestroyWindow(hwnd);
|
||||
CoUninitialize();
|
||||
FreeLibraryAndExitThread(huia_module, 0);
|
||||
|
@ -664,7 +755,7 @@ static HRESULT WINAPI uia_event_set_event_data(IWineUiaEvent *iface, const GUID
|
|||
static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_node, VARIANT in_nav_start_node)
|
||||
{
|
||||
struct uia_event *event = impl_from_IWineUiaEvent(iface);
|
||||
struct uia_queue_event *queue_event;
|
||||
struct uia_queue_uia_event *queue_event;
|
||||
struct uia_event_args *args;
|
||||
|
||||
TRACE("%p, %s, %s\n", iface, debugstr_variant(&in_node), debugstr_variant(&in_nav_start_node));
|
||||
|
@ -680,7 +771,6 @@ static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_nod
|
|||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
queue_event->queue_event_type = QUEUE_EVENT_TYPE_CLIENTSIDE;
|
||||
queue_event->args = args;
|
||||
queue_event->event = event;
|
||||
queue_event->u.clientside.node = V_I4(&in_node);
|
||||
|
@ -688,7 +778,7 @@ static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_nod
|
|||
queue_event->u.clientside.nav_start_node = V_I4(&in_nav_start_node);
|
||||
|
||||
IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface);
|
||||
uia_event_queue_push(queue_event);
|
||||
uia_event_queue_push(&queue_event->queue_entry, QUEUE_EVENT_TYPE_CLIENTSIDE);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -1277,7 +1367,7 @@ static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct u
|
|||
}
|
||||
else
|
||||
{
|
||||
struct uia_queue_event *queue_event;
|
||||
struct uia_queue_uia_event *queue_event;
|
||||
HUIANODE node2, nav_start_node2;
|
||||
|
||||
if (!(queue_event = calloc(1, sizeof(*queue_event))))
|
||||
|
@ -1302,7 +1392,6 @@ static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct u
|
|||
}
|
||||
}
|
||||
|
||||
queue_event->queue_event_type = QUEUE_EVENT_TYPE_SERVERSIDE;
|
||||
queue_event->args = args;
|
||||
queue_event->event = event;
|
||||
queue_event->u.serverside.node = node2;
|
||||
|
@ -1310,7 +1399,7 @@ static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct u
|
|||
|
||||
InterlockedIncrement(&args->ref);
|
||||
IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface);
|
||||
uia_event_queue_push(queue_event);
|
||||
uia_event_queue_push(&queue_event->queue_entry, QUEUE_EVENT_TYPE_SERVERSIDE);
|
||||
}
|
||||
|
||||
return hr;
|
||||
|
|
Loading…
Add table
Reference in a new issue