1 (изменено: kna1703, 2016-09-15 10:25:32)

Тема: Непрерывное воспроизведение при зажатом модификаторе

Здравствуйте!
Пришёл к новой проблеме и хотел бы спросить совета у знатоков.

Как приделать к такому коду возможность правильного вывода при зажатом модификаторе (alt, shift, ctrl)?

#MaxHotkeysPerInterval 1000
SetBatchLines -1
SetKeyDelay -1
SetTimer t,1
Arr := []

Arr["$vk31"] :=  {Send:"{vk31}" , Time:50 }
Arr["$vk31"] :=  {Send:"{vk31}" , Time:50 }
Arr["$vk32"] :=  {Send:"{vk32}" , Time:50 }
Arr["$vk33"] :=  {Send:"{vk33}" , Time:50 }
Arr["$vk34"] :=  {Send:"{vk34}" , Time:50 }
Arr["$vk35"] :=  {Send:"{vk35}" , Time:50 }
Arr["$vk36"] :=  {Send:"{vk36}" , Time:50 }
Arr["$vk46"] :=  {Send:"{vk46}" , Time:50 }
Arr["$vk47"] :=  {Send:"{vk47}" , Time:50 }
Arr["$vk51"] :=  {Send:"{vk51}" , Time:50 }
Arr["$vk43"] :=  {Send:"{vk43}" , Time:50 }
Arr["$vk45"] :=  {Send:"{vk45}" , Time:50 }
Arr["$vk54"] :=  {Send:"{vk54}" , Time:50 }
Arr["$vk54"] :=  {Send:"{vk54}" , Time:50 }
Arr["$vk56"] :=  {Send:"{vk56}" , Time:50 }
Arr["$vk5A"] :=  {Send:"{vk5A}" , Time:50 }
Arr["$vk58"] :=  {Send:"{vk58}" , Time:50 }
Arr["$vk52"] :=  {Send:"{vk52}" , Time:50 }

for i, k in Arr
    Hotkey %i%,pressing,On
pressing:
return
t:
for i, k in Arr
    if GetKeyState((RegExMatch(i,"(vk..)",hk)+"") hk1,"p")
    and (A_TickCount > Arr[i].Timer) && (Arr[i].Timer := A_TickCount + k.Time)
        Send % k.Send
return

vk2D::
Suspend
Pause,,1
return

А то получается при зажатии "shift (alt, ctrl) + 1"  что-то такое: !11111111!1!1!!1!!1!!1!!1!!1!!1
Как я понимаю, срабатывают 2 варианта обработки, а не только вывод, без задержки, восклицательного знака.
По этому получаю не верный вариант при нажимании способности с  модификатором.

p.s. Смысл кода в том, чтобы на выбранных мною кнопках не было задержки вывода символов + контролируемых повтор. Так сказать, зажал способность и пошёл автоспам.

2 (изменено: Indomito, 2016-09-15 18:35:42)

Re: Непрерывное воспроизведение при зажатом модификаторе

kna1703

1. Зачем "$"? Ответ в Справке

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

Проще использовать

#UseHook, On
Thread, NoTimers
;код например определения HotKey
Thread, NoTimers, false
#UseHook, Off

Почему проще, да просто забудешь где то поставить "$" и не сможешь найти, т.е. будешь долго искать опечатку

Удалён старый код, который был не по теме.

P.S. Это написано очень давно, т.е. когда я наткнулся первый раз на язык программирования AutoHotkey

"На каждое действие есть равная ему противодействующая критика." Постулат Харриссона
OS Windows 7 x64
AutoHotkey v1.1.32.00 - November 24, 2019
Click to Download

3 (изменено: kna1703, 2016-09-15 13:52:32)

Re: Непрерывное воспроизведение при зажатом модификаторе

Indomito пишет:

kna1703

1. Зачем "$"?

Точно не могу вспомнить почему я пришёл к "$", но это влияет на команду "Send", то есть на работу кода, который делает то, что мне нужно. (Плохо разбираюсь в AutoHotKey)

В данном случаем, если убрать символ "$", то не будет вывода.

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


