// Unmanaged DLL calls back on this to notify a UIAccess client of an event. internal void OnEvent(IntPtr argsAddr, object[,] requestedData, string treeStructure) { AutomationEventArgs e = UiaCoreApi.GetUiaEventArgs(argsAddr); if (e.EventId == AutomationElement.AutomationFocusChangedEvent) { uint eventTime = SafeNativeMethods.GetTickCount(); if (eventTime == 0) // 0 is used as a marker value, so bump up to 1 if we get it. eventTime = 1; // There's no FocusChangedEventArgs in core, but clients expect one, so substitute if needed... // (otherwise the cast in InvokeHandlers will fail...) e = new InternalAutomationFocusChangedEventArgs(0, 0, eventTime); } UiaCoreApi.UiaCacheResponse cacheResponse = new UiaCoreApi.UiaCacheResponse(requestedData, treeStructure, _eventListener.CacheRequest); // Invoke the listener's callback but not on this thread. Queuing this onto a worker thread allows // OnEvent to return (which allows the call on the server-side to complete) and avoids a deadlock // situation when the client accesses properties on the source element. ClientEventManager.CBQ.PostWorkItem(new CalloutQueueItem(_clientCallback, cacheResponse, e, _eventListener.CacheRequest)); }
// Unmanaged DLL calls back on this to notify a UIAccess client of an event. internal void OnEvent(IntPtr argsAddr, object[,] requestedData, string treeStructure) { AutomationEventArgs e = UiaCoreApi.GetUiaEventArgs(argsAddr); if (e.EventId == AutomationElement.AutomationFocusChangedEvent) { uint eventTime = SafeNativeMethods.GetTickCount(); if (eventTime == 0) // 0 is used as a marker value, so bump up to 1 if we get it. { eventTime = 1; } // There's no FocusChangedEventArgs in core, but clients expect one, so substitute if needed... // (otherwise the cast in InvokeHandlers will fail...) e = new InternalAutomationFocusChangedEventArgs(0, 0, eventTime); } UiaCoreApi.UiaCacheResponse cacheResponse = new UiaCoreApi.UiaCacheResponse(requestedData, treeStructure, _eventListener.CacheRequest); // Invoke the listener's callback but not on this thread. Queuing this onto a worker thread allows // OnEvent to return (which allows the call on the server-side to complete) and avoids a deadlock // situation when the client accesses properties on the source element. ClientEventManager.CBQ.PostWorkItem(new CalloutQueueItem(_clientCallback, cacheResponse, e, _eventListener.CacheRequest)); }
//------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods // HandleFocusChange - Called when a WinEvent we're listening to indicates the // focus has changed. This is where the callback to the client is queued. private void HandleFocusChange(IntPtr hwnd, Accessible acc, int idObject, int idChild, uint eventTime) { // If there is an hwnd then notify of a focus change if (hwnd != IntPtr.Zero) { Debug.Assert(acc != null, "HandleFocusChange got hwnd and null IAccessible"); // Create an event args and get the source logical element AutomationFocusChangedEventArgs e = new InternalAutomationFocusChangedEventArgs(idObject, idChild, eventTime); AutomationElement srcEl = GetFocusedElementFromWinEvent(hwnd, idObject, idChild); if (srcEl == null) { // Don't raise focus change events for UI that is gone. This has been seen when toolbar menus are // being manipulated (e.g. mnu.SubMenu("File").MenuItems("Close").Click() in MITA). We should be // seeing another focus change soon and with that event we can re-establish focus. return; } // Check that item is actually focused // Don't do this for statics - the controls in the color picker are statics, and // they get focus, but OLEACC assumes statics don't get focus, so never sets the // focus bit. So, for now, assume statics that send focus do actually have focus. if (!Accessible.IsStatic(hwnd) && !Accessible.IsComboDropdown(hwnd)) { // instead of depending on oleacc to see if something has focus ask provider if (!(bool)srcEl.GetCurrentPropertyValue(AutomationElement.HasKeyboardFocusProperty)) { return; } } // Do notifies ClientEventManager.RaiseEventInThisClientOnly(AutomationElement.AutomationFocusChangedEvent, srcEl, e); } // Keep track of where we are right now (may be unknown/null) _accCurrent = acc; }