1

Тема: AHK: Закрытие определённой вкладки Google Chrome

Доброго времени суток Форумчане. Существует ли возможность используя AHK закрыть вкладку браузера с определенным названием?

2

Re: AHK: Закрытие определённой вкладки Google Chrome

Желательно указать браузер и приложить скриншот. И ещё: название вкладки известно заранее или формируется динамически?

3

Re: AHK: Закрытие определённой вкладки Google Chrome

Браузер Google Chrome, имя закладки заранее известно.

4

Re: AHK: Закрытие определённой вкладки Google Chrome

Можно при помощи команды ImageSearch сначала найти в окне саму вкладку, затем найти справа её кнопку-крестик "закрыть" и послать в эти координаты нажатие ЛКМ командой ControlSend.

5

Re: AHK: Закрытие определённой вкладки Google Chrome

ypppu пишет:

Можно при помощи команды ImageSearch сначала найти в окне саму вкладку, затем найти справа её кнопку-крестик "закрыть" и послать в эти координаты нажатие ЛКМ командой ControlSend.

Зачем крестик-то искать? Клик и Ctrl+w.
В качестве альтернативы, более устроившей лично меня, - перебор вкладок посредством Ctrl+TAB с проверкой имени окна (оно меняется в соответствии с именем текущей вкладки), а при нахождении те же Ctrl+w.
А вообще давно и безуспешно пытаюсь найти решение без переборов и сравнения изображений. Одно время заголовки неактивных вкладок отображались как скрытый текст, что позволяло просто найти хотя бы вкладку с уникальным заголовком. Полагаю, курить надо гуглхромовые форумы, может есть плагин, выдающий сведения о вкладках в удобоваримой для внешнего софта форме. Но плагинов, связанных с вкладками - тьма, а интересующая нас функция не сказать, что сильно востребована...

6

Re: AHK: Закрытие определённой вкладки Google Chrome

У меня так получилось. Закрываем вкладку "Яндекс" в активном окне Хрома по F10:

TabName := "Яндекс"

F10::
   AccChrome := AccObjectFromWindow(hWnd := WinExist("A"))
   if oCoords := GetCloseButtonCoords(TabName, AccChrome)
   {
      WinGetPos, X, Y,,, ahk_id %hWnd%
      X := oCoords.x - X + oCoords.w//4
      Y := oCoords.y - Y + oCoords.h//2
      ControlClick, x%X% y%Y%, ahk_id %hWnd%
   }
   return

GetCloseButtonCoords(TabName, AccObj)
{
   if AccRole(AccObj) = "язычок страницы" && AccObj.accName(0) = TabName
      Return AccLocation(AccChild(AccObj, 1))
   
   for k, v in AccChildren(AccObj)
      if location := GetCloseButtonCoords(TabName, v)
         Return location
}

AccInit()
{
   static h
   !h ? h := DllCall("LoadLibrary","Str","oleacc","Ptr")
}

AccObjectFromWindow(hWnd, idObject = -4)
{
   AccInit()
   If   DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF
      , "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81
      , NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
   Return   ComObjEnwrap(9,pacc,1)
}

AccRole(Acc, ChildId=0)
{
   try return ComObjType(Acc,"Name")="IAccessible"?AccGetRoleText(Acc.accRole(ChildId)):"invalid object"
}

AccGetRoleText(nRole)
{
   nSize := DllCall("oleacc\GetRoleText", "Uint", nRole, "Ptr", 0, "Uint", 0)
   VarSetCapacity(sRole, (A_IsUnicode?2:1)*nSize)
   DllCall("oleacc\GetRoleText", "Uint", nRole, "str", sRole, "Uint", nSize+1)
   Return   sRole
}

AccLocation(Acc, ChildId=0)
{
   try Acc.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
   catch
      return
   return   {x:NumGet(x,0,"int"), y:NumGet(y,0,"int"), w:NumGet(w,0,"int"), h:NumGet(h,0,"int")
      ,   pos:"x" NumGet(x,0,"int")" y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")}
}

AccChildren(Acc)
{
   cChildren:=Acc.accChildCount, Children:=[]
   if DllCall("oleacc\AccessibleChildren", "Ptr", ComObjValue(Acc), "Int", 0, "Int", cChildren
      , "Ptr", VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*", cChildren)=0 {
      Loop %cChildren%
         i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i)
            , Children.Insert(NumGet(varChildren,i-8)=3?child:AccQuery(child)), ObjRelease(child)
      return Children
   }
   error:=Exception("",-1)
   MsgBox, 262420, AccChildren Failed, % "File:  " error.file "`nLine: " error.line "`n`nContinue Script?"
   IfMsgBox, No
      ExitApp
}

