/// <summary> /// Searches for a subrange of text that has the specified attribute. /// To search the entire document use the text pattern's document range. /// </summary> /// <param name="attribute">The attribute to search for.</param> /// <param name="value">The value of the specified attribute to search for. The value must be of the exact type specified for the /// attribute. For example when searching for font size you must specify the size in points as a double. /// If you specify the point size as an integer then you will never get any matches due to the differing types.</param> /// <param name="backward">true if the last occurring range should be returned instead of the first.</param> /// <returns>A subrange with the specified attribute, or null if no such subrange exists.</returns> public TextPatternRange FindAttribute(AutomationTextAttribute attribute, object value, bool backward) { Misc.ValidateArgumentNonNull(attribute, "attribute"); Misc.ValidateArgumentNonNull(value, "value"); // no text attributes can have null as a valid value // Check that attribute value is of expected type... AutomationAttributeInfo ai; if (!Schema.GetAttributeInfo(attribute, out ai)) { throw new ArgumentException(SR.Get(SRID.UnsupportedAttribute)); } if (value.GetType() != ai.Type) { throw new ArgumentException(SR.Get(SRID.TextAttributeValueWrongType, attribute, ai.Type.Name, value.GetType().Name), "value"); } // note: if we implement attributes whose values are logical elements, patterns, // or ranges then we'll need to unwrap the objects here before passing them on to // the provider. if (attribute == TextPattern.CultureAttribute) { if (value is CultureInfo) { value = ((CultureInfo)value).LCID; } } SafeTextRangeHandle hResultTextRange = UiaCoreApi.TextRange_FindAttribute(_hTextRange, attribute.Id, value, backward); return(Wrap(hResultTextRange, _pattern)); }
//------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors internal ClientSideQueueItem(Delegate clientCallback, AutomationElement srcEl, UiaCoreApi.UiaCacheRequest request, AutomationEventArgs e) { _clientCallback = clientCallback; _srcEl = srcEl; _request = request; _e = e; }
/// <summary> /// Retrieves the value of a text attribute over the entire range. /// </summary> /// <param name="attribute">The text attribute.</param> /// <returns>The value of the attribute across the range. /// If the attribute's value varies over the range then the value is TextPattern.MixedAttributeValue</returns> public object GetAttributeValue(AutomationTextAttribute attribute) { Misc.ValidateArgumentNonNull(attribute, "attribute"); AutomationAttributeInfo ai; if (!Schema.GetAttributeInfo(attribute, out ai)) { throw new ArgumentException(SR.Get(SRID.UnsupportedAttribute)); } object obj = UiaCoreApi.TextRange_GetAttributeValue(_hTextRange, attribute.Id); if (ai.Type.IsEnum && obj is int) { // Convert ints from COM Interop to the appropriate enum type obj = Enum.ToObject(ai.Type, (int)obj); } else if (obj != AutomationElement.NotSupported && ai.ObjectConverter != null) { // Use a custom converter, if needed (eg. converts LCIDs to CultureInfo) obj = ai.ObjectConverter(obj); } return(obj); }
//------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors // Private ctor, used mostly by CacheHelper when reconstructing AutomationElements from // a CacheResponse. internal AutomationElement(SafeNodeHandle hnode, object[,] cachedValues, int cachedValuesIndex, UiaCoreApi.UiaCacheRequest request) { _hnode = hnode; // Can be IntPtr.Zero for a lightweight object _cachedValues = cachedValues; // Can be null if there are no cached properties for this node _cachedValuesIndex = cachedValuesIndex; _request = request; // Set RuntimeId (if available; 'as int[]' filters out AutomationElement.NotAvailable) _runtimeId = LookupCachedValue(AutomationElement.RuntimeIdProperty, false, true) as int[]; // // One scenario that allows for null runtimeID - doing UpdatedCache() on a node and asking only // for children - gives us back a placeholder node that only has valid .CachedChildren, // the node itself doesn't have any cached properties or a node. // Since null is a valid value for these, we need another value to // indicate that they were not requested - it's a bit obscure, but // 'this' works well here, since these can never have it as legal value. _cachedParent = this; _cachedFirstChild = this; _cachedNextSibling = this; }
/// <summary> /// Moves one endpoint of the range the specified number of units in the text. /// If the endpoint being moved crosses the other endpoint then the other endpoint /// is moved along too resulting in a degenerate range and ensuring the correct ordering /// of the endpoints. (i.e. always Start<=End) /// </summary> /// <param name="endpoint">The endpoint to move.</param> /// <param name="unit">The textual unit for moving.</param> /// <param name="count">The number of units to move. A positive count moves the endpoint forward. /// A negative count moves backward. A count of 0 has no effect.</param> /// <returns>The number of units actually moved, which can be less than the number requested if /// moving the endpoint runs into the beginning or end of the document.</returns> public int MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, TextUnit unit, int count) { ValidateEndpointArgument(endpoint, "endpoint"); ValidateUnitArgument(unit, "unit"); return(UiaCoreApi.TextRange_MoveEndpointByUnit(_hTextRange, endpoint, unit, count)); }
/// <summary> /// Moves the range the specified number of units in the text. Note that the text is not altered. Instead the /// range spans a different part of the text. /// If the range is degenerate, this method tries to move the insertion point count units. If the range is nondegenerate /// and count is greater than zero, this method collapses the range at its end point, moves the resulting range forward /// to a unit boundary (if it is not already at one), and then tries to move count - 1 units forward. If the range is /// nondegenerate and count is less than zero, this method collapses the range at the starting point, moves the resulting /// range backward to a unit boundary (if it isn't already at one), and then tries to move |count| - 1 units backward. /// Thus, in both cases, collapsing a nondegenerate range, whether or not moving to the start or end of the unit following /// the collapse, counts as a unit. /// </summary> /// <param name="unit">The textual unit for moving.</param> /// <param name="count">The number of units to move. A positive count moves the range forward. /// A negative count moves backward. A count of 0 has no effect.</param> /// <returns>The number of units actually moved, which can be less than the number requested if /// moving the range runs into the beginning or end of the document.</returns> public int Move(TextUnit unit, int count) { ValidateUnitArgument(unit, "unit"); // note: we could optimize the case of count==0 and just return 0. return(UiaCoreApi.TextRange_Move(_hTextRange, unit, count)); }
//------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors internal CalloutQueueItem(Delegate clientCallback, UiaCoreApi.UiaCacheResponse cacheResponse, AutomationEventArgs e, UiaCoreApi.UiaCacheRequest cacheRequest) { _clientCallback = clientCallback; _cacheResponse = cacheResponse; _e = e; _cacheRequest = cacheRequest; }
/// <summary> /// Compares the endpoint of this range with the endpoint of another range. /// </summary> /// <param name="endpoint">The endpoint of this range to compare.</param> /// <param name="targetRange">The range with the other endpoint to compare. /// The range must have come from the same text provider or an InvalidArgumentException will be thrown.</param> /// <param name="targetEndpoint">The endpoint on the other range to compare.</param> /// <returns>Returns <0 if this endpoint occurs earlier in the text than the target endpoint. /// Returns 0 if this endpoint is at the same location as the target endpoint. /// Returns >0 if this endpoint occurs later in the text than the target endpoint.</returns> public int CompareEndpoints(TextPatternRangeEndpoint endpoint, TextPatternRange targetRange, TextPatternRangeEndpoint targetEndpoint) { ValidateEndpointArgument(endpoint, "endpoint"); ValidateRangeArgument(targetRange, "targetRange"); ValidateEndpointArgument(targetEndpoint, "targetEndpoint"); return(UiaCoreApi.TextRange_CompareEndpoints(_hTextRange, endpoint, targetRange._hTextRange, targetEndpoint)); }
/// <summary> /// Moves an endpoint of this range to coincide with the endpoint of another range. /// </summary> /// <param name="endpoint">The endpoint to move.</param> /// <param name="targetRange">Another range from the same text provider.</param> /// <param name="targetEndpoint">An endpoint on the other range.</param> public void MoveEndpointByRange(TextPatternRangeEndpoint endpoint, TextPatternRange targetRange, TextPatternRangeEndpoint targetEndpoint) { ValidateEndpointArgument(endpoint, "endpoint"); ValidateRangeArgument(targetRange, "targetRange"); ValidateEndpointArgument(targetEndpoint, "targetEndpoint"); UiaCoreApi.TextRange_MoveEndpointByRange(_hTextRange, endpoint, targetRange._hTextRange, targetEndpoint); }
/// <summary> /// Retrieves the range of a child object. /// </summary> /// <param name="childElement">The child element. If the element is not /// a child of the text container then an InvalidOperation exception is /// thrown.</param> /// <returns>A range that spans the child element.</returns> public TextPatternRange RangeFromChild(AutomationElement childElement) { if (childElement == null) { throw new ArgumentNullException("childElement"); } SafeTextRangeHandle hTextRange = UiaCoreApi.TextPattern_RangeFromChild(_hPattern, childElement.RawNode); return(TextPatternRange.Wrap(hTextRange, this)); }
//------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region Public Properties /// <summary> /// Retrieves a collection of all of the children that fall within the /// range. /// </summary> /// <returns>A collection of all children that fall within the range. Children /// that overlap with the range but are not entirely enclosed by it will /// also be included in the collection.</returns> public AutomationElement[] GetChildren() { object[] rawChildren = UiaCoreApi.TextRange_GetChildren(_hTextRange); AutomationElement[] wrappedChildren = new AutomationElement[rawChildren.Length]; for (int i = 0; i < rawChildren.Length; i++) { SafeNodeHandle hnode = UiaCoreApi.UiaHUiaNodeFromVariant(rawChildren[i]); wrappedChildren[i] = AutomationElement.Wrap(hnode); } return(wrappedChildren); }
/// <summary> /// Searches for an occurrence of text within the range. /// </summary> /// <param name="text">The text to search for.</param> /// <param name="backward">true if the last occurring range should be returned instead of the first.</param> /// <param name="ignoreCase">true if case should be ignored for the purposes of comparison.</param> /// <returns>A subrange with the specified text, or null if no such subrange exists.</returns> public TextPatternRange FindText(string text, bool backward, bool ignoreCase) { // PerSharp/PreFast will flag this as warning 6507/56507: Prefer 'string.IsNullOrEmpty(text)' over checks for null and/or emptiness. // A null string is not should throw an ArgumentNullException while an empty string should throw an ArgumentException. // Therefore we can not use IsNullOrEmpty() here, suppress the warning. Misc.ValidateArgumentNonNull(text, "text"); #pragma warning suppress 6507 Misc.ValidateArgument(text.Length != 0, SRID.TextMustNotBeNullOrEmpty); SafeTextRangeHandle hResultTextRange = UiaCoreApi.TextRange_FindText(_hTextRange, text, backward, ignoreCase); return(Wrap(hResultTextRange, _pattern)); }
//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods internal static AutomationElement BuildAutomationElementsFromResponse( UiaCoreApi.UiaCacheRequest cacheRequest, UiaCoreApi.UiaCacheResponse response) { if (response.TreeStructure == null) { Debug.Assert(response.RequestedData == null, "both RequestedData and TreeStructure should be null or non-null"); return null; } // FrozenCacheRequest should not be null one new AE code, but may // still be null on old code paths - eg. top level window events - where // prefetching is not yet enabled. if (cacheRequest == null) { cacheRequest = CacheRequest.DefaultUiaCacheRequest; } // ParseTreeDescription is the method that parses the returned data // and builds up the tree, setting properties on each node as it goes along... // index and propIndex keep track of where it is, and we check afterwards // that all are pointing to the end, to ensure that everything matched // up as expected. int index = 0; int propIndex = 0; bool askedForChildren = (cacheRequest.TreeScope & TreeScope.Children) != 0; bool askedForDescendants = (cacheRequest.TreeScope & TreeScope.Descendants) != 0; AutomationElement root = ParseTreeDescription(response.TreeStructure, response.RequestedData, ref index, ref propIndex, cacheRequest, askedForChildren, askedForDescendants); if (index != response.TreeStructure.Length) { Debug.Assert(false, "Internal error: got malformed tree description string (extra chars at end)"); return null; } if (response.RequestedData != null && propIndex != response.RequestedData.GetLength(0)) { Debug.Assert(false, "Internal error: mismatch between count of property buckets and nodes claiming them"); return null; } // Properties are wrapped (eg. pattern classes inserted in front of interface) as // they are being returned to the caller, in the AutomationElement accessors, not here. return root; }
/// <summary> /// Finds the range nearest to a screen coordinate. /// If the coordinate is within the bounding rectangle of a character then the /// range will contain that character. Otherwise, it will be a degenerate /// range near the point, chosen in an implementation-dependent manner. /// An InvalidOperation exception is thrown if the point is outside of the /// client area of the text container. /// </summary> /// <param name="screenLocation">The location in screen coordinates.</param> /// <returns>A degenerate range nearest the specified location.</returns> public TextPatternRange RangeFromPoint(Point screenLocation) { //If we are not within the client area throw an exception Rect rect = (Rect)_element.GetCurrentPropertyValue(AutomationElement.BoundingRectangleProperty); if (screenLocation.X < rect.Left || screenLocation.X >= rect.Right || screenLocation.Y < rect.Top || screenLocation.Y >= rect.Bottom) { throw new ArgumentException(SR.Get(SRID.ScreenCoordinatesOutsideBoundingRect)); } SafeTextRangeHandle hTextRange = UiaCoreApi.TextPattern_RangeFromPoint(_hPattern, screenLocation); return(TextPatternRange.Wrap(hTextRange, this)); }
//------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors // full ctor internal EventListener( AutomationEvent eventId, TreeScope scope, AutomationProperty [] properties, UiaCoreApi.UiaCacheRequest cacheRequest ) { _eventId = eventId; _scope = scope; if (properties != null) _properties = (AutomationProperty[])properties.Clone(); else _properties = null; _cacheRequest = cacheRequest; }
//------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Request to set the value that this UI element is representing /// </summary> /// <param name="value">Value to set the UI to, as a double</param> public void SetValue(double value) { // Test the Enabled state prior to the more general Read-Only state. object enabled = _el.GetCurrentPropertyValue(AutomationElementIdentifiers.IsEnabledProperty); if (enabled is bool && !(bool)enabled) { throw new ElementNotEnabledException(); } // Test the Read-Only state after the more specific Enabled state. object readOnly = _el.GetCurrentPropertyValue(IsReadOnlyProperty); if (readOnly is bool && (bool)readOnly) { throw new InvalidOperationException(SR.Get(SRID.ValueReadonly)); } UiaCoreApi.RangeValuePattern_SetValue(_hPattern, value); }
internal static object ConvertToElementArray(object value) { // Convert each item to an AutomationElement... object[] objArr = (object[])value; AutomationElement[] els = new AutomationElement[objArr.Length]; for (int i = 0; i < objArr.Length; i++) { if (objArr[i] == null) { els[i] = null; } else { SafeNodeHandle hnode = UiaCoreApi.UiaHUiaNodeFromVariant(objArr[i]); els[i] = AutomationElement.Wrap(hnode); } } return(els); }
private void PreWinEventProc(int eventId, IntPtr hwnd, int idObject, int idChild, uint eventTime) { // Ignore events from the UIA->MSAA bridge: these are recognizable as having // >0 idObject, and the target HWND having a UIA impl. if (idObject > 0) { if (UiaCoreApi.UiaHasServerSideProvider(hwnd)) { // Bridge event - ignore it. return; } } // 0 is used as a marker value elsewhere, so bump up to 1 if (eventTime == 0) { eventTime = 1; } WinEventProc(eventId, hwnd, idObject, idChild, eventTime); }
// 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)); }
//------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Find item by specified property/value. It will return /// placeholder which depending upon it's virtualization state may /// or may not have the information of the complete peer/Wrapper. /// /// Throws ArgumentException if the property requested is not one that the /// container supports searching over. Supports Name property, AutomationId, /// IsSelected and ControlType. /// /// This method is expected to be relatively slow, since it may need to /// traverse multiple objects in order to find a matching one. /// When used in a loop to return multiple items, no specific order is /// defined so long as each item is returned only once (ie. loop should /// terminate). This method is also item-centric, not UI-centric, so items /// with multiple UI representations need only be returned once. /// /// A special propertyId of 0 means ‘match all items’. This can be used /// with startAfter=NULL to get the first item, and then to get successive /// items. /// </summary> /// <param name="startAfter">this represents the item after which the container wants to begin search</param> /// <param name="property">corresponds to property for whose value it want to search over.</param> /// <param name="value">value to be searched for, for specified property</param> /// <returns>The first item which matches the searched criterion, if no item matches, it returns null </returns> public AutomationElement FindItemByProperty(AutomationElement startAfter, AutomationProperty property, object value) { SafeNodeHandle hNode; // Invalidate the "value" passed against the "property" before passing it to UIACore, Don't invalidate if search is being done for "null" property // FindItemByProperty supports find for null property. if (property != null) { value = PropertyValueValidateAndMap(property, value); } if (startAfter != null) { if (property != null) { hNode = UiaCoreApi.ItemContainerPattern_FindItemByProperty(_hPattern, startAfter.RawNode, property.Id, value); } else { hNode = UiaCoreApi.ItemContainerPattern_FindItemByProperty(_hPattern, startAfter.RawNode, 0, null); } } else { if (property != null) { hNode = UiaCoreApi.ItemContainerPattern_FindItemByProperty(_hPattern, new SafeNodeHandle(), property.Id, value); } else { hNode = UiaCoreApi.ItemContainerPattern_FindItemByProperty(_hPattern, new SafeNodeHandle(), 0, null); } } AutomationElement wrappedElement = AutomationElement.Wrap(hNode); return(wrappedElement); }
//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods internal override void Process() { // Grab properties for cache request here... AutomationElement src; if (_srcEl == null) { src = null; } else { UiaCoreApi.UiaCacheResponse response = UiaCoreApi.UiaGetUpdatedCache(_srcEl.RawNode, _request, UiaCoreApi.NormalizeState.View, null); src = CacheHelper.BuildAutomationElementsFromResponse(_request, response); } // if (!(src == null && _e.EventId == AutomationElement.AutomationFocusChangedEvent)) { InvokeHandlers.InvokeClientHandler(_clientCallback, src, _e); } }
//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods internal override void Process() { // Grab properties for cache request here... AutomationElement src; if (_srcEl == null) { src = null; } else { UiaCoreApi.UiaCacheResponse response = UiaCoreApi.UiaGetUpdatedCache(_srcEl.RawNode, _request, UiaCoreApi.NormalizeState.View, null); src = CacheHelper.BuildAutomationElementsFromResponse(_request, response); } // We need to find out why this situation should occur at (aside from a window closed event) and // handle the cause. if (!(src == null && _e.EventId == AutomationElement.AutomationFocusChangedEvent)) { InvokeHandlers.InvokeClientHandler(_clientCallback, src, _e); } }
/// <summary> /// Blocking method that returns after the element has been collapsed /// </summary> /// /// <outside_see conditional="false"> /// This API does not work inside the secure execution environment. /// <exception cref="System.Security.Permissions.SecurityPermission"/> /// </outside_see> public void Collapse() { UiaCoreApi.ExpandCollapsePattern_Collapse(_hPattern); }
//------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Blocking method that returns after the element has been expanded /// </summary> /// /// <outside_see conditional="false"> /// This API does not work inside the secure execution environment. /// <exception cref="System.Security.Permissions.SecurityPermission"/> /// </outside_see> public void Expand() { UiaCoreApi.ExpandCollapsePattern_Expand(_hPattern); }
//------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Request that a placeholder element make itself fully available. Blocks /// until element is available, which could take time. /// Parent control may scroll as a side effect if the container needs to /// bring the item into view in order to devirtualize it. /// </summary> public void Realize() { UiaCoreApi.VirtualizedItemPattern_Realize(_hPattern); }
override protected bool ReleaseHandle() { return(UiaCoreApi.UiaTextRangeRelease(handle)); }
/// <summary> /// Scrolls the text in the provider so the range is within the viewport. /// </summary> /// <param name="alignToTop">true if the provider should be scrolled so the range is flush with the top of the viewport. /// false if the provider should be scrolled so the range is flush with the bottom.</param> public void ScrollIntoView(bool alignToTop) { UiaCoreApi.TextRange_ScrollIntoView(_hTextRange, alignToTop); }
/// <summary> /// Removes the text range from the current selection. /// </summary> public void RemoveFromSelection() { UiaCoreApi.TextRange_RemoveFromSelection(_hTextRange); }
/// <summary> /// Adds the text range to the current selection. /// </summary> public void AddToSelection() { UiaCoreApi.TextRange_AddToSelection(_hTextRange); }
// called by FindFirst and FindAll private UiaCoreApi.UiaCacheResponse[] Find(TreeScope scope, Condition condition, UiaCoreApi.UiaCacheRequest request, bool findFirst, BackgroundWorker worker) { Misc.ValidateArgumentNonNull(condition, "condition"); if (scope == 0) { throw new ArgumentException(SR.Get(SRID.TreeScopeNeedAtLeastOne)); } if ((scope & ~(TreeScope.Element | TreeScope.Children | TreeScope.Descendants)) != 0) { throw new ArgumentException(SR.Get(SRID.TreeScopeElementChildrenDescendantsOnly)); } // Set up a find struct... UiaCoreApi.UiaFindParams findParams = new UiaCoreApi.UiaFindParams(); findParams.FindFirst = findFirst; if ((scope & TreeScope.Descendants) != 0) findParams.MaxDepth = -1; else if ((scope & TreeScope.Children) != 0) findParams.MaxDepth = 1; else findParams.MaxDepth = 0; if ((scope & TreeScope.Element) != 0) findParams.ExcludeRoot = false; else findParams.ExcludeRoot = true; UiaCoreApi.UiaCacheResponse[] retVal = UiaCoreApi.UiaFind(_hnode, findParams, condition, request); return retVal; }
/// <summary> /// Causes the calling code to block, waiting the specified number of milliseconds, for the /// associated window to enter an idle state. /// </summary> /// <remarks> /// The implementation is dependent on the underlying application framework therefore this /// call may return sometime after the window is ready for user input. The calling code /// should not rely on this call to understand exactly when the window has become idle. /// /// For now this method works reliably for both WinFx and Win32 Windows that are starting /// up. However, if called at other times on WinFx Windows (e.g. during a long layout) /// WaitForInputIdle may return true before the Window is actually idle. Additional work /// needs to be done to detect when WinFx Windows are idle. /// </remarks> /// <param name="milliseconds">The amount of time, in milliseconds, to wait for the /// associated process to become idle. The maximum is the largest possible value of a /// 32-bit integer, which represents infinity to the operating system /// </param> /// <returns> /// returns true if the window has reached the idle state and false if the timeout occurred. /// </returns> public bool WaitForInputIdle(int milliseconds) { return(UiaCoreApi.WindowPattern_WaitForInputIdle(_hPattern, milliseconds)); }
//------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Request to change the state that this UI element is currently representing /// </summary> /// /// <outside_see conditional="false"> /// This API does not work inside the secure execution environment. /// <exception cref="System.Security.Permissions.SecurityPermission"/> /// </outside_see> public void Toggle() { UiaCoreApi.TogglePattern_Toggle(_hPattern); }
/// <summary> /// Retrieves the text of the range. /// </summary> /// <param name="maxLength">Specifies the maximum length of the string to return or -1 if no limit is requested.</param> /// <returns>The text of the range possibly truncated to the specified limit.</returns> public string GetText(int maxLength) { Misc.ValidateArgumentInRange(maxLength >= -1, "maxLength"); return(UiaCoreApi.TextRange_GetText(_hTextRange, maxLength)); }
// drill for either focused raw element, or element at specified point private static AutomationElement DrillForPointOrFocus(bool atPoint, Point pt, UiaCoreApi.UiaCacheRequest cacheRequest) { UiaCoreApi.UiaCacheResponse response; if (atPoint) response = UiaCoreApi.UiaNodeFromPoint(pt.X, pt.Y, cacheRequest); else response = UiaCoreApi.UiaNodeFromFocus(cacheRequest); return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); }
// Private ctor used by Clone() private CacheRequest( Condition viewCondition, TreeScope scope, ArrayList properties, ArrayList patterns, AutomationElementMode automationElementMode, UiaCoreApi.UiaCacheRequest uiaCacheRequest) { _instanceLock = new object(); _viewCondition = viewCondition; _scope = scope; _properties = properties; _patterns = patterns; _automationElementMode = automationElementMode; _uiaCacheRequest = uiaCacheRequest; }
/// <summary> /// Non-blocking call to close this non-application window. /// When called on a split pane, it will close the pane (thereby removing a /// split), it may or may not also close all other panes related to the /// document/content/etc. This behavior is application dependent. /// </summary> public void Close() { UiaCoreApi.WindowPattern_Close(_hPattern); }
/// <summary> /// Selects the text of the range within the provider. /// </summary> public void Select() { UiaCoreApi.TextRange_Select(_hTextRange); }
//------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Changes the State of the window based on the passed enum. /// </summary> /// <param name="state">The requested state of the window.</param> public void SetWindowVisualState(WindowVisualState state) { UiaCoreApi.WindowPattern_SetWindowVisualState(_hPattern, state); }
//------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods // Parses the string as returned from ElementSearcher - see ElementSearcher.cs // for a description of the format string. Summary is that it is a lisp-like // set of parens indicating tree structure (eg. "(()())" indicates a node containing // two child nodes), but uses 'P' instead of an open paran to indicate that the // corresonding node has a property array that needs to be associated with it. // // index is the current position in the tree strucure string, // propIndex is the current position in the array of property arrays // (an array of properties returned for each element that matches the // condition specified in the Searcher condition.) private static AutomationElement ParseTreeDescription( string treeDescription, object[,] properties, ref int index, ref int propIndex, UiaCoreApi.UiaCacheRequest cacheRequest, bool askedForChildren, bool askedForDescendants ) { // Check that this is a 'begin node' tag (with or without properties)... if (string.IsNullOrEmpty(treeDescription)) return null; char c = treeDescription[index]; if (c != '(' && c != 'P') { return null; } bool havePropertiesForThisNode = c == 'P'; index++; SafeNodeHandle hnode = null; // If we have information for this node, and we want full remote // references back, then extract the hnode from the first slot of that // element's property row... if (havePropertiesForThisNode && cacheRequest.AutomationElementMode == AutomationElementMode.Full) { hnode = (SafeNodeHandle)properties[propIndex, 0]; } // Attach properties if present... object[,] cachedValues = null; int cachedValueIndex = 0; if (havePropertiesForThisNode) { cachedValues = properties; cachedValueIndex = propIndex; propIndex++; } AutomationElement node = new AutomationElement(hnode, cachedValues, cachedValueIndex, cacheRequest); if( askedForChildren || askedForDescendants ) { // If we did request children or descendants at this level, then set the // cached first child to null - it may get overwritten with // an actual value later; but the key thing is that it gets // set so we can distinguish the "asked, but doesn't have one" from // the "didn't ask" case. (Internally, AutomationElement uses // 'this' to indicate the later case, and throws an exception if // you ask for the children without having previously asked // for them in a CacheRequest.) node.SetCachedFirstChild(null); } // Add in children... AutomationElement prevChild = null; for (; ; ) { // Recursively parse the string... AutomationElement child = ParseTreeDescription( treeDescription, properties, ref index, ref propIndex, cacheRequest, askedForDescendants, askedForDescendants); if (child == null) break; // Then link child node into tree... child.SetCachedParent(node); if (prevChild == null) { node.SetCachedFirstChild(child); } else { prevChild.SetCachedNextSibling(child); } prevChild = child; } // Ensure that end node tag is present... if (treeDescription[index] != ')') { Debug.Assert(false, "Internal error: Got malformed tree description string, missing closing paren"); return null; } index++; return node; }