1

Тема: AHK: Ожидание запуска рандомного ярлыка из определенной папки

Доброго времени суток!

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

Вообщем смысл такой:

Есть определенная открытая папка.
В папке несколько ярлычков программ / игр (список и названия которых может меняться).
Возможно ли сделать в скрипте ожидание запуска пользователем любого рандомного ярлычка из этой определенной папки? Если да, с помощью чего и как?

Грубо говоря, как только пользователь запустит любой ярлык из папки "КонкретноеНазваниеПапки", будет выполняться дальнейший код.

2

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

Можно сделать такое:
Перехват определённой кнопки в окне. Как только в игре нажата эта кнопка - перехват вырубается и запускается некая метка в которой делаются необходимые действия.

Win10x64, AHK v1.1.37.01 (Unicode 64-bit) | AHK-Wiki | Переменные и выражения | RegEx101

3

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

Можно записать путь к папке в скрипт. При запуске скрипта открывать каждый ярлык и записывать в переменные пути к исполняемым .exe файлам, но это нужно уже разбираться как устроены ярлыки, открывать нужно бинарно. Плюс проблема для стим игр - в них url адрес для  запуска.

Win10x64, AHK v1.1.37.01 (Unicode 64-bit) | AHK-Wiki | Переменные и выражения | RegEx101

4

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

__Михаил__
Конкретизирую. Есть папка "Games" в ней куча ярлыков для игр - ярлыки прямые -  на ЕХЕшники, стима и площадок там нет. Поэтому с этим проблем не будет.

__Михаил__ пишет:

Можно записать путь к папке в скрипт. При запуске скрипта открывать каждый ярлык и записывать в переменные пути к исполняемым .exe файлам

Можно поподробнее? Или пример

__Михаил__ пишет:

Перехват определённой кнопки в окне. Как только в игре нажата эта кнопка - перехват вырубается и запускается некая метка

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

5

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

Примера нет - не в курсе как верно извлекать пути к .exe'шникам.
Если перехват не нужен, можно тогда сделать постоянный цикл, который будет постоянно мониторить - запущена ли игра. Но вечный цикл = зло.

Win10x64, AHK v1.1.37.01 (Unicode 64-bit) | AHK-Wiki | Переменные и выражения | RegEx101

6

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

Отслеживаете процессы, и проверяете, как они были запущены.
Будет непросто.
https://stackoverflow.com/questions/383 … m-shortcut

7

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

Вот и я говорю, проще определять нажатие в некоторых окнах, чем выдумывать костыли.

Win10x64, AHK v1.1.37.01 (Unicode 64-bit) | AHK-Wiki | Переменные и выражения | RegEx101

8

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

Костыли это

__Михаил__ пишет:

определять нажатие в некоторых окнах

9

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

В моём основном скрипте, при нажатии на некоторые клавиши - выполняется конкретные действия. Тут уже не костыль а функциональность. Главное знать что нужно, но Michael это не указывает, следовательно фиг его знает что нужно получить в итоге.

Win10x64, AHK v1.1.37.01 (Unicode 64-bit) | AHK-Wiki | Переменные и выражения | RegEx101

10 (изменено: Michael, 2021-02-21 20:50:01)

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

__Михаил__ пишет:

Главное знать что нужно, но Michael это не указывает, следовательно фиг его знает что нужно получить в итоге

Расскажу полностью.
Дело всё в той же программке:

#SingleInstance Force
#NoEnv
SetBatchLines -1

Name = Cam OverLay

GroupAdd, AppGroup, % Name

Gui +AlwaysOnTop
Gui Color, 0x000000
Gui Add, Button, x125 y50 w102 h23, Подтвердить
Gui Add, ListBox, vG1 hwndhListbox x25 y151 w196 h160
Gui Add, Button, gNewApp hwndhBut x125 y19 w102 h23, Поиск процесса
Gui Add, Button, gOBS x15 y19 w102 h23, OBS для ЗАПИСИ
Gui Add, Button, gOBS1 x15 y50 w102 h23, OBS для СТРИМА
Gui Add, Button, gReverse x125 y104 w102 h23, Реверс
Gui Add, Button, gHide x21 y330 w205 h23, Скрыть / показать значки
Gui Add, Text, x18 y90 w210 h2 +0x10
Gui Font, c0xFFFFFF
Gui Add, GroupBox, x18 y134 w211 h188, Выбрать процесс
Gui Font
Gui Add, Edit, hwndhSear gGet vPoisk x17 y105 w100 h21, Поиск процесса...
Menu, Tray, NoIcon

