1

Тема: AHK: Принудительно открывать окна на первом мониторе

По умолчанию окна открываются максимизированые на втором мониторе.
Нужно сделать чтобы они открывались максимизированными на первом мониторе (разрешения мониторов разные).
Вот что удалось написать, но никак не могу сделать так, что которые уже перенесены на первый монитор больше не переносились.
Дёргается всё как припадочное.
Понимаю, что сравниваю с последним активным окошком, а как сравнивать со всеми предыдущими?

#Persistent
SetTitleMatchMode 2
settimer, writer, 500
return
writer:
IfWinExist, OOo-dev Writer
{   
   winget, id, id
   if Prev_id = %id% 
   return      
   x++
   WinActivate,
   WinMinimize
   WinMove, 0, 0
   WinMaximize
   Prev_id = %id%
}
return

2 (изменено: Malcev, 2012-02-05 13:24:45)

Re: AHK: Принудительно открывать окна на первом мониторе

Вообщем, не мудрствуя лукаво...

SetTitleMatchMode 2
loop
{
   WinGet, maximized, MinMax,  OOo-dev Write
   if maximized = 1
   {
      WinRestore, OOo-dev Write
      winmove,OOo-dev Writer,, 0,0,%a_screenwidth%, %A_ScreenHeight% 
   }
}

3

Re: AHK: Принудительно открывать окна на первом мониторе

1) Нужно создать список уже развёрнутых окон.
2) Можно воспользоваться WinWaitNotActive для ожидания смены активного окна. Хотя не критично, AHK тоже просто проверяет состояние окон(для полноценного слежения за окнами нужна dll).

4

Re: AHK: Принудительно открывать окна на первом мониторе

Вот так?
А что написать вместо точек, чтобы запомнить состояние окон, которые мы уже переместили и при открытие новых окон они тоже перемещались бы на первый монитор?
В принципе мой предыдущий код решает эту проблему и меня устраивает, но хотелось бы разобраться.

SetTitleMatchMode 2
WinGet,WinArray,List, ahk_class Notepad
msgbox, %WinArray%
Loop % WinArray
{
  ......
}

5

Re: AHK: Принудительно открывать окна на первом мониторе

В AHK_L можно ассоциативные массивы использовать:

r := Array()
loop
{
   WinGet id, id, A
   if(!r[id]) ;Есть ли окно в списке
   {
      ;тут проверка, нужно ли что-то делать с окном
	  ;и если нужно, то:
	  r[id] := 1
	  ;хотя можно и все подряд окна сюда заносить, но тогда со временем список может очень сильно разростись
   }
   WinWaitNotActive, ahk_id%id% ;ждём пока активным станет другое окно
}

6

Re: AHK: Принудительно открывать окна на первом мониторе

То есть, этот код выполняет тоже самое, что и мой только с применением массивов?
И почему здесь стоит отрицание?

if(!r[id])

Получается наоборот, если нету такого номера массива.

7

Re: AHK: Принудительно открывать окна на первом мониторе

Malcev пишет:

То есть, этот код выполняет тоже самое, что и мой только с применением массивов?

Нет, это по сути способ решения целого класса задач, где нужно выполнять какие-то действия, когда окно впервые становится активным. Какая конкретно тут стоит задача я толком и не понял .

Malcev пишет:

Получается наоборот, если нету такого номера массива.

Верно, если нету, значит нужно проверить, а если есть, значит уже проверяли.

8 (изменено: Malcev, 2012-02-07 15:00:30)

Re: AHK: Принудительно открывать окна на первом мониторе

А это будет

if(r[id]) :=0

равносильно вот этому?

if(!r[id])

9

Re: AHK: Принудительно открывать окна на первом мониторе

Malcev пишет:

А это будет

if(r[id]) :=0

равносильно вот этому?

if(!r[id])