Indomito
Я когда-то спрашивал обо всём этом, только не учёл в будущем использование модификаторов, а с ними не корректно работает.

+ Ссылка на старую тему с вопросом

4 (изменено: Indomito, 2016-09-15 14:38:33)

Re: Непрерывное воспроизведение при зажатом модификаторе

kna1703 Я видел эту тему, по мне там рекомендации не идеальные, но всё зависит от твоего вопроса, т.е. от ТС

#UseHook, On
Thread, NoTimers
;код например определения HotKey
Thread, NoTimers, false
#UseHook, Off

Могу дать новые парсеры для HotKey, чтения INI-файлов, расчёта .
Они изолированы т.к. я решил основные/нужные функции делать независмыми от основного кода, т.е. это "чистые" библиотеки.
Вот пример

+ Функция расчёта контрольной суммы файла
;-----------------------------------------------------------------------------------------------------------------
;                                  Функция расчёта контрольной суммы файла
; HASH типы: MD2/MD5/SHA - поддержка всеми Windows, SHA256/SHA384/SHA512 - не поддерживается Windows XP/2000
;-----------------------------------------------------------------------------------------------------------------

;НА ВХОД:
; 1-й параметр(STRING): Полный путь к файлу
; 2-й параметр(STRING): HASH-типы из списка MD2/MD5/SHA/SHA256/SHA384/SHA512

;НА ВЫХОД:
; Или контольная сумма файла(STRING)
; Или слово "ERROR"(STRING)

fnHASH(FilePath, str)
{
  CaseSensitive := False ; Не чувствительность к регистру, те Б = б
  if (str = "MD2")
        vHASH := 1
  Else if (str = "MD5")
        vHASH := 2
  Else if (str = "SHA")
        vHASH := 3
  Else if (str = "SHA256")
        vHASH := 4
  Else if (str = "SHA384")
        vHASH := 5
  Else if (str = "SHA512")
        vHASH := 6
          Else
              Return "ERROR"
  CaseSensitive := True ; Чувствительность к регистру, те Б != б
  ret := HashFile(FilePath,vHASH)
Return ret
}

/*
HASH types:
1 - MD2
2 - MD5
3 - SHA
4 - SHA256 - not supported on XP,2000
5 - SHA384 - not supported on XP,2000
6 - SHA512 - not supported on XP,2000
*/

HashFile(filePath,hashType=2)
{
	PROV_RSA_AES := 24
	CRYPT_VERIFYCONTEXT := 0xF0000000
	BUFF_SIZE := 1024 * 1024 ; 1 MB
	HP_HASHVAL := 0x0002
	HP_HASHSIZE := 0x0004
	
	HASH_ALG := hashType = 1 ? (CALG_MD2 := 32769) : HASH_ALG
	HASH_ALG := hashType = 2 ? (CALG_MD5 := 32771) : HASH_ALG
	HASH_ALG := hashType = 3 ? (CALG_SHA := 32772) : HASH_ALG
	HASH_ALG := hashType = 4 ? (CALG_SHA_256 := 32780) : HASH_ALG	;Vista+ only
	HASH_ALG := hashType = 5 ? (CALG_SHA_384 := 32781) : HASH_ALG	;Vista+ only
	HASH_ALG := hashType = 6 ? (CALG_SHA_512 := 32782) : HASH_ALG	;Vista+ only
	
	f := FileOpen(filePath,"r","CP0")
	if !IsObject(f)
		return 0
	if !hModule := DllCall( "GetModuleHandleW", "str", "Advapi32.dll", "Ptr" )
		hModule := DllCall( "LoadLibraryW", "str", "Advapi32.dll", "Ptr" )
	if !dllCall("Advapi32\CryptAcquireContextW"
				,"Ptr*",hCryptProv
				,"Uint",0
				,"Uint",0
				,"Uint",PROV_RSA_AES
				,"UInt",CRYPT_VERIFYCONTEXT )
		Goto,FreeHandles
	
	if !dllCall("Advapi32\CryptCreateHash"
				,"Ptr",hCryptProv
				,"Uint",HASH_ALG
				,"Uint",0
				,"Uint",0
				,"Ptr*",hHash )
		Goto,FreeHandles
	
	VarSetCapacity(read_buf,BUFF_SIZE,0)
	
    hCryptHashData := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "CryptHashData", "Ptr")
	While (cbCount := f.RawRead(read_buf, BUFF_SIZE))
	{
		if (cbCount = 0)
			break
		
		if !dllCall(hCryptHashData
					,"Ptr",hHash
					,"Ptr",&read_buf
					,"Uint",cbCount
					,"Uint",0 )
			Goto,FreeHandles
	}
	
	if !dllCall("Advapi32\CryptGetHashParam"
				,"Ptr",hHash
				,"Uint",HP_HASHSIZE
				,"Uint*",HashLen
				,"Uint*",HashLenSize := 4
				,"UInt",0 ) 
		Goto,FreeHandles
		
	VarSetCapacity(pbHash,HashLen,0)
	if !dllCall("Advapi32\CryptGetHashParam"
				,"Ptr",hHash
				,"Uint",HP_HASHVAL
				,"Ptr",&pbHash
				,"Uint*",HashLen
				,"UInt",0 )
		Goto,FreeHandles	
	
	SetFormat,integer,Hex
	loop,%HashLen%
	{
		num := numget(pbHash,A_index-1,"UChar")
		hashval .= substr((num >> 4),0) . substr((num & 0xf),0)
	}
	SetFormat,integer,D
		