;-------------------------------------------------------------------------------------------------------

for Process in ComObjGet("Winmgmts:").ExecQuery("Select * From Win32_Process")
 Txt .= Process.Caption "|"
GetSortedProcessesByLoad()
GuiControl,, % hListbox, % Txt	; Вставить из переменной.

Gui Show, w246 h365, % Name
Return

GuiClose:
ExitApp

;-------------------------------------------------------------------------------------------------------

hide:
DesktopIcons()
DesktopIcons(Show:=-1, hWnd:=0) {
If ! hWnd := DllCall("GetWindow", "Ptr",WinExist("ahk_class Progman"), "UInt",5, "Ptr")
     hWnd := DllCall("GetWindow", "Ptr",WinExist("ahk_class WorkerW"), "UInt",5, "Ptr")
If DllCall("IsWindowVisible", "Ptr",DllCall("GetWindow","Ptr",hWnd, "UInt",5, "Ptr")) != Show
   DllCall("SendMessage","Ptr",hWnd, "Ptr",0x111, "Ptr",0x7402, "Ptr",0)
}
return

;-------------------------------------------------------------------------------------------------------

OBS:
Run, C:\Program Files\obs-studio\bin\64bit\obs64.exe, C:\Program Files\obs-studio\bin\64bit\
Sleep, 9000
WinSetTitle, ahk_class Qt5152QWindowIcon, , OBS
Sleep, 200
WinMove OBS,, 307, 15, 1244, 999 ; перемещаем OBS + ресайз
Sleep, 1000
MouseMove, 300, 780
Sleep, 200
MouseClick, left, 300, 780
Sleep, 200
MouseMove, 100, 780
Sleep, 200
MouseClick, left, 100, 780
MouseClick, right, 100, 780
Sleep, 200
MouseMove, 150, 666
Sleep, 200
MouseClick, left, 150, 666
Sleep, 200
If Not ОкноБезРамокДляВебки
{
		WinMove Оконный проектор (Источник) - Cam,, 0, -3, 404, 305 ; перемещаем окошко в угол + ресайз
		WinSet Style, -0x800000, Оконный проектор (Источник) - Cam ; -рамка
		WinSet Style, -0x40000, Оконный проектор (Источник) - Cam ; -рамка
		WinSet Style, -0x400000, Оконный проектор (Источник) - Cam ; -рамка
		ОкноБезРамокДляВебки := true
}
Sleep, 200
WinMove Cam OverLay,, 1206, 373, 252, 394 ; перемещаем Cam Overlay + ресайз (нулевой)
Sleep, 200
Run, C:\Users\Администратор\Desktop\Games
Sleep, 200
WinMove Games,, 376, 164, 1138, 733 ; перемещаем Games + ресайз (нулевой)
return

;-------------------------------------------------------------------------------------------------------

OBS1:
Run, C:\Program Files\obs-studio\bin\64bit\obs64.exe, C:\Program Files\obs-studio\bin\64bit\
Sleep, 9000
WinSetTitle, ahk_class Qt5152QWindowIcon, , OBS
Sleep, 200
WinMove OBS,, 307, 15, 1244, 999 ; перемещаем OBS + ресайз
Sleep, 1000
MouseMove, 300, 805
Sleep, 200
MouseClick, left, 300, 805
Sleep, 200
MouseMove, 75, 850
Sleep, 200
MouseClick, left, 75, 850
MouseClick, right, 75, 850
Sleep, 200
MouseMove, 130, 735
Sleep, 200
MouseClick, left, 130, 735
Sleep, 200
If Not ОкноБезРамокДляВебкиСТРИМ
{
		WinMove Оконный проектор (Источник) - Cam,, 0, 0, 408, 308 ; перемещаем окошко в угол + ресайз
		WinSet Style, -0x800000, Оконный проектор (Источник) - Cam ; -рамка
		WinSet Style, -0x40000, Оконный проектор (Источник) - Cam ; -рамка
		WinSet Style, -0x400000, Оконный проектор (Источник) - Cam ; -рамка
		ОкноБезРамокДляВебкиСТРИМ := true
}
Sleep, 200
WinMove Cam OverLay,, 1206, 373, 252, 394 ; перемещаем Cam Overlay + ресайз (нулевой)
Sleep, 200
Run, C:\Users\Администратор\Desktop\Games
Sleep, 200
WinMove Games,, 376, 164, 1138, 733 ; перемещаем Games + ресайз (нулевой)
return