Нет. Впервые вижу, что бы условному оператору что-то присваивали. if(!r[id]) эквивалентно if((r[id]=0)||(r[id]="")).

10 (изменено: Malcev, 2012-02-07 15:39:43)

Re: AHK: Принудительно открывать окна на первом мониторе

Спасибо за разъяснения.
Теперь наконец-то дошло, как этот скрипт действует и понял разницу между равенством и присваиванием.
Очень всё логично у вас получилось.
А ещё

if((r[id]=0)||(r[id]="")).

В чём разница между пустым местом и нулём?
И можем ли мы написать так

if(r[id])!=1

11 (изменено: Александр_, 2012-02-07 15:58:31)

Re: AHK: Принудительно открывать окна на первом мониторе

Malcev пишет:

В чём разница между пустым местом и нулём?

В типах. Чтобы сравнить два значения транслятор(AutoHotkey) должен привести их к одному типу. Пример:

if(0="")
   msgbox равно
else
   msgbox не равно

Тут сравниваются целое число и строка- поскольку не любую строку можно преобразовать в целое число, сравниваться будут строки, т.е. строка "0" и строка ""(пустая строка).
А восклицательный знак в AHK- это логическое отрицание, т.е. в результате его применения мы получим 0 или 1, точнее !0 = !"" = 1, в во всех остальных случаях ноль.

Malcev пишет:

И можем ли мы написать так

Выражение должно быть в скобках. В этом примере можно.

12

Re: AHK: Принудительно открывать окна на первом мониторе

Что-то код этот не всегда срабатывает.
Смысл такой. Есть программа Nview, которая привязывает определённую программу к определённому окну при работе с несколькими мониторами.
У меня Open Office всегда открывается на втором мониторе.
Но когда я захлжу на компьютер удалённо, то я вижу только один монитор, поэтому и решил взяться за изготовление скрипта, который будет документы Open Office перемещать на первый монитор.
А в вашем скрипте по-началу работает, а потом если я закрываю окна, потом открываю новые перестает

13

Re: AHK: Принудительно открывать окна на первом мониторе

Конечно, при повторном открытиии окно получает такой же id, а оно уже есть в списке -> скрипт не срабатывает.

14

Re: AHK: Принудительно открывать окна на первом мониторе

Так это я понимаю.
Не при повторном. А при открытии новых, закрытии старых....

15 (изменено: Irbis, 2012-02-07 20:29:07)

Re: AHK: Принудительно открывать окна на первом мониторе

Тогда надо сделать проверку, когда окно стало неактивным - не прекратило ли оно своё существование?
Если да - удалить его id из списка. Добавьте в код из #5 после

WinWaitNotActive, ahk_id%id% ;ждём пока активным станет другое окно

Следующие строки:

IfWinNotExist, ahk_id%id%
   r[id] := 0

16

Re: AHK: Принудительно открывать окна на первом мониторе

Settitlematchmode 2
r := Array()
loop
{
   WinGet id, id, Notepad, A
   if(!r[id]) ;Есть ли окно в списке
   {
      Winrestore, Notepad  
      winmove, Notepad,, 0,0,%a_screenwidth%, %A_ScreenHeight% 
      r[id] := 1
   }
   WinWaitNotActive, ahk_id%id% ;ждём пока активным станет другое окно
   IfWinNotExist, ahk_id%id%
   r[id] := 0
}

При минимизировании блокнота всё дёргается как припадочное.

17

Re: AHK: Принудительно открывать окна на первом мониторе

Irbis пишет:

Конечно, при повторном открытиии окно получает такой же id, а оно уже есть в списке -> скрипт не срабатывает.

Этот id никак не зависит от открываемой программы, более того, дескрипторы всех GUI объектов хранятся в одной таблице(HANDLEENTRY), т.е. id окна вполне может достаться, например, хуку или хоткею. Этот список, кстати, спроектирован в каждый процесс. В принципе все эти хендлы являются просто ссылками, поэтому если окно создать, потом удалить и снова создать, то оно получит тот же хэндл, я как-то об этом сразу не подумал. Тогда придётся удалять закрытые окна:

