1

Тема: AHK: Перебор меток после удержания горячей клавиши

Помогите, пожалуйста, реализовать следующее: спустя секунду после удержания горячей клавиши и до момента ее отжатия, отправляются нажатия клавиш "1", "2", "3" по кругу с заданным интервалом времени между каждым отправлением, например, в 0,2 секунды. Если горячая клавиша была отпущена ранее, чем за секунду после нажатия, то отправляет саму себя, т.е. работает как обычно.

Пытался самостоятельно реализовать данный сценарий на основе имеющихся примеров, однако, не получилось добиться необходимого результата.

Спасибо!

2

Re: AHK: Перебор меток после удержания горячей клавиши

#UseHook
q::
  KeyWait, %A_ThisHotkey%, T1
  If ErrorLevel
      While GetKeyState(A_ThisHotkey,"P") {
    SendInput {1}
    Sleep 200
    SendInput {2}
    Sleep 200
    SendInput {3}
    Sleep 200
  }
  Else
      SendInput % A_ThisHotkey
Return

3

Re: AHK: Перебор меток после удержания горячей клавиши

F1::
If f1_is_pressed != 1 ;игнорирует автоповтор
	{
	f1_is_pressed := 1
	start_time := A_TickCount
	Sleep, 1000
	While GetKeyState("F1","P")
 	{
	SoundBeep, 300, 30 ;действия при удержании F1 более секунды
	}
	}
Return



F1 Up::
f1_is_pressed := 0
elapsed_time := A_TickCount - start_time
If (elapsed_time < 1000)
SoundBeep, 1000, 100
;Send F1 ; F1 отправляет себя
Return

4

Re: AHK: Перебор меток после удержания горячей клавиши

F1::

KeyWait %A_ThisHotkey%, T1
#If ErrorLevel = 0
  n = 0
  Loop
    { n := n + 1
      If n = 4
         n = 1
      GetKeyState, state, %A_ThisHotkey%, P
      If state = U
         Return
      Send, % n
      Sleep, 200
    }
#If

5

Re: AHK: Перебор меток после удержания горячей клавиши

#UseHook
F1::
   KeyWait, % A_ThisHotkey, T1
   if !ErrorLevel
      SendInput, {%A_ThisHotkey%}
   else  {
      while GetKeyState(A_ThisHotkey, "P")  {
         SendInput, % (k := mod(A_Index, 3)) ? k : 3
         Sleep, 200
      }
   }
   Return
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

6 (изменено: becauseim, 2016-11-09 13:29:43)

Re: AHK: Перебор меток после удержания горячей клавиши

Спасибо! Не ожидал такой отзывчивости!
Вариант от teadrinker работает именно так, как задумывалось, т.к. если я отпускаю клавишу в момент отправления клавиши "2", то на этом перебор останавливается. Однако, мне не понятно, как редактировать сценарий, чтобы отправлялись по кругу совершенно иные клавиши, либо происходили иные действия.

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

7

Re: AHK: Перебор меток после удержания горячей клавиши

becauseim пишет:

Вариант от teadrinker работает именно так, как задумывалось, т.к. если я отпускаю клавишу в момент отправления клавиши "2", то на этом перебор останавливается.

Для моего скрипта, нужно добавлять, после каждого send, проверку удерживается ли клавиша, чтобы добиться такого эффекта:

#UseHook
q::
  KeyWait, %A_ThisHotkey%, T1
  If ErrorLevel
      While GetKeyState(A_ThisHotkey,"P") {
    SendInput {1}
    If !GetKeyState(A_ThisHotkey,"P")
    Break
    Sleep 200
    SendInput {2}
    If !GetKeyState(A_ThisHotkey,"P")
    Break
    Sleep 200
    SendInput {3}
    If !GetKeyState(A_ThisHotkey,"P")
    Break
    Sleep 200
  }
  Else
      SendInput % A_ThisHotkey
Return

Для варианта teadrinker, можно использовать массив, чтобы легче было добавлять\изменять посылаемые клавиши:

#UseHook
Array := Array("1", "2", "3") ; список посылаемых клавиш
for i in Array ; перебор массива, для подсчета количества элементов
ArrayCount++

