Установить фокус на определенную вкладку в IE и/или FireFox

Я хочу написать приложение, которое будет отслеживать содержимое всех открытых вкладок в IE/FireFox и запускать событие после отображения определенных данных на вкладке.

Я хотел бы знать, есть ли API для IE/FF для установки фокуса на конкретную вкладку, чтобы после запуска события я устанавливал фокус на соответствующую вкладку.

заранее спасибо


person Jack Juiceson    schedule 02.05.2010    source источник


Ответы (2)


К сожалению, нет специального API для активации вкладки или установки на нее фокуса.

Ниже приведен код, как вы можете активировать вкладку, но это только для IE!

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Accessibility;

namespace IETabsInteraction
{
    internal class TabActivator
    {
        #region Nested type: OBJID

        private enum OBJID : uint
        {
            OBJID_WINDOW = 0x00000000,
        }

        #endregion

        #region Declarations

        private const int CHILDID_SELF = 0;
        private readonly IntPtr _hWnd;
        private IAccessible _accessible;

        [DllImport("oleacc.dll")]
        private static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint id, ref Guid iid,
                                                             [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object
                                                                 ppvObject);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass,
                                                  string lpszWindow);

        [DllImport("oleacc.dll")]
        private static extern int AccessibleChildren(IAccessible paccContainer, int iChildStart, int cChildren,
                                                     [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] object[] rgvarChildren, out int pcObtained);

        #endregion

        #region Constructors

        internal TabActivator(IntPtr ieHandle)
        {
            _hWnd = ieHandle;
            AccessibleObjectFromWindow(GetDirectUIHWND(ieHandle), OBJID.OBJID_WINDOW, ref _accessible);

            CheckForAccessible();
        }

        private TabActivator(IAccessible acc)
        {
            if (acc == null)
                throw new Exception("Could not get accessible");

            _accessible = acc;
        }

        #endregion

        private TabActivator[] Children
        {
            get
            {
                var num = 0;
                var res = GetAccessibleChildren(_accessible, out num);

                if (res == null)
                    return new TabActivator[0];

                var list = new List<TabActivator>(res.Length);

                foreach (object obj in res)
                {
                    var acc = obj as IAccessible;

                    if (acc != null)
                        list.Add(new TabActivator(acc));
                }

                return list.ToArray();
            }
        }

        private int ChildCount
        {
            get { return _accessible.accChildCount; }
        }

        /// <summary>
        /// Gets LocationUrl of the tab
        /// </summary>
        private string LocationUrl
        {
            get
            {
                var url = _accessible.accDescription[CHILDID_SELF];

                if (url.Contains(Environment.NewLine))
                    url = url.Split('\n')[1];

                return url;
            }
        }

        private void CheckForAccessible()
        {
            if (_accessible == null)
                throw new Exception("Could not get accessible.  Accessible can't be null");
        }

        internal void ActivateByTabsUrl(string tabsUrl)
        {
            var tabIndexToActivate = GetTabIndexToActivate(tabsUrl);

            AccessibleObjectFromWindow(GetDirectUIHWND(_hWnd), OBJID.OBJID_WINDOW, ref _accessible);

            CheckForAccessible();

            var index = 0;
            var ieDirectUIHWND = new TabActivator(_hWnd);

            foreach (var accessor in ieDirectUIHWND.Children)
            {
                foreach (var child in accessor.Children)
                {
                    foreach (var tab in child.Children)
                    {
                        if (tabIndexToActivate >= child.ChildCount - 1)
                            return;

                        if (index == tabIndexToActivate)
                        {
                            tab.ActivateTab();
                            return;
                        }

                        index++;
                    }
                }
            }
        }

        private void ActivateTab()
        {
            _accessible.accDoDefaultAction(CHILDID_SELF);
        }

        private int GetTabIndexToActivate(string tabsUrl)
        {
            AccessibleObjectFromWindow(GetDirectUIHWND(_hWnd), OBJID.OBJID_WINDOW, ref _accessible);

            CheckForAccessible();

            var index = 0;
            var ieDirectUIHWND = new TabActivator(_hWnd);

            foreach (var accessor in ieDirectUIHWND.Children)
            {
                foreach (var child in accessor.Children)
                {
                    foreach (var tab in child.Children)
                    {
                        var tabUrl = tab.LocationUrl;

                        if (!string.IsNullOrEmpty(tabUrl))
                        {
                            if (tab.LocationUrl.Contains(tabsUrl))
                                return index;
                        }

                        index++;
                    }
                }
            }

            return -1;
        }