r := Array()
loop
{
   WinGet id, id, A
   if(!r[id]) ;Есть ли окно в списке
   {
      r[id] := 1
	  msgbox % id
   }
   WinWaitNotActive, ahk_id%id% ;ждём пока активным станет другое окно
   For Key, value in r
   {
      IfWinNotExist, ahk_id%Key%
	  {
		 r.Remove(Key)
	  }
   }
}

18

Re: AHK: Принудительно открывать окна на первом мониторе

settitlematchmode 2
r := Array()
loop
{
   WinGet id, id, Notepad, A
   if(!r[id]) ;Есть ли окно в списке
   {
     Winrestore, Notepad  
      winmove, Notepad,, 0,0,%a_screenwidth%, %A_ScreenHeight% 
      r[id] := 1
      ; msgbox % id
   }
   WinWaitNotActive, ahk_id%id% ;ждём пока активным станет другое окно
   For Key, value in r
   {
      IfWinNotExist, ahk_id%Key%
      {
         r.Remove(Key)
      }
   }
}

Если открыть одно окно блокнота и попытаться его минимизировать, то скрипт автоматом его максимизирует.

19 (изменено: Александр_, 2012-02-08 00:15:02)

Re: AHK: Принудительно открывать окна на первом мониторе

r := Array()
loop
{
   id := WinExist("A") ;берём активное окно!
   WinGetTitle, Title, ahk_id%id% ;получаем его заголовок
   if(InStr(Title, "Блокнот")&&(!r[id])) ;Если в заголовке есть слово "Блокнот" и окна нет в списке
   {
     Winrestore, ahk_id%id%
      winmove, ahk_id%id%,, 0,0,%a_screenwidth%, %A_ScreenHeight% 
      r[id] := 1
   }
   WinWaitNotActive, ahk_id%id%
   For Key, value in r
   {
      IfWinNotExist, ahk_id%Key%
      {
         r.Remove(Key)
      }
   }
}

20

Re: AHK: Принудительно открывать окна на первом мониторе

Не, не получается.
Открываем первый блокнот, он максимизируется.
Мы его сдвигаем.
Открываем второй блокнот, он максимизируется.
Мы его закрываем.
Потом активируем первый и первый опять максимизируется.

21 (изменено: Александр_, 2012-02-08 01:06:42)

Re: AHK: Принудительно открывать окна на первом мониторе

Malcev пишет:

Не, не получается.
Открываем первый блокнот, он максимизируется.
Мы его сдвигаем.
Открываем второй блокнот, он максимизируется.
Мы его закрываем.
Потом активируем первый и первый опять максимизируется.

Пришлось раз 20 повторить, чтобы так и произошло . Похоже разрабы накосячили с массивами, если имена ключей сделать строками, то проблема, вроде, пропадает:

r := Array()
loop
{
   id := 0|WinExist("A") ;берём активное окно!
   WinGetTitle, Title, ahk_id%id% ;получаем его заголовок
   if(InStr(Title, "Блокнот")&&(!r["_" . id])) ;Если в заголовке есть слово "Блокнот" и окна нет в списке
   {
     Winrestore, ahk_id%id%
      winmove, ahk_id%id%,, 0,0,%a_screenwidth%, %A_ScreenHeight% 
      r["_" . id] := id
   }
   WinWaitNotActive, ahk_id%id%
   For Key, value in r
   {
      IfWinNotExist, ahk_id%value%
      {
         r.Remove(Key)
      }
   }
}

22 (изменено: Malcev, 2012-02-08 01:50:05)

Re: AHK: Принудительно открывать окна на первом мониторе

