Multithreaded customizable RGB clicker

Post gaming related scripts
Faren
Posts: 5
Joined: 19 Sep 2023, 11:39

Multithreaded customizable RGB clicker

19 Sep 2023, 11:51

Figured with all the time i put into this trying to figure it out and amount of code i probably snagged from others posts here figure i should post what i got done now
This will check X,Y position for a RGB color and if found trigger the hotkey. You can create multiple threads for different locations. Dunno if anyone else would find this useful,but here goes nothing :)

Code: Select all

; Copyright © 2023 Faren <[email protected]>
; This work is free. You can redistribute it and/or modify it under the
; terms of the Do What The Fuck You Want To Public License, Version 2,
; as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.

#include <JSON>
;OPTIMIZATIONS START
#NoEnv
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
#KeyHistory 0
#Warn
ListLines Off
Process, Priority, , A
SetBatchLines, -1
SetKeyDelay, -1, -1
SetMouseDelay, -1
SetDefaultMouseSpeed, 0
SetWinDelay, -1
SetControlDelay, -1
SendMode Input
SetWorkingDir %A_ScriptDir%
DetectHiddenWindows, on
;OPTIMIZATIONS END
CoordMode, Pixel, Screen
CoordMode, Mouse, Screen
pixelSearchMode = "RGB"
global splashFile := ".\recycle.png"
file := ".\actions.ini"
; sample file format listed at end of script
toggle := 0,
paused := 0,
global debug := 0
global error := 1
global actions := []
global actionsJSON

global numThreads := 0

Loop read, %file%
{
if SubStr(A_LoopReadLine,1,2)=="//" or SubStr(A_LoopReadLine,1,1)==";"
	continue

subarray := StrSplit(A_LoopReadLine, "csv")
if SubStr(subarray,1,2)=="//"
	continue
if SubStr(subarray,1,1)==";"
	continue
actions.Insert(subarray)
}

actionsJSON = % JSON.Dump(actions)
global	PID1:=0, pname1, execScript1,
		PID2:=0, pname2, execScript2,
		numThreads := 2
execScript1 := buildScript(1, 637, 521, 30, 225, 670, "Secondary")
execScript2 := buildScript(2, 637, 477, 45, 200, 690, "Main")

^!r::Reload  ; Ctrl+Alt+R
;=============================================================================
;   alt-` : One-Key Rotation (Single Target)
;#ifWinActive <Window Title>
`::
	toggle := !toggle
	if (toggle) {
		Loop, %numThreads% {
			DetectHiddenWindows, on
			script := execScript%A_Index%
			sname = script%A_Index%
			PID := ExecScript(script,[actionsJSON],A_AhkPath).ProcessID
			PID%A_Index% := PID
			WinWait, ahk_pid %PID%
			WinGetTitle, pname%A_Index%, ahk_pid %PID%
		}
	} else {
		killCMD := "/c taskkill /F"
		loop, %numThreads% {
			pid = PID%A_Index%
			killCMD .= " /PID "%pid%
		}
		killCMD .= " /T && exit"
		run, %comspec%  %killCMD%,, hide
	}
	ScriptStatus(toggle)
	return

!`::
	paused := !paused
	loop, %numThreads% {
		pname := pname%A_Index%
		pauseSuspendScript(pname, paused, paused)
	}
	return

buildScript(script, X:=0, Y:=0, delay:=0, tipX:=0, tipY:=0, desc="") {
	var1 =
( %
	#include <JSON>
	;OPTIMIZATIONS START
	#NoTrayIcon
	#NoEnv
	#MaxHotkeysPerInterval 99000000
	#HotkeyInterval 99000000
	#KeyHistory 0
	#Warn
	ListLines Off
	Process, Priority, , A
	SetBatchLines, -1
	SetKeyDelay, -1, -1
	SetMouseDelay, -1
	SetDefaultMouseSpeed, 0
	SetWinDelay, -1
	SetControlDelay, -1
	SendMode Input
	SetWorkingDir %A_ScriptDir%
	DetectHiddenWindows, on
	CoordMode, Pixel, Screen
	CoordMode, Mouse, Screen
	;OPTIMIZATIONS END
	global pixelSearchMode = "RGB"
	actionsJSON = %1% ; arg sent as a JSON version of actions array
	global myactions := JSON.Load(actionsJSON)

loop {
)
var2 = checkPixel(%X%, %Y%, %script%, %tipX%, %tipY%, %delay%)

var3 =
( %
	}
 	checkPixel(Byref X, Byref Y, Byref script, Byref tipX, Byref tipY, delay:=0) {
		PixelGetColor, pColor, X, Y, %pixelSearchMode%
		for _, vAction in myactions {
			while (GetKeyState("LShift", "P")){
			}
			if ((vAction.5 = 0) or (vAction.5 = script)) {
				if (pColor = vAction.2) {
; Can uncomment this to see whats being triggered in a tooltip
;					tooltip % script ": " vAction.1 ": " vAction.4 , tipX, tipY
					send % vAction.4
					break
				}
			}
		}
		DllCall("Sleep","UInt",delay)
	}
)
	execScript := var1 "`n" var2 "`n" var3
	return execScript
}

;=============================================================================
;
ScriptStatus(mode) {
	if (mode) {
		Splashimage, %splashFile%, B W50 H50 X750 Y1,,, ScriptStatus
	} else {
		SplashImage, Off
	}
}

;=============================================================================
;
Log(text,newline) {
	OutputDebug % "AHK| " text
	if (newline)
		OutputDebug % "`n"
}