AccChild(Acc, ChildId=0)
{
   try child:=Acc.accChild(ChildId)
   return child?AccQuery(child):
}

AccQuery(Acc)
{
   try return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}

Язык интерфейса хрома должен быть русским.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

7

Re: AHK: Закрытие определённой вкладки Google Chrome

teadrinker, куда идти курить что бы это было без участия пользователя, и проверка была раз в 5 минут?и сложно будет это реализовать под другие браузеры?(opera, firefox)

8

Re: AHK: Закрытие определённой вкладки Google Chrome

kaipov пишет:

что бы это было без участия пользователя

Как вы себе это представляете?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9

Re: AHK: Закрытие определённой вкладки Google Chrome

teadrinker, я себе это представляю, как бесконечный цикл или вызов по таймеру той процедуры, которая в вашем скрипте вызывается по нажатии F10. Возможно, kaipov представляет себе это несколько иначе.

10

Re: AHK: Закрытие определённой вкладки Google Chrome

teadrinker, Вы правы. Я это представляю как бесконечный цикл, но в виде службы, которая запускается с ОС, и например раз в 5 минут, проверяет наличие вкладки с определенным названием, и при нахождении закрывает ее.

11

Re: AHK: Закрытие определённой вкладки Google Chrome

Тогда так примерно:

#Persistent
TabName := "Яндекс"
SetTimer, TabWatch, 300000
return

TabWatch:
   WinGet, List, List, ahk_class Chrome_WidgetWin_1
   Loop % List
   {
      AccChrome := AccObjectFromWindow(hWnd := List%A_Index%)
      if oCoords := GetCloseButtonCoords(TabName, AccChrome)
      {
         WinGetPos, X, Y,,, ahk_id %hWnd%
         X := oCoords.x - X + oCoords.w//4
         Y := oCoords.y - Y + oCoords.h//2
         ControlClick, x%X% y%Y%, ahk_id %hWnd%
      }
   }
   return

GetCloseButtonCoords(TabName, AccObj)
{
   if AccRole(AccObj) = "язычок страницы" && AccObj.accName(0) = TabName
      Return AccLocation(AccChild(AccObj, 1))
   
   for k, v in AccChildren(AccObj)
      if location := GetCloseButtonCoords(TabName, v)
         Return location
}

AccInit()
{
   static h
   !h ? h := DllCall("LoadLibrary","Str","oleacc","Ptr")
}

AccObjectFromWindow(hWnd, idObject = -4)
{
   AccInit()
   If   DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF
      , "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81
      , NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
   Return   ComObjEnwrap(9,pacc,1)
}

AccRole(Acc, ChildId=0)
{
   try return ComObjType(Acc,"Name")="IAccessible"?AccGetRoleText(Acc.accRole(ChildId)):"invalid object"
}

AccGetRoleText(nRole)
{
   nSize := DllCall("oleacc\GetRoleText", "Uint", nRole, "Ptr", 0, "Uint", 0)
   VarSetCapacity(sRole, (A_IsUnicode?2:1)*nSize)
   DllCall("oleacc\GetRoleText", "Uint", nRole, "str", sRole, "Uint", nSize+1)
   Return   sRole
}

AccLocation(Acc, ChildId=0)
{
   try Acc.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
   catch
      return
   return   {x:NumGet(x,0,"int"), y:NumGet(y,0,"int"), w:NumGet(w,0,"int"), h:NumGet(h,0,"int")
      ,   pos:"x" NumGet(x,0,"int")" y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")}
}

AccChildren(Acc)
{
   cChildren:=Acc.accChildCount, Children:=[]
   if DllCall("oleacc\AccessibleChildren", "Ptr", ComObjValue(Acc), "Int", 0, "Int", cChildren
      , "Ptr", VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*", cChildren)=0 {
      Loop %cChildren%
         i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i)
            , Children.Insert(NumGet(varChildren,i-8)=3?child:AccQuery(child)), ObjRelease(child)
      return Children
   }
   error:=Exception("",-1)
   MsgBox, 262420, AccChildren Failed, % "File:  " error.file "`nLine: " error.line "`n`nContinue Script?"
   IfMsgBox, No
      ExitApp
}

