/** * Sets the goal for the rule-sets supplied. * @param A goal with the name of a rule-set and parameters. * @return true if the goal can be met by a rule-set. */ public bool setGoal(EmptyElement goal) { if (m_ruleSets == null || m_ruleSets.Count == 0) { m_log.writeEltTime("fail"); m_log.writeAttr("rule-set", "none"); m_log.endElt(); return(false); } if (m_goal == null && goal == null) { m_log.writeEltTime("fail"); m_log.writeAttr("goal", "none"); m_log.endElt(); return(false); } if (goal != null) { m_goal = goal; // overwrite m_goal } else { goal = m_goal; } m_log.writeEltTime("new-goal"); goal.log(); m_log.endElt(); string name = goal.getName(); foreach (RuleSet rs in m_ruleSets) { if (name.Equals(rs.getName())) { m_ruleSet = rs; break; } // skip the rest of the rule-sets } if (m_ruleSet == null) { m_log.writeEltTime("fail"); m_log.writeAttr("goal", "no rule-set can solve"); m_log.endElt(); return(false); } m_substitutes = new ArrayList(2); for (int p = 0; p < m_ruleSet.formals(); p++) { // goal attributes are named the same as rule-set parameters string paramName = m_ruleSet.getParameterName(p); string value = goal.getValue(paramName); string formal = m_ruleSet.getParameterValue(p); m_substitutes.Add(new Substitute(formal, value)); } m_rules = m_ruleSet.getRules(); // use the active rule set return(true); }
/** Determines if this EmptyElement is the same as another. * Priority is ignored, negation is not ignored. * @param ee another EmptyElement that may be equal to this one * @return true if it is the same */ public bool equals(EmptyElement ee) { if (ee == null) { return(false); } bool same = m_name.Equals(ee.getName()); if (same) { return(hasSameAttributes(ee)); } return(false); }
/// <summary> /// Determines the result of a Simian action. /// When actions can't be performed the problem is logged /// and false is returned. /// </summary> /// <param name="actionRef">An action in a rule.</param> /// <returns>true if the action was initiated successfully.</returns> public bool doAction(EmptyElement actionRef) { if (actionRef.getName().Equals("launch")) { // launch the specified application bool usedModel = false; string path = actionRef.getValue("path"); if (path == null) { path = m_Config.getExePath(); usedModel = true; } string name = actionRef.getValue("name"); if (name == null) name = m_Config.getExeName(); string args = actionRef.getValue("args"); if (args == null && usedModel) args = m_Config.getExeArgs(); string work = actionRef.getValue("work"); if (work == null && usedModel) work = m_Config.getWorkDir(); return LaunchApp(path, name, args, work); } if (actionRef.getName().Equals("mark")) { // mark the node as indicated string id = actionRef.getValue("id"); // a VarNode if (id == null) return false; string As = actionRef.getValue("as"); // How to mark the node // As == null is valid for removing the mark. return m_views.Mark(id, As); } if (actionRef.getName().Equals("free")) { // free the VarNode named string id = actionRef.getValue("id"); // the VarNode to free if (id == null) return false; m_varNodes.add(id, null); } if (actionRef.getName().Equals("choose")) { // choose the control via the method and name it via id string control = actionRef.getValue("control"); // Type of the control to choose string id = actionRef.getValue("id"); // a VarNode string exclude = actionRef.getValue("exclude"); // How to choose string method = actionRef.getValue("method"); // How to choose if (!Utilities.isGoodStr(control)) return false; if (!Utilities.isGoodStr(id)) return false; if (!Utilities.isGoodStr(method)) return false; MarkedNode mn = null; if (control.Equals("view")) mn = m_views.Choose(method, exclude); if (mn == null) { m_log.writeEltTime("fail"); m_log.writeAttr(control, mn.node.Name); m_log.writeAttr("was", "not known"); m_log.endElt(); return false; } else { m_varNodes.add(id, mn); m_log.writeEltTime("selected"); m_log.writeAttr(control, mn.node.Name); m_log.writeAttr("as", id); m_log.endElt(); } } if (actionRef.getName().Equals("nav")) { // find a model path to the referenced node string to = actionRef.getValue("to"); // a VarNode string via = actionRef.getValue("via"); // a VarNode name, not set yet if (!Utilities.isGoodStr(to)) return false; MarkedNode mn = m_varNodes.get(to); if (mn == null) return false; // What kind of node is this? string role = XmlFiler.getStringAttr((XmlElement)mn.node, "role", "*not Found*"); if (role.Equals("*not Found*")) return false; MarkedNode viaN = null; if (role.Equals("view")) { // get the menu node via mn and name it "via" string xPath = "menubar//" + mn.node.Name + "[@role='menu']"; XmlPath mPath = m_GuiModel.selectToXmlPath(null, xPath); if (mPath == null) return false; // really bad! XmlNode menuNode = mPath.ModelNode; if (menuNode == null) return false; // really bad again! viaN = new MarkedNode(menuNode, null); m_varNodes.add(via, viaN); } if (viaN == null) return false; // nothing more to do at the moment } if (actionRef.getName().Equals("click")) { // click the specified control string id = actionRef.getValue("id"); // a VarNode string appPath = actionRef.getValue("on"); // an appPath string guiPath = actionRef.getValue("at"); // a giuPath string side = actionRef.getValue("side"); // "left" or "right" bool leftSide = true; if (side != null && side.Equals("right")) leftSide = false; // Id provides a context ah that must be used to find the rest of the path! // can't just use the appPath from it. What if it's a dialog? XmlNode context = null; MarkedNode mn = null; if (Utilities.isGoodStr(id)) { mn = m_varNodes.get(id); // bail out if id not defined yet. if (mn == null || mn.node == null) return false; context = mn.node; } return click(context, appPath, guiPath, leftSide); } if (actionRef.getName().Equals("close")) { // close the specified application if (m_proc != null) closeWindow(m_proc); } return true; }
/// <summary> /// Determines the result of a Simian sensation. /// Problems with sensors are not generally logged /// since they are frequently called and most are not /// fatal. /// </summary> /// <param name="sensorRef">A sensor expression in a rule.</param> /// <returns>true if the sensor detected its target.</returns> public bool sensation(EmptyElement sensorRef) { if (sensorRef.getName().Equals("window")) { // is the window showing? string id = sensorRef.getValue("id"); // a VarNode string title = sensorRef.getValue("title"); MarkedNode mn = null; if (Utilities.isGoodStr(id) && Utilities.isGoodStr(title)) { // fetch the title from the model node via id + title mn = m_varNodes.get(id); // bail out if id not defined yet. if (mn == null) return false; if (mn.node != null) title = m_GuiModel.selectToString(mn.node, title, "title"); if (!Utilities.isGoodStr(title)) return false; } else if (id == null && title == null) { // get the main window title from the model title = m_Config.getDataBase()+m_GuiModel.getTitle(); } if (title == null) return false; // model lacks title if (Utilities.isGoodStr(title)) { IntPtr winHand = FindWindow(null, title); if ((int)winHand != 0) { AccessibilityHelper ah = new AccessibilityHelper(winHand); // look for a titlebar GuiPath gPath = new GuiPath("1:NAMELESS"); AccessibilityHelper tah = ah.SearchPath(gPath, this); if (tah == null || !tah.Value.Equals(title)) return false; m_ah = ah; return true; } } } if (sensorRef.getName().Equals("tested")) { string id = sensorRef.getValue("id"); // which controls string control = sensorRef.getValue("control"); // which controls string count = sensorRef.getValue("count"); // indicates how many if (control != null && count == null) return false; if (control == null && count != null) return false; if (control == null && count == null && id == null) return false; if (id != null) { MarkedNode mn = m_varNodes.get(id); if (mn != null) { if (mn.mark == null) return false; return mn.mark.Equals("tested"); } } // if id fails to return a marked node, try a control count if (control != null) { int n = 0; int k = 0; if (control.Equals("view")) { if (m_views == null) m_views = new MarkedList(m_GuiModel, "//*[@role='view']"); n = m_views.Count(); k = m_views.Count("tested"); } if (count.Equals("all") && n == k) return true; if (count.Equals("not-all") && k < n) return true; return false; } return false; } if (sensorRef.getName().Equals("glimpse")) { string id = sensorRef.getValue("id"); // a VarNode string appPath = sensorRef.getValue("on"); // an appPath string guiPath = sensorRef.getValue("at"); // a giuPath string property = sensorRef.getValue("prop"); // an ah property string expect = sensorRef.getValue("expect"); // value expected // Id provides a context ah that must be used to find the rest of the path! // can't just use the appPath from it. What if it's a dialog? XmlNode context = null; MarkedNode mn = null; if (Utilities.isGoodStr(id)) { mn = m_varNodes.get(id); // bail out if id not defined yet. if (mn == null) return false; if (mn.node != null) context = mn.node; } return glimpse(context, appPath, guiPath, property, expect); } return false; }
/** * Sets the goal for the rule-sets supplied. * @param A goal with the name of a rule-set and parameters. * @return true if the goal can be met by a rule-set. */ public bool setGoal(EmptyElement goal) { if (m_ruleSets == null || m_ruleSets.Count == 0) { m_log.writeEltTime("fail"); m_log.writeAttr("rule-set","none"); m_log.endElt(); return false; } if (m_goal == null && goal == null) { m_log.writeEltTime("fail"); m_log.writeAttr("goal","none"); m_log.endElt(); return false; } if (goal != null) m_goal = goal; // overwrite m_goal else goal = m_goal; m_log.writeEltTime("new-goal"); goal.log(); m_log.endElt(); string name = goal.getName(); foreach (RuleSet rs in m_ruleSets) { if (name.Equals(rs.getName())) { m_ruleSet = rs; break; } // skip the rest of the rule-sets } if (m_ruleSet == null) { m_log.writeEltTime("fail"); m_log.writeAttr("goal","no rule-set can solve"); m_log.endElt(); return false; } m_substitutes = new ArrayList(2); for (int p = 0; p < m_ruleSet.formals(); p++) { // goal attributes are named the same as rule-set parameters string paramName = m_ruleSet.getParameterName(p); string value = goal.getValue(paramName); string formal = m_ruleSet.getParameterValue(p); m_substitutes.Add(new Substitute(formal,value)); } m_rules = m_ruleSet.getRules(); // use the active rule set return true; }
/** * Perform goal-driven actions based on sensor readings. * Performance continues until a "done" action is encountered. * Performance may be interrupted if a "fail" action, * runtime error or timeout occurs. * Rule order is important. Rules are evaluated in order. * The most difficult to evaluate should be the first rule, * the easiest to satisfy, the last. * @return true if the "done" action is reached, otherwise false. */ public bool act() { bool alive = true; bool result = false; Rule lastFired = null; while (alive) { // evaluate the rules in order. // the same rule can not fire twice in a row foreach (Rule rule in m_rules) { if (rule.evaluate(m_sensors, m_substitutes)) { // fire: get the rule's actions if (rule == lastFired && !rule.isFireAlways()) { break; } // skip the rest of the rules lastFired = rule; rule.logCondition(true, m_substitutes); ArrayList actions = rule.getActions(); // foreach action: foreach (EmptyElement act in actions) { // log the action. EmptyElement action = act.SubstituteCopy(m_substitutes); action.log(true); // if it is a sensact action, consume it string name = action.getName(); if (name.Equals("done")) { return(true); } if (name.Equals("fail")) { return(false); } // if (name.Equals("try")) {} // if (name.Equals("lookup")) {} // if (name.Equals("log")) {} // does the action activate another rule-set? RuleSet ActivateRs = null; foreach (RuleSet rs in m_ruleSets) { if (name.Equals(rs.getName())) { ActivateRs = rs; break; } // skip the rest of the rule-sets } if (ActivateRs != null) { // instantiate another Sensact to use the rule-set // suspend this rule-set, activate rs. result = doSubGoal(ActivateRs, action); alive = result; } else { // otherwise, send it to the appliction to exectue result = m_actions.doAction(action); alive = result; } if (!alive) { break; } } // end of for each action break; // skip the rest of the rules } // end of if rule fired } // end for each rule } return(result); }
/// <summary> /// Determines the result of a Simian sensation. /// Problems with sensors are not generally logged /// since they are frequently called and most are not /// fatal. /// </summary> /// <param name="sensorRef">A sensor expression in a rule.</param> /// <returns>true if the sensor detected its target.</returns> public bool sensation(EmptyElement sensorRef) { if (sensorRef.getName().Equals("window")) { // is the window showing? string id = sensorRef.getValue("id"); // a VarNode string title = sensorRef.getValue("title"); MarkedNode mn = null; if (Utilities.isGoodStr(id) && Utilities.isGoodStr(title)) { // fetch the title from the model node via id + title mn = m_varNodes.get(id); // bail out if id not defined yet. if (mn == null) { return(false); } if (mn.node != null) { title = m_GuiModel.selectToString(mn.node, title, "title"); } if (!Utilities.isGoodStr(title)) { return(false); } } else if (id == null && title == null) { // get the main window title from the model title = m_Config.getDataBase() + m_GuiModel.getTitle(); } if (title == null) { return(false); // model lacks title } if (Utilities.isGoodStr(title)) { IntPtr winHand = FindWindow(null, title); if ((int)winHand != 0) { AccessibilityHelper ah = new AccessibilityHelper(winHand); // look for a titlebar GuiPath gPath = new GuiPath("1:NAMELESS"); AccessibilityHelper tah = ah.SearchPath(gPath, this); if (tah == null || !tah.Value.Equals(title)) { return(false); } m_ah = ah; return(true); } } } if (sensorRef.getName().Equals("tested")) { string id = sensorRef.getValue("id"); // which controls string control = sensorRef.getValue("control"); // which controls string count = sensorRef.getValue("count"); // indicates how many if (control != null && count == null) { return(false); } if (control == null && count != null) { return(false); } if (control == null && count == null && id == null) { return(false); } if (id != null) { MarkedNode mn = m_varNodes.get(id); if (mn != null) { if (mn.mark == null) { return(false); } return(mn.mark.Equals("tested")); } } // if id fails to return a marked node, try a control count if (control != null) { int n = 0; int k = 0; if (control.Equals("view")) { if (m_views == null) { m_views = new MarkedList(m_GuiModel, "//*[@role='view']"); } n = m_views.Count(); k = m_views.Count("tested"); } if (count.Equals("all") && n == k) { return(true); } if (count.Equals("not-all") && k < n) { return(true); } return(false); } return(false); } if (sensorRef.getName().Equals("glimpse")) { string id = sensorRef.getValue("id"); // a VarNode string appPath = sensorRef.getValue("on"); // an appPath string guiPath = sensorRef.getValue("at"); // a giuPath string property = sensorRef.getValue("prop"); // an ah property string expect = sensorRef.getValue("expect"); // value expected // Id provides a context ah that must be used to find the rest of the path! // can't just use the appPath from it. What if it's a dialog? XmlNode context = null; MarkedNode mn = null; if (Utilities.isGoodStr(id)) { mn = m_varNodes.get(id); // bail out if id not defined yet. if (mn == null) { return(false); } if (mn.node != null) { context = mn.node; } } return(glimpse(context, appPath, guiPath, property, expect)); } return(false); }
/// <summary> /// Determines the result of a Simian action. /// When actions can't be performed the problem is logged /// and false is returned. /// </summary> /// <param name="actionRef">An action in a rule.</param> /// <returns>true if the action was initiated successfully.</returns> public bool doAction(EmptyElement actionRef) { if (actionRef.getName().Equals("launch")) { // launch the specified application bool usedModel = false; string path = actionRef.getValue("path"); if (path == null) { path = m_Config.getExePath(); usedModel = true; } string name = actionRef.getValue("name"); if (name == null) { name = m_Config.getExeName(); } string args = actionRef.getValue("args"); if (args == null && usedModel) { args = m_Config.getExeArgs(); } string work = actionRef.getValue("work"); if (work == null && usedModel) { work = m_Config.getWorkDir(); } return(LaunchApp(path, name, args, work)); } if (actionRef.getName().Equals("mark")) { // mark the node as indicated string id = actionRef.getValue("id"); // a VarNode if (id == null) { return(false); } string As = actionRef.getValue("as"); // How to mark the node // As == null is valid for removing the mark. return(m_views.Mark(id, As)); } if (actionRef.getName().Equals("free")) { // free the VarNode named string id = actionRef.getValue("id"); // the VarNode to free if (id == null) { return(false); } m_varNodes.add(id, null); } if (actionRef.getName().Equals("choose")) { // choose the control via the method and name it via id string control = actionRef.getValue("control"); // Type of the control to choose string id = actionRef.getValue("id"); // a VarNode string exclude = actionRef.getValue("exclude"); // How to choose string method = actionRef.getValue("method"); // How to choose if (!Utilities.isGoodStr(control)) { return(false); } if (!Utilities.isGoodStr(id)) { return(false); } if (!Utilities.isGoodStr(method)) { return(false); } MarkedNode mn = null; if (control.Equals("view")) { mn = m_views.Choose(method, exclude); } if (mn == null) { m_log.writeEltTime("fail"); m_log.writeAttr(control, mn.node.Name); m_log.writeAttr("was", "not known"); m_log.endElt(); return(false); } else { m_varNodes.add(id, mn); m_log.writeEltTime("selected"); m_log.writeAttr(control, mn.node.Name); m_log.writeAttr("as", id); m_log.endElt(); } } if (actionRef.getName().Equals("nav")) { // find a model path to the referenced node string to = actionRef.getValue("to"); // a VarNode string via = actionRef.getValue("via"); // a VarNode name, not set yet if (!Utilities.isGoodStr(to)) { return(false); } MarkedNode mn = m_varNodes.get(to); if (mn == null) { return(false); } // What kind of node is this? string role = XmlFiler.getStringAttr((XmlElement)mn.node, "role", "*not Found*"); if (role.Equals("*not Found*")) { return(false); } MarkedNode viaN = null; if (role.Equals("view")) { // get the menu node via mn and name it "via" string xPath = "menubar//" + mn.node.Name + "[@role='menu']"; XmlPath mPath = m_GuiModel.selectToXmlPath(null, xPath); if (mPath == null) { return(false); // really bad! } XmlNode menuNode = mPath.ModelNode; if (menuNode == null) { return(false); // really bad again! } viaN = new MarkedNode(menuNode, null); m_varNodes.add(via, viaN); } if (viaN == null) { return(false); // nothing more to do at the moment } } if (actionRef.getName().Equals("click")) { // click the specified control string id = actionRef.getValue("id"); // a VarNode string appPath = actionRef.getValue("on"); // an appPath string guiPath = actionRef.getValue("at"); // a giuPath string side = actionRef.getValue("side"); // "left" or "right" bool leftSide = true; if (side != null && side.Equals("right")) { leftSide = false; } // Id provides a context ah that must be used to find the rest of the path! // can't just use the appPath from it. What if it's a dialog? XmlNode context = null; MarkedNode mn = null; if (Utilities.isGoodStr(id)) { mn = m_varNodes.get(id); // bail out if id not defined yet. if (mn == null || mn.node == null) { return(false); } context = mn.node; } return(click(context, appPath, guiPath, leftSide)); } if (actionRef.getName().Equals("close")) { // close the specified application if (m_proc != null) { closeWindow(m_proc); } } return(true); }
/** Determines if this EmptyElement is the same as another. * Priority is ignored, negation is not ignored. * @param ee another EmptyElement that may be equal to this one * @return true if it is the same */ public bool equals(EmptyElement ee) { if (ee == null) return false; bool same = m_name.Equals(ee.getName()); if (same) return hasSameAttributes(ee); return false; }