;-------------------------------------------------------------------------------------------------------

#IfWinActive, Ahk_Group AppGroup

; Перехват клавиши Enter в своём окне:
Enter::
KeyWait, %A_ThisHotkey%, U

ControlGetFocus, F_Now, % Name	; Получить текущий выбранный контрол.
If (F_Now = "ListBox1")		; Если фокус на списке сохранить пункт и выйти:
{
 Gui, Submit, NoHide
 ToolTip, Переменная = %G1%
 Sleep, 300
 ToolTip
 Return
}
Else If (F_Now = "Edit1")	; Поиск в списке:
{
 GoTo, Get
}

;Else
; Send, {%A_ThisHotkey%}	; Нажать Enter если нет совпадений.
Return

#If

;-------------------------------------------------------------------------------------------------------

Get:
Gui, Submit, NoHide
T=
Loop, Parse, Txt, |
{
 If InStr(A_LoopField, Poisk)
 {
  SendMessage, 390, A_Index-1, 0,, ahk_id %hListbox%	; Выделить найденный пункт.
  T := A_Index
  Break
 }
}
If !T
{
 ToolTip, Нет такого.,0,0
 Sleep, 400
}
ToolTip
Return

;-------------------------------------------------------------------------------------------------------

ButtonПодтвердить:
myVar := MaxLoad.ProcessName
Gui, Submit, NoHide
WinActivate, ahk_exe %myVar%
Sleep, 1000
BorderSize:=0
WinMove, ahk_exe %myVar%,, -BorderSize, -BorderSize, 1920+2*BorderSize, 1080+2*BorderSize
WinSet, Style, -0xC00000, ahk_exe %myVar% ; убрать рамку
Sleep, 500
WinHide, ahk_exe Cam OverLay.exe
Return

;-------------------------------------------------------------------------------------------------------

Reverse:
Reverse := !Reverse
GoSub, App

If Reverse
 Sort, Txt, R D|

GuiControl,, % hListbox, |	; Очистить список.
GuiControl,, % hListbox, % Txt	; Вставить из переменной.
Return

;-------------------------------------------------------------------------------------------------------

NewApp_Old:
Txt2 := Txt			; Резерв тек. списка.
GuiControl,, % hListbox, |	; Очистить список.
GuiControl,, % hListbox, Ожидание...
GuiControl, Disable, % hBut	; Блок кнопки.
GuiControl, Disable, % hSear	; Разблок поиска.
SetTimer, NewP, 1000		; Тест каждую секунду.
Return

;-------------------------------------------------------------------------------------------------------

NewP:	; Отсев новых программ.
ZapList = System|explorer.exe|firefox.exe|vmware-vmx.exe|obs64.exe|nvcontainer.exe

SortedProcesses := GetSortedProcessesByLoad()
MaxLoad := SortedProcesses[1]

If (MaxLoad.ProcessName ~= ZapList)
{
 ;ToolTip, % MaxLoad.ProcessName " Запрещён!"
 Return
}

GuiControl,, G1, % "|"        ; Очистить перед добавлением процесса.
GuiControl,, G1, % "" . MaxLoad.ProcessName
Return

;-------------------------------------------------------------------------------------------------------

; Обновлённый участок:
NewApp:	; Запуск / Стоп таймера - кнопка.
SW++
If !Mod(SW,2)
 GoTo, Stop

GuiControl,, G1, % "|"        ; Очистить перед добавлением процесса.
GuiControl,, G1, Ожидание...
GuiControl,, % hBut, Остановить
GuiControl, Disable, % hSear	; Блок поиска.
SetTimer, NewP, 1000		; Тест каждую секунду.
Return

Stop:
GuiControl,, % hBut, Поиск процесса
GuiControl, Enable, % hSear	; Разблок поиска.
SetTimer, NewP, Off		; Выкл. обновление.
Return