FreeHandles:
	f.Close()
	DllCall("FreeLibrary", "Ptr", hModule)
	dllCall("Advapi32\CryptDestroyHash","Ptr",hHash)
	dllCall("Advapi32\CryptReleaseContext","Ptr",hCryptProv,"UInt",0)
	return hashval
}

P.S. Могу отправить на почту.

"На каждое действие есть равная ему противодействующая критика." Постулат Харриссона
OS Windows 7 x64
AutoHotkey v1.1.32.00 - November 24, 2019
Click to Download

5 (изменено: kna1703, 2016-09-15 14:38:17)

Re: Непрерывное воспроизведение при зажатом модификаторе

Indomito
Не совсем всё понимаю, что Вы хотите мне предложить (прочитал о парсерах - поиск информации).

Там были даны не рекомендации, а по сути готовый код, в котором я менял кнопки и скорость повтора.
Мне выстроили неплохой код (всем устраивал), при котором можно зажимать несколько хоткеев, без задержки и т.п., а сейчас мне интересно, как его сделать лучше исходя из новых задач.

6 (изменено: Indomito, 2016-09-15 15:12:52)

Re: Непрерывное воспроизведение при зажатом модификаторе

-del

"На каждое действие есть равная ему противодействующая критика." Постулат Харриссона
OS Windows 7 x64
AutoHotkey v1.1.32.00 - November 24, 2019
Click to Download

7 (изменено: Indomito, 2016-09-15 15:15:12)

Re: Непрерывное воспроизведение при зажатом модификаторе

kna1703 Парсинг - это не поиск, а разбор команд... грубо говоря.

Синтакси́ческий ана́лиз (жарг. па́рсинг) в лингвистике и информатике — процесс сопоставления линейной последовательности лексем (слов, токенов) естественного или формального языка с его формальной грамматикой. Результатом обычно является дерево разбора (синтаксическое дерево). Обычно применяется совместно с лексическим анализом. Википедия

kna1703 пишет:

Там были даны не рекомендации, а по сути готовый код, в котором я менял кнопки и скорость повтора.
Мне выстроили неплохой код (всем устраивал), при котором можно зажимать несколько хоткеев, без задержки и т.п., а сейчас мне интересно, как его сделать лучше исходя из новых задач.

Я как сис.программист ищу ошибки в том что мне предложили и его модифицирую в области стабильности, т.к. это и есть основная головная боль, т.е. кода код не срабатывает или работает ложно.

P.S. Можешь сам писать с нуля или воспользоваться готовыми библиотеками, во втором сучае я пошлю на почту, причем можешь их поправить/исправить как тебе хочется(я писал их немного сложно, учитывая все варианты).

"На каждое действие есть равная ему противодействующая критика." Постулат Харриссона
OS Windows 7 x64
AutoHotkey v1.1.32.00 - November 24, 2019
Click to Download