F1::
   KeyWait, % A_ThisHotkey, T1
   if !ErrorLevel
      SendInput, {%A_ThisHotkey%}
   else  {
      while GetKeyState(A_ThisHotkey, "P")  {
         SendInput, % Array[(k := mod(A_Index, ArrayCount)) ? k : ArrayCount]
         Sleep, 200
      }
   }
   Return

8

Re: AHK: Перебор меток после удержания горячей клавиши

SetKeyDelay, 200 ; пауза между отправленными клавишами

F1::
If f1_is_pressed != 1 ;игнорирует автоповтор
	{
	f1_is_pressed := 1
	start_time := A_TickCount
	Sleep, 1000
	While GetKeyState("F1","P")
	Send 123 ;действия при удержании F1 более секунды
	}
Return

F1 Up::
f1_is_pressed := 0
elapsed_time := A_TickCount - start_time
If (elapsed_time < 1000)
Send {F1} ;F1 отправляет себя
Return

9

Re: AHK: Перебор меток после удержания горячей клавиши

Nikva, спасибо! Ваш вариант, а также вариант от ypppu, немного не подходит, т.к. после отпускания горячей клавиши выполняется еще одна (идущая следом) метка. А вариант от teadrinker прекращает работу моментально, как и необходимо.

Заметил в моем случае неудобный момент. После длительного удержания (нескольких циклов перебора меток), модификаторы из массива переходят к горячей клавише. Т.е. проскакивает нажатие ^+m. Как от этого избавиться?

#UseHook
Array := Array("^+{f1}", "^+{f2}")
for i in Array ; перебор массива, для подсчета количества элементов
ArrayCount++

m::
   KeyWait, % A_ThisHotkey, T0.3
   if !ErrorLevel
      SendInput, {%A_ThisHotkey%}
   else  {
      while GetKeyState(A_ThisHotkey, "P")  {
         SendInput, % Array[(k := mod(A_Index, ArrayCount)) ? k : ArrayCount]
         Sleep, 500
      }
   }
   Return

10

Re: AHK: Перебор меток после удержания горячей клавиши

#UseHook
Array := ["^+{f1}", "^+{f2}"], max := Array.MaxIndex()
Return

#If processing
*sc32:: Return
#If

sc32::   ; m
   KeyWait, % A_ThisHotkey, T0.3
   if !ErrorLevel
      SendInput, {%A_ThisHotkey%}
   else  {
      while GetKeyState(A_ThisHotkey, "P") && processing := 1  {
         SendInput, % Array[(k := mod(A_Index, max)) ? k : max]
         Sleep, 500
      }
      processing := ""
   }
   Return
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

11

Re: AHK: Перебор меток после удержания горячей клавиши

teadrinker, Спасибо! Не получается задать условие работы клавиши в определенном контроле. В чем ошибка?

timeline()
{
	Global
	IfWinActive ahk_class Premiere Pro
	{
		MouseGetPos,,,, Ctrl, 2
		ControlGetPos, xCtrl, yCtrl,,,, ahk_id %ctrl%
		if ((yCtrl != 80) and (StateEditing = 520))
			{
				return !ErrorLevel
			}
	}
}

#UseHook
Array := ["^+{f2}", "^+{f7}", "^+{f5}", "^+{f6}", "^+{f1}"], max := Array.MaxIndex()
Return

#If processing
*sc32:: Return
#If

#if timeline()
sc32::   ; m
   KeyWait, % A_ThisHotkey, T0.3
   if !ErrorLevel
      SendInput, {%A_ThisHotkey%}
   else  {
      while GetKeyState(A_ThisHotkey, "P") && processing := 1  {
         SendInput, % Array[(k := mod(A_Index, max)) ? k : max]
         Sleep, 500
      }
      processing := ""
   }
   Return

12

Re: AHK: Перебор меток после удержания горячей клавиши

Давайте придерживаться темы.

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

13

Re: AHK: Перебор меток после удержания горячей клавиши

teadrinker, а как преобразовать Ваш вариант в функцию? Чтобы можно было задавать горячие клавиши примерно следующим образом:

sc32:: ; m
Hold("^+{f2}", "^+{f7}", "^+{f5}", "^+{f6}", "^+{f1}")
return

14 (изменено: teadrinker, 2017-03-20 20:33:13)