Да работает.
Ничего себе сколько тонкостей и сложностей, казалось бы для простой задачи.
Спасибо!

  For Key, value in r
   {
      IfWinNotExist, ahk_id%value%
      {
         r.Remove(Key)

А можете, пожалуйста, вот это объяснить.

23

Re: AHK: Принудительно открывать окна на первом мониторе

Malcev пишет:

Ничего себе сколько тонкостей и сложностей, казалось бы для простой задачи.

Тут скорее баг, чем тонкость

Malcev пишет:
  For Key, value in r
   {
      IfWinNotExist, ahk_id%value%
      {
         r.Remove(Key)

For Key, value in r- цикл по всем элементам массива r, ключ будет помещён в переменную Key, а значение в value. На примере всё понятно:

arr := Array()
arr["Key1"] := "Value1"
arr["Key2"] := "Value2"
arr["Key3"] := "Value3"
For Key, Value in arr
{
   MsgBox %Key%, %Value%
}

r.Remove(Key)- удаление элемента с ключом Key из массива r.

24 (изменено: Malcev, 2012-02-19 16:21:24)

Re: AHK: Принудительно открывать окна на первом мониторе

Александр_, случилась незадача - эти 2 кода не могут ужиться.

r := Array()
Color = 0x00000C 
Color1 = 0x0C0000
Color2 = 0x000C00
x = 500
y = 500
w = 1 
h = 1
loop
{   
  ;   1ый код
    If (InputLayout() = "Russian")
    {   
	Gui, +AlwaysOnTop -Caption +ToolWindow +LastFound
	Gui, Color, % Color
	Gui, Show, x%x% y%y% w%w% h%h% NA
    }
    Else If (InputLayout() = "Latvian")
    {   
	Gui, +AlwaysOnTop -Caption +ToolWindow +LastFound
	Gui, Color, % Color1
	Gui, Show, x%x% y%y% w%w% h%h% NA
    }
    Else If (InputLayout() = "English")
    {   
	Gui, +AlwaysOnTop -Caption +ToolWindow +LastFound
	Gui, Color, % Color2
	Gui, Show, x%x% y%y% w%w% h%h% NA
    }

  ;   2ой код

   id := 0|WinExist("A") ;берём активное окно!
   WinGetTitle, Title, ahk_id%id% ;получаем его заголовок
   if(InStr(Title, "OOo-dev")&&(!r["_" . id])) ;Если в заголовке есть слово "Блокнот" и окна нет в списке
   {
     Winrestore, ahk_id%id%
      winmove, ahk_id%id%,, 0,0,%a_screenwidth%, %A_ScreenHeight% 
      r["_" . id] := id
   }
   WinWaitNotActive, ahk_id%id%
   For Key, value in r
   {
      IfWinNotExist, ahk_id%value%
      {
         r.Remove(Key)
      }
   }
   sleep, 50
}
 
InputLayout()
{
    ThreadID := DllCall("GetWindowThreadProcessId", "Int", WinExist("A"), "Int", 0)
    HKL := DllCall("GetKeyboardLayout", "uint", ThreadID, "UShort")
    VarSetCapacity(sKbd, 260, 0)
    DllCall("GetLocaleInfo", "uint", HKL
                           , "uint", 0x1001
                           , "str",  sKbd
                           , "uint", 260)
    Return sKbd
}

И я подозреваю это из-за конфликта

WinExist("A")

Можно ли во втором коде, это чем-нибудь заменить?

25

Re: AHK: Принудительно открывать окна на первом мониторе

Не понятно, что конкретно значит "не могут ужиться", но подозреваю это из-за вызова "WinWaitNotActive"- эта функция ждёт деактивации окна и не возвращает управление пока это событие не произойдёт, т.е. раскладки будут проверятся только при смене активных окон.

26

Re: AHK: Принудительно открывать окна на первом мониторе

Да, точно!
Закомментировал эту строчку - заработало!
Притом, как вы сами сказали - она необязательна.
Спасибо!