8 (изменено: kna1703, 2016-09-16 16:51:59)

Re: Непрерывное воспроизведение при зажатом модификаторе

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

$vk51::
Send {vk51}
return

$+vk51::
Send {+vk51}
return

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

9

Re: Непрерывное воспроизведение при зажатом модификаторе

kna1703 Попробуй решить от частного к общему.
Ctrl+1 Shift+1 Alt+1
И увидеш ошибку.

А то что я предлагал - ИЗВИНЯЮСЬ. Я не верно понял твою проблему.

"На каждое действие есть равная ему противодействующая критика." Постулат Харриссона
OS Windows 7 x64
AutoHotkey v1.1.32.00 - November 24, 2019
Click to Download

10 (изменено: kna1703, 2016-09-15 15:46:09)

Re: Непрерывное воспроизведение при зажатом модификаторе

Indomito
Получается при зажатии "shift + 1"  что-то такое: !11111111!1!1!!1!!1!!1!!1!!1!!1
А должно так: !!!!!!!!!!!!!!!!!!!

То есть, восклицательный знак пишется, как не модифицируемый "HotKey", а единица воспроизводится от кода (происходит совместно).
Как заставить "!" воспроизводиться отдельно и как команды в коде?

p.s. Извиняюсь за свой стиль написания.

11 (изменено: Indomito, 2016-09-15 16:13:19)

Re: Непрерывное воспроизведение при зажатом модификаторе

-del

"На каждое действие есть равная ему противодействующая критика." Постулат Харриссона
OS Windows 7 x64
AutoHotkey v1.1.32.00 - November 24, 2019
Click to Download

12

Re: Непрерывное воспроизведение при зажатом модификаторе

kna1703, так?

vkArray := ["31", "32", "34", "35", "36", "43", "45", "46", "47", "51", "52", "54", "56", "58", "5A"]  ; vk-коды нужных клавиш
delay := 50

for k, v in vkArray
   Hotkey, % "*$vk" . v, handler, On
Return

handler:
   While GetKeyState(key := SubStr(A_ThisHotkey, -3), "P")  {
      SendInput, {%key%}
      Sleep, delay
   }
   Return
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

13 (изменено: kna1703, 2016-09-15 17:49:25)

Re: Непрерывное воспроизведение при зажатом модификаторе

teadrinker
Не выходит с модификатором, к примеру "shift".
Вместо "!" пишется "1".

И ещё в таком варианте не получается выводить одновременно несколько разных символов при зажатии соответствующих кнопок. (Зажимаешь 1 - пишется единица, потом не отпуская нажимаешь на 2 - пишется 2, но единица перестаёт. p.s. По стандарту в "Windows" точно так же, но при возможности хотелось бы расширить границы возможного.)

14

Re: Непрерывное воспроизведение при зажатом модификаторе

kna1703 пишет:

Не выходит с модификатором, к примеру "shift".

Так тогда можно:

vkArray := ["31", "32", "34", "35", "36", "43", "45", "46", "47", "51", "52", "54", "56", "58", "5A"]  ; vk-коды нужных клавиш
dalay := 50

for k, v in vkArray  {
   Hotkey, % "$vk" . v, handler, On
   Hotkey, % "$^vk" . v, handler, On
   Hotkey, % "$+vk" . v, handler, On
   Hotkey, % "$!vk" . v, handler, On
}
Return

handler:
   key := RegExReplace(A_ThisHotkey, "\$([\^+!])?(v.*)", "$1{$2}")
   While GetKeyState(SubStr(A_ThisHotkey, -3), "P")  {
      SendInput, % key
      Sleep, dalay
   }
   Return

С «одновременно» подумаю.

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

15 (изменено: kna1703, 2016-09-19 14:26:37)

Re: Непрерывное воспроизведение при зажатом модификаторе

Огромное спасибо! Очень близко к идеалу!

Заметил ещё одну маленькую особенность у вашего варианта кода: при последовательном зажимании кнопок, к примеру, 1-2-3, после 3-ей кнопки и началом повторения круга с кнопки 1 происходит лаг в течении ~0,5 сек.
Ход из 3-ёх последовательных нажиманий происходит нормально, на 4-ый лаг, следовательно, пользоваться "автоспамом" не совсем удобно.