;=============================================================================
;
StrSplit(InputVar, Delimiter=",", OmitChars=" `t") {
	array := []
	Loop Parse, InputVar, %Delimiter%, %OmitChars%
		array.Insert(A_LoopField)
	return array
}

;=============================================================================
; return difference in 2 rgb colors
ColorDiff(color1, color2, mode:=0) {
	Format:=A_FormatInteger
	SetFormat, Integer, hex
	r1:=color1>>16,  r2:=color2>>16
	g1:=color1>>8&0xFF,  g2:=color2>>8&0xFF
	b1:=color1&0xFF,  b2:=color2&0xFF
	SetFormat,Integer, % Format
	diffr:=Abs(r1 - r2),  diffg:=Abs(g1 - g2), diffb:=Abs(b1 - b2)
	if mode=1
		return diffr+diffg+diffb
	else return diffr>diffg&&diffr>diffb?diffr:diffg>diffb?diffg:diffb
}

;=============================================================================
; pauseSuspendScript(ScriptTitle, suspendHotkeys := False, pauseScript := False)
pauseSuspendScript(Byref ScriptTitle, suspendHotkeys := False, pauseScript := False) {	;-- function to suspend/pause another script
	prevDetectWindows := A_DetectHiddenWindows
	prevMatchMode := A_TitleMatchMode
	DetectHiddenWindows, On
	SetTitleMatchMode, 2
	if (script_id := WinExist(ScriptTitle " ahk_class AutoHotkey")) {
		; Force the script to update its Pause/Suspend checkmarks.
		SendMessage, 0x211,,,, ahk_id %script_id%  ; WM_ENTERMENULOOP
		SendMessage, 0x212,,,, ahk_id %script_id%  ; WM_EXITMENULOOP
		; Get script status from its main menu.
		mainMenu := DllCall("GetMenu", "uint", script_id)
		fileMenu := DllCall("GetSubMenu", "uint", mainMenu, "int", 0)
		isPaused := DllCall("GetMenuState", "uint", fileMenu, "uint", 4, "uint", 0x400) >> 3 & 1
		isSuspended := DllCall("GetMenuState", "uint", fileMenu, "uint", 5, "uint", 0x400) >> 3 & 1
		DllCall("CloseHandle", "uint", fileMenu)
		DllCall("CloseHandle", "uint", mainMenu)
		if (suspendHotkeys && !isSuspended) || (!suspendHotkeys && isSuspended)
			PostMessage, 0x111, 65305, 1,,  ahk_id %script_id% ; this toggles the current suspend state.
		if (pauseScript && !isPaused) || (!pauseScript && isPaused)
			PostMessage, 0x111, 65403,,,  ahk_id %script_id% ; this toggles the current pause state.
	}
	DetectHiddenWindows, %prevDetectWindows%
	SetTitleMatchMode, %prevMatchMode%
	return script_id
}