;-------------------------------------------------------------------------------------------------------


GetSortedProcessesByLoad() {
   static LoadByPid := {}, prevSystemTime := ""
   Processes := WTSEnumProcesses()
   systemTime := GetSystemTimes()
   for k, v in Processes {
      processTime := GetProcessTimes(v.PID)
      if LoadByPid[v.PID]
         v.Load := 100*(processTime - LoadByPid[v.PID]) / (systemTime - prevSystemTime)
      LoadByPid[v.PID] := processTime
   }
   if prevSystemTime
      SortedProcesses := SortByLoad(Processes)
   prevSystemTime := systemTime
   Return SortedProcesses
}

WTSEnumProcesses() {
   DllCall("Wtsapi32\WTSEnumerateProcesses", "Ptr", 0, "UInt", 0, "UInt", 1, "PtrP", pProcessInfo, "PtrP", count)
   Processes := []
   pPtr := pProcessInfo
   Loop % count {
      Processes.Push({ PID:         NumGet(pPtr + 4, "UInt")
                     , ProcessName: StrGet(NumGet(pPtr + 8)) })
      pPtr += A_PtrSize = 4 ? 16 : 24
   }
   DllCall("Wtsapi32\WTSFreeMemory", "Ptr", pProcessInfo)
   Return Processes
}

