public void Apply(Func <string, string> environmentVariableLookup = null, WindowsAutomationMapping.Map parentMap = null) { ParentMap = parentMap; var mapDesc = WindowsAutomationMappingExtensions.GetMapDescription(this); BreezyTrace.Log(TraceEventType.Verbose, String.Format("Searching for element for map {0}...", mapDesc)); BindElement(environmentVariableLookup); if (Element == null) { BreezyTrace.Log(TraceEventType.Verbose, String.Format("Element for map {0} could not be found or its conditions were not met. Terminating this search chain.", mapDesc)); return; } BreezyTrace.Log(TraceEventType.Verbose, String.Format("Found element. {0}.", WindowsAutomationMappingExtensions.GetElementDescription(this))); var element = Element as AutomationElement; ApplyInputs(environmentVariableLookup); //recurse through any child maps foreach (var childMap in Maps) { childMap.Apply(environmentVariableLookup, this); } }
private string EnvironmentVariableSubstitution(string value, Func <string, string> environmentVariableLookup) { if (environmentVariableLookup == null || !value.StartsWith("$")) { return(value); } //we should look this up but first... //strip the $ and any non-alphanums var regex = new Regex(@"\${1}(\w*|\d*)"); if (!regex.IsMatch(value)) { return(value); } var property = regex.Match(value).Groups[1].Value; var newValue = value; try { newValue = environmentVariableLookup(property); } catch (Exception ex) { BreezyTrace.Log(TraceEventType.Error, String.Format("Environment variable lookup failed for {0}", value), ex); return(value); } //just return the value if we don't get anything if (String.IsNullOrEmpty(newValue)) { return(value); } //replace whatever may have come after something like "\subfolder\stuff" value = value.Replace("$" + property, newValue); return(value); }
private static AutomationElement FindFirstInAncestors(Map map, Condition condition) { if (map.ParentMap == null || map.ParentMap.Element == null) { BreezyTrace.Log(TraceEventType.Verbose, String.Format("Terminated automation search in ancestor elements at the root (or the map is missing a parent reference).")); return(null); } var parentMap = map.ParentMap; var parentElement = parentMap.Element as AutomationElement; var e = parentElement.FindFirst(TreeScope.Element, condition); //keep going up until we find the element or terminate at the root if (e == null) { e = FindFirstInAncestors(parentMap, condition); } return(e); }
private void ApplyInputs(Func <string, string> environmentVariableLookup = null) { foreach (var input in Inputs) { var element = Element as AutomationElement; object pattern = null; try { switch (input.Type) { case WindowsAutomationMapping.Map.Input.InputTypes.Direction: var hwnd = NativeWindowsHandle; BreezyTrace.Log(TraceEventType.Verbose, String.Format("Sending direction key: {0} to hwnd: {1}", input.Value, hwnd)); var item = new EnumWindowsItem(hwnd, WindowsAutomation.TimeDilation); switch (input.Value) { case "Up": item.SendUp(); break; case "Down": item.SendDown(); break; case "Left": item.SendLeft(); break; case "Right": item.SendRight(); break; default: break; } break; case WindowsAutomationMapping.Map.Input.InputTypes.Esc: break; case WindowsAutomationMapping.Map.Input.InputTypes.Invoke: if (element.TryGetCurrentPattern(InvokePattern.Pattern, out pattern)) { (pattern as InvokePattern).Invoke(); } break; case WindowsAutomationMapping.Map.Input.InputTypes.ExpandCollapse: if (element.TryGetCurrentPattern(ExpandCollapsePattern.Pattern, out pattern)) { element.SetFocus(); var expandCollapse = pattern as ExpandCollapsePattern; if ( (expandCollapse.Current.ExpandCollapseState.HasFlag(ExpandCollapseState.Collapsed) || expandCollapse.Current.ExpandCollapseState.HasFlag(ExpandCollapseState.PartiallyExpanded)) && input.Value == "Expand" ) { expandCollapse.Expand(); } else if (input.Value == "Collapse") { expandCollapse.Collapse(); } } break; case WindowsAutomationMapping.Map.Input.InputTypes.SendKey: hwnd = NativeWindowsHandle; item = new EnumWindowsItem(hwnd, WindowsAutomation.TimeDilation); var b = Convert.ToByte(input.Value); item.SendKey(b); break; case WindowsAutomationMapping.Map.Input.InputTypes.Letter: //hwnd = NativeWindowsHandle; //item = new EnumWindowsItem(hwnd, WindowsAutomation.TimeDilation); //item.SendKey(input.Value); break; case WindowsAutomationMapping.Map.Input.InputTypes.Number: break; case WindowsAutomationMapping.Map.Input.InputTypes.Return: hwnd = NativeWindowsHandle; BreezyTrace.Log(TraceEventType.Verbose, String.Format("Sending Enter key: {0} to hwnd: {1}", input.Value, hwnd)); item = new EnumWindowsItem(hwnd, WindowsAutomation.TimeDilation); item.SendReturn(); break; case WindowsAutomationMapping.Map.Input.InputTypes.SelectionItem: if (element.TryGetCurrentPattern(SelectionItemPattern.Pattern, out pattern)) { (pattern as SelectionItemPattern).Select(); } break; case WindowsAutomationMapping.Map.Input.InputTypes.Selection: //doesn't do anything break; case WindowsAutomationMapping.Map.Input.InputTypes.Tab: break; case WindowsAutomationMapping.Map.Input.InputTypes.Text: //check to see if we're referencing an WF services environment variable (e.g. TempDir) and if so, get that value var val = EnvironmentVariableSubstitution(input.Value, environmentVariableLookup); if (element.TryGetCurrentPattern(ValuePattern.Pattern, out pattern)) { (pattern as ValuePattern).SetValue(val); } break; case WindowsAutomationMapping.Map.Input.InputTypes.Toggle: if (element.TryGetCurrentPattern(TogglePattern.Pattern, out pattern)) { var toggle = pattern as TogglePattern; if ( (toggle.Current.ToggleState == ToggleState.Off && input.Value == "On") || (toggle.Current.ToggleState == ToggleState.On && input.Value == "Off") ) { toggle.Toggle(); } } break; case WindowsAutomationMapping.Map.Input.InputTypes.Wait: var delay = Decimal.ToInt32(Convert.ToInt32(input.Value) * WindowsAutomation.TimeDilation); Thread.Sleep(delay); break; } } catch (Exception ex) { BreezyTrace.Log(TraceEventType.Information, "Input failed for this mapping.", ex); } BreezyTrace.Log(TraceEventType.Verbose, String.Format("Successfully applied input type: {0}", input.Type)); } }
private void BindElement(Func <string, string> environmentVariableLookup = null) { //first, build the condition Condition condition = null; if (!String.IsNullOrEmpty(Tag)) { _logger.(TraceEventType.Verbose, this.Tag); } var conditions = new List <PropertyCondition>(); if (!String.IsNullOrEmpty(ClassName)) { conditions.Add(new PropertyCondition(AutomationElement.ClassNameProperty, ClassName)); } if (!String.IsNullOrEmpty(Name)) { conditions.Add(new PropertyCondition(AutomationElement.NameProperty, EnvironmentVariableSubstitution(Name, environmentVariableLookup))); } if (!String.IsNullOrEmpty(AutomationId)) { conditions.Add(new PropertyCondition(AutomationElement.AutomationIdProperty, AutomationId)); } if (!String.IsNullOrEmpty(ControlTypeLocalizedControlType)) { conditions.Add(new PropertyCondition(AutomationElement.LocalizedControlTypeProperty, ControlTypeLocalizedControlType)); } //if we have more than one condition if (conditions.Count == 0) { throw new ArgumentNullException("ClassName, Name, ControlType and AutomationId cannot all be null."); } else if (conditions.Count > 1) { condition = new AndCondition(conditions.ToArray()); } //otherwise just create the condition direcly else { condition = conditions[0]; } //.NET doesn't support TreeScope.Ancestors natively, so we'll implement by searching back up the chain AutomationElement element = null; if (this.Scope == TreeScope.Ancestors) { element = FindFirstInAncestors(this, condition); } else { var parentElement = ParentMap == null ? AutomationElement.RootElement : ParentMap.Element as AutomationElement; element = parentElement.FindFirst(this.Scope, condition); } if (element != null && CustomConditions.Count > 0) { //just assume AND operation for all custom conditions for now foreach (var cond in CustomConditions) { if (cond.Type == CustomCondition.ConditionTypes.MapExists) { cond.Map.ParentMap = ParentMap; cond.Map.BindElement(environmentVariableLookup); if (cond.Map.Element == null) { BreezyTrace.Log(TraceEventType.Information, "Custom 'MapExists' condition defined but was not satisfied. No additional action taken."); break; } else { BreezyTrace.Log(TraceEventType.Information, "Custom 'MapExists' condition returned 'true'."); switch (cond.Action) { case CustomCondition.Actions.Skipover: BreezyTrace.Log(TraceEventType.Information, "Skipping current element."); element = null; break; case CustomCondition.Actions.Continue: BreezyTrace.Log(TraceEventType.Information, "Continuing to process current element."); break; case CustomCondition.Actions.Abort: BreezyTrace.Log(TraceEventType.Information, "Aborting current element (aborting the processing chain)."); element = null; break; default: break; } } } } } this.Element = element; }