/* ===========================================================================
 * Function: ExecScript
 *     Run/execute AutoHotkey script[file, through named pipe(s) or from stdin]
 *     Mod of/inspired by HotKeyIt's DynaRun()
 * License:
 *     WTFPL [http://wtfpl.net/]
 * Syntax:
 *     exec := ExecScript( code [ , args, kwargs* ] )
 * Parameter(s)/Return Value:
 *     exec           [retval] - a WshScriptExec object [http://goo.gl/GlEzk5]
 *                               if WshShell.Exec() method is used else 0 for
 *                               WshShell.Run()
 *     script             [in] - AHK script(file) or code(string) to run/execute.
 *                               When running from stdin(*), if code contains
 *                               unicode characters, WshShell will raise an
 *                               exception.
 *     args          [in, opt] - array of command line arguments to pass to the
 *                               script. Quotes(") are automatically escaped(\").
 *     kwargs*  [in, variadic] - string in the following format: 'option=value',
 *                               where 'option' is one or more of the following
 *                               listed in the next section.
 * Options(kwargs* parameter):
 *     ahk   - path to the AutoHotkey executable to use which is relative to
 *             A_WorkingDir if an absolute path isn't specified.
 *     name  - when running through named pipes, 'name' specifies the pipe name.
 *             If omitted, a random value is generated. Otherwise, specify an
 *             asterisk(*) to run from stdin. This option is ignored when a file
 *             is specified for the 'script' parameter.
 *     dir   - working directory which is assumed to be relative to A_WorkingDir
 *             if an absolute path isn't specified.
 *     cp    - codepage [UTF-8, UTF-16, CPnnn], default is 'CP0'. 'CP' may be
 *             omitted when passing in 'CPnnn' format. Omit or use 'CP0' when
 *             running code from stdin(*).
 *     child - if 1(true), WshShell.Exec() method is used, otherwise .Run().
 *             Default is 1. Value is ignored and .Exec() is always used when
 *             running code from stdin.
 * Example:
 *     exec := ExecScript("MsgBox", ["arg"], "name=some_name", "dir=C:\Users")
 * Credits:
 *     - Lexikos for his demonstration [http://goo.gl/5IkP5R]
 *     - HotKeyIt for DynaRun() [http://goo.gl/92BBMr]
 */