RunAsAdmin(exitIfNotAdmin := false) {
   commandLine := DllCall("GetCommandLine", "str")
   isRestarted := !!RegExMatch(commandLine, " /restart(?!\S)")
   while !( A_IsAdmin || isRestarted ) {
      try Run, % "*RunAs " . (A_IsCompiled ? """" . A_ScriptFullPath . """ /restart"
                                           : """" . A_AhkPath . """ /restart """ . A_ScriptFullPath . """")
      catch
         break 
      ExitApp
   }
   if !A_IsAdmin {
      MsgBox, Failed to run the script as admin!
      if exitIfNotAdmin
         ExitApp
   }
}

SetPrivilege(privilege, enable := true) {
   static PROCESS_QUERY_INFORMATION := 0x400, TOKEN_ADJUST_PRIVILEGES := 0x20, SE_PRIVILEGE_ENABLED := 0x2
   
   hProc := DllCall("OpenProcess", "UInt", PROCESS_QUERY_INFORMATION, "Int", false, "UInt", DllCall("GetCurrentProcessId"), "Ptr")
   DllCall("Advapi32\OpenProcessToken", "Ptr", hProc, "UInt", TOKEN_ADJUST_PRIVILEGES, "PtrP", token)
   
   DllCall("Advapi32\LookupPrivilegeValue", "Ptr", 0, "Str", privilege, "Int64P", luid)
   VarSetCapacity(TOKEN_PRIVILEGES, 16, 0)
   NumPut(1, TOKEN_PRIVILEGES, "UInt")
   NumPut(luid, TOKEN_PRIVILEGES, 4, "Int64")
   NumPut(SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, 12, "UInt")
   DllCall("Advapi32\AdjustTokenPrivileges", "Ptr", token, "Int", !enable, "Ptr", &TOKEN_PRIVILEGES, "UInt", 0, "Ptr", 0, "Ptr", 0)
   res := A_LastError
   DllCall("CloseHandle", "Ptr", token)
   DllCall("CloseHandle", "Ptr", hProc)
   Return res  ; success — 0
}

GetProcessTimes(PID) {
   hProc := DllCall("OpenProcess", "UInt", PROCESS_QUERY_INFORMATION := 0x400, "int", 0, "UInt", PID, "Ptr")
   DllCall("GetProcessTimes", "Ptr", hProc, "Int64P", CreationTime, "Int64P", ExitTime, "Int64P", KernelTime, "Int64P", UserTime)
   DllCall("CloseHandle", "Ptr", hProc)
   Return KernelTime + UserTime
}

GetSystemTimes() {
   DllCall("GetSystemTimes", "Int64P", IdleTime, "Int64P", KernelTime, "Int64P", UserTime)
   Return KernelTime + UserTime
}

SortByLoad(Processes) {
   str := ""
   for k, v in Processes {
      if v.PID
         str .= (str ? "`n" : "") . v.Load . "|" . v.ProcessName . "|" . v.PID
   }
   Sort, str, N R
   SortedProcesses := []
   Loop, parse, str, `n
   {
      RegExMatch(A_LoopField, "(.*)\|(.*)\|(.+)", m)
      SortedProcesses.Push({Load: m1, ProcessName: m2, PID: m3})
   }
   Return SortedProcesses
}
Return

App:	; Создать список запущенных.
Txt = 
for Process in ComObjGet("Winmgmts:").ExecQuery("Select * From Win32_Process")
 Txt .= Process.Caption "|"
Return

F9:: 
	IfWinExist, Оконный проектор (Источник) - Cam
	{
		WinGet ExStyle, ExStyle
		if Not (ExStyle & 0x8)  ; 0x8 is WS_EX_TOPMOST. The window is always-on-top.
		{
			WinSet ExStyle, +0x20 ; чтобы клики проходили сквозь окошко
			WinSet Transparent, 255 ; прозрачность окна: 0 - максимальная, 255 - непрозрачное 
			WinSet AlwaysOnTop, On
		} else 
		 {
			WinSet ExStyle, -0x20
			WinSet Transparent, 255
			WinSet AlwaysOnTop, Off
			; переключаем режим "поверх всех" в окне игры, чтобы окошко ушло на задний план
			WinSet AlwaysOnTop, On, A
			WinSet AlwaysOnTop, Off, A
		 }
	}
Return

F12::
Run, R:\VIDEOS\РОЛИКИ НА ОБРАБОТКУ
Return

Numpad5::
WinShow, ahk_exe Cam OverLay.exe
Return

При нажатии на кнопку OBS для ЗАПИСИ либо на кнопку OBS для СТРИМА происходит следующее (вкратце):
[<Начало>] Открывается OBS, открывается оконный проектор с вебкой, все это дело ресайзится и подгоняется под мои нужны. Следом открывается папка, где у меня ярлыки игр хранятся.
[<Середина>] Я в ручную запускаю рандомный ярлык из этой папки.
[<Конец>] Далее жму кнопку Поиск процесса, в GroupBox'e высвечивается нужный процесс с игрой, я останавливаю поиск, выбираю найденный процесс и жму "Подтвердить".

Так вот, что хотелось бы:
После выполнения <Начало>, я в ручную делаю <Середина>, и как только я запустил какой либо ярлык с той папки, началось автоматическое выполнение <Конец>.

11

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

Не легче ли тогда записать свои игры сразу в программу и запускать одной кнопкой всё необходимое? Стоит ли городить огород для этого?

Win10x64, AHK v1.1.37.01 (Unicode 64-bit) | AHK-Wiki | Переменные и выражения | RegEx101

12

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

__Михаил__
Возможно, но не в моем случае, ибо игр очень много и они довольно часто меняются, чтобы записывать каждую из них.
Поэтому и хочу довести процесс программки максимально до автоматизма, ибо когда нужно все это дело использовать - времени катастрофически мало.

13

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

Вот лишние проблемы создаёте на пустом месте. Как по мне - легче в любой игре нажать например Alt + F1 - скрипт понял что это именно то окно в котором нужны какие либо манипуляции.
Зачем окно настроек вообще тогда? Зачем искать процесс игры, который нагружает процессор, зачем всё это, когда можно одной кнопкой определить уже нужный процесс.
Я не понимаю. Объясните выгоду лишних манипуляций и телодвижений.

Win10x64, AHK v1.1.37.01 (Unicode 64-bit) | AHK-Wiki | Переменные и выражения | RegEx101

14

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

Я например создал группу, добавил в неё по некому признаку либо титулу игры, теперь исключительно в них клавиши меняют свои стандартные действия на мне необходимый функционал.
Например F3 - скриншотит, G - запускает бег персонажа, Мышь5 - голосовой чат и т.д.

Win10x64, AHK v1.1.37.01 (Unicode 64-bit) | AHK-Wiki | Переменные и выражения | RegEx101

15

Re: AHK: Ожидание запуска рандомного ярлыка из определенной папки

Michael пишет:

[<Середина>] Я в ручную запускаю рандомный ярлык из этой папки.
[<Конец>] Далее жму кнопку Поиск процесса, в GroupBox'e высвечивается нужный процесс с игрой, я останавливаю поиск, выбираю найденный процесс и жму "Подтвердить".

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

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