【问题标题】:How to activate a Google Chrome tab item using UI Automation如何使用 UI 自动化激活 Google Chrome 标签项
【发布时间】:2017-01-02 23:57:41
【问题描述】:

我正在使用来自 C# 应用程序的代码在 Google Chrome 中查找选项卡:

        Process[] procsChrome = Process.GetProcessesByName("chrome");
        foreach (Process chrome in procsChrome)
        {
            // the chrome process must have a window
            if (chrome.MainWindowHandle == IntPtr.Zero)
            {
                continue;
            }

            AutomationElement root = AutomationElement.FromHandle(chrome.MainWindowHandle);
            /*
            Condition condNewTab = new PropertyCondition(AutomationElement.NameProperty, "Nueva pestaña");
            AutomationElement elmNewTab = root.FindFirst(TreeScope.Descendants, condNewTab);
            // get the tabstrip by getting the parent of the 'new tab' button 
            TreeWalker treewalker = TreeWalker.ControlViewWalker;
            AutomationElement elmTabStrip = treewalker.GetParent(elmNewTab);
             */
            // loop through all the tabs and get the names which is the page title 
            Condition condTabItem = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
            foreach (AutomationElement tabitem in root.FindAll(TreeScope.Descendants, condTabItem))
            {
                Console.WriteLine(tabitem.Current.Name);

                // I NEED TO ACTIVATE THE TAB HERE

                break;
            }

            Condition condUrl = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit);
            foreach (AutomationElement edit in root.FindAll(TreeScope.Descendants, condUrl))
            {
                string value = ((System.Windows.Automation.ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern)).Current.Value;
                Console.WriteLine(value);
            }

        }

我需要使用 UI 自动化选择某些选项卡项。我该怎么做?