        private IntPtr GetDirectUIHWND(IntPtr ieFrame)
        {
            // For IE 8:
            var directUI = FindWindowEx(ieFrame, IntPtr.Zero, "CommandBarClass", null);
            directUI = FindWindowEx(directUI, IntPtr.Zero, "ReBarWindow32", null);
            directUI = FindWindowEx(directUI, IntPtr.Zero, "TabBandClass", null);
            directUI = FindWindowEx(directUI, IntPtr.Zero, "DirectUIHWND", null);

            if (directUI == IntPtr.Zero)
            {
                // For IE 9:
                //directUI = FindWindowEx(ieFrame, IntPtr.Zero, "WorkerW", "Navigation Bar");
                directUI = FindWindowEx(ieFrame, IntPtr.Zero, "WorkerW", null);
                directUI = FindWindowEx(directUI, IntPtr.Zero, "ReBarWindow32", null);
                directUI = FindWindowEx(directUI, IntPtr.Zero, "TabBandClass", null);
                directUI = FindWindowEx(directUI, IntPtr.Zero, "DirectUIHWND", null);
            }

            return directUI;
        }

        private static int AccessibleObjectFromWindow(IntPtr hwnd, OBJID idObject, ref IAccessible acc)
        {
            var guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessibleobject obj = null;
            object obj = null;

            var num = AccessibleObjectFromWindow(hwnd, (uint) idObject, ref guid, ref obj);

            acc = (IAccessible) obj;

            return num;
        }

        private static object[] GetAccessibleChildren(IAccessible ao, out int childs)
        {
            childs = 0;
            object[] ret = null;
            var count = ao.accChildCount;

            if (count > 0)
            {
                ret = new object[count];
                AccessibleChildren(ao, 0, count, ret, out childs);
            }

            return ret;
        }
    }
}

Да, много строк для такой простой задачи :)

Для того, чтобы его выполнить вам понадобятся:

var ie = new ShellWindows();

// check if ie is open and get first tab of the ie
if (ie.Count > 0)
{    
    var hWnd = (IntPtr)ie.Item(0).HWND;
    new TabActivator(hWnd).ActivateByTabsUrl("www.stackoverflow.com");
}

Этот код устанавливает фокус на вкладку с определенным URL-адресом, но вы можете изменить его, чтобы активировать вкладку с определенным заголовком и т. д.

person Vlad Bezden    schedule 25.05.2012
comment
Я знаю, что это немного старый вопрос, но я нашел ваш ответ в Google. Я пытаюсь реализовать это для IE8 и IE9, но получаю ошибку LocationURL в строке var url = _accessible.accDescription[CHILDID_SELF];. Ошибка говорит Property, indexer, or event 'accDescription' is not supported by the language; try directly calling accessor method 'Accessibility.IAccessible.get_accDescription(object). Я использую .NET 3.5, может в этом проблема? Можно ли это исправить? Я действительно хотел бы использовать Ваше решение :) - person Misiu; 04.10.2012
comment
Похоже, это единственный способ активировать вкладку. По моему опыту, если пользователь отключил просмотр вкладок в IE, этот код каким-то образом зависает, но в конечном итоге выдает ошибку. Теперь я сначала проверяю в реестре, включен ли просмотр вкладок, прежде чем использовать это. - person darbid; 09.07.2015

Вам придется написать доп.

Вкладки выглядят как окна для содержимого, поэтому вы можете использовать обычный объект DOM Window для получения некоторой информации о текущей вкладке и выполнения некоторых действий — close(), focus(), resizeTo() и т. д. Проблема заключается в том, что Firefox и другие современные браузеры подавляют или игнорировать некоторые из этих событий из-за блокировки всплывающих окон по умолчанию. Кроме того, содержимое не может сказать, сколько вкладок открыто или что в них запущено из соображений безопасности, поэтому, например, не будет возможности опросить их. Лучшее, что вы можете сделать, это вызвать window.opener из одного окна, чтобы узнать, какое другое окно его открыло.

Единственный способ получить полный уровень доступа — это написать надстройку. У каждого браузера есть свой собственный способ написания дополнений, некоторые из которых написать будет легче, чем другие.

person locka    schedule 18.08.2010