AccChild(Acc, ChildId=0)
{
   try child:=Acc.accChild(ChildId)
   return child?AccQuery(child):
}

AccQuery(Acc)
{
   try return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}

Окно может быть неактивным и перекрытым, но не должно быть свёрнутым.
Ярлык скрипта положить в папку автозагрузки.
С Оперй так же нельзя, с FF можно.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

12

Re: AHK: Закрытие определённой вкладки Google Chrome

teadrinker пишет:

Тогда так примерно:

код

Окно может быть неактивным и перекрытым, но не должно быть свёрнутым.
Ярлык скрипта положить в папку автозагрузки.
С Оперй так же нельзя, с FF можно.

Чрезвычайно интересно, но много моментов, очень далеких от собственно АНК. Может кто-нибудь (не обязательно автор) взялся бы откомментировать код, чтобы, поняв его хоть отчасти, можно было бы переделать под свои нужды? Меня в частности более всего интересует механизм перебора вкладок и получения их заголовков.

13

Re: AHK: Закрытие определённой вкладки Google Chrome

Инструмент для исследования accessible-структуры окон, библиотека для работы с accessible-интерфейсом.
Accessible-структура имеет древовидную форму, объекты структуры имеют отношения parent-children. Функция GetCloseButtonCoords() в моём коде рекурсивно исследует структуру окна, двигаясь от родительских объектов к дочерним до тех пор, пока не найдёт вкладку ("язычок страницы") с нужным названием. После этого она получает и возвращает координаты кнопки закрытия вкладки. В случае с хромом это четырёхугольник вокруг реальной кнопки "с запасом", сама кнопка находится в центре его левой части. Всё это наглядно можно исследовать с помощью указанного выше инструмента.
Информация об интерфейсе Accessible в MSDN.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

14

Re: AHK: Закрытие определённой вкладки Google Chrome

teadrinker пишет:

Инструмент для исследования accessible-структуры окон, библиотека для работы с accessible-интерфейсом.
Accessible-структура имеет древовидную форму, объекты структуры имеют отношения parent-children. Функция GetCloseButtonCoords() в моём коде рекурсивно исследует структуру окна, двигаясь от родительских объектов к дочерним до тех пор, пока не найдёт вкладку ("язычок страницы") с нужным названием. После этого она получает и возвращает координаты кнопки закрытия вкладки. В случае с хромом это четырёхугольник вокруг реальной кнопки "с запасом", сама кнопка находится в центре его левой части. Всё это наглядно можно исследовать с помощью указанного выше инструмента.
Информация об интерфейсе Accessible в MSDN.

Есть ли шансы найти информацию на русском? Изучение английского даже для решения давней проблемы не входит в мои планы.

15

Re: AHK: Закрытие определённой вкладки Google Chrome

Не знаю, я не искал.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

16

Re: AHK: Закрытие определённой вкладки Google Chrome

http://images.vfl.ru/ii/1393475142/bf1a8c11/4353322.png

17

Re: AHK: Закрытие определённой вкладки Google Chrome

Бывает, не обращайте внимания.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

18

Re: AHK: Закрытие определённой вкладки Google Chrome

Дело в том, что там нет опции "разрешить" или "пропустить". А "бывает" всякий раз, как я пытаюсь скачать.
Какие сопроматы мне скурить для решения этой проблемы?

19

Re: AHK: Закрытие определённой вкладки Google Chrome

Нажми в хроме Ctrl+J, откроются загрузки и там ты сможешь скачать.

Как сказал мой дед - Я твой дед

20

Re: AHK: Закрытие определённой вкладки Google Chrome

sergeiplugatyr пишет:

Нажми в хроме Ctrl+J, откроются загрузки и там ты сможешь скачать.

Нет, там тоже не пускает.
Но таким вот образом присутствие Opera в моей системе получило практическое обоснование.
Таки интересно, что это гугл пометил сию приладу как вредоносную?

21

Re: AHK: Закрытие определённой вкладки Google Chrome

Что ж, в целом концепция ясна, но освоение для меня чрезмерно трудоемко.
Правильно ли я понимаю, что из всех этих элементов собственно к содержимому вкладки имеет отношение только текст на язычке?
Тогда получается фактически то же самое, что и при переключении вкладок с проверкой названия окна, только без этого самого переключения?
Просто в наиболее меня интересующем на данный момент частном случае заголовки вкладок одинаковы, да и вообще в Accessible Info Viewer они различаются только номером язычка и координатой-х. В этом случае метод бесполезен? Или возможно извлечь еще какие-то сведения о вкладках, не отображаемые в окне Accessible Info Viewer?