ExecScript(Byref script, args:="", kwargs*) {
	;// Set default values for options first
	child  := true ;// use WshShell.Exec(), otherwise .Run()
	, name := "AHK_" . A_TickCount
	, dir  := ""
	, ahk  := A_AhkPath
	, cp   := 0

	for i, kwarg in kwargs
		if ( option := SubStr(kwarg, 1, (i := InStr(kwarg, "="))-1) )
		; the RegEx check is not really needed but is done anyways to avoid
		; accidental override of internal local var(s)
		&& ( option ~= "i)^child|name|dir|ahk|cp$" )
			%option% := SubStr(kwarg, i+1)

	pipe := (run_file := FileExist(script)) || (name == "*") ? 0 : []
	Loop % pipe ? 2 : 0
	{
		;// Create named pipe(s), throw exception on failure
		if (( pipe[A_Index] := DllCall(
		(Join, Q C
			"CreateNamedPipe"            ; http://goo.gl/3aJQg7
			"Str",  "\\.\pipe\" . name   ; lpName
			"UInt", 2                    ; dwOpenMode = PIPE_ACCESS_OUTBOUND
			"UInt", 0                    ; dwPipeMode = PIPE_TYPE_BYTE
			"UInt", 255                  ; nMaxInstances
			"UInt", 0                    ; nOutBufferSize
			"UInt", 0                    ; nInBufferSize
			"Ptr",  0                    ; nDefaultTimeOut
			"Ptr",  0                    ; lpSecurityAttributes
		)) ) == -1) ; INVALID_HANDLE_VALUE
			throw Exception("ExecScript() - Failed to create named pipe", -1, A_LastError)
	}

	; Command = {ahk_exe} /ErrorStdOut /CP{codepage} {file}
	static fso := ComObjCreate("Scripting.FileSystemObject")
	static q := Chr(34) ;// quotes("), for v1.1 and v2.0-a compatibility
	cmd := Format("{4}{1}{4} /ErrorStdOut /CP{2} {4}{3}{4}"
	    , fso.GetAbsolutePathName(ahk)
	    , cp="UTF-8" ? 65001 : cp="UTF-16" ? 1200 : cp := Round(LTrim(cp, "CPcp"))
	    , pipe ? "\\.\pipe\" . name : run_file ? script : "*", q)

	; Process and append parameters to pass to the script
	for each, arg in args
	{
		i := 0
		while (i := InStr(arg, q,, i+1)) ;// escape '"' with '\'
			if (SubStr(arg, i-1, 1) != "\")
				arg := SubStr(arg, 1, i-1) . "\" . SubStr(arg, i++)
		cmd .= " " . (InStr(arg, " ") ? q . arg . q : arg)
	}

	if cwd := (dir != "" ? A_WorkingDir : "") ;// change working directory if needed
		SetWorkingDir %dir%

	static WshShell := ComObjCreate("WScript.Shell")
	exec := (child || name == "*") ? WshShell.Exec(cmd) : WshShell.Run(cmd)

	if cwd ;// restore working directory if altered above
		SetWorkingDir %cwd%

	if !pipe ;// file or stdin(*)
	{
		if !run_file ;// run stdin
			exec.StdIn.WriteLine(script), exec.StdIn.Close()
		return exec
	}

	DllCall("ConnectNamedPipe", "Ptr", pipe[1], "Ptr", 0) ;// http://goo.gl/pwTnxj
	DllCall("CloseHandle", "Ptr", pipe[1])
	DllCall("ConnectNamedPipe", "Ptr", pipe[2], "Ptr", 0)

	if !(f := FileOpen(pipe[2], "h", cp))
		return A_LastError
	f.Write(script) ;// write dynamic code into pipe
	f.Close(), DllCall("CloseHandle", "Ptr", pipe[2]) ;// close pipe

	return exec
}

;=============================================================================
; Sample actions.ini file with 80 possible trigger colors listed
;
; var is to check for a variance in the color to trigger
; hotkey is the triggered hotkey
; zone will only let that hotkey trigger if it's in the X,Y "zone" or script # listed. 0 ignores
; should just need to modify RGB values and hotkey and a name if you want, rest can be left as is
;
;Name(color),						RGB hex,	var,	hotkey,		zone
;========================================================================
;action1(black), 					0x000000, 	0, 		!1, 		0
;action2(dark gray 4), 				0x434343, 	0, 		+2, 		0
;action3(dark gray 3), 				0x666666, 	0, 		3, 			0
;action4(dark gray 2),				0x999999, 	0, 		4, 			0
;action5(dark gray 1), 				0xB7B7B7, 	0, 		5, 			0
;action6(gray), 					0xCCCCCC, 	0, 		6, 			0
;action7(light gray 1),				0xD9D9D9, 	0, 		7, 			0
;action8(light gray 2),				0xEFEFEF, 	0, 		8, 			0
;action9(light gray 3),				0xF3F3F3, 	0, 		9, 			0
;action10(white),					0xFFFFFF, 	0, 		10, 		0
;action11(red berry),				0x980000, 	0, 		11, 		0
;action12(red),						0xFF0000, 	0, 		12, 		0
;action13(orange),					0xFF9900, 	0, 		13, 		0
;action14(yellow),					0xFFFF00, 	0, 		14, 		0
;action15(green),					0x00FF00, 	0, 		15, 		0
;action16(cyan),					0x00FFFF, 	0, 		16, 		0
;action17(cornflower blue),			0x4A86E8, 	0, 		17, 		0
;action18(blue),					0x0000FF, 	0, 		18, 		0
;action19(purple),					0x9900FF, 	0, 		19, 		0
;action20(magenta),					0xFF00FF, 	0, 		20, 		0
;action21(light red berry 3),		0xE6B8AF, 	0, 		21, 		0
;action22(light red 3),				0xF4CCCC, 	0, 		22, 		0
;action23(light orange 3),			0xFCE5CD, 	0, 		23, 		0
;action24(light yellow 3),			0xFFF2CC, 	0, 		24, 		0
;action25(light green 3),			0xD9EAD3, 	0, 		25, 		0
;action26(light cyan 3),			0xD0E0E3, 	0, 		26, 		0
;action27(light cornflower blue 3),	0xC9DAF8, 	0, 		27, 		0
;action28(light blue 3),			0xCFE2F3, 	0, 		28, 		0
;action29(light purple 3),			0xD9D2E9, 	0, 		29, 		0
;action30(light magenta 3),			0xEAD1DC, 	0, 		30, 		0
;action31(light red berry 2),		0xDD7E6B, 	0, 		31, 		0
;action32(light red 2),				0xEA9999, 	0, 		32, 		0
;action33(light orange 2),			0xF9CB9C, 	0, 		33, 		0
;action34(light yellow 2),			0xFFE599, 	0, 		34, 		0
;action35(light green 2),			0xB6D7A8, 	0, 		35, 		0
;action36(light cyan 2),			0xA2C4C9, 	0, 		36, 		0
;action37(light cornflower blue 2),	0xA4C2F4, 	0, 		37, 		0
;action38(light blue 2),			0x9FC5E8, 	0, 		38, 		0
;action39(light purple 2),			0xB4A7D6, 	0, 		39, 		0
;action40(light magenta 2),			0xD5A6BD, 	0, 		40, 		0
;action41(light red berry 1),		0xCC4125, 	0, 		41, 		0
;action42(light red 1),				0xE06666, 	0, 		42, 		0
;action43(light orange 1),			0xF6B26B, 	0, 		43, 		0
;action44(light yellow 1),			0xFFD966, 	0, 		44, 		0
;action45(light green 1),			0x93C47D, 	0, 		45, 		0
;action46(light cyan 1),			0x76A5AF, 	0, 		46, 		0
;action47(light cornflower blue 1),	0x6D9EEB, 	0, 		47, 		0
;action48(light blue 1),			0x6FA8DC, 	0, 		48, 		0
;action49(light purple 1),			0x8E7CC3, 	0, 		49, 		0
;action50(light magenta 1),			0xC27BA0, 	0, 		50, 		0
;action51(dark red berry 1),		0xA61C00, 	0, 		51, 		0
;action52(dark red 1),				0xCC0000, 	0, 		52, 		0
;action53(dark orange 1),			0xE69138, 	0, 		53, 		0
;action54(dark yellow 1),			0xF1C232, 	0, 		54, 		0
;action55(dark green 1),			0x6AA84F, 	0, 		55, 		0
;action56(dark cyan 1),				0x45818E, 	0, 		56, 		0
;action57(dark cornflower blue 1),	0x3C78D8, 	0, 		57, 		0
;action58(dark blue 1),				0x3D85C6, 	0, 		58, 		0
;action59(dark purple 1),			0x674EA7, 	0, 		59, 		0
;action60(dark magenta 1),			0xA64D79, 	0, 		60, 		0
;action61(dark red berry 2),		0x85200C, 	0, 		61, 		0
;action62(dark red 2),				0x990000, 	0, 		62, 		0
;action63(dark orange 2),			0xB45F06, 	0, 		63, 		0
;action64(dark yellow 2),			0xBF9000, 	0, 		64, 		0
;action65(dark green 2),			0x38761D, 	0, 		65, 		0
;action66(dark cyan 2),				0x134F5C, 	0, 		66, 		0
;action67(dark cornflower blue 2),	0x1155CC, 	0, 		67, 		0
;action68(dark blue 2),				0x0B5394, 	0, 		68, 		0
;action69(dark purple 2),			0x351C75, 	0, 		69, 		0
;action70(dark magenta 2),			0x741B47, 	0, 		70, 		0
;action71(dark red berry 3),		0x5B0F00, 	0, 		71, 		0
;action72(dark red 3),				0x660000, 	0, 		72, 		0
;action73(dark orange 3),			0x783F04, 	0, 		73, 		0
;action74(dark yellow 3),			0x7F6000, 	0, 		74, 		0
;action75(dark green 3),			0x274E13, 	0, 		75, 		0
;action76(dark cyan 3),				0x0C343D, 	0, 		76, 		0
;action77(dark cornflower blue 3),	0x1C4587, 	0, 		77, 		0
;action78(dark blue 3),				0x073763, 	0, 		78, 		0
;action79(dark purple 3),			0x20124D, 	0, 		79, 		0
;action80(dark magenta 3),			0x4C1130, 	0, 		80, 		0
mysteriouslin
Posts: 7
Joined: 06 Sep 2023, 10:09

Re: Multithreaded customizable RGB clicker

20 Sep 2023, 20:15

but your code is ahkv1
User avatar
boiler
Posts: 16985
Joined: 21 Dec 2014, 02:44

Re: Multithreaded customizable RGB clicker

20 Sep 2023, 20:21

mysteriouslin wrote: but your code is ahkv1
What’s your point? It’s posted in the v1 section.
Faren
Posts: 5
Joined: 19 Sep 2023, 11:39

Re: Multithreaded customizable RGB clicker

21 Sep 2023, 06:58

Ya sorry lol, didn't even know there was a v2 or v1 really when i started trying to figure this out. I've already changed it to use GDI_all cause GetPixel i(and everyone else on forums) realized it slow on win10 :)

Return to “Gaming Scripts (v1)”

Who is online

Users browsing this forum: No registered users and 28 guests