16

Re: Непрерывное воспроизведение при зажатом модификаторе

kna1703, ещё так можно попробовать:

SetBatchLines, -1
delay := 50
vkArray := [delay, "31", "32", "34", "35", "36", "43", "45", "46", "47", "51", "52", "54", "56", "58", "5A"]  ; vk-коды нужных клавиш, не должно быть модификаторов

DllCall("SetWindowsHookEx"
   , Int, WH_KEYBOARD_LL := 13
   , Ptr, RegisterCallback("LowLevelKeyboardProc", "Fast", 3, ptr := Object(vkArray))
   , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
   , UInt, 0, Ptr)
ObjRelease(ptr)
Return

LowLevelKeyboardProc(nCode, wParam, lParam)
{
   static LLKHF_INJECTED := 0x10, keyArr := {}
      , oMsg := {0x100: "WM_KEYDOWN", 0x101: "WM_KEYUP"}
   
   msg := wParam   
   vk := NumGet(lParam + 0, "UInt")
   flags := NumGet(lParam + 8, "UInt")
   INJECTED := (flags & LLKHF_INJECTED) >> 4
   
   for k, v in Object(A_EventInfo)  {
      if (k = 1)  {
         delay := v
         continue
      }
      if ( vk = Format("{:u}", "0x" . v) && !INJECTED )  {
         if (oMsg[msg] = "WM_KEYUP")  {
            keyArr.Delete(v)
            handler := Func("Handler").Bind(v, false)
            SetTimer, % handler, -10
         }
         else if !keyArr.HasKey(v)  {
            keyArr[v] := true
            handler := Func("Handler").Bind(v, true, delay)
            SetTimer, % handler, -10
         }
         Return true
      }
   }
   Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, Ptr, wParam, Ptr, lParam)
}
   
Handler(vk, mode, delay := "")  {
   static timers := {}
   if mode  {
      timer := Func("Sender").Bind(vk)
      timers[vk] := timer
      Sender(vk)
      SetTimer, % timer, % delay
   }
   else  {
      timer := timers[vk]
      SetTimer, % timer, Delete
   }
}
      
Sender(vk)  {
   for k, v in { Alt: "!", Ctrl: "^", Shift: "+" }
      if GetKeyState(k, "P")
         modifier .= v
   
   SendPlay, % modifier . "{vk" vk "}"
}
   
Esc::ExitApp
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

17 (изменено: kna1703, 2016-09-16 01:04:57)

Re: Непрерывное воспроизведение при зажатом модификаторе

teadrinker
Кнопки из добавленного списка не нажимаются, то есть не происходит ничего.

18

Re: Непрерывное воспроизведение при зажатом модификаторе

У меня работает, если проверять в блокноте.

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

19 (изменено: kna1703, 2016-09-16 12:37:46)

Re: Непрерывное воспроизведение при зажатом модификаторе

Кто-нибудь, проверьте пожалуйста код teadrinker, а то у меня совершенно не выходит увидеть его работоспособность + кнопка "ESC" выключает скрипт.

20

Re: Непрерывное воспроизведение при зажатом модификаторе

kna1703 пишет:

кнопка "ESC" выключает скрипт

Так и должно быть, там в конце горячая клавиша, можно убрать. Просто запустите скрипт и откройте блокнот (Notepad).

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

21 (изменено: kna1703, 2016-09-16 15:45:40)

Re: Непрерывное воспроизведение при зажатом модификаторе

teadrinker
Записал видео подтверждение своих действий.

+ Ссылка на видео

22

Re: Непрерывное воспроизведение при зажатом модификаторе

А какая ОС и какая версия AHK?

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

23 (изменено: kna1703, 2016-09-16 16:56:40)

Re: Непрерывное воспроизведение при зажатом модификаторе

teadrinker
Windows 10 Pro 64-разрядная build 10586 (с обновлениями)
Autohotkey version v1.1.24.01

p.s. То же самое и дома происходит. Хотя там такая же ОСь и версия Autohotkey'я.

24