Re: AHK: Перебор меток после удержания горячей клавиши

#Persistent
Hold("sc32", "0.3", 500, "+{a}", "+{b}")

Hold(MyHotkey := "", TimeOut := "", SleepTime := "", HeldKeys*)  {
   static processing
   
   if (MyHotkey = "")
      Return
   
   else if (MyHotkey != "HotkeyFunc")  {
      HotkeyFunc := Func(A_ThisFunc).Bind("HotkeyFunc", TimeOut, SleepTime, HeldKeys*)
      Hotkey, % MyHotkey, % HotkeyFunc, On
      Hotkey, If, processing
      Hotkey, % "*" . MyHotkey, % A_ThisFunc, On
   }
   else  {
      KeyWait, % A_ThisHotkey, T%TimeOut%
      if !ErrorLevel
         SendInput, {%A_ThisHotkey%}
      else  {
         max := HeldKeys.MaxIndex()
         while GetKeyState(A_ThisHotkey, "P") && processing := 1  {
            SendInput, % HeldKeys[(k := mod(A_Index, max)) ? k : max]
            Sleep, SleepTime
         }
         processing := ""
      }
   }
   #If processing
   #If
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

15

Re: AHK: Перебор меток после удержания горячей клавиши

teadrinker, спасибо! Оформлено лучше ожидаемого, а именно с возможностью отдельно задавать задержку, но кажется, проскакивает отправление самой горячей клавиши, т.е. буквы М.

16

Re: AHK: Перебор меток после удержания горячей клавиши

Да есть такое, подумаю, как исправить.

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

17

Re: AHK: Перебор меток после удержания горячей клавиши

#Persistent
Hold("sc32", "0.3", 100, "+{a}", "+{b}")

Hold(MyHotkey := "", TimeOut := "", SleepTime := "", HeldKeys*)  {
   if (MyHotkey != "HotkeyFunc")  {
      HotkeyFunc := Func(A_ThisFunc).Bind("HotkeyFunc", TimeOut, SleepTime, HeldKeys*)
      Hotkey, % "*" . MyHotkey, % HotkeyFunc, On
   }
   else  {
      key := SubStr(A_ThisHotkey, 2)
      KeyWait, % key, T%TimeOut%
      if !ErrorLevel
         SendInput, {%key%}
      else  {
         max := HeldKeys.MaxIndex()
         while GetKeyState(key, "P")  {
            SendInput, % HeldKeys[(k := mod(A_Index, max)) ? k : max]
            Sleep, SleepTime
         }
      }
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

18

Re: AHK: Перебор меток после удержания горячей клавиши

teadrinker, спасибо! Не то, чтобы есть в этом необходимость, но интересно, почему клавиши A и B отправляются в малом регистре, если активна раскладка клавиатуры на русском языке?

19

Re: AHK: Перебор меток после удержания горячей клавиши

Сочетание Shift+b имеет смысл, только если эмулировано нажатие клавиши «b», а когда в данной раскладке такой клавиши нет, отправка осуществляется по-другому, читайте справку по Send.

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

20

Re: AHK: Перебор меток после удержания горячей клавиши

teadrinker, спасибо! А как исключить работу гк из других сочетаний? Например, функция срабатывает даже при зажатии Ctrl+Shift+M.

21 (изменено: teadrinker, 2017-03-21 23:13:14)

Re: AHK: Перебор меток после удержания горячей клавиши

У меня так вроде работает:

#Persistent
Hold( "sc32"  ; m
     , 300, 100
     , "+{m}", "{y}", "+{s}", "{c}", "{r}", "{i}", "{p}", "{t}", "{sc39}" )
Return

Hold(MyHotkey, TimeOut, SleepTime, HeldKeys*)  {
   static oInfo, WH_KEYBOARD_LL := 13
   oInfo := { MyHotkey: MyHotkey, MyHotkeySC: "0x" . SubStr(MyHotkey, 3)
            , TimeOut: TimeOut, SleepTime: SleepTime, HeldKeys: HeldKeys }
   
   DllCall("SetWindowsHookEx", Int, WH_KEYBOARD_LL
      , Ptr, RegisterCallback("LowLevelKeyboardProc", "Fast", 3, pInfo := Object(oInfo))
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr), UInt, 0, Ptr)
   ObjRelease(pInfo)
}

LowLevelKeyboardProc(nCode, wParam, lParam)  {
   static LLKHF_INJECTED := 0x10, WM_KEYDOWN := 0x100, WM_KEYUP := 0x101, timer
   
   Critical
   msg   := wParam
   flags := NumGet(lParam + 8, "UInt")
   ext   := flags & 1
   sc    := NumGet(lParam + 4, "UInt") | ext << 8
   time  := NumGet(lParam + 12, "UInt")
   INJECTED := (flags & LLKHF_INJECTED) >> 4
   oInfo := Object(A_EventInfo)
   
   if (!INJECTED && msg = WM_KEYDOWN && oInfo.KeyDownTime != "")
      Return 1
   
   if (!INJECTED && msg = WM_KEYDOWN && sc = oInfo.MyHotkeySC && oInfo.KeyDownTime = "")  {
      if GetKeyState("Shift", "P") || GetKeyState("Alt", "P") || GetKeyState("Ctrl", "P")
         Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, Ptr, wParam, Ptr, lParam)
      
      oInfo.KeyDownTime := time
      timer := Func("SendKeys").Bind(oInfo)
      SetTimer, % timer, % "-" . oInfo.TimeOut
      Return 1
   }
   
   if (!INJECTED && msg = WM_KEYUP && sc = oInfo.MyHotkeySC && oInfo.KeyDownTime != "")  {
      SetTimer, % timer, Delete
      if (A_TickCount - oInfo.KeyDownTime <= oInfo.TimeOut)
         SendInput, % "{" oInfo.MyHotkey "}"
      oInfo.KeyDownTime := ""
      Return 1
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, Ptr, wParam, Ptr, lParam)
}

SendKeys(oInfo)  {
   max := oInfo.HeldKeys.MaxIndex()
   while oInfo.KeyDownTime  {
      SendInput, % oInfo.HeldKeys[(k := mod(A_Index, max)) ? k : max]
      Sleep, oInfo.SleepTime
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

22

Re: AHK: Перебор меток после удержания горячей клавиши

teadrinker, да, вроде работает. Спасибо! Скажите, а почему же последний вариант столь сильно увеличился в объеме в сравнении с вариантом без оформления в функцию?

23

Re: AHK: Перебор меток после удержания горячей клавиши

becauseim, если вы заметили, тут совсем другой подход.

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

24

Re: AHK: Перебор меток после удержания горячей клавиши

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

25

Re: AHK: Перебор меток после удержания горячей клавиши

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

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

26

Re: AHK: Перебор меток после удержания горячей клавиши

teadrinker, вот изначальный Ваш вариант, который мне подходит. Для того, чтобы задать несколько клавиш подобного функционала показалось целесообразным заключить скрипт в функцию, чтобы не увеличивать объем, да и упростить задание таких клавиш.

27

Re: AHK: Перебор меток после удержания горячей клавиши

becauseim пишет:

вот изначальный Ваш вариант, который мне подходит.

Он недостаточно надёжный, в нём иногда сама нажатая клавиша отсылается.

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

28

Re: AHK: Перебор меток после удержания горячей клавиши

teadrinker, горячая клавиша глобальна, несмотря на установку. Что я делаю неправильно?


#Persistent
#IfWinActive ahk_exe app.exe 
Hold( "sc32", 300, 100, "+{m}", "{y}", "+{s}", "{c}", "{r}", "{i}", "{p}", "{t}", "{sc39}" )
Return
#IfWinActive

29 (изменено: stealzy, 2017-03-26 09:59:52)

Re: AHK: Перебор меток после удержания горячей клавиши

Вы не задали ГК между двумя диезами.
Выражения # обрабатываются отдельно до запуска скрипта и внутрь ф-ии не глядят.
Либо разверните ф-ию между #If, либо засуньте #If внутрь ф-ии.
Правильным подходом будет использование Hotkey, тогда вы сможете передать WinTitle как параметр ф-ии.

Hotkey("ctrl shift C", "ahk_class CabinetWClass", "Explorer_CopySelPath", true, true, false) ; копирование пути выделеного в проводнике объекта

Hotkey(keyName, winTitle:="", func:="", args*)  {
	keyName := GetAHKhotkey(keyName) ; "ctrl shift C" → ^+vk43
	funcObj := Func(func).Bind(args*)
	Hotkey IfWinActive, % winTitle
	Hotkey % keyName, % funcObj
}

30

Re: AHK: Перебор меток после удержания горячей клавиши

becauseim пишет:

teadrinker, горячая клавиша глобальна, несмотря на установку. Что я делаю неправильно?

А в моем скрипте нет установки горячих клавиш, там другой механизм.

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

31

Re: AHK: Перебор меток после удержания горячей клавиши

teadrinker, зажатие не работает, если рядом задан хотей, например, ^+{m}.
И все еще не понял, как задать работу зажатия в конкретном окне? stealzy привел пример, но он отличается от Вашей ф-ии.

$^+m:: MsgBox 123
#Persistent
Hold("sc32", 300, 500, "^+{f2}", "^+{f7}", "^+{f5}", "^+{f6}", "^+{f8}", "^+{f4}", "^+{f3}", "^+{f1}")


Hold(MyHotkey, TimeOut, SleepTime, HeldKeys*)  {
   static oInfo, WH_KEYBOARD_LL := 13
   oInfo := { MyHotkey: MyHotkey, MyHotkeySC: "0x" . SubStr(MyHotkey, 3)
            , TimeOut: TimeOut, SleepTime: SleepTime, HeldKeys: HeldKeys }
   
   DllCall("SetWindowsHookEx", Int, WH_KEYBOARD_LL
      , Ptr, RegisterCallback("LowLevelKeyboardProc", "Fast", 3, pInfo := Object(oInfo))
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr), UInt, 0, Ptr)
   ObjRelease(pInfo)
}

LowLevelKeyboardProc(nCode, wParam, lParam)  {
   static LLKHF_INJECTED := 0x10, WM_KEYDOWN := 0x100, WM_KEYUP := 0x101, timer
   
   Critical
   msg   := wParam
   flags := NumGet(lParam + 8, "UInt")
   ext   := flags & 1
   sc    := NumGet(lParam + 4, "UInt") | ext << 8
   time  := NumGet(lParam + 12, "UInt")
   INJECTED := (flags & LLKHF_INJECTED) >> 4
   oInfo := Object(A_EventInfo)
   
   if (!INJECTED && msg = WM_KEYDOWN && oInfo.KeyDownTime != "")
      Return 1
   
   if (!INJECTED && msg = WM_KEYDOWN && sc = oInfo.MyHotkeySC && oInfo.KeyDownTime = "")  {
      if GetKeyState("Shift", "P") || GetKeyState("Alt", "P") || GetKeyState("Ctrl", "P")
         Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, Ptr, wParam, Ptr, lParam)
      
      oInfo.KeyDownTime := time
      timer := Func("SendKeys").Bind(oInfo)
      SetTimer, % timer, % "-" . oInfo.TimeOut
      Return 1
   }
   
   if (!INJECTED && msg = WM_KEYUP && sc = oInfo.MyHotkeySC && oInfo.KeyDownTime != "")  {
      SetTimer, % timer, Delete
      if (A_TickCount - oInfo.KeyDownTime <= oInfo.TimeOut)
         SendInput, % "{" oInfo.MyHotkey "}"
      oInfo.KeyDownTime := ""
      Return 1
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, Ptr, wParam, Ptr, lParam)
}

SendKeys(oInfo)  {
   max := oInfo.HeldKeys.MaxIndex()
   while oInfo.KeyDownTime  {
      SendInput, % oInfo.HeldKeys[(k := mod(A_Index, max)) ? k : max]
      Sleep, oInfo.SleepTime
   }
}

32

Re: AHK: Перебор меток после удержания горячей клавиши

becauseim

$^+m::MsgBox 123
MsgBox MsgBox не работает
becauseim пишет:

в конкретном окне?

Попроще: проверяете активность конкретного окна, посложнее: ставите оконный хук и вкл/выкл хоткей на активацию/появление окон.

33

Re: AHK: Перебор меток после удержания горячей клавиши

stealzy, а как решить проблему, при которой зажатие не работает, если рядом задана горячая клавиша с буквой M?

^+m::MsgBox 123