22

Re: AHK: Закрытие определённой вкладки Google Chrome

Вопрос вдогонку.

teadrinker пишет:

Окно может быть неактивным и перекрытым, но не должно быть свёрнутым.

Это условие для работы скрипта в целом или и для работы с accessible-интерфейсом в частности?

23

Re: AHK: Закрытие определённой вкладки Google Chrome

Не удается запустить вышеприведенный скрипт.
http://images.vfl.ru/ii/1393485980/8267294f/4354095.png

24

Re: AHK: Закрытие определённой вкладки Google Chrome

многобанофф пишет:

Правильно ли я понимаю, что из всех этих элементов собственно к содержимому вкладки имеет отношение только текст на язычке?

К содержимому кнопки вкладки.

многобанофф пишет:

Тогда получается фактически то же самое, что и при переключении вкладок с проверкой названия окна, только без этого самого переключения?

Ну да, именно без переключения, просто определение координат и посыл клика.

многобанофф пишет:

Вопрос вдогонку.

teadrinker пишет:

Окно может быть неактивным и перекрытым, но не должно быть свёрнутым.

Это условие для работы скрипта в целом или и для работы с accessible-интерфейсом в частности?

Имеет значение только для определения координат.

многобанофф пишет:

Не удается запустить вышеприведенный скрипт.

Виноват, отредактировал, у меня просто эти функции в библиотеке, а в скрипте название исправить забыл.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

25

Re: AHK: Закрытие определённой вкладки Google Chrome

teadrinker пишет:

Функция GetCloseButtonCoords() в моём коде рекурсивно исследует структуру окна, двигаясь от родительских объектов к дочерним до тех пор, пока не найдёт вкладку ("язычок страницы") с нужным названием. После этого она получает и возвращает координаты кнопки закрытия вкладки.

Рекурсия и прочие изящные рациональности кода, несомненно понятные и приятные для специалистов, чрезвычайно затрудняют мне использование его качестве примера.
Был бы признателен за простой пример получения названия язычка в такой частности:
http://images.vfl.ru/ii/1393519672/503515fc/4358348.png
Попутно вопросы:
1. Перебор объектов по нисходящей обязателен? Нет ли возможности прямого обращения (типа пути или адреса, для моего скрина, например, 4/1/2/3/1/3 - нечто подобное отображается в Accessible Info Viewer, только через точку)? Просто как бы я не надругивался над хромом, все равно все вкладки (в смысле язычки) располагаются в одном и том же месте древа и в одной и той же последовательности (то есть 4/1/2/3/1/1 - кнопка создания новой вкладки, а начиная с 4/1/2/3/1/2 - вкладки).
2. Скачав библиотеку, я ожидал увидеть dll, но это оказалась библиотека в смысле АНК. Я так понимаю, необходимые выдержки из нее - уже в коде приведенного выше скрипта?

26

Re: AHK: Закрытие определённой вкладки Google Chrome

многобанофф пишет:

Был бы признателен за простой пример получения названия язычка

1. В последней версии библиотеки есть Acc_Get():

MsgBox % Acc_Get("Name", "4.1.2.3.1.2", 0, "ahk_class Chrome_WidgetWin_1")   ; название первой вкладки

Но нет гарантии, что в будущих версиях Chrome этот путь останется прежним.
2. Да, чтобы можно было пользоваться, не имея библиотеки.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

27

Re: AHK: Закрытие определённой вкладки Google Chrome

teadrinker пишет:
многобанофф пишет:

Был бы признателен за простой пример получения названия язычка

1. В последней версии библиотеки есть Acc_Get():

MsgBox % Acc_Get("Name", "4.1.2.3.1.2", 0, "ahk_class Chrome_WidgetWin_1")   ; название первой вкладки

Но нет гарантии, что в будущих версиях Chrome этот путь останется прежним.

Шикааарно. Главное, чтобы вообще остался (а я так понимаю, никуда не денется), а уж какой - глянуть недолго. Премного благодарен.

28

Re: AHK: Закрытие определённой вкладки Google Chrome

