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;
|
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.
|
* UI Automation event map.
|
||||||
*/
|
*/
|
||||||
|
@ -247,6 +261,7 @@ struct uia_event_thread
|
||||||
LONG ref;
|
LONG ref;
|
||||||
|
|
||||||
struct list *event_queue;
|
struct list *event_queue;
|
||||||
|
HWINEVENTHOOK hook;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define WM_UIA_EVENT_THREAD_STOP (WM_USER + 1)
|
#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 {
|
enum uia_queue_event_type {
|
||||||
QUEUE_EVENT_TYPE_SERVERSIDE,
|
QUEUE_EVENT_TYPE_SERVERSIDE,
|
||||||
QUEUE_EVENT_TYPE_CLIENTSIDE,
|
QUEUE_EVENT_TYPE_CLIENTSIDE,
|
||||||
|
QUEUE_EVENT_TYPE_WIN_EVENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uia_queue_event
|
struct uia_queue_event
|
||||||
{
|
{
|
||||||
struct list event_queue_entry;
|
struct list event_queue_entry;
|
||||||
int queue_event_type;
|
int queue_event_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uia_queue_uia_event
|
||||||
|
{
|
||||||
|
struct uia_queue_event queue_entry;
|
||||||
|
|
||||||
struct uia_event_args *args;
|
struct uia_event_args *args;
|
||||||
struct uia_event *event;
|
struct uia_event *event;
|
||||||
|
@ -285,14 +306,40 @@ struct uia_queue_event
|
||||||
} u;
|
} 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);
|
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);
|
assert(event_thread.event_queue);
|
||||||
list_add_tail(event_thread.event_queue, &event->event_queue_entry);
|
list_add_tail(event_thread.event_queue, &event->event_queue_entry);
|
||||||
PostMessageW(event_thread.hwnd, WM_UIA_EVENT_THREAD_PROCESS_QUEUE, 0, 0);
|
PostMessageW(event_thread.hwnd, WM_UIA_EVENT_THREAD_PROCESS_QUEUE, 0, 0);
|
||||||
|
|
||||||
|
exit:
|
||||||
LeaveCriticalSection(&event_thread_cs);
|
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,
|
static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct uia_event_args *args,
|
||||||
struct uia_event *event);
|
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;
|
HUIANODE node, nav_start_node;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -354,7 +401,7 @@ static HRESULT uia_raise_clientside_event(struct uia_queue_event *event)
|
||||||
return hr;
|
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;
|
HRESULT hr = S_OK;
|
||||||
LRESULT lr, lr2;
|
LRESULT lr, lr2;
|
||||||
|
@ -397,29 +444,70 @@ static void uia_event_thread_process_queue(struct list *event_queue)
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
struct uia_queue_event *event;
|
struct uia_queue_event *event;
|
||||||
HRESULT hr;
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
if (!(event = uia_event_queue_pop(event_queue)))
|
if (!(event = uia_event_queue_pop(event_queue)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (event->queue_event_type == QUEUE_EVENT_TYPE_SERVERSIDE)
|
switch (event->queue_event_type)
|
||||||
hr = uia_raise_serverside_event(event);
|
{
|
||||||
else
|
case QUEUE_EVENT_TYPE_SERVERSIDE:
|
||||||
hr = uia_raise_clientside_event(event);
|
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))
|
if (FAILED(hr))
|
||||||
WARN("Failed to raise event type %d with hr %#lx\n", event->queue_event_type, 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);
|
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)
|
static DWORD WINAPI uia_event_thread_proc(void *arg)
|
||||||
{
|
{
|
||||||
HANDLE initialized_event = arg;
|
HANDLE initialized_event = arg;
|
||||||
struct list event_queue;
|
struct list event_queue;
|
||||||
|
HWINEVENTHOOK hook;
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
MSG msg;
|
MSG msg;
|
||||||
|
|
||||||
|
@ -435,6 +523,8 @@ static DWORD WINAPI uia_event_thread_proc(void *arg)
|
||||||
|
|
||||||
event_thread.hwnd = hwnd;
|
event_thread.hwnd = hwnd;
|
||||||
event_thread.event_queue = &event_queue;
|
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. */
|
/* Initialization complete, thread can now process window messages. */
|
||||||
SetEvent(initialized_event);
|
SetEvent(initialized_event);
|
||||||
|
@ -455,6 +545,7 @@ static DWORD WINAPI uia_event_thread_proc(void *arg)
|
||||||
|
|
||||||
TRACE("Shutting down UI Automation event thread.\n");
|
TRACE("Shutting down UI Automation event thread.\n");
|
||||||
|
|
||||||
|
UnhookWinEvent(hook);
|
||||||
DestroyWindow(hwnd);
|
DestroyWindow(hwnd);
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
FreeLibraryAndExitThread(huia_module, 0);
|
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)
|
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_event *event = impl_from_IWineUiaEvent(iface);
|
||||||
struct uia_queue_event *queue_event;
|
struct uia_queue_uia_event *queue_event;
|
||||||
struct uia_event_args *args;
|
struct uia_event_args *args;
|
||||||
|
|
||||||
TRACE("%p, %s, %s\n", iface, debugstr_variant(&in_node), debugstr_variant(&in_nav_start_node));
|
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;
|
return E_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_event->queue_event_type = QUEUE_EVENT_TYPE_CLIENTSIDE;
|
|
||||||
queue_event->args = args;
|
queue_event->args = args;
|
||||||
queue_event->event = event;
|
queue_event->event = event;
|
||||||
queue_event->u.clientside.node = V_I4(&in_node);
|
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);
|
queue_event->u.clientside.nav_start_node = V_I4(&in_nav_start_node);
|
||||||
|
|
||||||
IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface);
|
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;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -1277,7 +1367,7 @@ static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct u
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct uia_queue_event *queue_event;
|
struct uia_queue_uia_event *queue_event;
|
||||||
HUIANODE node2, nav_start_node2;
|
HUIANODE node2, nav_start_node2;
|
||||||
|
|
||||||
if (!(queue_event = calloc(1, sizeof(*queue_event))))
|
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->args = args;
|
||||||
queue_event->event = event;
|
queue_event->event = event;
|
||||||
queue_event->u.serverside.node = node2;
|
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);
|
InterlockedIncrement(&args->ref);
|
||||||
IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface);
|
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;
|
return hr;
|
||||||
|
|
Loading…
Add table
Reference in a new issue