Re: Непрерывное воспроизведение при зажатом модификаторе

А, ясно. В моём коде используется клавиатурный хук, в десятке, наверно, его что-нибудь блокирует, UAC, или что-то такое, я не разбираюсь, у меня 7. Попробуйте отключить UAC, или запустить код от администратора.

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

25 (изменено: kna1703, 2016-09-19 14:26:18)

Re: Непрерывное воспроизведение при зажатом модификаторе

Сможет ли кто-то указать на возможные ошибки в несовпадениях функции кода с windows 10?
У меня так и не вышло сделать его работоспособным.

p.s. Этот код,..:

vkArray := ["31", "32", "34", "35", "36", "43", "45", "46", "47", "51", "52", "54", "56", "58", "5A"]  ; vk-коды нужных клавиш
dalay := 50

for k, v in vkArray  {
   Hotkey, % "$vk" . v, handler, On
   Hotkey, % "$^vk" . v, handler, On
   Hotkey, % "$+vk" . v, handler, On
   Hotkey, % "$!vk" . v, handler, On
}
Return

handler:
   key := RegExReplace(A_ThisHotkey, "\$([\^+!])?(v.*)", "$1{$2}")
   While GetKeyState(SubStr(A_ThisHotkey, -3), "P")  {
      SendInput, % key
      Sleep, dalay
   }
   Return

.., вполне себе хороший вариант, только как я писал выше, есть небольшой баг (не удобство) - при последовательном зажимании кнопок, к примеру, 1-2-3, после 3-ей кнопки и началом повторения круга с кнопки 1 происходит лаг в течении ~0,5 сек.
Ход из 3-ёх последовательных нажиманий происходит нормально, на 4-ый лаг, следовательно, пользоваться "автоспамом" не совсем удобно.

+ Видео на данный эффект

Или же, как можно приделать данную функцию:

for k, v in vkArray  {
   Hotkey, % "$vk" . v, handler, On
   Hotkey, % "$^vk" . v, handler, On
   Hotkey, % "$+vk" . v, handler, On
   Hotkey, % "$!vk" . v, handler, On
}
Return

К этому коду:

#MaxHotkeysPerInterval 1000
SetBatchLines -1
SetKeyDelay -1
SetTimer t,1
Arr := []

Arr["$vk31"] :=  {Send:"{vk31}" , Time:50 }
Arr["$vk31"] :=  {Send:"{vk31}" , Time:50 }
Arr["$vk32"] :=  {Send:"{vk32}" , Time:50 }
Arr["$vk33"] :=  {Send:"{vk33}" , Time:50 }
Arr["$vk34"] :=  {Send:"{vk34}" , Time:50 }
Arr["$vk35"] :=  {Send:"{vk35}" , Time:50 }
Arr["$vk36"] :=  {Send:"{vk36}" , Time:50 }
Arr["$vk46"] :=  {Send:"{vk46}" , Time:50 }
Arr["$vk47"] :=  {Send:"{vk47}" , Time:50 }
Arr["$vk51"] :=  {Send:"{vk51}" , Time:50 }
Arr["$vk43"] :=  {Send:"{vk43}" , Time:50 }
Arr["$vk45"] :=  {Send:"{vk45}" , Time:50 }
Arr["$vk54"] :=  {Send:"{vk54}" , Time:50 }
Arr["$vk54"] :=  {Send:"{vk54}" , Time:50 }
Arr["$vk56"] :=  {Send:"{vk56}" , Time:50 }
Arr["$vk5A"] :=  {Send:"{vk5A}" , Time:50 }
Arr["$vk58"] :=  {Send:"{vk58}" , Time:50 }
Arr["$vk52"] :=  {Send:"{vk52}" , Time:50 }

for i, k in Arr
    Hotkey %i%,pressing,On
pressing:
return
t:
for i, k in Arr
    if GetKeyState((RegExMatch(i,"(vk..)",hk)+"") hk1,"p")
    and (A_TickCount > Arr[i].Timer) && (Arr[i].Timer := A_TickCount + k.Time)
        Send % k.Send
return

vk2D::
Suspend
Pause,,1
return

Для того, чтобы он работал с модификаторами.