Пытаюсь все-таки в меру возможностей вдумчиво укуривать басурманское чтиво.
Поднакопились вопросы, представляющиеся неразрешимыми самостоятельно.
1. Заинтересовали методы IAccessible - accDoDefaultAction, put_accValue, get_accDescription, accSelect. Первые два - просто как полезная возможность что-то нажать или ввести данные получается без (?) активизации окна. Get_accDescription занадобился, когда стал изучать кнопку "обновить страницу" хрома, по внешнему виду которой до сих пор в моих скриптах определяется окончание загрузки страницы. Так вот Description тоже при этом меняется, его отслеживать куда удобнее, чем цвет пиксела. АccSelect тоже для хрома - как я уже писал когда-то фокус при отображении флеш-приложений становится неочевидным. Accessible Info Viewer позволил в этом разобраться. Оказалось, что фокус может быть отдельно на окне с флешем и на заголовке окна. В первом случае как обычно доступны все команды окну, во втором почти все они окно минуют и идут в приложение, образно выражаясь. До сего момента приходилось лишний раз клацать по заголовку. АccSelect - заманчивая альтернатива лишнему клацанию.
Собственно вопрос. В Асс.анк я их не нашел, в Acc_Get пихать пытался, но безрезультатно. Я так понял адаптированы для АНК посредством Асс.анк не все методы, а использовать неадаптированные можно посредством DllCall с указанием туевой хучи параметров? Если да, то нельзя ли дополнить хотя бы get_accDescription и accSelect, а то сам уж точно не вкурю?
2. Пока писал, забыл. Отдельно напишу.

29

Re: AHK: Закрытие определённой вкладки Google Chrome

Попутно.
В ходе изысканий обнаружилась пресловутая строка состояния хрома (4.2). Появляется в структуре древа на время визуального отображения. Содержит элемент "текст", для которого можно извлечь некоторые атрибуты, но Value не извлекается. Жаль.

30

Re: AHK: Закрытие определённой вкладки Google Chrome

многобанофф пишет:

нельзя ли дополнить хотя бы get_accDescription и accSelect

Как будет время.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

31

Re: AHK: Закрытие определённой вкладки Google Chrome

Метод get_accDescription реализуется просто через

Description := AccObj.accDescription(varID)

где varID либо 0 (если нужно получить описание самого объекта), либо индекс дочернего объекта. Description есть не у всех объектов.
Метод accSelect так же:

AccObj.accSelect(flagsSelect, varID)

где flagsSelect — один или комбинация флагов отсюда.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

32 (изменено: teadrinker, 2014-03-03 23:25:29)

Re: AHK: Закрытие определённой вкладки Google Chrome

Я так понимаю, это подразумевает необходимость спуститься по иерархии до нужного элемента.
А можно ли достичь того же опять используя Path из Accessible Info Viewer?
Если нет - нельзя ли объяснить как навигация происходит? Из приведенного в теме скрипта никак понять не могу - обилие функций мешает. Ясно, что можно, среди прочих свойств (? здесь и далее не уверен в терминологии), узнать количество дочерних объектов, но как начать оперировать с одним из них мне непонятно.

33

Re: AHK: Закрытие определённой вкладки Google Chrome

многобанофф, избегайте ненужного цитирования, я отредактировал Ваш пост.

многобанофф пишет:

Я так понимаю, это подразумевает необходимость спуститься по иерархии до нужного элемента.
А можно ли достичь того же опять используя Path из Accessible Info Viewer?

Без разницы, как получать ссылку на объект, можно и так, и так. Браузер Crome не слишком удачный пример для использования IAccessible, он поддерживает этот интерфейс пока в незначительной степени. Если остались вопросы, создайте соответствующую тему.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

34

Re: AHK: Закрытие определённой вкладки Google Chrome

Хотелось бы задать автозакрытие определенной вкладки/сайта (или нескольких) в браузере Chrome спустя, например, минуту после ее открытия. Как это можно реализовать?

35

Re: AHK: Закрытие определённой вкладки Google Chrome

Доброго времени суток. Прошло 5 лет и способ уже не работает Если использовать скрип выше то вкладка просто выделяется, но не закрывается к сожалению. Помогите пожалуйста исправить этот не достаток, буду признателен!

36

Re: AHK: Закрытие определённой вкладки Google Chrome

Kvisk
Возможно, в Хроме какие-то использованные в скрипте названия поменялись.

37

Re: AHK: Закрытие определённой вкладки Google Chrome

Для анализа структуры iaccessible не используйте багнутый accviewer, а используйте либо:
AccExplorer32:
https://github.com/blackrosezy/gui-insp … orer32.exe
либо Inspect:
https://github.com/guolaok/Python-UIAut … er/inspect