【问题讨论】:

    标签: c# google-chrome ui-automation


    【解决方案1】:

    对于那些绝望的灵魂,仍在寻找答案。这是我的方法,完全基于 UI 自动化 API,没有聚焦窗口和发送点击事件或热键。要使用下面的代码,您需要使用 UIAutomationCore.dll 的互操作引用,如 Guy Barker 所述。

        Process[] allChromeProcesses = Process.GetProcessesByName("chrome");
        Process[] mainChromes = allChromeProcesses.Where(p => !String.IsNullOrEmpty(p.MainWindowTitle)).ToArray();
        //...
        //Here you need to check if you have found correct chrome instance
        //...
        var uiaClassObject = new CUIAutomation();
    
        IUIAutomationElement chromeMainUIAElement = uiaClassObject.ElementFromHandle(mainChromes[0].MainWindowHandle);
        //UIA_ControlTypePropertyId =30003, UIA_TabItemControlTypeId = 50019
        IUIAutomationCondition chromeTabCondition = uiaClassObject.CreatePropertyCondition(30003, 50019); 
        var chromeTabCollection = chromeMainUIAElement.FindAll(TreeScope.TreeScope_Descendants, chromeTabCondition);
        //UIA_LegacyIAccessiblePatternId = 10018, 0 -> Number of Chrome tab you want to activate
        var lp = chromeTabCollection.GetElement(0).GetCurrentPattern(10018) as IUIAutomationLegacyIAccessiblePattern;
        lp.DoDefaultAction();
    

    您需要记住的唯一一件事是不可能搜索最小化 Chrome 窗口的选项卡。

    【讨论】:

      【解决方案2】:

      我需要解决类似的问题。由于 Chrome 没有完全实现 Windows 自动化功能,因此必须以不同的方式实现。

      感谢这个 GitHub project 我能够激活正确的 Chrome 选项卡。诀窍是按下Ctrl+tab index 来激活选项卡,如果它的位置在 1 到 8 之间(9 切换到最后一个选项卡,请参阅Chromebook keyboard shortcuts)。对于出现在集合中的标签,Ctrl+Tab 被反复按下,直到到达所需的标签。

      但是,这并不容易,因为有时选项卡可能会乱序出现在 UI 自动化集合中。我已通过为每个选项卡调用 TryGetClickablePoint 方法并按返回点的 X 坐标对选项卡进行排序来解决此问题。

      bool ActivateChromeTab(string title)
      {
        Process[] procsChrome = Process.GetProcessesByName("chrome");
        foreach (Process proc in procsChrome)
        {
          if (proc.MainWindowHandle == IntPtr.Zero)
          {
              continue;
          }
          AutomationElement root = AutomationElement.FromHandle(proc.MainWindowHandle);
          Condition condNewTab = new PropertyCondition(AutomationElement.NameProperty, "New Tab");
          AutomationElement elmNewTab = root.FindFirst(TreeScope.Descendants, condNewTab);
          TreeWalker treewalker = TreeWalker.ControlViewWalker;
          AutomationElement elmTabStrip = treewalker.GetParent(elmNewTab);
          Condition condTabItem = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
          var index = 0;
      
          var tabItems = elmTabStrip.FindAll(TreeScope.Children, condTabItem);
      
          var coll = new List<AutomationElement>();
          foreach (AutomationElement element in tabItems)
          {
              coll.Add(element);
          }
      
          bool NameMatch(string name)
          {
              return name == title || name.StartsWith(title + " ");
          }
      
          // short-circuit the search when no searched string cannot be found
          if (!coll.Any(e => NameMatch(e.Current.Name)))
          {
              continue;
          }
      
          var t = new Stopwatch();
          t.Start();
          var withPoints = coll.AsParallel().Select(e =>
          {
              var point = new System.Windows.Point(int.MaxValue, int.MaxValue);
              if (e.TryGetClickablePoint(out point))
              {
      
              }
      
              return new
              {
                  Name = e.Current.Name,
                  Element = e,
                  Point = point
              };
          }).OrderBy(e => e.Point.X);
      
          foreach (var tabItem in withPoints)
          {
              index++;
              var name = tabItem.Name;
              if (NameMatch(name))
              {
                  SetForegroundWindow(proc.MainWindowHandle); // activate window
                  Select(index); // select tab                
                  return true;
              }
          }
        }
      
        return false;
      }
      

      以及选择选项卡的方法:

      public void Select(int tabIndex)
      {
        const int maxShortcutNumber = 8;
      
        if (tabIndex <= 0) { return; }
      
        KeyDown(LCtrl);
      
        if (tabIndex <= maxShortcutNumber)
        {
          KeyPress(GetKeyNumber(tabIndex));
        }
        else
        {
          KeyPress(GetKeyNumber(maxShortcutNumber));
      
          for (var i = 0; i < tabIndex - maxShortcutNumber; i++)
          {
              i.Dump();
              const int timeToDigestPreviousKeyPress = 75;
              Thread.Sleep(timeToDigestPreviousKeyPress);
              KeyPress(Tab);
          }
        }
        KeyUp(LCtrl);
      }
      

      及键盘处理方法(改编自KeyboardSend类) [DllImport("user32.dll")] private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

      public static byte GetKeyNumber(int number)
      {
          if (number < 0 || number > 9)
              throw new ApplicationException("Invalid number for key press.");
      
          return (byte)(0x30 + number);
      }
      
      public static void KeyDown(byte vKey)
      {
          keybd_event(vKey, 0, KEYEVENTF_EXTENDEDKEY, 0);
      }
      
      public static void KeyUp(byte vKey)
      {
          keybd_event(vKey, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
      }
      
      public static void KeyPress(byte vKey)
      {
          KeyDown(vKey);
          KeyUp(vKey);
      }
      
      public static byte LCtrl = 0xA2; //VK_LCONTROL
      public static byte LWin = 0x5B; //VK_LWIN
      public static byte LAlt = 0xA4; //VK_LMENU
      public static byte Tab = 0x09; //VK_TAB
      private const int KEYEVENTF_EXTENDEDKEY = 1;
      private const int KEYEVENTF_KEYUP = 2;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-05-18
        • 2011-08-20
        • 2019-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多