//------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors internal EventListenerClientSide(AutomationElement elRoot, Delegate clientCallback, EventListener l) { _eventListener = l; _refElement = elRoot; // Ensure that RuntimeId is cached on elRoot so that later compares can be done w/o accessing the native element _refRid = elRoot.GetRuntimeId(); _clientCallback = clientCallback; _callbackDelegate = new UiaCoreApi.UiaEventCallback(OnEvent); _gch = GCHandle.Alloc(_callbackDelegate); // }
/// <summary> /// Called by a client to add a listener for focus changed events. /// </summary> /// <param name="eventHandler">Delegate to call when a focus change event occurs.</param> /// /// <outside_see conditional="false"> /// This API does not work inside the secure execution environment. /// <exception cref="System.Security.Permissions.SecurityPermission"/> /// </outside_see> public static void AddAutomationFocusChangedEventHandler( AutomationFocusChangedEventHandler eventHandler ) { Misc.ValidateArgumentNonNull(eventHandler, "eventHandler" ); // Add a client-side listener for for this event request EventListener l = new EventListener(AutomationElement.AutomationFocusChangedEvent, TreeScope.Subtree | TreeScope.Ancestors, null, CacheRequest.CurrentUiaCacheRequest); ClientEventManager.AddFocusListener(eventHandler, l); }
/// <summary> /// Called by a client to add a listener for structure change events. /// </summary> /// <param name="element">Element on which to listen for structure change events.</param> /// <param name="scope">Specifies whether to listen to property changes events on the specified element, and/or its ancestors and children.</param> /// <param name="eventHandler">Delegate to call when a structure change event occurs.</param> /// /// <outside_see conditional="false"> /// This API does not work inside the secure execution environment. /// <exception cref="System.Security.Permissions.SecurityPermission"/> /// </outside_see> public static void AddStructureChangedEventHandler(AutomationElement element, TreeScope scope, StructureChangedEventHandler eventHandler) { Misc.ValidateArgumentNonNull(element, "element"); Misc.ValidateArgumentNonNull(eventHandler, "eventHandler"); // Add a client-side listener for for this event request EventListener l = new EventListener(AutomationElement.StructureChangedEvent, scope, null, CacheRequest.CurrentUiaCacheRequest); ClientEventManager.AddListener(element, eventHandler, l); }
/// <summary> /// Called by a client to add a listener for property changed events. /// </summary> /// <param name="element">Element on which to listen for property changed events.</param> /// <param name="scope">Specifies whether to listen to property changes events on the specified element, and/or its ancestors and children.</param> /// <param name="eventHandler">Callback object to call when a specified property change occurs.</param> /// <param name="properties">Params array of properties to listen for changes in.</param> /// /// <outside_see conditional="false"> /// This API does not work inside the secure execution environment. /// <exception cref="System.Security.Permissions.SecurityPermission"/> /// </outside_see> public static void AddAutomationPropertyChangedEventHandler( AutomationElement element, // reference element for listening to the event TreeScope scope, // scope to listen to AutomationPropertyChangedEventHandler eventHandler, // callback object params AutomationProperty [] properties // listen for changes to these properties ) { Misc.ValidateArgumentNonNull(element, "element" ); Misc.ValidateArgumentNonNull(eventHandler, "eventHandler" ); Misc.ValidateArgumentNonNull(properties, "properties" ); if (properties.Length == 0) { throw new ArgumentException( SR.Get(SRID.AtLeastOnePropertyMustBeSpecified) ); } // Check that no properties are interpreted properties // foreach (AutomationProperty property in properties) { Misc.ValidateArgumentNonNull(property, "properties" ); } // Add a client-side listener for for this event request EventListener l = new EventListener(AutomationElement.AutomationPropertyChangedEvent, scope, properties, CacheRequest.CurrentUiaCacheRequest); ClientEventManager.AddListener(element, eventHandler, l); }
/// <summary> /// Called by a client to add a listener for pattern or custom events. /// </summary> /// <param name="eventId">A control pattern or custom event identifier.</param> /// <param name="element">Element on which to listen for control pattern or custom events.</param> /// <param name="scope">Specifies whether to listen to property changes events on the specified element, and/or its ancestors and children.</param> /// <param name="eventHandler">Delegate to call when the specified event occurs.</param> /// /// <outside_see conditional="false"> /// This API does not work inside the secure execution environment. /// <exception cref="System.Security.Permissions.SecurityPermission"/> /// </outside_see> public static void AddAutomationEventHandler( AutomationEvent eventId, AutomationElement element, TreeScope scope, AutomationEventHandler eventHandler ) { Misc.ValidateArgumentNonNull(element, "element" ); Misc.ValidateArgumentNonNull(eventHandler, "eventHandler" ); Misc.ValidateArgument( eventId != AutomationElement.AutomationFocusChangedEvent, SRID.EventIdMustNotBeAutomationFocusChanged ); Misc.ValidateArgument( eventId != AutomationElement.StructureChangedEvent,SRID.EventIdMustNotBeStructureChanged ); Misc.ValidateArgument( eventId != AutomationElement.AutomationPropertyChangedEvent, SRID.EventIdMustNotBeAutomationPropertyChanged ); if (eventId == WindowPattern.WindowClosedEvent) { // Once a window closes and the hwnd is destroyed we won't be able to determine where it was in the // Automation tree; therefore only support WindowClosed events for all windows (eg. src==root and scope // is descendants) or a specific WindowPattern element (src==root of a Window and scope is the element). // Also handle odd combinations (eg. src==specific element and scope is subtree|ancestors). bool paramsValidated = false; if ( Misc.Compare( element, AutomationElement.RootElement ) ) { // For root element need to have Descendants scope set (Note: Subtree includes Descendants) if ( ( scope & TreeScope.Descendants ) == TreeScope.Descendants ) { paramsValidated = true; } } else { // otherwise non-root elements must have the entire tree (Anscestors, Element and Descendants)... if ( ( scope & ( TreeScope.Ancestors | TreeScope.Element | TreeScope.Descendants ) ) == ( TreeScope.Ancestors | TreeScope.Element | TreeScope.Descendants ) ) { paramsValidated = true; } else if ( ( scope & TreeScope.Element ) == TreeScope.Element ) { // ...OR Element where the element implements WindowPattern // PRESHARP will flag this as warning 56506/6506:Parameter 'element' to this public method must be validated: A null-dereference can occur here. // False positive, element is checked, see above #pragma warning suppress 6506 object val = element.GetCurrentPropertyValue(AutomationElement.NativeWindowHandleProperty); if ( val != null && val is int && (int)val != 0 ) { if ( HwndProxyElementProvider.IsWindowPatternWindow( NativeMethods.HWND.Cast( new IntPtr( (int)val ) ) ) ) { paramsValidated = true; } } } } if ( !paramsValidated ) { throw new ArgumentException( SR.Get( SRID.ParamsNotApplicableToWindowClosedEvent ) ); } } // Add a client-side Handler for for this event request EventListener l = new EventListener(eventId, scope, null, CacheRequest.CurrentUiaCacheRequest); ClientEventManager.AddListener(element, eventHandler, l); }
// AddListener - Adds a listener for this client and notifies the UIA server. All event // handler additions call through to this method. internal static void AddListener(AutomationElement rawEl, Delegate eventCallback, EventListener l) { lock (_classLock) { // If we are adding a listener then a proxy could be created as a result of an event so make sure they are loaded ProxyManager.LoadDefaultProxies(); if (_listeners == null) { // enough space for 16 AddXxxListeners (100 bytes) _listeners = new ArrayList(16); } // Start the callback queue that gets us off the server's // UI thread when events arrive cross-proc CheckStartCallbackQueueing(); // // The framework handles some events on behalf of providers; do those here // // If listening for BoundingRectangleProperty then may need to start listening on the // client-side for LocationChange WinEvent (only use *one* BoundingRectTracker instance). if (_winEventTrackers[(int)Tracker.BoundingRect] == null && HasProperty(AutomationElement.BoundingRectangleProperty, l.Properties)) { // AddWinEventListener(Tracker.BoundingRect, new BoundingRectTracker()); } // Start listening for menu event in order to raise MenuOpened/Closed events. if ( _winEventTrackers [(int)Tracker.MenuOpenedOrClosed] == null && (l.EventId == AutomationElement.MenuOpenedEvent || l.EventId == AutomationElement.MenuClosedEvent) ) { AddWinEventListener( Tracker.MenuOpenedOrClosed, new MenuTracker( new MenuHandler( OnMenuEvent ) ) ); } // Begin watching for hwnd open/close/show/hide so can advise of what events are being listened for. // Only advise UI contexts of events being added if the event might be raised by a provider. // TopLevelWindow event is raised by UI Automation framework so no need to track new UI. // if (_winEventTrackers[(int)Tracker.WindowShowOrOpen] == null ) { AddWinEventListener( Tracker.WindowShowOrOpen, new WindowShowOrOpenTracker( new WindowShowOrOpenHandler( OnWindowShowOrOpen ) ) ); AddWinEventListener( Tracker.WindowHideOrClose, new WindowHideOrCloseTracker( new WindowHideOrCloseHandler( OnWindowHideOrClose ) ) ); } // If listening for WindowInteractionStateProperty then may need to start listening on the // client-side for ObjectStateChange WinEvent. if (_winEventTrackers[(int)Tracker.WindowInteractionState] == null && HasProperty(WindowPattern.WindowInteractionStateProperty, l.Properties)) { AddWinEventListener(Tracker.WindowInteractionState, new WindowInteractionStateTracker()); } // If listening for WindowVisualStateProperty then may need to start listening on the // client-side for ObjectLocationChange WinEvent. if (_winEventTrackers[(int)Tracker.WindowVisualState] == null && HasProperty(WindowPattern.WindowVisualStateProperty, l.Properties)) { AddWinEventListener(Tracker.WindowVisualState, new WindowVisualStateTracker()); } // Wrap and store this record on the client... EventListenerClientSide ec = new EventListenerClientSide(rawEl, eventCallback, l); _listeners.Add(ec); // Only advise UI contexts of events being added if the event might be raised by // a provider. TopLevelWindow event is raised by UI Automation framework. if (ShouldAdviseProviders( l.EventId )) { // .. then let the server know about this listener ec.EventHandle = UiaCoreApi.UiaAddEvent(rawEl.RawNode, l.EventId.Id, ec.CallbackDelegate, l.TreeScope, PropertyArrayToIntArray(l.Properties), l.CacheRequest); } } }
//------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors // Static class, no ctor #endregion Constructors //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods // AddFocusListener - Adds a focus listener for this client. internal static void AddFocusListener(Delegate eventCallback, EventListener l) { AddRootListener(Tracker.Focus, eventCallback, l); }
// AddRootListener - Add a listener for an event whose reference is always the // root and scope is all elements private static void AddRootListener(Tracker idx, Delegate eventCallback, EventListener l) { lock ( _classLock ) { // Add this listener to client-side store of listeners and give the server // a chance to enable accessibility for this event AddListener( AutomationElement.RootElement, eventCallback, l ); // Track WinEvents WinEventWrap eventWrapper = _winEventTrackers[(int)idx]; if ( eventWrapper == null ) { // First time create a WinEvent tracker and start listening AddWinEventListener( idx, GetNewRootTracker( idx ) ); } else { // Subsequent times just add the callback to the existing WinEvent eventWrapper.AddCallback( eventCallback ); } } }