Script Help for Menu selection from a Windows taskbar icon

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
jaaypeso24
Posts: 46
Joined: 23 Jul 2016, 10:54

Script Help for Menu selection from a Windows taskbar icon

19 Apr 2021, 00:20

I would like to develop a script that selects an item in a submenu that is in a windows taskbar icon.

In order to get their manually, with a mouse, I have to go to the windows taskbar at the bottom, right click on the icon then select "set ASIO Buffer Size" and then select "512 samples".

I would like to be able to do this with the Numpad9 key.

Any ideas?

Code: Select all

;;; BEGINNING OF AUTOHOTKEY SCRIPT

#SingleInstance, Force
SetBatchLines, -1
SetKeyDelay, -1

Numpad9::
	WinMenuSelectItem,ahk_class JUCE_178db6f03a6,,Set ASIO Buffer Size,1024 Samples
	return

;;;END OF AUTOHOTKEYSCRIPT
[Mod edit: [code][/code] tags added.]

In the script above "JUCE_178db6f03a6" is the ahk_class I get from windows spy when I click the taskbar icon I want to access. I've used a script similar to the one above to access a menu item in an active program and it functions. But i'm not sure if this is appropriate for accessing a windows taskbar icon at the bottom. Also, i'm not sure if it matters, but I have my taskbar hidden until I move my mouse to the bottom of the screen (in Windows 10), then it pops up.

I've attached 3 images below that shows: 1) the windows spy class that comes up when I right click on the icon, 2) the submenu that pops up, and 3) the options I am choosing the number of samples from in the submenu

image.png
image.png (96.13 KiB) Viewed 1255 times
image.png
image.png (25.63 KiB) Viewed 1255 times
image.png
image.png (34.31 KiB) Viewed 1255 times
User avatar
boiler
Posts: 16925
Joined: 21 Dec 2014, 02:44

Re: Script Help for Menu selection from a Windows taskbar icon

19 Apr 2021, 07:35

Should you not find a more direct way to accomplish this, you could have a script mimic what you do manually: Move the mouse to the bottom of the screen to reveal the taskbar, locate the desired icon using ImageSearch, perform a right-click on that location to summon the menu, and send keystrokes to navigate the menu and sub-menus (or click on the menu items via known relative locations, but keystrokes are likely easier).
jaaypeso24
Posts: 46
Joined: 23 Jul 2016, 10:54

Re: Script Help for Menu selection from a Windows taskbar icon

19 Apr 2021, 07:53

boiler wrote:
19 Apr 2021, 07:35
Should you not find a more direct way to accomplish this, you could have a script mimic what you do manually: Move the mouse to the bottom of the screen to reveal the taskbar, locate the desired icon using ImageSearch, perform a right-click on that location to summon the menu, and send keystrokes to navigate the menu and sub-menus (or click on the menu items via known relative locations, but keystrokes are likely easier).
That's a great idea! I thought about that but didn't know how to set it up properly so that it happens smoothly. I'm an amateur with autohotkey ( I mainly use it to replace key commands directly which is pretty straightforward), so I haven't gotten good at automating mouse moves.

As I wrap my head around this, the manual move I need would be:

1)Move mouse to position at very bottom of screen
2) wait 0.5 second (for the taskbar to pop up)
3) move mouse to icon position
3) right click on the icon position (brings up the menu)
then to navigate the menu...
4) up arrow 3 times
5) right arrow once
6) down arrow 3 times
7) press enter (to select the menu item I want)
---end of script

Can any autohotkey gods help a newb out with the script structure? If so, feel free to just throw in X and Y wherever I need a position value as I can get those from Window Spy). Then I can learn from that general script structure and fine tune it as needed.
User avatar
boiler
Posts: 16925
Joined: 21 Dec 2014, 02:44

Re: Script Help for Menu selection from a Windows taskbar icon

19 Apr 2021, 08:15

Something like the following should do it. It's assigned to the hotkey Ctrl+F1 but could obviously be anything you want. You would need to create an image of the icon and add the path to it where shown. It can be a relative path (from the script directory) or an absolute path. The image should be a small part in the center (no background), just enough to be unique. The image should be a .png or .bmp, not .jpg. The line where it sends the keystrokes might need to be broken up into multiple lines with something like Sleep, 50 in between.

Code: Select all

CoordMode, Mouse, Screen
CoordMode, Pixel, Screen

^F1::
	MouseGetPos, OrigX, OrigY ; get original mouse position
	MouseMove, 200, A_ScreenHeight - 1
	loop {
		ImageSearch, FoundX, FoundY, 0, A_ScreenHeight - 40, A_ScreenWidth, A_ScreenHeight, PathToMyIconImage.png
		Sleep, 50
		if (A_Index = 100) {
			MsgBox, 8240, Taskbar icon not found, The image of the the taskbar icon could not be found., 3
			return
		}
	} until !ErrorLevel
	Click, R, %FoundX%, %FoundY%
	WinWaitActive, ahk_exe ShellExperienceHost.exe
	Send, {Up 3}{Right}{Down 3}{Enter}
	MouseMove, OrigX, OrigY ; move mouse back to original position
return
jaaypeso24
Posts: 46
Joined: 23 Jul 2016, 10:54

Re: Script Help for Menu selection from a Windows taskbar icon

19 Apr 2021, 10:26

I REALLY appreciate you taking the time out of your day to help me out. I'm trying your script and getting it setup now but had a question. I created an image of the icon and saved that file with the name "PathToMyIcon.png" with no background.

However, my guess is the hint you left me was that I should put my path in the place where you have "PathToMyIcon.png" in your script. I have the .png image of my icon stored in the same folder where my script is located and its absolute location is:

C:/Documents/PathToMyIcon.pgn

So is it correct that my script would have the line:

ImageSearch, FoundX, FoundY, 0, A_ScreenHeight - 40, A_ScreenWidth, A_ScreenHeight, C:/Documents/PathToMyIconImage.png


Also, do I need to replace the A_screenheight and A_screenwidth, or do those commands automatically pull the screen dimensions from your computer?
User avatar
boiler
Posts: 16925
Joined: 21 Dec 2014, 02:44

Re: Script Help for Menu selection from a Windows taskbar icon

19 Apr 2021, 10:35

jaaypeso24 wrote: So is it correct that my script would have the line:

ImageSearch, FoundX, FoundY, 0, A_ScreenHeight - 40, A_ScreenWidth, A_ScreenHeight, C:/Documents/PathToMyIconImage.png
Only if that's really the path. The path to your Documents folder is usually more something like C:\users\<username>\Documents. Note that you should use \ to be accurate, not /, although I think it handles it either way. However, you can just use the built-in variable for your Documents path like this:

Code: Select all

ImageSearch, FoundX, FoundY, 0, A_ScreenHeight - 40, A_ScreenWidth, A_ScreenHeight, %A_MyDocuments%\PathToMyIconImage.png
Or you can just put the file in your script directory and not put any path other than the file name itself.


jaaypeso24 wrote: Also, do I need to replace the A_screenheight and A_screenwidth, or do those commands automatically pull the screen dimensions from your computer?
No, those automatically contain the dimensions of your screen, so leave them as is.
User avatar
boiler
Posts: 16925
Joined: 21 Dec 2014, 02:44

Re: Script Help for Menu selection from a Windows taskbar icon

19 Apr 2021, 10:46

If you want to verify the values of those built-in variables, run this script:

Code: Select all

MsgBox, % "Screen dimensions: " A_ScreenWidth " x " A_ScreenHeight "`n`nMy Documents path:`n" A_MyDocuments
Windows apparently now has inserted "OneDrive" into my Documents folder path. :roll: I have never knowingly implemented OneDrive.
jaaypeso24
Posts: 46
Joined: 23 Jul 2016, 10:54

Re: Script Help for Menu selection from a Windows taskbar icon

19 Apr 2021, 11:49

Hmmm...I feel close.....but its not working for some reason.

I'm getting the "image note found" message that you wisely setup to help me troubleshoot lol.

I've attached the icon image I saved in case that's the issue. I just did a screenshot of the icon, and saved it as a .png file with no background. So I think it should be fine.

Maybe since the icon doesn't move I can do it based on position instead of image search. You can see the same icon on the bottom right of the other attached image if that helps. I can see my mouse move to a different place after I initiate the script, but it seems to not be finding the image. The other thing I noticed is that the mouse position it ends on is neither the original position, nor the position where the icon is (but that could be tied to the fact it can't find the image and may just be stopping at a random location at the bottom after it can't find my png. Hmmm.....I'll keep tinkering on my end as well (and report back if I figure something out).
image.png
image.png (76.92 KiB) Viewed 1151 times
Attachments
PathToMyIconImage.png
PathToMyIconImage.png (925 Bytes) Viewed 1151 times
maleko48
Posts: 15
Joined: 19 Jul 2019, 13:35

Re: Script Help for Menu selection from a Windows taskbar icon

19 Apr 2021, 12:39

jaaypeso24 wrote:
19 Apr 2021, 07:53
boiler wrote:
19 Apr 2021, 07:35
Should you not find a more direct way to accomplish this, you could have a script mimic what you do manually: Move the mouse to the bottom of the screen to reveal the taskbar, locate the desired icon using ImageSearch, perform a right-click on that location to summon the menu, and send keystrokes to navigate the menu and sub-menus (or click on the menu items via known relative locations, but keystrokes are likely easier).
That's a great idea! I thought about that but didn't know how to set it up properly so that it happens smoothly. I'm an amateur with autohotkey ( I mainly use it to replace key commands directly which is pretty straightforward), so I haven't gotten good at automating mouse moves.

As I wrap my head around this, the manual move I need would be:

1)Move mouse to position at very bottom of screen
2) wait 0.5 second (for the taskbar to pop up)
3) move mouse to icon position
3) right click on the icon position (brings up the menu)
then to navigate the menu...
4) up arrow 3 times
5) right arrow once
6) down arrow 3 times
7) press enter (to select the menu item I want)
---end of script

Can any autohotkey gods help a newb out with the script structure? If so, feel free to just throw in X and Y wherever I need a position value as I can get those from Window Spy). Then I can learn from that general script structure and fine tune it as needed.
Run this, F12 is the hotkey I set it up to use. There is some extra stuff in the script too you can explore / get rid of if you want. This is my general purpose script that I use for most automation tasks. It uses FindText and does the bulk of the heavy lifting purely optically without the need to screenshot and crop images for matching. The helper functions I wrote should be pretty straight forward if you choose to use it to automate or extend other functionality.

If you copy from line 512 to the end, and save that as FindText.ahk, that is the tool used to generate the unique image hashes so you don't have to go the ImageSearch route. Just run FindText.ahk and the GUI of the tool will appear and be ready to use. Any questions, just ask and I will do my best to explain. I made this single file script with ease of use in mind for newer AHK users. :)

EDIT:

I forgot to mention, I used the image you posted to generate the FindText image hash string by rightclicking it and saving the image then opening the PNG in paint to make the hash string. If your desktop resolution or scaling are different than mine (1080p at 100% scale) you will likely need to recreate it from your own desktop. The only way around that, or for me or someone else to generate it automatically for you, would require an original bitmap screenshot of your desktop to take the image from, otherwise FindText won't actually find it.

Code: Select all

;###############################################################################
;####						MAIN SCRIPT						 ####
;###############################################################################
#SingleInstance, Force
#NoEnv
#InstallKeybdHook



;###############################################################################
;####				CONFIGURE EXECUTION ENVIRONMENT				 ####
;###############################################################################
SendMode, Input
CoordMode, Pixel
CoordMode, Mouse

SoundBeep, 300, 100		; SIGNAL SCRIPT START
SoundBeep, 400, 150		; SIGNAL SCRIPT START



;###############################################################################
;####				INITIALIZE SUPER GLOBAL VARIABLES				 ####
;###############################################################################
global ok:= []
global comment:=""
global X:= 0, Y:= 0
global mouseX:= 0, mouseY:= 0
global origX:= 0, origY:= 0
global winX:= 0, winY:= 0
global Target_TLX:= -1, Target_TLY:= -1			; (TLX, TLY)
global Target_BRX:= -1, Target_BRY:= -1			; (BRX, BRY)
global Target_Width:= -1, Target_Height:= -1		; (W, H)
global offset:= 0
global speed:=0
global Mspd:= 0							; 0 - 100  -->  0 = INSTANT MOUSE MOVEMENTS
global TXT_ERR:= 0.0						; 0.1 - 0.9  -->  % ERROR IN FINDTEXT ALGORITHM
global BG_ERR:= 0.0							; 0.1 - 0.9  -->  % ERROR IN FINDTEXT ALGORITHM
global Text:="", Target:="", Payload:=""		; FindText TARGETS
global WinName:= "", TLX:= 0, TLY:= 0, BRX:= 0, BRY:= 0, Xoff:=0, Yoff:= 0, W:= 0, H:= 0, Numerator:= 0, Denominator:= 0
global Field:="", Focus:=""



;###############################################################################
;####					MONITOR INITIALIZATION					 ####
;###############################################################################
SysGet, NumMonitors, MonitorCount
global SYS_NumMonitors:= NumMonitors
global SYS_TLX:= 0
global SYS_TLY:= 0
SysGet, VirtualScreenWidth, 78
global SYS_BRX:= VirtualScreenWidth
global SYS_W:= VirtualScreenWidth
SysGet, VirtualScreenHeight, 79
global SYS_BRY:= VirtualScreenHeight
global SYS_H:= VirtualScreenHeight
global M1_TLX:= -1, M1_TLY:= -1, M1_BRX:= -1, M1_BRY:= -1
global M2_TLX:= -1, M2_TLY:= -1, M2_BRX:= -1, M2_BRY:= -1
global M3_TLX:= -1, M3_TLY:= -1, M3_BRX:= -1, M3_BRY:= -1

Loop, %NumMonitors%
{
	SysTarget=M%A_Index%_
	SysGet, %SysTarget%, Monitor, %A_Index%
	SYS_M%A_Index%:=1
	
	M%A_Index%_TLX:= M%A_Index%_Left	; TLX
	M%A_Index%_TLY:= M%A_Index%_Top	; TLY
	M%A_Index%_BRX:= M%A_Index%_Right	; BRX
	M%A_Index%_BRY:= M%A_Index%_Bottom	; BRY
}
; CONFIRM RESULTS
;MsgBox, M1_TLX: %M1_TLX%,  M1_TLY: %M1_TLY%, M1_BRX: %M1_BRX%, M1_BRY: %M1_BRY%
;MsgBox, M2_TLX: %M2_TLX%,  M2_TLY: %M2_TLY%, M2_BRX: %M2_BRX%, M2_BRY: %M2_BRY%
;MsgBox, M3_TLX: %M3_TLX%,  M3_TLY: %M3_TLY%, M3_BRX: %M3_BRX%, M3_BRY: %M3_BRY%
;
;MsgBox, SYS_M1=%SYS_M1% `n SYS_M2=%SYS_M2% `n SYS_M3=%SYS_M3%
;MsgBox, M1_LEFT=%M1_Left% `n M1_TOP=%M1_Top% `n M1_RIGHT=%M1_Right% `n M1_BOTTOM=%M1_Bottom%
;MsgBox, M2_LEFT=%M2_Left% `n M2_TOP=%M2_Top% `n M2_RIGHT=%M2_Right% `n M2_BOTTOM=%M2_Bottom%
;MsgBox, M3_LEFT=%M3_Left% `n M3_TOP=%M3_Top% `n M3_RIGHT=%M3_Right% `n M3_BOTTOM=%M3_Bottom%



;###############################################################################
;####					SCRIPT CONTROLS						 ####
;###############################################################################

^Escape::			; CTRL + ESC		--	KILL SCRIPT
ExitApp
return


!Escape::			; ALT + ESC		--	RELOAD SCRIPT
Reload
return


^!Escape::		; CTRL + ALT + ESC	--	SUSPEND (TOGGLE) SCRIPT
Suspend, Toggle
return



;###############################################################################
;####						TO DO LIST						 ####
;###############################################################################

; WRITE TO DO LIST HERE
;	- ETC
;	- ETC
;	- ETC
;	- ETC



;#######################################################################################################################
;####										GLOBAL HOTKEYS										 ####
;#######################################################################################################################
;###############################################################################
#IfWinActive					; THESE HOT KEYS ARE NOT CONTEXT SENSITIVE!
;###############################################################################
NumLock::SetNumlockState, AlwaysOn

CapsLock::Set_ActiveWindow_AlwaysOnTop()

$Launch_App2::SYS_Calculator()

!`::MouseJiggler()

F11::Click_Taskbar_SoundIcon()

F12::RightClick_Icon()

;###############################################################################
;####										GLOBAL FUNCTIONS
;###############################################################################
RightClick_Icon()
{
	; REMEMBER STARTING POSITION OF MOUSE
	MouseGetPos, mouseX, mouseY
	
	; MOVE MOUSE TO BOTTOM CENTER OF SCREEN TO BRING UP AUTO-HIDING TASKBAR
	MouseMove, SYS_W/2, SYS_H

	; WAIT FOR DESIRED TARGET TO BE VISIBLE
	SYS_WaitTarget("|<WindowsDesktop_Taskbar_IconToClick>*139$12.yTs7k3Xlbt6070bzXzk3s7yTU")

	; CLICK DESIRED TARGET
	SYS_ClickTarget("|<WindowsDesktop_Taskbar_IconToClick>*139$12.yTs7k3Xlbt6070bzXzk3s7yTU",,,15,,,,"Right")
	Sleep, 500
	Send, {Up}{Up}{Up}{Right}{Down}{Down}{Down}{Enter}

	; RETURN MOUSE TO ORIGINAL STARTING POSITION
	MouseMove, mouseX, mouseY
}

Click_Taskbar_SoundIcon()
{
	MouseGetPos, mouseX, mouseY
	SYS_ClickTarget("|<WindowsDesktop_Taskbar_SoundIcon>*136$16.zzjvyTDRuykPNbiqSvNvhbiq6qPfvDDRyzbzys",,,15)
	MouseMove, mouseX, mouseY
}

Set_ActiveWindow_AlwaysOnTop()
{
	SetCapsLockState, AlwaysOff
	WinSet, AlwaysOnTop,,A
	WinGetTitle, WinTitle, A
	ToolTip, ALWAYS ON TOP: [ %WinTitle% ]
	Sleep, 1500
	ToolTip
}

SYS_Calculator()
{
	if not WinExist("Calculator")
		Run, C:\Windows\System32\calc.exe
	if WinActive("Calculator")
		Send {Alt down}{F4}{Alt up}
	if WinExist("Calculator")
		WinActivate, Calculator
}

MouseJiggler()
{
	SendMode, Event
	MouseGetPos, X, Y
	while ( !GetKeyState("Escape") )
	{
		Loop
		{
			offset:= 200
			pulse:= 25
			pitch:= 20
			length:= 50
			
			Random, rand_X, (0 + offset), (SYS_W - offset)
			Random, rand_Y, (0 + offset), (SYS_H - offset)
			
			MouseMove, rand_X, rand_Y, 2
			
			if (Mod(A_INDEX, pulse) == 0)
			{
				SoundBeep, (rand_X / pitch), length
				SoundBeep, (rand_Y / pitch), length
			}	
		}
	}
}
;##############################################################################
SYS_ClickTarget(Target, Xoff:=0, Yoff:=0, Mspd:=0, TXT_ERR:=0, BG_ERR:=0, ClickAll:=0, WhichButton:="")
{
	global TLX, TLY, BRX, BRY, H, W, Numerator, Denominator
	
	SetDefaultMouseSpeed, %Mspd%
	
	if (ClickAll == 0 && ok:=FindText(SYS_TLX, SYS_TLY, SYS_BRX, SYS_BRY, TXT_ERR, BG_ERR, Target))
	{
		CoordMode, Mouse
		X:=ok.1.x + Xoff, Y:=ok.1.y + Yoff, Comment:=ok.1.id
		if (WhichButton != "")
			Click, %X%, %Y%, %WhichButton%
		else
			Click, %X%, %Y%
	}
	else if (ClickAll == 1 && ok:=FindText(SYS_TLX, SYS_TLY, SYS_BRX, SYS_BRY, TXT_ERR, BG_ERR, Target))
	{
		CoordMode, Mouse
		for i,v in Ok
		{
			X:=ok[i].x + Xoff, Y:=ok[i].y + Yoff, Comment:=ok[1].id
			if (WhichButton != "")
				Click, %X%, %Y%, %WhichButton%
			else
				Click, %X%, %Y%
		}
	}
}

SYS_WinClickTarget(WinName, Target, Xoff:=0, Yoff:=0, Mspd:=0, TXT_ERR:=0, BG_ERR:=0, Zone:="", ClickAll:=0, WhichButton:="")
{
	global TLX, TLY, BRX, BRY, H, W, Numerator, Denominator, X, Y
	
	SetTitleMatchMode, 2
	SetTitleMatchMode, Fast
	SetDefaultMouseSpeed, %Mspd%
	
	WinGetPos, TLX, TLY, W, H, %WinName%
	BRX:= TLX + W
	BRY:= TLY + H
	;MsgBox, INITIAL`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
	
	if (Zone != "")
		SYS_WinGetZone(Zone)	; THIS SETS THE GLOBAL VARS: TLX, TLY, BRX, BRY, Numerator, Denominator
	
	;MsgBox, POST-PROCESSING`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
	
	if (ClickAll == 0 && ok:=FindText(TLX, TLY, BRX, BRY, TXT_ERR, BG_ERR, Target))
	{
		CoordMode, Mouse
		X:=ok.1.x + Xoff, Y:=ok.1.y + Yoff, Comment:=ok.1.id
		if (WhichButton != "")
			Click, %X%, %Y%, %WhichButton%
		else
			Click, %X%, %Y%
	}
	
	else if (ClickAll == 1 && ok:=FindText(TLX, TLY, BRX, BRY, TXT_ERR, BG_ERR, Target))
	{
		CoordMode, Mouse
		for i,v in ok
			if (i<=ok.MaxIndex())
			{
				X:=ok[i].x + Xoff, Y:=ok[i].y + Yoff, Comment:=ok[i].id
				if (WhichButton != "")
					Click, %X%, %Y%, %WhichButton%
				else
					Click, %X%, %Y%
			}
	}
	
	else if (ClickAll == -1 && ok:=FindText(TLX, TLY, BRX, BRY, TXT_ERR, BG_ERR, Target))
	{
		CoordMode, Mouse
		for i,v in ok
			if (i<=ok.MaxIndex())
			{
				X:=ok[i].x + Xoff, Y:=ok[i].y + Yoff, Comment:=ok[i].id
				MouseMove, %X%, %Y%
			}
	}
}

SYS_WinGetZone(str)
{
	global TLX, TLY, BRX, BRY, H, W, Numerator, Denominator
	
	ZoneArray:= StrSplit(str, A_SPACE)
	Zone:= ZoneArray[1]
	Frac:= ZoneArray[2]
	if (Frac != "")
	{
		Fraction:= StrSplit(Frac,"/")
		Numerator:= Fraction[1]
		Denominator:= Fraction[2]
	}
	;MsgBox, Zone=%Zone% `nFrac=%Frac% `nNumer:%Numerator% `nDenom:%Denominator%
	
	if (Zone = "TOP" || Zone = "T")
	{
		TLX:= TLX, TLY:= TLY
		;MsgBox, TOP`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		if (Frac != "")
		{
			BRX:= TLX + W
			BRY:= TLY + (H / Denominator)
			;MsgBox, TOP-MOD`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		}
		;return {TLX: %TLX%, TLY: %TLY%, BRX: %BRX%, BRY: %BRY%}
	}
	else if (Zone = "LEFT" || Zone = "L")
	{
		TLX:= TLX, TLY:= TLY
		;MsgBox, LEFT`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		if (Frac != "")
		{
			BRX:= TLX + (W / Denominator)
			BRY:= TLY + H
			;MsgBox, LEFT-MOD`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		}
		;return {TLX: %TLX%, TLY: %TLY%, BRX: %BRX%, BRY: %BRY%}
	}
	else if  (Zone = "BOTTOM" || Zone = "B")
	{
		BRX:= TLX + W, BRY:= TLY + H
		;MsgBox, BOTTOM`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		if (Frac != "")
		{
			TLX:= TLX
			TLY:= (TLY + H) - (H / Denominator)
			;MsgBox, BOTTOM-MOD`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		}
		;return {TLX: %TLX%, TLY: %TLY%, BRX: %BRX%, BRY: %BRY%}
	}
	else if  (Zone = "RIGHT" || Zone = "R")
	{
		BRX:= TLX + W, BRY:= TLY + H
		;MsgBox, RIGHT`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		if (Frac != "")
		{
			TLX:= (TLX + W) - (W / Denominator)
			TLY:= TLY
			;MsgBox, RIGHT-MOD`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		}
		;return {TLX: %TLX%, TLY: %TLY%, BRX: %BRX%, BRY: %BRY%}
	}
	else if (Zone  = "TOPLEFT" || Zone = "TL")
	{
		TLX:= TLX, TLY:= TLY, BRX:= TLX + ((1/4) * W), BRY:= TLY + ((1/4) * H)
		;MsgBox, TOPLEFT`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		;return {TLX: %TLX%, TLY: %TLY%, BRX: %BRX%, BRY: %BRY%}
	}
	else if (Zone  = "BOTTOMLEFT" || Zone = "BL")
	{
		TLX:= TLX, TLY:= TLY + ((3/4) * H), BRX:= TLX + ((1/4) * W), BRY:= TLY + H
		;MsgBox, BOTTOMLEFT`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		;return {TLX: %TLX%, TLY: %TLY%, BRX: %BRX%, BRY: %BRY%}
	}
	else if (Zone  = "BOTTOMRIGHT" || Zone = "BR")
	{
		TLX:= TLX + ((3/4) * W), TLY:= TLY + ((3/4) * H), BRX:= TLX + W, BRY:= TLY + H				
		;MsgBox, BOTTOMRIGHT`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		;return {TLX: %TLX%, TLY: %TLY%, BRX: %BRX%, BRY: %BRY%}
	}
	else if (Zone  = "TOPRIGHT" || Zone = "TR")
	{
		TLX:= TLX + ((3/4) * W), TLY:= TLY, BRX:= TLX + W, BRY:= TLY + ((1/4) * H)
		;MsgBox, TOPRIGHT`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		;return {TLX: %TLX%, TLY: %TLY%, BRX: %BRX%, BRY: %BRY%}
	}
	else if (Zone  = "CENTER" || Zone = "CTR")
	{
		TLX:= TLX + ((1/3) * W), TLY:= TLY + ((1/3) * H), BRX:= TLX + ((2/3) * W), BRY:= TLY + ((2/3) * H)
		;MsgBox, CENTER`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
		;return {TLX: %TLX%, TLY: %TLY%, BRX: %BRX%, BRY: %BRY%}
	}
}

SYS_WaitTarget(Target, TXT_ERR:=0, BG_ERR:=0, Zone:="", Mspd:=0, delay:=0, adaptive:=0)
{
	global TLX, TLY, BRX, BRY, H, W, Numerator, Denominator	; DEFAULT
	global SYS_TLX, SYS_TLY, SYS_BRX, SYS_BRY, SYS_H, SYS_W	; SYSTEM VIEWPORT GLOBAL VARIABLES
	
	if (Zone != "")
	{
		SYS_WinGetZone(Zone)	; THIS SETS THE GLOBAL VARS: TLX, TLY, BRX, BRY, Numerator, Denominator
		
		while (FindText(TLX, TLY, BRX, BRY, TXT_ERR, BG_ERR, Target) == 0)
		{
			if (Mspd != 0)
				MouseMove, %X%, %Y%, %Mspd%
			Sleep, %delay%
			SoundBeep, 100, 50
		}
	}
	else
	{
		while (FindText(SYS_TLX, SYS_TLY, SYS_BRX, SYS_BRY, TXT_ERR, BG_ERR, Target) == 0)
		{
			if (Mspd != 0)
				MouseMove, %X%, %Y%, %Mspd%
			Sleep, %delay%
			SoundBeep, 100, 50
		}
	}
}

SYS_WinWaitTarget(WinName, Target, TXT_ERR:=0, BG_ERR:=0, Zone:="", Mspd:=0, delay:=0)
{
	global TLX, TLY, BRX, BRY, H, W, Numerator, Denominator
	
	SetTitleMatchMode, 2
	
	WinGetPos, TLX, TLY, W, H, %WinName%
	BRX:= TLX + W
	BRY:= TLY + H
	;MsgBox TLX: %TLX% , TLY: %TLY% `nBRX: %BRX% , BRY: %BRY%
	
	if (Zone != "")
		SYS_WinGetZone(Zone)	; THIS SETS THE GLOBAL VARS: TLX, TLY, BRX, BRY, Numerator, Denominator
	
	;MsgBox, POST-PROCESSING`n`nTLX:`t%TLX%`t`tTLY:`t%TLY%`nW:`t%W%`t`tH:`t%H%`nBRX:`t%BRX%`tBRY:`t%BRY%
	
	while (FindText(TLX, TLY, BRX, BRY, TXT_ERR, BG_ERR, Target) == 0)
	{
		if (Mspd != 0)
			MouseMove, %X%, %Y%, %Mspd%
		Sleep, %delay%
		SoundBeep, 100, 50
	}
}

;#######################################################################################################################
;####									  GLOBAL HOTSTRINGS										 ####
;#######################################################################################################################
;###############################################################################
; HOTSTRING  --  ACTIVATOR KEYS & CHARS
;###############################################################################
#Hotstring EndChars `t `n `	; ONLY USE THE FOLLOWING KEYS TO ACTIVATE HOTSTRINGS: TAB, ENTER, SPACE

;###############################################################################
; HOTSTRING  --  EXPANSIONS
;###############################################################################
:OR:usa::United States of America


;###############################################################################
; HOTSTRING  --  REPLACEMENTS  --  CONVERT CUSTOMER NAMES TO PHONE NUMBERS
;###############################################################################
; John Doe
:O:CompanyName/JohnDoe::321-456-7890



;#######################################################################################################################
;####										GOOGLE CHROME										 ####
;#######################################################################################################################
;###############################################################################
;####						HOTKEYS & MACROS
;###############################################################################
#IfWinActive, ahk_exe chrome.exe
;###############################################################################
Browser_Back::CHROME_PrevTab()

Browser_Forward::CHROME_NextTab()

;Escape::CHROME_CloseTab()

;###############################################################################
#IfWinActive, Mail
;###############################################################################
Escape::OUTLOOK_ClosePDFPreview()

;###############################################################################
;####							FUNCTIONS
;###############################################################################
CHROME_NextTab()
{
	Send {Ctrl down}{Tab down}{Tab up}{Ctrl up}
}

CHROME_PrevTab()
{
	Send {Ctrl down}{Shift down}{Tab down}{Tab up}{Shift up}{Ctrl up}
}

CHROME_CloseTab()
{
	Send ^w	
}

OUTLOOK_ClosePDFPreview()
{
	MouseGetPos, origX, origY
	SYS_WinClickTarget(Outlook, "|<CHROME_OUTLOOK_ClosePDFPreview_BUTTON>*145$12.U1E284482E1U1U2E4884E2U1U",,,,,,"TopRight")
	MouseMove, origX, origY, 0
}



;#######################################################################################################################
;####										FINDTEXT											 ####
;#######################################################################################################################

;/*
;===========================================
;  FindText - Capture screen image into text and then find it
;  https://autohotkey.com/boards/viewtopic.php?f=6&t=17834
;
;  Author  : FeiYue
;  Version : 8.4
;  Date    : 2021-04-02
;
;  Usage:  (required AHK v1.1.31+)
;  1. Capture the image to text string.
;  2. Test find the text string on full Screen.
;  3. When test is successful, you may copy the code
;     and paste it into your own script.
;     Note: Copy the "FindText()" function and the following
;     functions and paste it into your own script Just once.
;  4. The more recommended way is to save the script as
;     "FindText.ahk" and copy it to the "Lib" subdirectory
;     of AHK program, instead of copying the "FindText()"
;     function and the following functions, add a line to
;     the beginning of your script: #Include <FindText>
;
;===========================================
;*/


if (!A_IsCompiled and A_LineFile=A_ScriptFullPath)
	FindText.Gui("Show")


;===== Copy The Following Functions To Your Own Code Just once =====


;--------------------------------
;  FindText - Capture screen image into text and then find it
;--------------------------------
;  returnArray := FindText(
;      X1 --> the search scope's upper left corner X coordinates
;    , Y1 --> the search scope's upper left corner Y coordinates
;    , X2 --> the search scope's lower right corner X coordinates
;    , Y2 --> the search scope's lower right corner Y coordinates
;    , err1 --> Fault tolerance percentage of text       (0.1=10%)
;    , err0 --> Fault tolerance percentage of background (0.1=10%)
;    , Text --> can be a lot of text parsed into images, separated by "|"
;    , ScreenShot --> if the value is 0, the last screenshot will be used
;    , FindAll --> if the value is 0, Just find one result and return
;    , JoinText --> if the value is 1, Join all Text for combination lookup
;    , offsetX --> Set the max text offset (X) for combination lookup
;    , offsetY --> Set the max text offset (Y) for combination lookup
;    , dir --> Nine directions for searching: up, down, left, right and center
;  )
;
;  The function returns a second-order array containing
;  all lookup results, Any result is an associative array
;  {1:X, 2:Y, 3:W, 4:H, x:X+W//2, y:Y+H//2, id:Comment}
;  if no image is found, the function returns 0.
;  All coordinates are relative to Screen, colors are in RGB format
;
;  If the return variable is set to "ok", ok.1 is the first result found.
;  Where ok.1.1 is the X coordinate of the upper left corner of the found image,
;  and ok.1.2 is the Y coordinate of the upper left corner of the found image,
;  ok.1.3 is the width of the found image, and ok.1.4 is the height of the found image,
;  ok.1.x <==> ok.1.1+ok.1.3//2 ( is the Center X coordinate of the found image ),
;  ok.1.y <==> ok.1.2+ok.1.4//2 ( is the Center Y coordinate of the found image ),
;  ok.1.id is the comment text, which is included in the <> of its parameter.
;  ok.1.x can also be written as ok[1].x, which supports variables. (eg: ok[A_Index].x)
;
;--------------------------------

FindText(args*)
{
  return FindText.FindText(args*)
}

Class FindText
{  ;// Class Begin

static bind:=[], bits:=[], Lib:=[]

__New()
{
  this.bind:=[], this.bits:=[], this.Lib:=[]
}

__Delete()
{
  if (this.bits.hBM)
    DllCall("DeleteObject", "Ptr",this.bits.hBM)
}

FindText(x1:=0, y1:=0, x2:=0, y2:=0, err1:=0, err0:=0
  , text:="", ScreenShot:=1, FindAll:=1
  , JoinText:=0, offsetX:=20, offsetY:=10, dir:=1)
{
  local
  SetBatchLines, % (bch:=A_BatchLines)?"-1":"-1"
  centerX:=Round(x1+x2)//2, centerY:=Round(y1+y2)//2
  if (x1*x1+y1*y1+x2*x2+y2*y2<=0)
    n:=150000, x:=y:=-n, w:=h:=2*n
  else
    x:=Min(x1,x2), y:=Min(y1,y2), w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1
  bits:=this.GetBitsFromScreen(x,y,w,h,ScreenShot,zx,zy,zw,zh)
  , info:=[]
  Loop, Parse, text, |
    if IsObject(j:=this.PicInfo(A_LoopField))
      info.Push(j)
  if (w<1 or h<1 or !(num:=info.MaxIndex()) or !bits.Scan0)
  {
    SetBatchLines, %bch%
    return 0
  }
  arr:=[], in:={zx:zx, zy:zy, zw:zw, zh:zh
  , sx:x-zx, sy:y-zy, sw:w, sh:h}, k:=0
  For i,j in info
    k:=Max(k, j.2*j.3, (j.8=5)*2*j.10), in.comment .= j.11
  VarSetCapacity(s1, k*4), VarSetCapacity(s0, k*4)
  , VarSetCapacity(gs, (w+2)*(h+2)), VarSetCapacity(ss, w*h)
  , FindAll:=(dir=9 ? 1 : FindAll)
  , JoinText:=(num=1 ? 0 : JoinText)
  , allpos_max:=(FindAll or JoinText ? 10240 : 1)
  , VarSetCapacity(allpos, allpos_max*8)
  Loop, 2
  {
    if (err1=0 and err0=0) and (num>1 or A_Index>1)
      err1:=0.05, err0:=0.05
    Loop, % JoinText ? 1 : num
    {
      this.PicFind(arr, in, info, A_Index, err1, err0
        , FindAll, JoinText, offsetX, offsetY, dir
        , bits, gs, ss, s1, s0, allpos, allpos_max)
      if (!FindAll and arr.MaxIndex())
        Break
    }
    if (err1!=0 or err0!=0 or arr.MaxIndex() or info.1.12)
      Break
  }
  if (dir=9)
    arr:=this.Sort2(arr, centerX, centerY)
  SetBatchLines, %bch%
  return arr.MaxIndex() ? arr:0
}

PicFind(arr, in, info, index, err1, err0
  , FindAll, JoinText, offsetX, offsetY, dir
  , bits, ByRef gs, ByRef ss, ByRef s1, ByRef s0
  , ByRef allpos, allpos_max)
{
  local
  static MyFunc:=""
  if (!MyFunc)
  {
    x32:=""
    . "5557565383EC7C8BAC249000000083FD050F84D80800008B8424D8000000C744"
    . "24080000000085C00F8E6810000031FF31C089AC2490000000C7442404000000"
    . "0031C9C744241000000000897C240C89C58B5C240C8BBC24D40000008B742410"
    . "8B54240801DF89D829DE8B9C24D400000003B424D000000085DB7E5B893C2489"
    . "EB89D7EB198BAC24CC00000083C70483C00189548D0083C101390424742C83BC"
    . "24900000000389FA0F45D0803C063175D48BAC24C800000083C70483C0018954"
    . "9D0083C30139042475D489DD8B9C24D4000000015C241083442404018B9C24B8"
    . "0000008B442404015C240C8B9C24A4000000015C2408398424D80000000F854E"
    . "FFFFFF892C248BAC2490000000894C240831C08B0C24398C24DC0000008B7424"
    . "080F4DC839B424E0000000890C240F4CC639C1894424080F4DC183FD03894424"
    . "040F84490700008B8424A40000008B8C24B00000000FAF8424B4000000C1E102"
    . "894C242C01C88B8C24A4000000894424288B8424B8000000F7D885ED8D048189"
    . "4424240F859D0300008B842494000000C744241C00000000C744242000000000"
    . "8B7C2428C1E8100FB6C0894424108B8424940000000FB6C4894424140FB68424"
    . "94000000894424188B8424B8000000C1E0028944242C8B8424BC00000085C00F"
    . "8EBB0000008B8424B800000085C00F8E920000008BB424A00000008B6C242003"
    . "AC24C400000001FE037C242C897C242803BC24A0000000897C240C908D742600"
    . "0FB64E028B5C24100FB646010FB6162B4424142B54241889CF01D929DF8D9900"
    . "0400000FAFC00FAFDFC1E00B0FAFDF01C3B8FE05000029C80FAFC20FAFD001D3"
    . "399C24980000000F93450083C60483C5013B74240C75A98B8C24B8000000014C"
    . "24208B7C24288344241C01037C24248B44241C398424BC0000000F8545FFFFFF"
    . "8B8424B80000002B8424D4000000BA01000000C644243F00C644243E00C74424"
    . "5C00000000C744246800000000894424388B8424BC0000002B8424D800000089"
    . "4424708B84249C00000083E80183F8070F873605000083BC249C000000047E28"
    . "8B4424388B4C247083AC249C00000004894C2438894424708B4C245C8B442468"
    . "894C24688944245C8B4424703944245C0F8F860C00008B8C24B0000000894424"
    . "6C8B4424688BB424A0000000C7442434000000000FAFCAC1E0020FAF9424B400"
    . "0000894C2448894424748B0C248B8424C80000008D048889542478894424508B"
    . "4C24688B5C243883BC249C000000038B54246C0F4C54245C39D90F8F60010000"
    . "8B442478894C241C01D0894424448B8424A40000000FAFC2034424740FAF9424"
    . "B80000008D1C0603842494000000895C242401CA89442430895424208D742600"
    . "807C243E000F85A5020000807C243F000F85EA0200008B6C240485ED0F847F00"
    . "00008BBC24E00000008B9C24DC00000031C08B542420039424C40000008B0C24"
    . "89B424A0000000897C24108B7C2408895C240C39C17E1C8B9C24C80000008B34"
    . "8301D6803E00750B836C240C010F88CD03000039C77E1C8B9C24CC0000008B34"
    . "8301D6803E00740B836C2410010F88AD03000083C00139C575B98BB424A00000"
    . "008B042485C074268B5C24208B8C24C40000008B8424C800000001D98B5C2450"
    . "8B1083C00401CA39C3C6020075F28B44241C034424488B4C24348B9C24E40000"
    . "008904CB89D88B5C2444895CC80483C1013B8C24E8000000894C24347D3A8344"
    . "241C0183442424048B44241C83442430048344242001394424380F8DE0FEFFFF"
    . "8344245C01836C246C018B44245C394424700F8D67FEFFFF8B44243483C47C5B"
    . "5E5F5DC25C0083FD010F849A0A000083FD020F84D80700008B8424940000000F"
    . "B6AC2494000000C744241000000000C1E8100FB6D08B84249400000089D70FB6"
    . "DC8B842498000000C1E8100FB6C88B84249800000029CF01D1897C245489DF89"
    . "4C24400FB6F40FB684249800000029F78D0C338B9C24BC000000897C244C89EF"
    . "894C245829C701E831ED894424648B8424B8000000897C2460C1E00285DB8944"
    . "24180F8ED8FCFFFF896C240C8B7C24288B6C24548B8C24B800000085C90F8E8E"
    . "0000008B8424A00000008B542410039424C400000001F8037C2418897C241403"
    . "BC24A0000000EB3C908DB42600000000395C24407C3D394C244C7F37394C2458"
    . "7C3189F30FB6F3397424600F9EC3397424640F9DC183C00483C20121D9884AFF"
    . "39C7741E0FB658020FB648010FB63039DD7EBD31C983C00483C201884AFF39C7"
    . "75E28B8C24B8000000014C24108B7C24148344240C01037C24248B44240C3984"
    . "24BC0000000F8549FFFFFFE910FCFFFF8B4C24240FB64102394424540F8F3CFE"
    . "FFFF394424400F8C32FEFFFF0FB641013944244C0F8F24FEFFFF394424580F8C"
    . "1AFEFFFF0FB601394424600F8F0DFEFFFF3B4424640F8ED3FDFFFFE9FEFDFFFF"
    . "8B4C24308B54240489C82B84249400000085D28944241889C80FB64C0E02894C"
    . "240C0FB64C06010FB60406894C2410894424140F8495FDFFFF8B8424E0000000"
    . "31DB8944242C8B8424DC00000089442428391C247E658B8424C80000008B5424"
    . "188B7C240C0314980FB64C16020FB64416012B4424100FB614162B54241489CD"
    . "01F929FD8DB9000400000FAFC00FAFFDC1E00B0FAFFD01C7B8FE05000029C80F"
    . "AFC20FAFD001D739BC2498000000730B836C2428010F8843FDFFFF395C24087E"
    . "658B8424CC0000008B5424188B7C240C0314980FB64C16020FB64416012B4424"
    . "100FB614162B54241489CD01F929FD8DB9000400000FAFC00FAFFDC1E00B0FAF"
    . "FD01C7B8FE05000029C80FAFC20FAFD001D739BC2498000000720B836C242C01"
    . "0F88D8FCFFFF83C301395C24040F851EFFFFFFE996FCFFFF908DB42600000000"
    . "8BB424A0000000E9B2FCFFFFC784249C00000001000000E9ECFAFFFF8B8424CC"
    . "0000008B00898424940000008B9C2494000000C1E8100FB6C089C601D00FB6CF"
    . "0FB69C249400000029D6897424548944244089CE8D040A29D68974244C894424"
    . "5889DE8D041A29D6897424608944246483FD058B8424B00000000F9444243E83"
    . "FD030F9444243F038424B800000031D22B8424D4000000894424388B8424B400"
    . "0000038424BC0000002B8424D8000000894424708B8424B40000008944245C8B"
    . "8424B000000089442468E9F4F9FFFF8B8424980000008B94249400000085C089"
    . "4424040F85E00200008B8424D00000008B0089C78B8424D400000081E7FFFFFF"
    . "008D88FFFFFF3F8B8424D80000008D1C8D0000000083E8010FAF8424D4000000"
    . "89C28B8424D00000008B049089042425FFFFFF0039F80F95C089C68B8424D000"
    . "00008B048889F125FFFFFF0039F80F95C008C175218B8424D40000008B8C24D0"
    . "0000008D8402FFFFFF3F8B048125FFFFFF0039F87405BFFFFFFFFF8B8424D800"
    . "000085C00F8EAE0000008D430431ED8B4C2404C744240800000000C744240C00"
    . "00000089442410896C24048BAC24D400000085ED7E5D8BB424D00000008B5C24"
    . "0C8B4424048B6C24108D349E01C529C68934248B34248B140681E2FFFFFF0039"
    . "D7741E8BB424C80000008D1C8D0000000089048E8BB424CC00000083C1018914"
    . "1E83C00439C575CB8BB424D40000000174240C83442408018B9C24A40000008B"
    . "442408015C2404398424D80000000F8577FFFFFF894C24048B8424D80000008B"
    . "BC24D4000000894424088B8424B0000000038424B800000029F8894424208B84"
    . "24B4000000038424BC0000002B442408398424B4000000894424340F8F070500"
    . "008B8424A40000008B8C24B00000000FAF8424B40000008BAC24940000008BB4"
    . "24A0000000F7DD8D04888944241C8B8424B40000008944240C8B44241C890424"
    . "8B8424B0000000894424108B442420398424B00000000F8F8E0400008B7C2404"
    . "85FF0F8EB70000008B8424C80000008B142403108B8424CC0000008B000FB60C"
    . "160FB6D829D939CD0F8F45040000398C24940000000F8C3804000031DBEB3690"
    . "8B8424C80000008B14240314988B8424CC0000008B04980FB60C160FB6F829F9"
    . "398C24940000000F8C0604000039CD0F8FFE0300000FB64C16010FB6FC29F939"
    . "8C24940000000F8CE703000039CD0F8FDF0300000FB6541602C1E8100FB6C029"
    . "C2399424940000000F8CC503000039D50F8FBD03000083C301395C240475818B"
    . "8424E40000008B4C2410C74424340100000089088B4C240C8948048B44243483"
    . "C47C5B5E5F5DC25C0083BC2498000000010F8445FCFFFF8B8424D800000001C0"
    . "89C1894424288B8424D8000000C1E81F038424D8000000D1F889C68B8424D800"
    . "000001CE89742430894424188B4C2430394C24180F8F820300008B7424188B4C"
    . "242839CE8974240889C87E0FC1E81F01C8D1F801C829F0894424088B4424080F"
    . "AF8424D400000099F7BC24D80000008D0C008944241489CE894C242489C1C1E8"
    . "1F01C8D1F801F08944242C8B4C242C394C24140F8F1C0400008B4C24148B4424"
    . "2439C189CF7E0D89C7C1EF1F01C7D1FF01C729CF8B44240485C00F8EAAFDFFFF"
    . "8BB424C80000008D2C868B44240431D28B0C8683C60489C8C1E8100FAF442408"
    . "F7B424D800000031D20FAF8424A400000089C30FB7C10FAFC7F7B424D4000000"
    . "8D04838946FC39F575C0E95BFDFFFF908B8424B0000000038424B80000008B8C"
    . "24B4000000894424188B8424B400000083E901038424BC000000894C240C39C8"
    . "0F8C5C0300008B8C24B000000083C001C744242000000000894424248B8424B8"
    . "00000083E901894C24288B4C240C83C0020FAF8C24A4000000894424148B4424"
    . "188D6801894C241C8B442428394424180F8C990000008B4C240C8B5C241C8B74"
    . "2420035C242C2BB424B0000000039C24A0000000C1E91F03B424C0000000894C"
    . "2410EB4B398424A80000007E4B807C24100075448B4C240C398C24AC0000007E"
    . "370FB64BFE0FB653FD83C3040FB67BF86BD24B6BC92601D189FAC1E20429FA01"
    . "CAC1FA078854060183C00139E8741889C2C1EA1F84D274ACC64406010083C001"
    . "83C30439E875E88B4C2414014C24208344240C018BB424A40000008B44240C01"
    . "74241C394424240F853BFFFFFF8BBC24BC00000085FF0F8E44F4FFFF8B8424BC"
    . "0000008B6C241403AC24C0000000C744241801000000C744241C0000000083C0"
    . "01894424208B8424B8000000896C241083C004894424248B8424980000008BB4"
    . "24B800000085F60F8E9F0000008B4424108B5C241C8B742424039C24C4000000"
    . "89C12B8C24B800000089C201C6894C240C0FB642010FB62ABF01000000038424"
    . "9400000039E8723D0FB66A0239E872358B4C240C0FB669FF39E872290FB66EFF"
    . "39E872210FB669FE39E872190FB62939E872120FB66EFE39E8720A0FB63E39F8"
    . "0F92C189CF89F98344240C0183C201880B83C60183C3018B4C240C394C241075"
    . "908BB424B80000000174241C83442418018B5C24148B4C2418015C2410394C24"
    . "200F8537FFFFFF89842498000000E92DF3FFFF8344241001830424048B442410"
    . "394424200F8D72FBFFFF8344240C018B9C24A40000008B44240C015C241C3944"
    . "24340F8D31FBFFFF8BB42498000000834424140285F60F85CFFCFFFFC7442434"
    . "00000000E94FF5FFFF8B84249400000031EDC744240C0000000083C001C1E007"
    . "898424940000008B8424B8000000C1E002894424188B8424BC00000085C00F8E"
    . "9CF2FFFF896C24108B7C24288BAC24940000008B8424B800000085C07E5D8B8C"
    . "24A00000008B5C2410039C24C400000001F9037C2418897C241403BC24A00000"
    . "000FB651020FB641010FB6316BC04B6BD22601C289F0C1E00429F001D039C50F"
    . "970383C10483C30139F975D58B8C24B8000000014C24108B7C24148344240C01"
    . "037C24248B44240C398424BC0000007582E90AF2FFFFC7042400000000E96FF0"
    . "FFFF8B8424B800000083C00289442414E998FDFFFF8344241802E96DFBFFFF90"
    x64:=""
    . "4157415641554154555756534881ECA8000000488BAC2410010000488BBC2458"
    . "01000083F90589542448448944240844898C24080100004C8BA424680100000F"
    . "84C6090000448BAC24800100004531F64531FF4585ED0F8ECC0000004889AC24"
    . "100100004889BC24580100004531ED488BBC24600100008BAC247801000031DB"
    . "31F64531F64531FFC744240C0000000085ED7E65486354240C448D5C1D0089D8"
    . "48039424700100004589E8EB1E0F1F0083C0014D63D64183C0044183C6014883"
    . "C2014139C347890C94742A83F9034589C1440F45C8803A3175D683C0014D63D7"
    . "4183C0044183C7014883C2014139C346890C9775D6016C240C83C601039C2440"
    . "0100004403AC241801000039B424800100000F8578FFFFFF488BAC2410010000"
    . "488BBC245801000031C04439BC2488010000440F4DF84439B42490010000440F"
    . "4DF04539F74589F5450F4DEF83F9030F84540800008B8424180100008B9C2430"
    . "0100000FAF8424380100008D04988B9C2418010000894424188B842440010000"
    . "F7D885C98D0483894424100F85100400008B742448448B9424480100004889F0"
    . "89F30FB6C4C1EB104585D289C1400FB6C60FB6DB89C20F8E2E0100008B842440"
    . "010000448974242831F644896C24344889BC2458010000448B742418448B6C24"
    . "088BBC2440010000C1E00244897C24204889AC24100100004C89A42468010000"
    . "4189F7C744240C000000008944243089CD4189D485FF0F8E8C000000488BB424"
    . "100100004963C64531DB4C8D5406024963F74803B42458010000660F1F440000"
    . "410FB652FE450FB60A410FB642FF4429E24489C94189D0428D140B29D929E844"
    . "8D8A000400000FAFC0440FAFC9C1E00B440FAFC9B9FE05000029D189CA410FAF"
    . "D0418D0401410FAFD001D04139C5420F93041E4983C3014983C2044439DF7FA0"
    . "44037424304101FF8344240C0144037424108B44240C398424480100000F8551"
    . "FFFFFF448B7C2420448B742428448B6C2434488BAC2410010000488BBC245801"
    . "00004C8BA424680100008B8424400100002B842478010000BA01000000C64424"
    . "3C00C644243800C744245C00000000C744247000000000894424348B84244801"
    . "00002B8424800100008984248C0000008B84240801000083E80183F8070F870E"
    . "06000083BC2408010000047E2E8B4424348B9C248C00000083AC240801000004"
    . "895C24348984248C0000008B5C245C8B442470895C24708944245C8B84248C00"
    . "00003944245C0F8F580D00008B9C2430010000898424880000008B442470C744"
    . "2428000000000FAFDAC1E0020FAF942438010000895C24448984249800000048"
    . "98488B9C24600100004889842490000000418D47FF488D4483044C89E34989EC"
    . "4489ED4C8BAC24600100008994249C00000048894424508B7424708B4C243483"
    . "BC240801000003448B942488000000440F4C54245C39CE0F8F4E0100008B8424"
    . "180100008B8C249C0000008974240C410FAFC24401D1440FAF94244001000089"
    . "4C24408B8C249800000001C148984863D1034C244848898424800000004101F2"
    . "488BB424900000004D8D5C14024C895C24104829D6894C242048897424786690"
    . "807C2438000F85B5020000807C243C000F850C03000085ED7450448B8C249001"
    . "0000448B84248801000031C00F1F40004139C789C27E144489D141034C850080"
    . "3C0F0075064183E801787E4139D67E124489D2031483803C170074064183E901"
    . "78674883C00139C57FC64585FF7423488B4C24504C89E8660F1F840000000000"
    . "4489D203104883C0044839C1C604170075EE8B7424288B54240C03542444488B"
    . "8C249801000089F001C048988914818B5424408954810489F083C0013B8424A0"
    . "010000894424287D408344240C014883442410044183C2018B44240C83442420"
    . "04394424340F8D15FFFFFF8344245C0183AC2488000000018B44245C3984248C"
    . "0000000F8D6EFEFFFF8B4424284881C4A80000005B5E5F5D415C415D415E415F"
    . "C383F9010F84470B000083F9020F84100800008B74244889F0440FB6D6C1E810"
    . "0FB6D04889F08B7424080FB6DC4189D889F0440FB6DEC1E8100FB6C84889F089"
    . "D60FB6C429CE4189C189D84489D34429C84429DB897424588944246C4489D889"
    . "5C24644401D08D1C0A4531DB894424688B842440010000895C2460438D1C088D"
    . "3485000000008B842448010000895C247431DB85C00F8EAFFCFFFF44897C2430"
    . "448974242044896C24284889BC24580100004C89A424680100008974240C448B"
    . "7C2474448B6C246C448B7424188B7C2458448B6424608BB4244001000085F67E"
    . "7D4963C64C63D331D2488D4405024C03942458010000EB3B0F1F840000000000"
    . "4539C47C404139CD7F3B4139CF7C3644394C2464410F9EC044394C24680F9DC1"
    . "4883C0044421C141880C124883C20139D67E24440FB6000FB648FF440FB648FE"
    . "4439C77EBB31C94883C00441880C124883C20139D67FDC440374240C01F34183"
    . "C301440374241044399C24480100000F8568FFFFFF448B7C2430448B74242044"
    . "8B6C2428488BBC24580100004C8BA42468010000E9B1FBFFFF0F1F8000000000"
    . "488B7424100FB606394424580F8FF7FDFFFF394424600F8CEDFDFFFF0FB646FF"
    . "3944246C0F8FDFFDFFFF394424740F8CD5FDFFFF488B4424784801F0488BB424"
    . "800000000FB64430FE394424640F8FB6FDFFFF3B4424680F8E75FDFFFFE9A7FD"
    . "FFFF8B74242089F02B44244885ED89C18D46024898410FB604044189C38D4601"
    . "4898410FB6040489C24863C6410FB604040F843BFDFFFF8BB424900100004889"
    . "BC24580100004531C94C89AC246001000048899C246801000089CF448954244C"
    . "4189C589D3897424188BB42488010000897424304539CF4589CA7E71488B8424"
    . "60010000428B148801FA8D42024898410FB60C048D42014863D2410FB6141448"
    . "98410FB6040489CE4401D9448D81000400004429DE4429EA440FAFC629D80FAF"
    . "C0440FAFC6C1E00B4101C0B8FE05000029C80FAFC20FAFD04101D04439442408"
    . "730B836C2430010F88A20000004539D67E6E488B842468010000428B148801FA"
    . "8D42024898410FB60C048D42014863D2410FB614144898410FB604044189CA44"
    . "01D9448D81000400004529DA4429EA450FAFC229D80FAFC0450FAFC2C1E00B41"
    . "01C0B8FE05000029C80FAFC20FAFD04101D044394424087207836C241801782F"
    . "4983C1014439CD0F8F07FFFFFF448B54244C488BBC24580100004C8BAC246001"
    . "0000488B9C2468010000E9E3FBFFFF448B54244C488BBC24580100004C8BAC24"
    . "60010000488B9C2468010000E9F8FBFFFFC784240801000001000000E91AFAFF"
    . "FF418B042489C689442448C1E8100FB6C0440FB6C64889F389C60FB6DF01D029"
    . "D6894424608D041A8974245889DE29D689442474428D04028974246C4489C629"
    . "D6894424688974246483F9058B8424300100000F9444243883F9030F9444243C"
    . "0384244001000031D22B842478010000894424348B8424380100000384244801"
    . "00002B8424800100008984248C0000008B8424380100008944245C8B84243001"
    . "000089442470E925F9FFFF8B4424088B54244885C04189C50F8579020000488B"
    . "842470010000488B9C24700100008B004189C1894424308B8424800100004181"
    . "E1FFFFFF0083E8010FAF84247801000089C248638424780100008B4483FC25FF"
    . "FFFF004439C84863C28B04830F95C125FFFFFF004439C80F95C008C175198B84"
    . "247801000001D048988B4483FC25FFFFFF004439C8740641B9FFFFFFFF8BBC24"
    . "8001000031DB4531DB31F685FF7E6C4C8BB42460010000448B94247801000044"
    . "8BBC24800100004585D27E3F488BBC24700100004863C689D931D2488D3C8790"
    . "8B049725FFFFFF004139C1740F4D63C54183C50143890C86438904844883C201"
    . "83C1044139D27FD84401D64183C301039C24180100004539DF75AC8BBC248001"
    . "0000448B9424780100008B842430010000038424400100004429D0894424188B"
    . "8424380100000384244801000029F8398424380100008944243C0F8F71050000"
    . "8B8424180100008B9C2430010000418D75FF0FAF842438010000448B54244844"
    . "8BB4243801000048C1E602897C24404589D141F7D98D0498488B9C2460010000"
    . "89442430448BBC24300100008B442418448B5C24304139C70F8FF50400004585"
    . "ED0F8EB40000008B03418B14244401D8440FB6C24863C80FB64C0D004429C141"
    . "39CA0F8CB80400004139C90F8FAF0400004531C0EB3A662E0F1F840000000000"
    . "428B440304438B5404044983C0044401D80FB6FA4863C80FB64C0D0029F94139"
    . "CA0F8C790400004139C90F8F700400008D48010FB6FE4863C90FB64C0D0029F9"
    . "4139CA0F8C570400004139C90F8F4E04000083C002C1EA1048980FB6D20FB644"
    . "050029D04139C20F8C330400004139C10F8F2A0400004C39C67585488B842498"
    . "010000C74424280100000044893844897004E9F2F8FFFF837C2408010F84BFFC"
    . "FFFF8B84248001000001C089C3894424288B842480010000C1E81F0384248001"
    . "0000D1F889C78B84248001000001DF897C2438894424108B5C2438395C24100F"
    . "8FFF0300008B7424108B5C242839DE89F789D87E0DC1E81F01D8D1F801D829F0"
    . "89C78B8424780100000FAFC799F7BC24800100008D1C008944240C89DE895C24"
    . "2089C3C1E81F01D8D1F801F0894424348B5C2434395C240C0F8F990400008B5C"
    . "240C8B44242039C34189DA7E134189C241C1EA1F4101C241D1FA4101C24129DA"
    . "4585ED0F8EC1FDFFFF4C8B8C2460010000418D45FF4D63DD498D5C8104438B0C"
    . "9931D24983C10489C8C1E8100FAFC7F7B4248001000031D20FAF842418010000"
    . "4189C00FB7C1410FAFC2F7B42478010000418D0480418941FC4C39CB75BFE967"
    . "FDFFFF8B842430010000038424400100008B9C2438010000894424108B842438"
    . "01000083EB010384244801000039D80F8CCF0300008BB4243001000083C0018B"
    . "8C241801000089442420448B942420010000C74424180000000044897C243C83"
    . "EE01448974244044896C24448D04B500000000897424380FAFCB894424344898"
    . "48894424288B842440010000894C243083C0028944240C8B4424108D70018B44"
    . "2438394424100F8CA70000008B4C24308B5424344189DD4C8B7C24284C634424"
    . "1841C1ED1F4C0384245001000001CA4C63F14863D24C8D4C15004929D7EB5090"
    . "4139C27E534584ED754E399C24280100007E45410FB64902410FB6510183C001"
    . "4983C0016BD24B6BC92601D14B8D140F4983C104460FB61C324489DAC1E20444"
    . "29DA01D1C1F907418848FF39C6741C89C2C1EA1F84D274A883C00141C6000049"
    . "83C1044983C00139C675E48B4C240C014C241883C3018B8C2418010000014C24"
    . "30395C24200F8533FFFFFF448B7C243C448B742440448B6C2444448B84244801"
    . "00004585C00F8E9FF3FFFF486344240C488B9C2450010000BE0100000044897C"
    . "24348B542408448B7C2448C744240C0000000044897424384889442410488D5C"
    . "03018B84244801000083C001894424304863842440010000488D480348F7D048"
    . "894424208B84244001000048894C241883E8014883C00148894424288B8C2440"
    . "01000085C90F8EA8000000488B44241848634C240C4C8D0C18488B4424204801"
    . "F94C8D0418488B4424284C8D34184889D80FB610440FB650FF41BB0100000044"
    . "01FA4439D27249440FB650014439D2723F450FB650FF4439D27235450FB651FF"
    . "4439D2722B450FB650FE4439D27221450FB6104439D27218450FB651FE4439D2"
    . "720E450FB6114439D2410F92C30F1F004883C0014488194983C1014883C10149"
    . "83C0014C39F075898B8C2440010000014C240C83C60148035C2410397424300F"
    . "8537FFFFFF448B7C2434448B74243889542408E952F2FFFF0F1F840000000000"
    . "4183C7014183C30444397C24180F8D0BFBFFFF4183C6018BBC2418010000017C"
    . "2430443974243C0F8DD7FAFFFF8B7C2440448B5C24088344240C024585DB0F85"
    . "4CFCFFFFC744242800000000E998F4FFFF8B442448448B8C24480100004531DB"
    . "31DB83C001C1E0074585C9894424488B8424400100008D3485000000000F8EC7"
    . "F1FFFF44897C240C44897424304C89A42468010000448B7C2448448BB4244001"
    . "0000448B6424184585F67E4E4963C44C63D34531C0488D4C05024901FA0F1F00"
    . "0FB6110FB641FF440FB649FE6BC04B6BD22601C24489C8C1E0044429C801D041"
    . "39C7430F9704024983C0014883C1044539C67FCC4101F44401F34183C3014403"
    . "64241044399C2448010000759A448B7C240C448B7424304C8BA42468010000E9"
    . "26F1FFFF8B84244001000083C0028944240CE963FDFFFF8344241002E9F6FAFF"
    . "FF909090909090909090909090909090"
    this.MCode(MyFunc, A_PtrSize=8 ? x64:x32)
  }
  num:=info.MaxIndex(), j:=info[index]
  , text:=j.1, w:=j.2, h:=j.3, len1:=j.4, len0:=j.5
  , e1:=(j.12 ? j.6 : Round(len1*err1))
  , e0:=(j.12 ? j.7 : Round(len0*err0))
  , mode:=j.8, color:=j.9, n:=j.10, comment:=j.11
  , sx:=in.sx, sy:=in.sy, sw:=in.sw, sh:=in.sh, Stride:=bits.Stride
  if (JoinText and index>1)
  {
    x:=in.x, y:=in.y, sw:=Min(x+offsetX+w,sx+sw), sx:=x, sw-=sx
    , sh:=Min(y+offsetY+h,sy+sh), sy:=Max(y-offsetY,sy), sh-=sy
  }
  if (mode=5 and n>0)
  {
    ListLines, % (lls:=A_ListLines)?"Off":"Off"
    r:=StrSplit(text,"/"), text:=0, i:=1, k:=4*n-4, v:=-4
    Loop, % n
      NumPut(r[i++], s1, k+=4, "uint")
      , NumPut(r[i++], s0, v+=4, "uint")
    ListLines, %lls%
  }
  else if (mode=3)
  {
    color:=(color//w)*Stride+Mod(color,w)*4
  }
  ok:=!bits.Scan0 ? 0:DllCall(&MyFunc
    , "int",mode, "uint",color, "uint",n, "int",dir
    , "Ptr",bits.Scan0, "int",Stride, "int",in.zw, "int",in.zh
    , "int",sx, "int",sy, "int",sw, "int",sh
    , "Ptr",&gs, "Ptr",&ss, "Ptr",&s1, "Ptr",&s0
    , (mode=5 ? "Ptr":"AStr"),text
    , "int",w, "int",h, "int",e1, "int",e0
    , "Ptr",&allpos, "int",allpos_max)
  pos:=[]
  Loop, % ok
    pos.Push( NumGet(allpos, 8*A_Index-8, "uint")
    , NumGet(allpos, 8*A_Index-4, "uint") )
  Loop, % ok
  {
    x:=pos[2*A_Index-1], y:=pos[2*A_Index]
    if (!JoinText)
    {
      x1:=x+in.zx, y1:=y+in.zy
      , arr.Push( {1:x1, 2:y1, 3:w, 4:h
      , x:x1+w//2, y:y1+h//2, id:comment} )
    }
    else if (index=1)
    {
      in.x:=x+w, in.y:=y, in.minY:=y, in.maxY:=y+h
      Loop, % num-1
        if !this.PicFind(arr, in, info, A_Index+1, err1, err0
        , FindAll, JoinText, offsetX, offsetY, 5
        , bits, gs, ss, s1, s0, allpos, 1)
          Continue, 2
      x1:=x+in.zx, y1:=in.minY+in.zy
      , w1:=in.x-x, h1:=in.maxY-in.minY
      , arr.Push( {1:x1, 2:y1, 3:w1, 4:h1
      , x:x1+w1//2, y:y1+h1//2, id:in.comment} )
    }
    else
    {
      in.x:=x+w, in.y:=y
      , (y<in.minY && in.minY:=y)
      , (y+h>in.maxY && in.maxY:=y+h)
      return 1
    }
    if (!FindAll and arr.MaxIndex())
      return
  }
}

GetBitsFromScreen(ByRef x, ByRef y, ByRef w, ByRef h
  , ScreenShot:=1, ByRef zx:="", ByRef zy:=""
  , ByRef zw:="", ByRef zh:="")
{
  local
  static Ptr:="Ptr"
  bits:=this.bits
  if (!ScreenShot)
  {
    zx:=bits.zx, zy:=bits.zy, zw:=bits.zw, zh:=bits.zh
    if IsByRef(x)
      w:=Min(x+w,zx+zw), x:=Max(x,zx), w-=x
      , h:=Min(y+h,zy+zh), y:=Max(y,zy), h-=y
    return bits
  }
  bch:=A_BatchLines, cri:=A_IsCritical
  Critical
  if (id:=this.BindWindow(0,0,1))
  {
    WinGet, id, ID, ahk_id %id%
    WinGetPos, zx, zy, zw, zh, ahk_id %id%
  }
  if (!id)
  {
    SysGet, zx, 76
    SysGet, zy, 77
    SysGet, zw, 78
    SysGet, zh, 79
  }
  bits.zx:=zx, bits.zy:=zy, bits.zw:=zw, bits.zh:=zh
  , w:=Min(x+w,zx+zw), x:=Max(x,zx), w-=x
  , h:=Min(y+h,zy+zh), y:=Max(y,zy), h-=y
  if (zw>bits.oldzw or zh>bits.oldzh or !bits.hBM)
  {
    hBM:=bits.hBM
    , bits.hBM:=this.CreateDIBSection(zw, zh, bpp:=32, ppvBits)
    , bits.Scan0:=(!bits.hBM ? 0:ppvBits)
    , bits.Stride:=((zw*bpp+31)//32)*4
    , bits.oldzw:=zw, bits.oldzh:=zh
    , DllCall("DeleteObject", Ptr,hBM)
  }
  if (bits.hBM) and !(w<1 or h<1)
  {
    mDC:=DllCall("CreateCompatibleDC", Ptr,0, Ptr)
    oBM:=DllCall("SelectObject", Ptr,mDC, Ptr,bits.hBM, Ptr)
    if (id)
    {
      if (mode:=this.BindWindow(0,0,0,1))<2
      {
        hDC2:=DllCall("GetDCEx", Ptr,id, Ptr,0, "int",3, Ptr)
        DllCall("BitBlt",Ptr,mDC,"int",x-zx,"int",y-zy,"int",w,"int",h
        , Ptr,hDC2, "int",x-zx, "int",y-zy, "uint",0xCC0020|0x40000000)
        DllCall("ReleaseDC", Ptr,id, Ptr,hDC2)
      }
      else
      {
        hBM2:=this.CreateDIBSection(zw, zh)
        mDC2:=DllCall("CreateCompatibleDC", Ptr,0, Ptr)
        oBM2:=DllCall("SelectObject", Ptr,mDC2, Ptr,hBM2, Ptr)
        DllCall("PrintWindow", Ptr,id, Ptr,mDC2, "uint",(mode>3)*3)
        DllCall("BitBlt",Ptr,mDC,"int",x-zx,"int",y-zy,"int",w,"int",h
        , Ptr,mDC2, "int",x-zx, "int",y-zy, "uint",0xCC0020|0x40000000)
        DllCall("SelectObject", Ptr,mDC2, Ptr,oBM2)
        DllCall("DeleteDC", Ptr,mDC2)
        DllCall("DeleteObject", Ptr,hBM2)
      }
    }
    else
    {
      win:=DllCall("GetDesktopWindow", Ptr)
      hDC:=DllCall("GetWindowDC", Ptr,win, Ptr)
      DllCall("BitBlt",Ptr,mDC,"int",x-zx,"int",y-zy,"int",w,"int",h
      , Ptr,hDC, "int",x, "int",y, "uint",0xCC0020|0x40000000)
      DllCall("ReleaseDC", Ptr,win, Ptr,hDC)
    }
    if this.CaptureCursor(0,0,0,0,0,1)
      this.CaptureCursor(mDC, zx, zy, zw, zh)
    DllCall("SelectObject", Ptr,mDC, Ptr,oBM)
    DllCall("DeleteDC", Ptr,mDC)
  }
  Critical, %cri%
  SetBatchLines, %bch%
  return bits
}

CreateDIBSection(w, h, bpp:=32, ByRef ppvBits:=0, ByRef bi:="")
{
  local
  VarSetCapacity(bi, 40, 0), NumPut(40, bi, 0, "int")
  , NumPut(w, bi, 4, "int"), NumPut(-h, bi, 8, "int")
  , NumPut(1, bi, 12, "short"), NumPut(bpp, bi, 14, "short")
  return DllCall("CreateDIBSection", "Ptr",0, "Ptr",&bi
    , "int",0, "Ptr*",ppvBits:=0, "Ptr",0, "int",0, "Ptr")
}

PicInfo(text)
{
  local
  static info:=[], Ptr:="Ptr"
  if !InStr(text,"$")
    return
  if (info[text])
    return info[text]
  v:=text, comment:="", seterr:=e1:=e0:=len1:=len0:=0
  ; You Can Add Comment Text within The <>
  if RegExMatch(v,"<([^>]*)>",r)
    v:=StrReplace(v,r), comment:=Trim(r1)
  ; You can Add two fault-tolerant in the [], separated by commas
  if RegExMatch(v,"\[([^\]]*)]",r)
  {
    v:=StrReplace(v,r), r:=StrSplit(r1, ",")
    , seterr:=1, e1:=r.1, e0:=r.2
  }
  color:=StrSplit(v,"$").1, v:=Trim(SubStr(v,InStr(v,"$")+1))
  mode:=InStr(color,"##") ? 5
    : InStr(color,"-") ? 4 : InStr(color,"#") ? 3
    : InStr(color,"**") ? 2 : InStr(color,"*") ? 1 : 0
  color:=RegExReplace(color,"[*#]")
  if (mode=5) and FileExist(v)
  {
    if !IsObject(r:=info["file:" v])
    {
      if !(hBM:=LoadPicture(v))
        return
      VarSetCapacity(bm, size:=(A_PtrSize=8 ? 32:24), 0)
      DllCall("GetObject", Ptr,hBM, "int",size, Ptr,&bm)
      w:=NumGet(bm,4,"int"), h:=Abs(NumGet(bm,8,"int"))
      hBM2:=this.CreateDIBSection(w, h, 32, ppvBits)
      this.CopyHBM(hBM2, hBM, 0, 0, w, h)
      DllCall("DeleteObject", Ptr,hBM)
      if (w<1 or h<1 or !ppvBits)
        return
      info["file:" v]:=r:=[ppvBits, w, h]
    }
    v:=r.1, w:=r.2, h:=r.3, n:=0, seterr:=1
  }
  else if (mode=5)
  {
    v:=Trim(StrReplace(RegExReplace(v,"\s"),",","/"),"/")
    r:=StrSplit(v,"/"), n:=r.MaxIndex()//3
    if (!n)
      return
    v:="", x1:=x2:=r.1, y1:=y2:=r.2, i:=j:=-2
    ListLines, % (lls:=A_ListLines)?"Off":"Off"
    Loop, % n
      x:=r[i+=3], y:=r[i+1]
      , (x<x1 && x1:=x), (x>x2 && x2:=x)
      , (y<y1 && y1:=y), (y>y2 && y2:=y)
    Loop, % n
      v.="/" (r[j+=3]-x1)|((r[j+1]-y1)<<16)
      . "/0x" . StrReplace(r[j+2],"0x")
    ListLines, %lls%
    v:=SubStr(v,2), w:=x2-x1+1, h:=y2-y1+1, seterr:=1
  }
  else
  {
    r:=StrSplit(v,"."), w:=r.1
    , v:=this.base64tobit(r.2), h:=StrLen(v)//w
    if (w<1 or h<1 or StrLen(v)!=w*h)
      return
    if (mode=4)
    {
      r:=StrSplit(StrReplace(color,"0x"),"-")
      , color:=Round("0x" r.1), n:=Round("0x" r.2)
    }
    else
    {
      r:=StrSplit(color,"@")
      , color:=r.1, n:=Round(r.2,2)+(!r.2)
      , n:=Floor(512*9*255*255*(1-n)*(1-n))
    }
    StrReplace(v,"1","",len1), len0:=StrLen(v)-len1
    , e1:=Round(len1*e1), e0:=Round(len0*e0)
  }
  return info[text]:=[v,w,h,len1,len0,e1,e0
    , mode,color,n,comment,seterr]
}

CopyHBM(hBM, hBM2, x, y, w, h)
{
  local
  static Ptr:="Ptr"
  mDC:=DllCall("CreateCompatibleDC", Ptr,0, Ptr)
  oBM:=DllCall("SelectObject", Ptr,mDC, Ptr,hBM, Ptr)
  mDC2:=DllCall("CreateCompatibleDC", Ptr,0, Ptr)
  oBM2:=DllCall("SelectObject", Ptr,mDC2, Ptr,hBM2, Ptr)
  DllCall("BitBlt",Ptr,mDC,"int",0,"int",0,"int",w,"int",h
  , Ptr,mDC2, "int",x, "int",y, "uint",0xCC0020)
  DllCall("SelectObject", Ptr,mDC2, Ptr,oBM2)
  DllCall("DeleteDC", Ptr,mDC2)
  DllCall("SelectObject", Ptr,mDC, Ptr,oBM)
  DllCall("DeleteDC", Ptr,mDC)
}

; Bind the window so that it can find images when obscured
; by other windows, it's equivalent to always being
; at the front desk. Unbind Window using FindText.BindWindow(0)

BindWindow(bind_id:=0, bind_mode:=0, get_id:=0, get_mode:=0)
{
  local
  bind:=this.bind
  if (get_id)
    return bind.id
  if (get_mode)
    return bind.mode
  if (bind_id)
  {
    bind.id:=bind_id, bind.mode:=bind_mode, bind.oldStyle:=0
    if (bind_mode & 1)
    {
      WinGet, oldStyle, ExStyle, ahk_id %bind_id%
      bind.oldStyle:=oldStyle
      WinSet, Transparent, 255, ahk_id %bind_id%
      Loop, 30
      {
        Sleep, 100
        WinGet, i, Transparent, ahk_id %bind_id%
      }
      Until (i=255)
    }
  }
  else
  {
    bind_id:=bind.id
    if (bind.mode & 1)
      WinSet, ExStyle, % bind.oldStyle, ahk_id %bind_id%
    bind.id:=0, bind.mode:=0, bind.oldStyle:=0
  }
}

; Use FindText.CaptureCursor(1) to Capture Cursor
; Use FindText.CaptureCursor(0) to Cancel Capture Cursor

CaptureCursor(hDC:=0, zx:=0, zy:=0, zw:=0, zh:=0, get_cursor:=0)
{
  local
  if (get_cursor)
    return this.Cursor
  if (hDC=1 or hDC=0) and (zw=0)
  {
    this.Cursor:=hDC
    return
  }
  Ptr:=(A_PtrSize ? "Ptr":"UInt"), PtrSize:=(A_PtrSize=8 ? 8:4)
  VarSetCapacity(mi, 40, 0), NumPut(16+PtrSize, mi, "int")
  DllCall("GetCursorInfo", Ptr,&mi)
  bShow   := NumGet(mi, 4, "int")
  hCursor := NumGet(mi, 8, Ptr)
  x := NumGet(mi, 8+PtrSize, "int")
  y := NumGet(mi, 12+PtrSize, "int")
  if (!bShow) or (x<zx or y<zy or x>=zx+zw or y>=zy+zh)
    return
  VarSetCapacity(ni, 40, 0)
  DllCall("GetIconInfo", Ptr,hCursor, Ptr,&ni)
  xCenter  := NumGet(ni, 4, "int")
  yCenter  := NumGet(ni, 8, "int")
  hBMMask  := NumGet(ni, (PtrSize=8?16:12), Ptr)
  hBMColor := NumGet(ni, (PtrSize=8?24:16), Ptr)
  DllCall("DrawIconEx", Ptr,hDC
    , "int",x-xCenter-zx, "int",y-yCenter-zy, Ptr,hCursor
    , "int",0, "int",0, "int",0, "int",0, "int",3)
  DllCall("DeleteObject", Ptr,hBMMask)
  DllCall("DeleteObject", Ptr,hBMColor)
}

MCode(ByRef code, hex)
{
  local
  ListLines, % (lls:=A_ListLines)?"Off":"Off"
  SetBatchLines, % (bch:=A_BatchLines)?"-1":"-1"
  VarSetCapacity(code, len:=StrLen(hex)//2)
  Loop, % len
    NumPut("0x" SubStr(hex,2*A_Index-1,2),code,A_Index-1,"uchar")
  DllCall("VirtualProtect","Ptr",&code,"Ptr",len,"uint",0x40,"Ptr*",0)
  SetBatchLines, %bch%
  ListLines, %lls%
}

base64tobit(s)
{
  local
  Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    . "abcdefghijklmnopqrstuvwxyz"
  ListLines, % (lls:=A_ListLines)?"Off":"Off"
  Loop, Parse, Chars
  {
    i:=A_Index-1, v:=(i>>5&1) . (i>>4&1)
      . (i>>3&1) . (i>>2&1) . (i>>1&1) . (i&1)
    s:=RegExReplace(s,"[" A_LoopField "]",StrReplace(v,"0x"))
  }
  ListLines, %lls%
  return RegExReplace(RegExReplace(s,"10*$"),"[^01]+")
}

bit2base64(s)
{
  local
  s:=RegExReplace(s,"[^01]+")
  s.=SubStr("100000",1,6-Mod(StrLen(s),6))
  s:=RegExReplace(s,".{6}","|$0")
  Chars:="0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    . "abcdefghijklmnopqrstuvwxyz"
  ListLines, % (lls:=A_ListLines)?"Off":"Off"
  Loop, Parse, Chars
  {
    i:=A_Index-1, v:="|" . (i>>5&1) . (i>>4&1)
      . (i>>3&1) . (i>>2&1) . (i>>1&1) . (i&1)
    s:=StrReplace(s,StrReplace(v,"0x"),A_LoopField)
  }
  ListLines, %lls%
  return s
}

xywh2xywh(x1,y1,w1,h1, ByRef x, ByRef y, ByRef w, ByRef h
  , ByRef zx:="", ByRef zy:="", ByRef zw:="", ByRef zh:="")
{
  local
  SysGet, zx, 76
  SysGet, zy, 77
  SysGet, zw, 78
  SysGet, zh, 79
  w:=Min(x1+w1,zx+zw), x:=Max(x1,zx), w-=x
  , h:=Min(y1+h1,zy+zh), y:=Max(y1,zy), h-=y
}

ASCII(s)
{
  local
  if RegExMatch(s,"\$(\d+)\.([\w+/]+)",r)
  {
    s:=RegExReplace(this.base64tobit(r2),".{" r1 "}","$0`n")
    s:=StrReplace(StrReplace(s,"0","_"),"1","0")
  }
  else s=
  return s
}

; You can put the text library at the beginning of the script,
; and Use FindText.PicLib(Text,1) to add the text library to PicLib()'s Lib,
; Use FindText.PicLib("comment1|comment2|...") to get text images from Lib

PicLib(comments, add_to_Lib:=0, index:=1)
{
  local
  Lib:=this.Lib
  if (add_to_Lib)
  {
    re:="<([^>]*)>[^$]+\$\d+\.[\w+/]+"
    Loop, Parse, comments, |
      if RegExMatch(A_LoopField,re,r)
      {
        s1:=Trim(r1), s2:=""
        Loop, Parse, s1
          s2.="_" . Format("{:d}",Ord(A_LoopField))
        Lib[index,s2]:=r
      }
    Lib[index,""]:=""
  }
  else
  {
    Text:=""
    Loop, Parse, comments, |
    {
      s1:=Trim(A_LoopField), s2:=""
      Loop, Parse, s1
        s2.="_" . Format("{:d}",Ord(A_LoopField))
      Text.="|" . Lib[index,s2]
    }
    return Text
  }
}

; Decompose a string into individual characters and get their data

PicN(Number, index:=1)
{
  return this.PicLib(RegExReplace(Number,".","|$0"), 0, index)
}

; Use FindText.PicX(Text) to automatically cut into multiple characters
; Can't be used in ColorPos mode, because it can cause position errors

PicX(Text)
{
  local
  if !RegExMatch(Text,"(<[^$]+)\$(\d+)\.([\w+/]+)",r)
    return Text
  v:=this.base64tobit(r3), Text:=""
  c:=StrLen(StrReplace(v,"0"))<=StrLen(v)//2 ? "1":"0"
  txt:=RegExReplace(v,".{" r2 "}","$0`n")
  While InStr(txt,c)
  {
    While !(txt~="m`n)^" c)
      txt:=RegExReplace(txt,"m`n)^.")
    i:=0
    While (txt~="m`n)^.{" i "}" c)
      i:=Format("{:d}",i+1)
    v:=RegExReplace(txt,"m`n)^(.{" i "}).*","$1")
    txt:=RegExReplace(txt,"m`n)^.{" i "}")
    if (v!="")
      Text.="|" r1 "$" i "." this.bit2base64(v)
  }
  return Text
}

; Screenshot and retained as the last screenshot.

ScreenShot(x1:=0, y1:=0, x2:=0, y2:=0)
{
  this.FindText(x1, y1, x2, y2)
}

; Get the RGB color of a point from the last screenshot.
; If the point to get the color is beyond the range of
; Screen, it will return White color (0xFFFFFF).

GetColor(x, y, fmt:=1)
{
  local
  bits:=this.GetBitsFromScreen(0,0,0,0,0,zx,zy,zw,zh)
  , c:=(x<zx or x>=zx+zw or y<zy or y>=zy+zh or !bits.Scan0)
  ? 0xFFFFFF : NumGet(bits.Scan0+(y-zy)*bits.Stride+(x-zx)*4,"uint")
  return (fmt ? Format("0x{:06X}",c&0xFFFFFF) : c)
}

; Set the RGB color of a point in the last screenshot

SetColor(x, y, color:=0x000000)
{
  local
  bits:=this.GetBitsFromScreen(0,0,0,0,0,zx,zy,zw,zh)
  if !(x<zx or x>=zx+zw or y<zy or y>=zy+zh or !bits.Scan0)
    NumPut(color,bits.Scan0+(y-zy)*bits.Stride+(x-zx)*4,"uint")
}

; Identify a line of text or verification code
; based on the result returned by FindText().
; offsetX is the maximum interval between two texts,
; if it exceeds, a "*" sign will be inserted.
; offsetY is the maximum height difference between two texts.
; Return Association array {text:Text, x:X, y:Y, w:W, h:H}

Ocr(ok, offsetX:=20, offsetY:=20)
{
  local
  ocr_Text:=ocr_X:=ocr_Y:=min_X:=dx:=""
  For k,v in ok
    x:=v.1
    , min_X:=(A_Index=1 or x<min_X ? x : min_X)
    , max_X:=(A_Index=1 or x>max_X ? x : max_X)
  While (min_X!="" and min_X<=max_X)
  {
    LeftX:=""
    For k,v in ok
    {
      x:=v.1, y:=v.2
      if (x<min_X) or Abs(y-ocr_Y)>offsetY
        Continue
      ; Get the leftmost X coordinates
      if (LeftX="" or x<LeftX)
        LeftX:=x, LeftY:=y, LeftW:=v.3, LeftH:=v.4, LeftOCR:=v.id
    }
    if (LeftX="")
      Break
    if (ocr_X="")
      ocr_X:=LeftX, min_Y:=LeftY, max_Y:=LeftY+LeftH
    ; If the interval exceeds the set value, add "*" to the result
    ocr_Text.=(ocr_Text!="" and LeftX>dx ? "*":"") . LeftOCR
    ; Update for next search
    min_X:=LeftX+LeftW-LeftW//2, dx:=LeftX+LeftW+offsetX
    , ocr_Y:=LeftY, (LeftY<min_Y && min_Y:=LeftY)
    , (LeftY+LeftH>max_Y && max_Y:=LeftY+LeftH)
  }
  return {text:ocr_Text, x:ocr_X, y:min_Y
    , w: min_X-ocr_X, h: max_Y-min_Y}
}

; Sort the results returned by FindText() from left to right
; and top to bottom, ignore slight height difference

Sort(ok, dy:=10)
{
  local
  if !IsObject(ok)
    return ok
  ypos:=[]
  For k,v in ok
  {
    x:=v.x, y:=v.y, add:=1
    For k2,v2 in ypos
      if Abs(y-v2)<=dy
      {
        y:=v2, add:=0
        Break
      }
    if (add)
      ypos.Push(y)
    n:=(y*150000+x) "." k, s:=A_Index=1 ? n : s "-" n
  }
  Sort, s, N D-
  ok2:=[]
  Loop, Parse, s, -
    ok2.Push( ok[(StrSplit(A_LoopField,".")[2])] )
  return ok2
}

; Reordering according to the nearest distance

Sort2(ok, px, py)
{
  local
  if !IsObject(ok)
    return ok
  For k,v in ok
    n:=((v.x-px)**2+(v.y-py)**2) "." k, s:=A_Index=1 ? n : s "-" n
  Sort, s, N D-
  ok2:=[]
  Loop, Parse, s, -
    ok2.Push( ok[(StrSplit(A_LoopField,".")[2])] )
  return ok2
}

; Prompt mouse position in remote assistance

MouseTip(x:="", y:="", w:=10, h:=10, d:=4)
{
  local
  if (x="")
  {
    VarSetCapacity(pt,16,0), DllCall("GetCursorPos","ptr",&pt)
    x:=NumGet(pt,0,"uint"), y:=NumGet(pt,4,"uint")
  }
  x:=Round(x-w-d), y:=Round(y-h-d), w:=(2*w+1)+2*d, h:=(2*h+1)+2*d
  ;-------------------------
  Gui, _MouseTip_: +AlwaysOnTop -Caption +ToolWindow +Hwndmyid -DPIScale
  Gui, _MouseTip_: Show, Hide w%w% h%h%
  ;-------------------------
  DetectHiddenWindows, % (dhw:=A_DetectHiddenWindows)?"On":"On"
  i:=w-d, j:=h-d
  s=0-0 %w%-0 %w%-%h% 0-%h% 0-0  %d%-%d% %i%-%d% %i%-%j% %d%-%j% %d%-%d%
  WinSet, Region, %s%, ahk_id %myid%
  DetectHiddenWindows, %dhw%
  ;-------------------------
  Gui, _MouseTip_: Show, NA x%x% y%y%
  Loop, 4
  {
    Gui, _MouseTip_: Color, % A_Index & 1 ? "Red" : "Blue"
    Sleep, 500
  }
  Gui, _MouseTip_: Destroy
}

; Quickly get the search data of screen image

GetTextFromScreen(x1, y1, x2, y2, Threshold:=""
  , ScreenShot:=1, ByRef rx:="", ByRef ry:="")
{
  local
  SetBatchLines, % (bch:=A_BatchLines)?"-1":"-1"
  x:=Min(x1,x2), y:=Min(y1,y2), w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1
  this.GetBitsFromScreen(x,y,w,h,ScreenShot,zx,zy,zw,zh)
  if (w<1 or h<1)
  {
    SetBatchLines, %bch%
    return
  }
  ListLines, % (lls:=A_ListLines)?"Off":"Off"
  gs:=[], k:=0
  Loop, %h%
  {
    j:=y+A_Index-1
    Loop, %w%
      i:=x+A_Index-1, c:=this.GetColor(i,j,0)
      , gs[++k]:=(((c>>16)&0xFF)*38+((c>>8)&0xFF)*75+(c&0xFF)*15)>>7
  }
  if InStr(Threshold,"**")
  {
    Threshold:=StrReplace(Threshold,"*")
    if (Threshold="")
      Threshold:=50
    s:="", sw:=w, w-=2, h-=2, x++, y++
    Loop, %h%
    {
      y1:=A_Index
      Loop, %w%
        x1:=A_Index, i:=y1*sw+x1+1, j:=gs[i]+Threshold
        , s.=( gs[i-1]>j || gs[i+1]>j
        || gs[i-sw]>j || gs[i+sw]>j
        || gs[i-sw-1]>j || gs[i-sw+1]>j
        || gs[i+sw-1]>j || gs[i+sw+1]>j ) ? "1":"0"
    }
    Threshold:="**" Threshold
  }
  else
  {
    Threshold:=StrReplace(Threshold,"*")
    if (Threshold="")
    {
      pp:=[]
      Loop, 256
        pp[A_Index-1]:=0
      Loop, % w*h
        pp[gs[A_Index]]++
      IP:=IS:=0
      Loop, 256
        k:=A_Index-1, IP+=k*pp[k], IS+=pp[k]
      Threshold:=Floor(IP/IS)
      Loop, 20
      {
        LastThreshold:=Threshold
        IP1:=IS1:=0
        Loop, % LastThreshold+1
          k:=A_Index-1, IP1+=k*pp[k], IS1+=pp[k]
        IP2:=IP-IP1, IS2:=IS-IS1
        if (IS1!=0 and IS2!=0)
          Threshold:=Floor((IP1/IS1+IP2/IS2)/2)
        if (Threshold=LastThreshold)
          Break
      }
    }
    s:=""
    Loop, % w*h
      s.=gs[A_Index]<=Threshold ? "1":"0"
    Threshold:="*" Threshold
  }
  ;--------------------
  w:=Format("{:d}",w), CutUp:=CutDown:=0
  re1=(^0{%w%}|^1{%w%})
  re2=(0{%w%}$|1{%w%}$)
  While RegExMatch(s,re1)
    s:=RegExReplace(s,re1), CutUp++
  While RegExMatch(s,re2)
    s:=RegExReplace(s,re2), CutDown++
  rx:=x+w//2, ry:=y+CutUp+(h-CutUp-CutDown)//2
  s:="|<>" Threshold "$" w "." this.bit2base64(s)
  ;--------------------
  SetBatchLines, %bch%
  ListLines, %lls%
  return s
}

; Quickly save screen image to BMP file for debugging

SavePic(file, x1:=0, y1:=0, x2:=0, y2:=0, ScreenShot:=1)
{
  local
  static Ptr:="Ptr"
  if (x1*x1+y1*y1+x2*x2+y2*y2<=0)
    n:=150000, x:=y:=-n, w:=h:=2*n
  else
    x:=Min(x1,x2), y:=Min(y1,y2), w:=Abs(x2-x1)+1, h:=Abs(y2-y1)+1
  bits:=this.GetBitsFromScreen(x,y,w,h,ScreenShot,zx,zy,zw,zh)
  if (w<1 or h<1 or !bits.hBM)
    return
  hBM:=this.CreateDIBSection(w, h, bpp:=24, ppvBits, bi)
  this.CopyHBM(hBM, bits.hBM, x-zx, y-zy, w, h)
  size:=((w*bpp+31)//32)*4*h, NumPut(size, bi, 20, "uint")
  VarSetCapacity(bf, 14, 0), StrPut("BM", &bf, "CP0")
  NumPut(54+size, bf, 2, "uint"), NumPut(54, bf, 10, "uint")
  f:=FileOpen(file,"w"), f.RawWrite(bf,14), f.RawWrite(bi,40)
  , f.RawWrite(ppvBits+0, size), f.Close()
  DllCall("DeleteObject", Ptr,hBM)
}

; Show the saved BMP file

ShowPic(file:="", show:=1)
{
  local
  static Ptr:="Ptr"
  Gui, FindText_Screen: Destroy
  if (file="") or !FileExist(file)
    return
  bits:=this.GetBitsFromScreen(0,0,0,0,1,zx,zy,zw,zh)
  hBM:=bits.hBM, hBM2:=LoadPicture(file)
  this.CopyHBM(hBM, hBM2, 0, 0, zw, zh)
  DllCall("DeleteObject", Ptr,hBM2)
  if (!show)
    return
  Gui, FindText_Screen: +AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000
  Gui, FindText_Screen: Margin, 0, 0
  Gui, FindText_Screen: Add, Pic,, HBITMAP:*%hBM%
  Gui, FindText_Screen: Show, NA x%zx% y%zy% w%zw% h%zh%, Show Pic
}

; Running AHK code dynamically with new threads

Class Thread
{
  __New(args*)
  {
    this.pid:=this.Exec(args*)
  }
  __Delete()
  {
    Process, Close, % this.pid
  }
  Exec(s, Ahk:="", args:="")
  {
    local
    Ahk:=Ahk ? Ahk:A_IsCompiled ? A_ScriptDir "\AutoHotkey.exe":A_AhkPath
    s:="DllCall(""SetWindowText"",""Ptr"",A_ScriptHwnd,""Str"",""<AHK>"")`n"
      . StrReplace(s,"`r"), pid:=""
    Try
    {
      shell:=ComObjCreate("WScript.Shell")
      oExec:=shell.Exec("""" Ahk """ /f * " args)
      oExec.StdIn.Write(s)
      oExec.StdIn.Close(), pid:=oExec.ProcessID
    }
    Catch
    {
      f:=A_Temp "\~ahk.tmp"
      s:="`n FileDelete, " f "`n" s
      FileDelete, %f%
      FileAppend, %s%, %f%
      r:=ObjBindMethod(this, "Clear")
      SetTimer, %r%, -3000
      Run, "%Ahk%" /f "%f%" %args%,, UseErrorLevel, pid
    }
    return pid
  }
  Clear()
  {
    FileDelete, % A_Temp "\~ahk.tmp"
    SetTimer,, Off
  }
}

WindowToScreen(ByRef x, ByRef y, x1, y1, id:="")
{
  local
  WinGetPos, winx, winy,,, % id ? "ahk_id " id : "A"
  x:=x1+Floor(winx), y:=y1+Floor(winy)
}

ScreenToWindow(ByRef x, ByRef y, x1, y1, id:="")
{
  local
  this.WindowToScreen(dx,dy,0,0,id), x:=x1-dx, y:=y1-dy
}

ClientToScreen(ByRef x, ByRef y, x1, y1, id:="")
{
  local
  if (!id)
    WinGet, id, ID, A
  VarSetCapacity(pt,8,0), NumPut(0,pt,"int64")
  , DllCall("ClientToScreen","Ptr",id,"Ptr",&pt)
  , x:=x1+NumGet(pt,"int"), y:=y1+NumGet(pt,4,"int")
}

ScreenToClient(ByRef x, ByRef y, x1, y1, id:="")
{
  local
  this.ClientToScreen(dx,dy,0,0,id), x:=x1-dx, y:=y1-dy
}

QPC()  ; <==> A_TickCount
{
  local
  static c:=0, f:=0, init:=DllCall("QueryPerformanceFrequency", "Int*",f)
  return (!DllCall("QueryPerformanceCounter","Int64*",c))*0+(c/f)*1000
}

; It is not like FindText always use Screen Coordinates,
; But like built-in command ImageSearch using CoordMode Settings

ImageSearch(ByRef rx, ByRef ry, x1, y1, x2, y2, text
  , ScreenShot:=1, FindAll:=0)
{
  local
  dx:=dy:=0
  if (A_CoordModePixel="Window")
    this.WindowToScreen(dx,dy,0,0)
  else if (A_CoordModePixel="Client")
    this.ClientToScreen(dx,dy,0,0)
  if (ok:=this.FindText(x1+dx, y1+dy, x2+dx, y2+dy
    , 0, 0, text, ScreenShot, FindAll))
  {
    rx:=ok.1.x-dx, ry:=ok.1.y-dy, ErrorLevel:=0
    return 1
  }
  else
  {
    rx:=ry:="", ErrorLevel:=1
    return 0
  }
}


/***** C source code of machine code *****

int __attribute__((__stdcall__)) PicFind(
  int mode, unsigned int c, unsigned int n, int dir
  , unsigned char * Bmp, int Stride, int zw, int zh
  , int sx, int sy, int sw, int sh
  , unsigned char * gs, char * ss
  , unsigned int * s1, unsigned int * s0
  , char * text, int w, int h, int err1, int err0
  , unsigned int * allpos, int allpos_max )
{
  int ok=0, o, i, j, k, v, r, g, b, rr, gg, bb;
  int x, y, x1, y1, x2, y2, len1, len0, e1, e0, max;
  int r_min, r_max, g_min, g_max, b_min, b_max;
  int x3, y3, ww, hh, w1, h1, w2, h2, w3, h3;
  unsigned int * Bmp2;
  //----------------------
  // MultiColor or PixelSearch or ImageSearch Mode
  if (mode==5)
  {
    max=n; e1=c; e0=-c;
    if (max==0)  // ImageSearch
    {
      o=0; Bmp2=(unsigned int *)text;
      i=Bmp2[0]&0xFFFFFF; j=Bmp2[w-1]&0xFFFFFF;
      k=Bmp2[w*h-w]&0xFFFFFF; v=Bmp2[w*h-1]&0xFFFFFF;
      if (i!=j || i!=k || i!=v) i=-1;
      for (y=0; y<h; y++)
      for (x=0; x<w; x++)
      {
        j=Bmp2[o++]&0xFFFFFF;
        if (j!=i) { s1[max]=y*Stride+x*4; s0[max++]=j; }
      }
      ww=w; hh=h;
      goto GoSub5;
    }
    if (max==1)  // PixelSearch
    {
      c=s0[0]; r=(c>>16)&0xFF; g=(c>>8)&0xFF; b=c&0xFF;
      r_min=r-e1; g_min=g-e1; b_min=b-e1;
      r_max=r+e1; g_max=g+e1; b_max=b+e1;
      goto StartLookUp;
    }
    // MultiColor Search
    for (h1=h, h2=h1*2, h3=h2+h1/2; h1<=h3; h1+=2)
    {
      hh=(h1>h2) ? h2+h2/2-h1 : h1;
      for (w1=w*hh/h, w2=w1*2, w3=w2+w1/2; w1<=w3; w1+=2)
      {
        ww=(w1>w2) ? w2+w2/2-w1 : w1;
        for (i=0; i<max; i++)
        {
          c=s1[i+max];
          s1[i]=((c>>16)*hh/h)*Stride+((c&0xFFFF)*ww/w)*4;
        }
        GoSub5:
        x2=sx+sw-ww; y2=sy+sh-hh;
        for (y=sy; y<=y2; y++)
        for (x=sx; x<=x2; x++)
        {
          o=y*Stride+x*4;
          for (i=0; i<max; i++)
          {
            j=o+s1[i]; c=s0[i];
            b=Bmp[j]-(c&0xFF);
            if (b>e1 || b<e0) goto NoMatch5;
            g=Bmp[1+j]-((c>>8)&0xFF);
            if (g>e1 || g<e0) goto NoMatch5;
            r=Bmp[2+j]-((c>>16)&0xFF);
            if (r>e1 || r<e0) goto NoMatch5;
          }
          allpos[0]=x; allpos[1]=y; ok=1; goto Return1;
          NoMatch5:;
        }
        if (n==0) goto Return1;
      }
    }
    goto Return1;
  }
  //----------------------
  // Generate Lookup Table
  o=0; len1=0; len0=0;
  for (y=0; y<h; y++)
  {
    for (x=0; x<w; x++)
    {
      i=(mode==3) ? y*Stride+x*4 : y*sw+x;
      if (text[o++]=='1')
        s1[len1++]=i;
      else
        s0[len0++]=i;
    }
  }
  if (err1>=len1) len1=0;
  if (err0>=len0) len0=0;
  max=(len1>len0) ? len1 : len0;
  //----------------------
  // Color Position Mode
  // only used to recognize multicolored Verification Code
  if (mode==3) goto StartLookUp;
  //----------------------
  // Generate Two Value Image
  o=sy*Stride+sx*4; j=Stride-sw*4; i=0;
  if (mode==0)  // Color Mode
  {
    rr=(c>>16)&0xFF; gg=(c>>8)&0xFF; bb=c&0xFF;
    for (y=0; y<sh; y++, o+=j)
      for (x=0; x<sw; x++, o+=4, i++)
      {
        r=Bmp[2+o]-rr; g=Bmp[1+o]-gg; b=Bmp[o]-bb; v=r+rr+rr;
        ss[i]=((1024+v)*r*r+2048*g*g+(1534-v)*b*b<=n) ? 1:0;
      }
  }
  else if (mode==1)  // Gray Threshold Mode
  {
    c=(c+1)<<7;
    for (y=0; y<sh; y++, o+=j)
      for (x=0; x<sw; x++, o+=4, i++)
        ss[i]=(Bmp[2+o]*38+Bmp[1+o]*75+Bmp[o]*15<c) ? 1:0;
  }
  else if (mode==2)  // Gray Difference Mode
  {
    x2=sx+sw; y2=sy+sh;
    for (y=sy-1; y<=y2; y++)
    {
      for (x=sx-1; x<=x2; x++, i++)
        if (x<0 || x>=zw || y<0 || y>=zh)
          gs[i]=0;
        else
        {
          o=y*Stride+x*4;
          gs[i]=(Bmp[2+o]*38+Bmp[1+o]*75+Bmp[o]*15)>>7;
        }
    }
    k=sw+2; i=0;
    for (y=1; y<=sh; y++)
      for (x=1; x<=sw; x++, i++)
      {
        o=y*k+x; n=gs[o]+c;
        ss[i]=(gs[o-1]>n || gs[o+1]>n
          || gs[o-k]>n   || gs[o+k]>n
          || gs[o-k-1]>n || gs[o-k+1]>n
          || gs[o+k-1]>n || gs[o+k+1]>n) ? 1:0;
      }
  }
  else  // (mode==4) Color Difference Mode
  {
    r=(c>>16)&0xFF; g=(c>>8)&0xFF; b=c&0xFF;
    rr=(n>>16)&0xFF; gg=(n>>8)&0xFF; bb=n&0xFF;
    r_min=r-rr; g_min=g-gg; b_min=b-bb;
    r_max=r+rr; g_max=g+gg; b_max=b+bb;
    for (y=0; y<sh; y++, o+=j)
      for (x=0; x<sw; x++, o+=4, i++)
      {
        r=Bmp[2+o]; g=Bmp[1+o]; b=Bmp[o];
        ss[i]=(r>=r_min && r<=r_max
            && g>=g_min && g<=g_max
            && b>=b_min && b<=b_max) ? 1:0;
      }
  }
  //----------------------
  StartLookUp:
  if (mode==5 || mode==3)
    { x1=sx; y1=sy; x2=sx+sw-w; y2=sy+sh-h; k=0; }
  else
    { x1=0; y1=0; x2=sw-w; y2=sh-h; k=1; }
  if (dir<1 || dir>8) dir=1;
  // 1 ==> Top to Bottom ( Left to Right )
  // 2 ==> Top to Bottom ( Right to Left )
  // 3 ==> Bottom to Top ( Left to Right )
  // 4 ==> Bottom to Top ( Right to Left )
  // 5 ==> Left to Right ( Top to Bottom )
  // 6 ==> Left to Right ( Bottom to Top )
  // 7 ==> Right to Left ( Top to Bottom )
  // 8 ==> Right to Left ( Bottom to Top )
  if (dir>4)
    { i=x1; j=x2; x1=y1; x2=y2; y1=i; y2=j; dir-=4; }
  for (y3=y1; y3<=y2; y3++)
  {
    y=(dir>2) ? y1+y2-y3 : y3;
    for (x3=x1; x3<=x2; x3++)
    {
      x=(dir & 1 == 0) ? x1+x2-x3 : x3;
      if (mode==5)
      {
        o=y*Stride+x*4; r=Bmp[2+o]; g=Bmp[1+o]; b=Bmp[o];
        if (r<r_min || r>r_max
        ||  g<g_min || g>g_max
        ||  b<b_min || b>b_max)
          goto NoMatch;
      }
      else if (mode==3)
      {
        o=y*Stride+x*4; e1=err1; e0=err0;
        j=o+c; rr=Bmp[2+j]; gg=Bmp[1+j]; bb=Bmp[j];
        for (i=0; i<max; i++)
        {
          if (i<len1)
          {
            j=o+s1[i]; r=Bmp[2+j]-rr; g=Bmp[1+j]-gg; b=Bmp[j]-bb; v=r+rr+rr;
            if ((1024+v)*r*r+2048*g*g+(1534-v)*b*b>n && (--e1)<0)
              goto NoMatch;
          }
          if (i<len0)
          {
            j=o+s0[i]; r=Bmp[2+j]-rr; g=Bmp[1+j]-gg; b=Bmp[j]-bb; v=r+rr+rr;
            if ((1024+v)*r*r+2048*g*g+(1534-v)*b*b<=n && (--e0)<0)
              goto NoMatch;
          }
        }
      }
      else
      {
        o=y*sw+x; e1=err1; e0=err0;
        for (i=0; i<max; i++)
        {
          if (i<len1 && ss[o+s1[i]]==0 && (--e1)<0) goto NoMatch;
          if (i<len0 && ss[o+s0[i]]!=0 && (--e0)<0) goto NoMatch;
        }
        // Clear the image that has been found
        for (i=0; i<len1; i++) ss[o+s1[i]]=0;
      }
      allpos[ok*2]=k*sx+x; allpos[ok*2+1]=k*sy+y;
      if (++ok>=allpos_max) goto Return1;
      NoMatch:;
    }
  }
  //----------------------
  Return1:
  return ok;
}

*/


;==== Optional GUI interface ====


Gui(cmd, arg1:="")
{
  local
  static
  global FindText
  local lls, bch, cri
  ListLines, % InStr("|KeyDown|LButtonDown|MouseMove|"
    , "|" cmd "|") ? "Off" : A_ListLines
  static init:=0
  if (!init)
  {
    init:=1
    Gui_:=ObjBindMethod(FindText,"Gui")
    Gui_G:=ObjBindMethod(FindText,"Gui","G")
    Gui_Run:=ObjBindMethod(FindText,"Gui","Run")
    Gui_Off:=ObjBindMethod(FindText,"Gui","Off")
    Gui_Show:=ObjBindMethod(FindText,"Gui","Show")
    Gui_KeyDown:=ObjBindMethod(FindText,"Gui","KeyDown")
    Gui_LButtonDown:=ObjBindMethod(FindText,"Gui","LButtonDown")
    Gui_MouseMove:=ObjBindMethod(FindText,"Gui","MouseMove")
    Gui_ScreenShot:=ObjBindMethod(FindText,"Gui","ScreenShot")
    Gui_ShowPic:=ObjBindMethod(FindText,"Gui","ShowPic")
    Gui_ToolTip:=ObjBindMethod(FindText,"Gui","ToolTip")
    Gui_ToolTipOff:=ObjBindMethod(FindText,"Gui","ToolTipOff")
    bch:=A_BatchLines, cri:=A_IsCritical
    Critical
    #NoEnv
    %Gui_%("Load_Language_Text")
    %Gui_%("MakeCaptureWindow")
    %Gui_%("MakeMainWindow")
    OnMessage(0x100, Gui_KeyDown)
    OnMessage(0x201, Gui_LButtonDown)
    OnMessage(0x200, Gui_MouseMove)
    Menu, Tray, Add
    Menu, Tray, Add, % Lang["1"], %Gui_Show%
    if (!A_IsCompiled and A_LineFile=A_ScriptFullPath)
    {
      Menu, Tray, Default, % Lang["1"]
      Menu, Tray, Click, 1
      Menu, Tray, Icon, Shell32.dll, 23
    }
    Critical, %cri%
    SetBatchLines, %bch%
  }
  Switch cmd
  {
  Case "Off":
    return
  Case "G":
    GuiControl, +g, %id%, %Gui_Run%
    return
  Case "Run":
    Critical
    %Gui_%(A_GuiControl)
    return
  Case "Show":
    Gui, FindText_Main: Default
    Gui, Show, Center
    GuiControl, Focus, scr
    return
  Case "MakeCaptureWindow":
    ww:=35, hh:=12, WindowColor:="0xDDEEFF"
    Gui, FindText_Capture: New
    Gui, +AlwaysOnTop -DPIScale
    Gui, Margin, 15, 15
    Gui, Color, %WindowColor%
    Gui, Font, s12, Verdana
    Gui, -Theme
    nW:=71, nH:=25, w:=12, C_:=[], Cid_:=[]
    Loop, % nW*(nH+1)
    {
      i:=A_Index, j:=i=1 ? "" : Mod(i,nW)=1 ? "xm y+1":"x+1"
      j.=i>nW*nH ? " cRed BackgroundFFFFAA" : ""
      Gui, Add, Progress, w%w% h%w% %j% Hwndid
      Control, ExStyle, -0x20000,, ahk_id %id%
      C_[i]:=id, Cid_[id]:=i
    }
    Gui, +Theme
    GuiControlGet, p, Pos, %id%
    w:=pX+pW-15, h:=pY+pH-15
    Gui, Add, Slider, xm w%w% vMySlider1 Hwndid Disabled
      +Center Page20 Line10 NoTicks AltSubmit
    %Gui_G%()
    Gui, Add, Slider, ym h%h% vMySlider2 Hwndid Disabled
      +Center Page20 Line10 NoTicks AltSubmit +Vertical
    %Gui_G%()
    GuiControlGet, p, Pos, %id%
    k:=pX+pW, MySlider1:=MySlider2:=dx:=dy:=0
    ;--------------
    Gui, Add, Button, xm Hwndid Hidden Section, % Lang["Auto"]
    GuiControlGet, p, Pos, %id%
    w:=Round(pW*0.75), i:=Round(w*3+15+pW*0.5-w*1.5)
    Gui, Add, Button, xm+%i% yp w%w% hp -Wrap vRepU Hwndid, % Lang["RepU"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp hp -Wrap vCutU Hwndid, % Lang["CutU"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp hp -Wrap vCutU3 Hwndid, % Lang["CutU3"]
    %Gui_G%()
    Gui, Add, Button, xm wp hp -Wrap vRepL Hwndid, % Lang["RepL"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp hp -Wrap vCutL Hwndid, % Lang["CutL"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp hp -Wrap vCutL3 Hwndid, % Lang["CutL3"]
    %Gui_G%()
    Gui, Add, Button, x+15 w%pW% hp -Wrap vAuto Hwndid, % Lang["Auto"]
    %Gui_G%()
    Gui, Add, Button, x+15 w%w% hp -Wrap vRepR Hwndid, % Lang["RepR"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp hp -Wrap vCutR Hwndid, % Lang["CutR"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp hp -Wrap vCutR3 Hwndid, % Lang["CutR3"]
    %Gui_G%()
    Gui, Add, Button, xm+%i% wp hp -Wrap vRepD Hwndid, % Lang["RepD"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp hp -Wrap vCutD Hwndid, % Lang["CutD"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp hp -Wrap vCutD3 Hwndid, % Lang["CutD3"]
    %Gui_G%()
    ;--------------
    Gui, Add, Text, x+80 ys+3 Section, % Lang["SelGray"]
    Gui, Add, Edit, x+3 yp-3 w60 vSelGray ReadOnly
    Gui, Add, Text, x+15 ys, % Lang["SelColor"]
    Gui, Add, Edit, x+3 yp-3 w120 vSelColor ReadOnly
    Gui, Add, Text, x+15 ys, % Lang["SelR"]
    Gui, Add, Edit, x+3 yp-3 w60 vSelR ReadOnly
    Gui, Add, Text, x+5 ys, % Lang["SelG"]
    Gui, Add, Edit, x+3 yp-3 w60 vSelG ReadOnly
    Gui, Add, Text, x+5 ys, % Lang["SelB"]
    Gui, Add, Edit, x+3 yp-3 w60 vSelB ReadOnly
    ;--------------
    x:=w*6+pW+15*4, w:=k-x
    Gui, Add, Tab3, x%x% y+15 w%w% -Wrap, % Lang["2"]
    Gui, Tab, 1
    Gui, Add, Text, x+15 y+15, % Lang["Threshold"]
    Gui, Add, Edit, x+15 w100 vThreshold
    Gui, Add, Button, x+15 yp-3 vGray2Two Hwndid, % Lang["Gray2Two"]
    %Gui_G%()
    Gui, Tab, 2
    Gui, Add, Text, x+15 y+15, % Lang["GrayDiff"]
    Gui, Add, Edit, x+15 w100 vGrayDiff, 50
    Gui, Add, Button, x+15 yp-3 vGrayDiff2Two Hwndid, % Lang["GrayDiff2Two"]
    %Gui_G%()
    Gui, Tab, 3
    Gui, Add, Text, x+15 y+15, % Lang["Similar1"] " 0"
    Gui, Add, Slider, x+0 w120 vSimilar1 Hwndid
      +Center Page1 NoTicks ToolTip, 100
    %Gui_G%()
    Gui, Add, Text, x+0, 100
    Gui, Add, Button, x+15 yp-3 vColor2Two Hwndid, % Lang["Color2Two"]
    %Gui_G%()
    Gui, Tab, 4
    Gui, Add, Text, x+15 y+15, % Lang["Similar2"] " 0"
    Gui, Add, Slider, x+0 w120 vSimilar2 Hwndid
      +Center Page1 NoTicks ToolTip, 100
    %Gui_G%()
    Gui, Add, Text, x+0, 100
    Gui, Add, Button, x+15 yp-3 vColorPos2Two Hwndid, % Lang["ColorPos2Two"]
    %Gui_G%()
    Gui, Tab, 5
    Gui, Add, Text, x+10 y+15, % Lang["DiffR"]
    Gui, Add, Edit, x+5 w80 vDiffR Limit3
    Gui, Add, UpDown, vdR Range0-255 Wrap
    Gui, Add, Text, x+5, % Lang["DiffG"]
    Gui, Add, Edit, x+5 w80 vDiffG Limit3
    Gui, Add, UpDown, vdG Range0-255 Wrap
    Gui, Add, Text, x+5, % Lang["DiffB"]
    Gui, Add, Edit, x+5 w80 vDiffB Limit3
    Gui, Add, UpDown, vdB Range0-255 Wrap
    Gui, Add, Button, x+15 yp-3 vColorDiff2Two Hwndid, % Lang["ColorDiff2Two"]
    %Gui_G%()
    Gui, Tab, 6
    Gui, Add, Text, x+10 y+15, % Lang["DiffRGB"]
    Gui, Add, Edit, x+5 w80 vDiffRGB Limit3
    Gui, Add, UpDown, vdRGB Range0-255 Wrap
    Gui, Add, Checkbox, x+15 yp+5 vMultiColor Hwndid, % Lang["MultiColor"]
    %Gui_G%()
    Gui, Add, Button, x+15 yp-5 vUndo Hwndid, % Lang["Undo"]
    %Gui_G%()
    Gui, Tab
    ;--------------
    Gui, Add, Button, xm vReset Hwndid, % Lang["Reset"]
    %Gui_G%()
    Gui, Add, Checkbox, x+15 yp+5 vModify Hwndid, % Lang["Modify"]
    %Gui_G%()
    Gui, Add, Text, x+30, % Lang["Comment"]
    Gui, Add, Edit, x+5 yp-2 w150 vComment
    Gui, Add, Button, x+30 yp-3 vSplitAdd Hwndid, % Lang["SplitAdd"]
    %Gui_G%()
    Gui, Add, Button, x+10 vAllAdd Hwndid, % Lang["AllAdd"]
    %Gui_G%()
    Gui, Add, Button, x+10 wp vOK Hwndid, % Lang["OK"]
    %Gui_G%()
    Gui, Add, Button, x+10 wp vCancel gCancel, % Lang["Cancel"]
    Gui, Add, Button, xm vBind0 Hwndid, % Lang["Bind0"]
    %Gui_G%()
    Gui, Add, Button, x+15 vBind1 Hwndid, % Lang["Bind1"]
    %Gui_G%()
    Gui, Add, Button, x+15 vBind2 Hwndid, % Lang["Bind2"]
    %Gui_G%()
    Gui, Add, Button, x+15 vBind3 Hwndid, % Lang["Bind3"]
    %Gui_G%()
    Gui, Add, Button, x+15 vBind4 Hwndid, % Lang["Bind4"]
    %Gui_G%()
    Gui, Show, Hide, % Lang["3"]
    return
  Case "MakeMainWindow":
    Gui, FindText_Main: New
    Gui, +AlwaysOnTop -DPIScale
    Gui, Margin, 15, 15
    Gui, Color, %WindowColor%
    Gui, Font, s12, Verdana
    Gui, Add, Text, xm, % Lang["NowHotkey"]
    Gui, Add, Edit, x+5 w200 vNowHotkey ReadOnly
    Gui, Add, Hotkey, x+5 w200 vSetHotkey1
    Gui, Add, DDL, x+5 w180 vSetHotkey2
      , % "||F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|LWin|MButton"
      . "|ScrollLock|CapsLock|Ins|Esc|BS|Del|Tab|Home|End|PgUp|PgDn"
      . "|NumpadDot|NumpadSub|NumpadAdd|NumpadDiv|NumpadMult"
    Gui, Add, GroupBox, xm y+0 w280 h55 vMyGroup cBlack
    Gui, Add, Text, xp+15 yp+20 Section, % Lang["Myww"] ": "
    Gui, Add, Text, x+0 w60, %ww%
    Gui, Add, UpDown, vMyww Range1-100, %ww%
    Gui, Add, Text, x+15 ys, % Lang["Myhh"] ": "
    Gui, Add, Text, x+0 w60, %hh%
    Gui, Add, UpDown, vMyhh Hwndid Range1-100, %hh%
    GuiControlGet, p, Pos, %id%
    GuiControl, Move, MyGroup, % "w" (pX+pW) " h" (pH+30)
    x:=pX+pW+15*2
    Gui, Add, Button, x%x% ys-8 w150 vApply Hwndid, % Lang["Apply"]
    %Gui_G%()
    Gui, Add, Checkbox, x+30 ys Checked vAddFunc, % Lang["AddFunc"] " FindText()"
    Gui, Add, Button, xm y+18 w144 vCutL2 Hwndid, % Lang["CutL2"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp vCutR2 Hwndid, % Lang["CutR2"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp vCutU2 Hwndid, % Lang["CutU2"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp vCutD2 Hwndid, % Lang["CutD2"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp vUpdate Hwndid, % Lang["Update"]
    %Gui_G%()
    Gui, Font, s6 bold, Verdana
    Gui, Add, Edit, xm y+10 w720 r20 vMyPic -Wrap
    Gui, Font, s12 norm, Verdana
    Gui, Add, Button, xm w240 vCapture Hwndid, % Lang["Capture"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp vTest Hwndid, % Lang["Test"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp vCopy Hwndid, % Lang["Copy"]
    %Gui_G%()
    Gui, Add, Button, xm y+0 wp vCaptureS Hwndid, % Lang["CaptureS"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp vGetRange Hwndid, % Lang["GetRange"]
    %Gui_G%()
    Gui, Add, Button, x+0 wp vTestClip Hwndid, % Lang["TestClip"]
    %Gui_G%()
    Gui, Font, s12 cBlue, Verdana
    Gui, Add, Edit, xm w720 h350 vscr Hwndhscr -Wrap HScroll
    Gui, Show, Hide, % Lang["4"]
    return
  Case "Capture","CaptureS":
    Critical
    Gui, FindText_Main: +Hwndid
    if (show_gui:=(WinExist()=id))
    {
      WinMinimize
      Gui, FindText_Main: Hide
    }
    ShowScreenShot:=InStr(cmd,"CaptureS")
    if (ShowScreenShot)
    {
      f:=%Gui_%("SelectPic")
      if (f="") or !FileExist(f)
      {
        if (show_gui)
        {
          Gui, FindText_Main: Show
          GuiControl, FindText_Main: Focus, scr
        }
        Exit
      }
      FindText.ShowPic(f)
    }
    ;----------------------
    Gui, FindText_HotkeyIf: New, -Caption +ToolWindow +E0x80000
    Gui, Show, NA x0 y0 w0 h0, FindText_HotkeyIf
    Hotkey, IfWinExist, FindText_HotkeyIf
    Hotkey, *RButton, %Gui_Off%, On UseErrorLevel
    ListLines, % (lls:=A_ListLines)?"Off":"Off"
    CoordMode, Mouse
    KeyWait, RButton
    KeyWait, Ctrl
    w:=ww, h:=hh, oldx:=oldy:="", r:=StrSplit(Lang["5"],"|")
    if (!show_gui)
      w:=20, h:=8
    Loop
    {
      Sleep, 50
      MouseGetPos, x, y, Bind_ID
      if (!show_gui)
      {
        w:=x<=1 ? w-1 : x>=A_ScreenWidth-2 ? w+1:w
        h:=y<=1 ? h-1 : y>=A_ScreenHeight-2 ? h+1:h
        w:=(w<1 ? 1:w), h:=(h<1 ? 1:h)
      }
      %Gui_%("Mini_Show")
      if (oldx=x and oldy=y)
        Continue
      oldx:=x, oldy:=y
      ToolTip, % r.1 " : " x "," y "`n" r.2
    }
    Until GetKeyState("RButton","P") or GetKeyState("Ctrl","P")
    KeyWait, RButton
    KeyWait, Ctrl
    px:=x, py:=y, oldx:=oldy:=""
    Loop
    {
      Sleep, 50
      %Gui_%("Mini_Show")
      MouseGetPos, x1, y1
      if (oldx=x1 and oldy=y1)
        Continue
      oldx:=x1, oldy:=y1
      ToolTip, % r.1 " : " x "," y "`n" r.2
    }
    Until GetKeyState("RButton","P") or GetKeyState("Ctrl","P")
    KeyWait, RButton
    KeyWait, Ctrl
    ToolTip
    %Gui_%("Mini_Hide")
    ListLines, %lls%
    Hotkey, *RButton, %Gui_Off%, Off UseErrorLevel
    Hotkey, IfWinExist
    Gui, FindText_HotkeyIf: Destroy
    if (ShowScreenShot)
      FindText.ShowPic()
    if (!show_gui)
      return [px-w, py-h, px+w, py+h]
    ;-----------------------
    %Gui_%("getcors", !ShowScreenShot)
    %Gui_%("Reset")
    Gui, FindText_Capture: Default
    Loop, 71
      GuiControl,, % C_[71*25+A_Index], 0
    Loop, 6
      GuiControl,, Edit%A_Index%
    GuiControl,, Modify, % Modify:=0
    GuiControl,, MultiColor, % MultiColor:=0
    GuiControl,, GrayDiff, 50
    GuiControl, Focus, Gray2Two
    GuiControl, +Default, Gray2Two
    Gui, Show, Center
    Event:=Result:=""
    DetectHiddenWindows, Off
    Critical, Off
    Gui, +LastFound
    WinWaitClose, % "ahk_id " WinExist()
    Critical
    ToolTip
    Gui, FindText_Main: Default
    ;--------------------------------
    if (cors.bind!="")
    {
      WinGetTitle, tt, ahk_id %Bind_ID%
      WinGetClass, tc, ahk_id %Bind_ID%
      tt:=Trim(SubStr(tt,1,30) (tc ? " ahk_class " tc:""))
      tt:=StrReplace(RegExReplace(tt,"[;``]","``$0"),"""","""""")
      Result:="`nSetTitleMatchMode, 2`nid:=WinExist(""" tt """)"
        . "`nFindText.BindWindow(id" (cors.bind=0 ? "":"," cors.bind)
        . ")  `; " Lang["6"] " FindText.BindWindow(0)`n`n" Result
    }
    if (Event="OK")
    {
      if (!A_IsCompiled)
      {
        FileRead, s, %A_LineFile%
        s:=SubStr(s, s~="i)\n[;=]+ Copy The")
      }
      else s:=""
      GuiControl,, scr, % Result "`n" s
      if !InStr(Result,"##")
        GuiControl,, MyPic, % Trim(FindText.ASCII(Result),"`n")
      Result:=s:=""
    }
    else if (Event="SplitAdd") or (Event="AllAdd")
    {
      GuiControlGet, s,, scr
      i:=j:=0, r:="<[^>\n]*>[^$\n]+\$[\w+/,.\-]+"
      While j:=RegExMatch(s,r,"",j+1)
        i:=InStr(s,"`n",0,j)
      GuiControl,, scr, % SubStr(s,1,i) . Result . SubStr(s,i+1)
      if !InStr(Result,"##")
        GuiControl,, MyPic, % Trim(FindText.ASCII(Result),"`n")
      Result:=s:=""
    }
    ;----------------------
    Gui, Show
    GuiControl, Focus, scr
    return
  Case "SelectPic":
    Gui, FindText_SelectPic: +LastFoundExist
    IfWinExist
      return
    Pics:=[], Names:=[], s:=""
    Loop, Files, % A_Temp "\Ahk_ScreenShot\*.bmp"
      Pics.Push(LoadPicture(v:=A_LoopFileFullPath, "w800 h500"))
      , Names.Push(v), s.="|" RegExReplace(v,"i)^.*\\|\.bmp$")
    if !Pics.Length()
    {
      Pics:="", Names:=""
      SetTimer, %Gui_ToolTip%, Off
      ToolTip
      MsgBox, 4096, Tip, % "`n" Lang["15"] " !`n", 3
      return
    }
    Gui, FindText_SelectPic: New
    Gui, +LastFound +AlwaysOnTop -DPIScale
    Gui, Margin, 15, 15
    Gui, Font, s12, Verdana
    Gui, Add, Pic, HwndhPic w800 h500 +Border, % "HBITMAP:*" Pics.1
    Gui, Add, ListBox, % "x+15 w120 hp vSelectBox Hwndid"
      . " AltSubmit 0x100 Choose1", % Trim(s,"|")
    %Gui_G%()
    Gui, Add, Button, xm w223 vOK2 Hwndid Default, % Lang["OK2"]
    %Gui_G%()
    Gui, Add, Button, x+15 wp vCancel2 gCancel, % Lang["Cancel2"]
    Gui, Add, Button, x+15 wp vClearAll Hwndid, % Lang["ClearAll"]
    %Gui_G%()
    Gui, Add, Button, x+15 wp vOpenDir Hwndid, % Lang["OpenDir"]
    %Gui_G%()
    GuiControl, Focus, SelectBox
    Gui, Show,, Select ScreenShot
    ;-----------------------
    DetectHiddenWindows, Off
    Critical, Off
    file:=""
    WinWaitClose, % "ahk_id " WinExist()
    Critical
    Gui, Destroy
    Loop, % Pics.Length()
      DllCall("DeleteObject", "Ptr",Pics[A_Index])
    Pics:="", Names:=""
    return file
  Case "SelectBox":
    Gui, FindText_SelectPic: Default
    GuiControlGet, SelectBox
    if (Pics[SelectBox])
      GuiControl,, %hPic%, % "HBITMAP:*" Pics[SelectBox]
    return
  Case "OK2":
    GuiControlGet, SelectBox
    file:=Names[SelectBox]
    Gui, FindText_SelectPic: Hide
    return
  Case "ClearAll":
    FileDelete, % A_Temp "\Ahk_ScreenShot\*.bmp"
    Gui, FindText_SelectPic: Hide
    return
  Case "OpenDir":
    Run, % A_Temp "\Ahk_ScreenShot\"
    return
  Case "Mini_Show":
    Gui, FindText_Mini_4: +LastFoundExist
    IfWinNotExist
    {
      Loop, 4
      {
        i:=A_Index
        Gui, FindText_Mini_%i%: +AlwaysOnTop -Caption +ToolWindow -DPIScale +E0x08000000
        Gui, FindText_Mini_%i%: Show, Hide, Mini
      }
    }
    d:=2, w:=w<0 ? 0:w, h:=h<0 ? 0:h, c:=A_MSec<500 ? "Red":"Blue"
    Loop, 4
    {
      i:=A_Index
      x1:=Floor(i=3 ? x+w+1 : x-w-d)
      y1:=Floor(i=4 ? y+h+1 : y-h-d)
      w1:=Floor(i=1 or i=3 ? d : 2*(w+d)+1)
      h1:=Floor(i=2 or i=4 ? d : 2*(h+d)+1)
      Gui, FindText_Mini_%i%: Color, %c%
      Gui, FindText_Mini_%i%: Show, NA x%x1% y%y1% w%w1% h%h1%
    }
    return
  Case "Mini_Hide":
    Gui, FindText_Mini_4: +Hwndid
    Loop, 4
      Gui, FindText_Mini_%A_Index%: Destroy
    WinWaitClose, ahk_id %id%,, 3
    return
  Case "getcors":
    FindText.xywh2xywh(px-ww,py-hh,2*ww+1,2*hh+1,x,y,w,h)
    if (w<1 or h<1)
      return
    SetBatchLines, % (bch:=A_BatchLines)?"-1":"-1"
    if (arg1)
      FindText.ScreenShot()
    cors:=[], gray:=[], k:=0
    ListLines, % (lls:=A_ListLines)?"Off":"Off"
    Loop, %nH%
    {
      j:=py-hh+A_Index-1, i:=px-ww
      Loop, %nW%
        cors[++k]:=c:=FindText.GetColor(i++,j,0)
        , gray[k]:=(((c>>16)&0xFF)*38+((c>>8)&0xFF)*75+(c&0xFF)*15)>>7
    }
    ListLines, %lls%
    cors.CutLeft:=Abs(px-ww-x)
    cors.CutRight:=Abs(px+ww-(x+w-1))
    cors.CutUp:=Abs(py-hh-y)
    cors.CutDown:=Abs(py+hh-(y+h-1))
    SetBatchLines, %bch%
    return
  Case "GetRange":
    Critical
    Gui, FindText_Main: +Hwndid
    if (show_gui:=(WinExist()=id))
      Gui, FindText_Main: Hide
    ;---------------------
    Gui, FindText_GetRange: New
    Gui, +LastFound +AlWaysOnTop +ToolWindow -Caption -DPIScale +E0x08000000
    Gui, Color, White
    WinSet, Transparent, 10
    FindText.xywh2xywh(0,0,0,0,0,0,0,0,x,y,w,h)
    Gui, Show, NA x%x% y%y% w%w% h%h%, GetRange
    ;---------------------
    Gui, FindText_HotkeyIf: New, -Caption +ToolWindow +E0x80000
    Gui, Show, NA x0 y0 w0 h0, FindText_HotkeyIf
    Hotkey, IfWinExist, FindText_HotkeyIf
    Hotkey, *LButton, %Gui_Off%, On UseErrorLevel
    ListLines, % (lls:=A_ListLines)?"Off":"Off"
    CoordMode, Mouse
    KeyWait, LButton
    KeyWait, Ctrl
    oldx:=oldy:="", r:=Lang["7"]
    Loop
    {
      Sleep, 50
      MouseGetPos, x, y
      if (oldx=x and oldy=y)
        Continue
      oldx:=x, oldy:=y
      ToolTip, %r%
    }
    Until GetKeyState("LButton","P") or GetKeyState("Ctrl","P")
    px:=x, py:=y, oldx:=oldy:=""
    Loop
    {
      Sleep, 50
      MouseGetPos, x, y
      w:=Abs(px-x)//2, h:=Abs(py-y)//2, x:=(px+x)//2, y:=(py+y)//2
      %Gui_%("Mini_Show")
      if (oldx=x and oldy=y)
        Continue
      oldx:=x, oldy:=y
      ToolTip, %r%
    }
    Until !(GetKeyState("LButton","P") or GetKeyState("Ctrl","P"))
    ToolTip
    %Gui_%("Mini_Hide")
    ListLines, %lls%
    Hotkey, *LButton, %Gui_Off%, Off UseErrorLevel
    Hotkey, IfWinExist
    Gui, FindText_HotkeyIf: Destroy
    Gui, FindText_GetRange: Destroy
    Clipboard:=p:=(x-w) ", " (y-h) ", " (x+w) ", " (y+h)
    if (!show_gui)
      return StrSplit(p, ",", " ")
    ;---------------------
    Gui, FindText_Main: Default
    GuiControlGet, s,, scr
    if RegExMatch(s, "i)(=\s*FindText\()([^,]*,){4}", r)
    {
      s:=StrReplace(s, r, r1 . p ",", 0, 1)
      GuiControl,, scr, %s%
    }
    Gui, Show
    return
  Case "Test","TestClip":
    Gui, FindText_Main: Default
    Gui, +LastFound
    WinMinimize
    Gui, Hide
    DetectHiddenWindows, Off
    WinWaitClose, % "ahk_id " WinExist()
    Sleep, 100
    ;----------------------
    if (cmd="Test")
      GuiControlGet, s,, scr
    else
      s:=Clipboard
    if (!A_IsCompiled) and InStr(s,"MCode(") and (cmd="Test")
    {
      s:="`n#NoEnv`nMenu, Tray, Click, 1`n" s "`nExitApp`n"
      Thread:= new FindText.Thread(s)
      DetectHiddenWindows, On
      WinWait, % "ahk_class AutoHotkey ahk_pid " Thread.pid,, 3
      if (!ErrorLevel)
        WinWaitClose,,, 30
      Thread:=""  ; kill the Thread
    }
    else
    {
      Gui, +OwnDialogs
      t:=A_TickCount, n:=150000
      , RegExMatch(s,"<[^>\n]*>[^$\n]+\$[\w+/,.\-]+",k)
      , v:=FindText.FindText(-n, -n, n, n, 0, 0, k)
      , X:=v.1.x, Y:=v.1.y, Comment:=v.1.id
      r:=StrSplit(Lang["8"],"|")
      MsgBox, 4096, Tip, % r.1 ":`t" Round(v.MaxIndex()) "`n`n"
        . r.2 ":`t" (A_TickCount-t) " " r.3 "`n`n"
        . r.4 ":`t" X ", " Y "`n`n"
        . r.5 ":`t" (v ? r.6 " ! " Comment : r.7 " !"), 3
      for i,j in v
        if (i<=2)
          FindText.MouseTip(j.x, j.y)
      v:=""
    }
    ;----------------------
    Gui, Show
    GuiControl, Focus, scr
    return
  Case "Copy":
    Gui, FindText_Main: Default
    ControlGet, s, Selected,,, ahk_id %hscr%
    if (s="")
    {
      GuiControlGet, s,, scr
      GuiControlGet, r,, AddFunc
      if (r != 1)
        s:=RegExReplace(s,"\n\K[\s;=]+ Copy The[\s\S]*")
    }
    Clipboard:=RegExReplace(s,"\R","`r`n")
    ;----------------------
    Gui, Hide
    Sleep, 100
    Gui, Show
    GuiControl, Focus, scr
    return
  Case "Apply":
    Gui, FindText_Main: Default
    GuiControlGet, NowHotkey
    GuiControlGet, SetHotkey1
    GuiControlGet, SetHotkey2
    if (NowHotkey!="")
      Hotkey, *%NowHotkey%,, Off UseErrorLevel
    k:=SetHotkey1!="" ? SetHotkey1 : SetHotkey2
    if (k!="")
      Hotkey, *%k%, %Gui_ScreenShot%, On UseErrorLevel
    GuiControl,, NowHotkey, %k%
    GuiControl,, SetHotkey1
    GuiControl, Choose, SetHotkey2, 0
    ;------------------------
    GuiControlGet, Myww
    GuiControlGet, Myhh
    if (Myww!=ww or Myhh!=hh)
    {
      nW:=71, dx:=dy:=0
      Loop, % 71*25
        k:=A_Index, c:=WindowColor, %Gui_%("SetColor")
      ww:=Myww, hh:=Myhh, nW:=2*ww+1, nH:=2*hh+1
      i:=nW>71, j:=nH>25
      Gui, FindText_Capture: Default
      GuiControl, Enable%i%, MySlider1
      GuiControl, Enable%j%, MySlider2
      GuiControl,, MySlider1, % MySlider1:=0
      GuiControl,, MySlider2, % MySlider2:=0
    }
    return
  Case "ScreenShot":
    Critical
    f:=A_Temp "\Ahk_ScreenShot"
    if !InStr(r:=FileExist(f), "D")
    {
      if (r)
      {
        FileSetAttrib, -R, %f%
        FileDelete, %f%
      }
      FileCreateDir, %f%
    }
    Loop
      f:=A_Temp "\Ahk_ScreenShot\" Format("{:03d}",A_Index) ".bmp"
    Until !FileExist(f)
    FindText.SavePic(f)
    Gui, FindText_Tip: New
    ; WS_EX_NOACTIVATE:=0x08000000, WS_EX_TRANSPARENT:=0x20
    Gui, +LastFound +AlwaysOnTop +ToolWindow -Caption -DPIScale +E0x08000020
    Gui, Color, Yellow
    Gui, Font, cRed s48 bold
    Gui, Add, Text,, % Lang["9"]
    WinSet, Transparent, 200
    Gui, Show, NA y0, ScreenShot Tip
    Sleep, 100
    Gui, Destroy
    return
  Case "Bind0","Bind1","Bind2","Bind3","Bind4":
    Critical
    FindText.BindWindow(Bind_ID, bind_mode:=SubStr(cmd,0))
    Gui, FindText_HotkeyIf: New, -Caption +ToolWindow +E0x80000
    Gui, Show, NA x0 y0 w0 h0, FindText_HotkeyIf
    Hotkey, IfWinExist, FindText_HotkeyIf
    Hotkey, *RButton, %Gui_Off%, On UseErrorLevel
    ListLines, % (lls:=A_ListLines)?"Off":"Off"
    CoordMode, Mouse
    KeyWait, RButton
    KeyWait, Ctrl
    oldx:=oldy:=""
    Loop
    {
      Sleep, 50
      MouseGetPos, x, y
      if (oldx=x and oldy=y)
        Continue
      oldx:=x, oldy:=y
      ;---------------
      px:=x, py:=y, %Gui_%("getcors",1)
      %Gui_%("Reset"), r:=StrSplit(Lang["10"],"|")
      ToolTip, % r.1 " : " x "," y "`n" r.2
    }
    Until GetKeyState("RButton","P") or GetKeyState("Ctrl","P")
    KeyWait, RButton
    KeyWait, Ctrl
    ToolTip
    ListLines, %lls%
    Hotkey, *RButton, %Gui_Off%, Off UseErrorLevel
    Hotkey, IfWinExist
    Gui, FindText_HotkeyIf: Destroy
    FindText.BindWindow(0), cors.bind:=bind_mode
    return
  Case "MySlider1","MySlider2":
    Thread, Priority, 10
    Critical, Off
    dx:=nW>71 ? Round((nW-71)*MySlider1/100) : 0
    dy:=nH>25 ? Round((nH-25)*MySlider2/100) : 0
    if (oldx=dx and oldy=dy)
      return
    oldx:=dx, oldy:=dy, k:=0
    Loop, % nW*nH
      c:=(!show[++k] ? WindowColor
      : bg="" ? cors[k] : ascii[k]
      ? "Black":"White"), %Gui_%("SetColor")
    if (cmd="MySlider2")
      return
    Loop, 71
      GuiControl,, % C_[71*25+A_Index], 0
    Loop, % nW
    {
      i:=A_Index-dx
      if (i>=1 && i<=71 && show[nW*nH+A_Index])
        GuiControl,, % C_[71*25+i], 100
    }
    return
  Case "Reset":
    show:=[], ascii:=[], bg:=""
    CutLeft:=CutRight:=CutUp:=CutDown:=k:=0
    Loop, % nW*nH
      show[++k]:=1, c:=cors[k], %Gui_%("SetColor")
    Loop, % cors.CutLeft
      %Gui_%("CutL")
    Loop, % cors.CutRight
      %Gui_%("CutR")
    Loop, % cors.CutUp
      %Gui_%("CutU")
    Loop, % cors.CutDown
      %Gui_%("CutD")
    return
  Case "SetColor":
    if (nW=71 && nH=25)
      tk:=k
    else
    {
      tx:=Mod(k-1,nW)-dx, ty:=(k-1)//nW-dy
      if (tx<0 || tx>=71 || ty<0 || ty>=25)
        return
      tk:=ty*71+tx+1
    }
    c:=c="Black" ? 0x000000 : c="White" ? 0xFFFFFF
      : ((c&0xFF)<<16)|(c&0xFF00)|((c&0xFF0000)>>16)
    SendMessage, 0x2001, 0, c,, % "ahk_id " . C_[tk]
    return
  Case "RepColor":
    show[k]:=1, c:=(bg="" ? cors[k] : ascii[k]
      ? "Black":"White"), %Gui_%("SetColor")
    return
  Case "CutColor":
    show[k]:=0, c:=WindowColor, %Gui_%("SetColor")
    return
  Case "RepL":
    if (CutLeft<=cors.CutLeft)
    or (bg!="" and InStr(color,"**")
    and CutLeft=cors.CutLeft+1)
      return
    k:=CutLeft-nW, CutLeft--
    Loop, %nH%
      k+=nW, (A_Index>CutUp and A_Index<nH+1-CutDown
        ? %Gui_%("RepColor") : "")
    return
  Case "CutL":
    if (CutLeft+CutRight>=nW)
      return
    CutLeft++, k:=CutLeft-nW
    Loop, %nH%
      k+=nW, (A_Index>CutUp and A_Index<nH+1-CutDown
        ? %Gui_%("CutColor") : "")
    return
  Case "CutL3":
    Loop, 3
      %Gui_%("CutL")
    return
  Case "RepR":
    if (CutRight<=cors.CutRight)
    or (bg!="" and InStr(color,"**")
    and CutRight=cors.CutRight+1)
      return
    k:=1-CutRight, CutRight--
    Loop, %nH%
      k+=nW, (A_Index>CutUp and A_Index<nH+1-CutDown
        ? %Gui_%("RepColor") : "")
    return
  Case "CutR":
    if (CutLeft+CutRight>=nW)
      return
    CutRight++, k:=1-CutRight
    Loop, %nH%
      k+=nW, (A_Index>CutUp and A_Index<nH+1-CutDown
        ? %Gui_%("CutColor") : "")
    return
  Case "CutR3":
    Loop, 3
      %Gui_%("CutR")
    return
  Case "RepU":
    if (CutUp<=cors.CutUp)
    or (bg!="" and InStr(color,"**")
    and CutUp=cors.CutUp+1)
      return
    k:=(CutUp-1)*nW, CutUp--
    Loop, %nW%
      k++, (A_Index>CutLeft and A_Index<nW+1-CutRight
        ? %Gui_%("RepColor") : "")
    return
  Case "CutU":
    if (CutUp+CutDown>=nH)
      return
    CutUp++, k:=(CutUp-1)*nW
    Loop, %nW%
      k++, (A_Index>CutLeft and A_Index<nW+1-CutRight
        ? %Gui_%("CutColor") : "")
    return
  Case "CutU3":
    Loop, 3
      %Gui_%("CutU")
    return
  Case "RepD":
    if (CutDown<=cors.CutDown)
    or (bg!="" and InStr(color,"**")
    and CutDown=cors.CutDown+1)
      return
    k:=(nH-CutDown)*nW, CutDown--
    Loop, %nW%
      k++, (A_Index>CutLeft and A_Index<nW+1-CutRight
        ? %Gui_%("RepColor") : "")
    return
  Case "CutD":
    if (CutUp+CutDown>=nH)
      return
    CutDown++, k:=(nH-CutDown)*nW
    Loop, %nW%
      k++, (A_Index>CutLeft and A_Index<nW+1-CutRight
        ? %Gui_%("CutColor") : "")
    return
  Case "CutD3":
    Loop, 3
      %Gui_%("CutD")
    return
  Case "Gray2Two":
    Gui, FindText_Capture: Default
    GuiControl, Focus, Threshold
    GuiControlGet, Threshold
    if (Threshold="")
    {
      pp:=[]
      Loop, 256
        pp[A_Index-1]:=0
      Loop, % nW*nH
        if (show[A_Index])
          pp[gray[A_Index]]++
      IP:=IS:=0
      Loop, 256
        k:=A_Index-1, IP+=k*pp[k], IS+=pp[k]
      Threshold:=Floor(IP/IS)
      Loop, 20
      {
        LastThreshold:=Threshold
        IP1:=IS1:=0
        Loop, % LastThreshold+1
          k:=A_Index-1, IP1+=k*pp[k], IS1+=pp[k]
        IP2:=IP-IP1, IS2:=IS-IS1
        if (IS1!=0 and IS2!=0)
          Threshold:=Floor((IP1/IS1+IP2/IS2)/2)
        if (Threshold=LastThreshold)
          Break
      }
      GuiControl,, Threshold, %Threshold%
    }
    Threshold:=Round(Threshold)
    color:="*" Threshold, k:=i:=0
    Loop, % nW*nH
    {
      ascii[++k]:=v:=(gray[k]<=Threshold)
      if (show[k])
        i:=(v?i+1:i-1), c:=(v?"Black":"White"), %Gui_%("SetColor")
    }
    bg:=i>0 ? "1":"0"
    return
  Case "GrayDiff2Two":
    Gui, FindText_Capture: Default
    GuiControlGet, GrayDiff
    if (GrayDiff="")
    {
      Gui, +OwnDialogs
      MsgBox, 4096, Tip, % "`n" Lang["11"] " !`n", 1
      return
    }
    if (CutLeft=cors.CutLeft)
      %Gui_%("CutL")
    if (CutRight=cors.CutRight)
      %Gui_%("CutR")
    if (CutUp=cors.CutUp)
      %Gui_%("CutU")
    if (CutDown=cors.CutDown)
      %Gui_%("CutD")
    GrayDiff:=Round(GrayDiff)
    color:="**" GrayDiff, k:=i:=0
    Loop, % nW*nH
    {
      j:=gray[++k]+GrayDiff
      , ascii[k]:=v:=( gray[k-1]>j or gray[k+1]>j
      or gray[k-nW]>j or gray[k+nW]>j
      or gray[k-nW-1]>j or gray[k-nW+1]>j
      or gray[k+nW-1]>j or gray[k+nW+1]>j )
      if (show[k])
        i:=(v?i+1:i-1), c:=(v?"Black":"White"), %Gui_%("SetColor")
    }
    bg:=i>0 ? "1":"0"
    return
  Case "Color2Two","ColorPos2Two":
    Gui, FindText_Capture: Default
    GuiControlGet, c,, SelColor
    if (c="")
    {
      Gui, +OwnDialogs
      MsgBox, 4096, Tip, % "`n" Lang["12"] " !`n", 1
      return
    }
    UsePos:=(cmd="ColorPos2Two") ? 1:0
    GuiControlGet, n,, Similar1
    n:=Round(n/100,2), color:=c "@" n
    , n:=Floor(512*9*255*255*(1-n)*(1-n)), k:=i:=0
    , rr:=(c>>16)&0xFF, gg:=(c>>8)&0xFF, bb:=c&0xFF
    Loop, % nW*nH
    {
      c:=cors[++k], r:=((c>>16)&0xFF)-rr
      , g:=((c>>8)&0xFF)-gg, b:=(c&0xFF)-bb, j:=r+rr+rr
      , ascii[k]:=v:=((1024+j)*r*r+2048*g*g+(1534-j)*b*b<=n)
      if (show[k])
        i:=(v?i+1:i-1), c:=(v?"Black":"White"), %Gui_%("SetColor")
    }
    bg:=i>0 ? "1":"0"
    return
  Case "ColorDiff2Two":
    Gui, FindText_Capture: Default
    GuiControlGet, c,, SelColor
    if (c="")
    {
      Gui, +OwnDialogs
      MsgBox, 4096, Tip, % "`n" Lang["12"] " !`n", 1
      return
    }
    GuiControlGet, dR
    GuiControlGet, dG
    GuiControlGet, dB
    rr:=(c>>16)&0xFF, gg:=(c>>8)&0xFF, bb:=c&0xFF
    , n:=Format("{:06X}",(dR<<16)|(dG<<8)|dB)
    , color:=StrReplace(c "-" n,"0x"), k:=i:=0
    Loop, % nW*nH
    {
      c:=cors[++k], r:=(c>>16)&0xFF, g:=(c>>8)&0xFF
      , b:=c&0xFF, ascii[k]:=v:=(Abs(r-rr)<=dR
      and Abs(g-gg)<=dG and Abs(b-bb)<=dB)
      if (show[k])
        i:=(v?i+1:i-1), c:=(v?"Black":"White"), %Gui_%("SetColor")
    }
    bg:=i>0 ? "1":"0"
    return
  Case "Modify":
    GuiControlGet, Modify
    return
  Case "MultiColor":
    GuiControlGet, MultiColor
    Result:=""
    ToolTip
    return
  Case "Undo":
    Result:=RegExReplace(Result,",[^/]+/[^/]+/[^/]+$")
    ToolTip, % Trim(Result,"/,")
    return
  Case "Similar1":
    GuiControl, FindText_Capture:, Similar2, %Similar1%
    return
  Case "Similar2":
    GuiControl, FindText_Capture:, Similar1, %Similar2%
    return
  Case "GetTxt":
    txt:=""
    if (bg="")
      return
    ListLines, % (lls:=A_ListLines)?"Off":"Off"
    k:=0
    Loop, %nH%
    {
      v:=""
      Loop, %nW%
        v.=!show[++k] ? "" : ascii[k] ? "1":"0"
      txt.=v="" ? "" : v "`n"
    }
    ListLines, %lls%
    return
  Case "Auto":
    %Gui_%("GetTxt")
    if (txt="")
    {
      Gui, FindText_Capture: +OwnDialogs
      MsgBox, 4096, Tip, % "`n" Lang["13"] " !`n", 1
      return
    }
    While InStr(txt,bg)
    {
      if (txt~="^" bg "+\n")
        txt:=RegExReplace(txt,"^" bg "+\n"), %Gui_%("CutU")
      else if !(txt~="m`n)[^\n" bg "]$")
        txt:=RegExReplace(txt,"m`n)" bg "$"), %Gui_%("CutR")
      else if (txt~="\n" bg "+\n$")
        txt:=RegExReplace(txt,"\n\K" bg "+\n$"), %Gui_%("CutD")
      else if !(txt~="m`n)^[^\n" bg "]")
        txt:=RegExReplace(txt,"m`n)^" bg), %Gui_%("CutL")
      else Break
    }
    txt:=""
    return
  Case "OK","SplitAdd","AllAdd":
    Gui, FindText_Capture: Default
    Gui, +OwnDialogs
    %Gui_%("GetTxt")
    if (txt="") and (!MultiColor)
    {
      MsgBox, 4096, Tip, % "`n" Lang["13"] " !`n", 1
      return
    }
    if InStr(color,"@") and (UsePos) and (!MultiColor)
    {
      r:=StrSplit(color,"@")
      k:=i:=j:=0
      Loop, % nW*nH
      {
        if (!show[++k])
          Continue
        i++
        if (k=cors.SelPos)
        {
          j:=i
          Break
        }
      }
      if (j=0)
      {
        MsgBox, 4096, Tip, % "`n" Lang["12"] " !`n", 1
        return
      }
      color:="#" (j-1) "@" r.2
    }
    GuiControlGet, Comment
    if (cmd="SplitAdd") and (!MultiColor)
    {
      if InStr(color,"#")
      {
        MsgBox, 4096, Tip, % Lang["14"], 3
        return
      }
      bg:=StrLen(StrReplace(txt,"0"))
        > StrLen(StrReplace(txt,"1")) ? "1":"0"
      s:="", i:=0, k:=nW*nH+1+CutLeft
      Loop, % w:=nW-CutLeft-CutRight
      {
        i++
        if (!show[k++] and A_Index<w)
          Continue
        i:=Format("{:d}",i)
        v:=RegExReplace(txt,"m`n)^(.{" i "}).*","$1")
        txt:=RegExReplace(txt,"m`n)^.{" i "}"), i:=0
        While InStr(v,bg)
        {
          if (v~="^" bg "+\n")
            v:=RegExReplace(v,"^" bg "+\n")
          else if !(v~="m`n)[^\n" bg "]$")
            v:=RegExReplace(v,"m`n)" bg "$")
          else if (v~="\n" bg "+\n$")
            v:=RegExReplace(v,"\n\K" bg "+\n$")
          else if !(v~="m`n)^[^\n" bg "]")
            v:=RegExReplace(v,"m`n)^" bg)
          else Break
        }
        if (v!="")
        {
          v:=Format("{:d}",InStr(v,"`n")-1) "." FindText.bit2base64(v)
          s.="`nText.=""|<" SubStr(Comment,1,1) ">" color "$" v """`n"
          Comment:=SubStr(Comment, 2)
        }
      }
      Event:=cmd, Result:=s
      Gui, Hide
      return
    }
    if (!MultiColor)
      txt:=Format("{:d}",InStr(txt,"`n")-1) "." FindText.bit2base64(txt)
    else
    {
      GuiControlGet, dRGB
      r:=StrSplit(Trim(StrReplace(Result,",","/"),"/"),"/")
      , x:=r.1, y:=r.2, s:="", i:=1
      Loop, % r.MaxIndex()//3
        s.="," (r[i++]-x) "/" (r[i++]-y) "/" r[i++]
      txt:=SubStr(s,2), color:="##" dRGB
    }
    s:="`nText.=""|<" Comment ">" color "$" txt """`n"
    if (cmd="AllAdd")
    {
      Event:=cmd, Result:=s
      Gui, Hide
      return
    }
    x:=px-ww+CutLeft+(nW-CutLeft-CutRight)//2
    y:=py-hh+CutUp+(nH-CutUp-CutDown)//2
    s:=StrReplace(s, "Text.=", "Text:="), r:=StrSplit(Lang["8"],"|")
    s:="`; #Include <FindText>`n"
    . "`n t1:=A_TickCount, X:=Y:=""""`n" s
    . "`n if (ok:=FindText(" x "-150000, " y "-150000, " x "+150000, " y "+150000, 0, 0, Text))"
    . "`n {"
    . "`n   CoordMode, Mouse"
    . "`n   X:=ok.1.x, Y:=ok.1.y, Comment:=ok.1.id"
    . "`n   `; Click, `%X`%, `%Y`%"
    . "`n }`n"
    . "`n MsgBox, 4096, Tip, `% """ r.1 ":``t"" Round(ok.MaxIndex())"
    . "`n   . ""``n``n" r.2 ":``t"" (A_TickCount-t1) "" " r.3 """"
    . "`n   . ""``n``n" r.4 ":``t"" X "", "" Y"
    . "`n   . ""``n``n" r.5 ":``t"" (ok ? """ r.6 " !"" : """ r.7 " !"")`n"
    . "`n for i,v in ok"
    . "`n   if (i<=2)"
    . "`n     FindText.MouseTip(ok[i].x, ok[i].y)`n"
    Event:=cmd, Result:=s
    Gui, Hide
    return
  Case "KeyDown":
    Critical
    if (A_Gui="FindText_Main" && A_GuiControl="scr")
      SetTimer, %Gui_ShowPic%, -150
    return
  Case "ShowPic":
    ControlGet, i, CurrentLine,,, ahk_id %hscr%
    ControlGet, s, Line, %i%,, ahk_id %hscr%
    GuiControl, FindText_Main:, MyPic, % Trim(FindText.ASCII(s),"`n")
    return
  Case "LButtonDown":
    Critical
    if (A_Gui!="FindText_Capture")
      return %Gui_%("KeyDown")
    MouseGetPos,,,, k2, 2
    if (k1:=Round(Cid_[k2]))<1
      return
    Gui, FindText_Capture: Default
    if (k1>71*25)
    {
      GuiControlGet, k3,, %k2%
      GuiControl,, %k2%, % k3 ? 0:100
      show[nW*nH+(k1-71*25)+dx]:=(!k3)
      return
    }
    k2:=Mod(k1-1,71)+dx, k3:=(k1-1)//71+dy
    if (k2>=nW || k3>=nH)
      return
    k1:=k, k:=k3*nW+k2+1, k2:=c
    if (MultiColor and show[k])
    {
      c:="," Mod(k-1,nW) "/" k3 "/"
      . Format("0x{:06X}",cors[k]&0xFFFFFF)
      , Result.=InStr(Result,c) ? "":c
      ToolTip, % Trim(Result,"/,")
    }
    else if (Modify and bg!="" and show[k])
    {
      c:=((ascii[k]:=!ascii[k]) ? "Black":"White")
      , %Gui_%("SetColor")
    }
    else
    {
      c:=cors[k], cors.SelPos:=k
      GuiControl,, SelGray, % gray[k]
      GuiControl,, SelColor, % Format("0x{:06X}",c&0xFFFFFF)
      GuiControl,, SelR, % (c>>16)&0xFF
      GuiControl,, SelG, % (c>>8)&0xFF
      GuiControl,, SelB, % c&0xFF
    }
    k:=k1, c:=k2
    return
  Case "MouseMove":
    static PrevControl:=""
    if (PrevControl!=A_GuiControl)
    {
      PrevControl:=A_GuiControl
      SetTimer, %Gui_ToolTip%, % PrevControl ? -500 : "Off"
      SetTimer, %Gui_ToolTipOff%, % PrevControl ? -5500 : "Off"
      ToolTip
    }
    return
  Case "ToolTip":
    MouseGetPos,,, _TT
    IfWinExist, ahk_id %_TT% ahk_class AutoHotkeyGUI
      ToolTip, % Tip_Text[PrevControl ""]
    return
  Case "ToolTipOff":
    ToolTip
    return
  Case "CutL2","CutR2","CutU2","CutD2":
    Gui, FindText_Main: Default
    GuiControlGet, s,, MyPic
    s:=Trim(s,"`n") . "`n", v:=SubStr(cmd,4,1)
    if (v="U")
      s:=RegExReplace(s,"^[^\n]+\n")
    else if (v="D")
      s:=RegExReplace(s,"[^\n]+\n$")
    else if (v="L")
      s:=RegExReplace(s,"m`n)^[^\n]")
    else if (v="R")
      s:=RegExReplace(s,"m`n)[^\n]$")
    GuiControl,, MyPic, % Trim(s,"`n")
    return
  Case "Update":
    Gui, FindText_Main: Default
    GuiControl, Focus, scr
    ControlGet, i, CurrentLine,,, ahk_id %hscr%
    ControlGet, s, Line, %i%,, ahk_id %hscr%
    if !RegExMatch(s,"(<[^>]*>[^$]+\$)\d+\.[\w+/]+",r)
      return
    GuiControlGet, v,, MyPic
    v:=Trim(v,"`n") . "`n", w:=Format("{:d}",InStr(v,"`n")-1)
    v:=StrReplace(StrReplace(v,"0","1"),"_","0")
    s:=StrReplace(s,r,r1 . w "." FindText.bit2base64(v))
    v:="{End}{Shift Down}{Home}{Shift Up}{Del}"
    ControlSend,, %v%, ahk_id %hscr%
    Control, EditPaste, %s%,, ahk_id %hscr%
    ControlSend,, {Home}, ahk_id %hscr%
    return
  Case "Load_Language_Text":
    s=
    (
Myww       = Width = Adjust the width of the capture range
Myhh       = Height = Adjust the height of the capture range
AddFunc    = Add = Additional FindText() in Copy
NowHotkey  = Hotkey = Current screenshot hotkey
SetHotkey1 = = First sequence Screenshot hotkey
SetHotkey2 = = Second sequence Screenshot hotkey
Apply      = Apply = Apply new screenshot hotkey and adjusted capture range values
CutU2      = CutU = Cut the Upper Edge of the text in the edit box below
CutL2      = CutL = Cut the Left Edge of the text in the edit box below
CutR2      = CutR = Cut the Right Edge of the text in the edit box below
CutD2      = CutD = Cut the Lower Edge of the text in the edit box below
Update     = Update = Update the text in the edit box below to the line of code
GetRange   = GetRange = Get screen range to clipboard and replace the range in the code
TestClip   = TestClipboard = Test the Text data in the clipboard for searching images
Capture    = Capture = Initiate Image Capture Sequence
CaptureS   = CaptureS = Restore the Saved ScreenShot By Hotkey and then start capturing
Test       = Test = Test Results of Code
Copy       = Copy = Copy Code to Clipboard
Reset      = Reset = Reset to Original Captured Image
SplitAdd   = SplitAdd = Using Markup Segmentation to Generate Text Library
AllAdd     = AllAdd = Append Another FindText Search Text into Previously Generated Code
OK         = OK = Create New FindText Code for Testing
Cancel     = Cancel = Close the Window Don't Do Anything
Gray2Two      = Gray2Two = Converts Image Pixels from Gray Threshold to Black or White
GrayDiff2Two  = GrayDiff2Two = Converts Image Pixels from Gray Difference to Black or White
Color2Two     = Color2Two = Converts Image Pixels from Color Similar to Black or White
ColorPos2Two  = ColorPos2Two = Converts Image Pixels from Color Position to Black or White
ColorDiff2Two = ColorDiff2Two = Converts Image Pixels from Color Difference to Black or White
SelGray    = Gray = Gray value of the selected color
SelColor   = Color = The selected color
SelR       = R = Red component of the selected color
SelG       = G = Green component of the selected color
SelB       = B = Blue component of the selected color
RepU       = -U = Undo Cut the Upper Edge by 1
CutU       = U = Cut the Upper Edge by 1
CutU3      = U3 = Cut the Upper Edge by 3
RepL       = -L = Undo Cut the Left Edge by 1
CutL       = L = Cut the Left Edge by 1
CutL3      = L3 = Cut the Left Edge by 3
Auto       = Auto = Automatic Cut Edge after image has been converted to black and white
RepR       = -R = Undo Cut the Right Edge by 1
CutR       = R = Cut the Right Edge by 1
CutR3      = R3 = Cut the Right Edge by 3
RepD       = -D = Undo Cut the Lower Edge by 1
CutD       = D = Cut the Lower Edge by 1
CutD3      = D3 = Cut the Lower Edge by 3
Modify     = Modify = Allows Modify the Black and White Image
MultiColor = FindMultiColor = Click multiple colors with the mouse, then Click OK button
Undo       = Undo = Undo the last selected color
Comment    = Comment = Optional Comment used to Label Code ( Within <> )
Threshold  = Gray Threshold = Gray Threshold which Determines Black or White Pixel Conversion (0-255)
GrayDiff   = Gray Difference = Gray Difference which Determines Black or White Pixel Conversion (0-255)
Similar1   = Similarity = Adjust color similarity as Equivalent to The Selected Color
Similar2   = Similarity = Adjust color similarity as Equivalent to The Selected Color
DiffR      = R = Red Difference which Determines Black or White Pixel Conversion (0-255)
DiffG      = G = Green Difference which Determines Black or White Pixel Conversion (0-255)
DiffB      = B = Blue Difference which Determines Black or White Pixel Conversion (0-255)
DiffRGB    = R/G/B = Determine the allowed R/G/B Error (0-255) when Find MultiColor
Bind0      = BindWindow1 = Bind the window and Use GetDCEx() to get the image of background window
Bind1      = BindWindow1+ = Bind the window Use GetDCEx() and Modify the window to support transparency
Bind2      = BindWindow2 = Bind the window and Use PrintWindow() to get the image of background window
Bind3      = BindWindow2+ = Bind the window Use PrintWindow() and Modify the window to support transparency
Bind4      = BindWindow3 = Bind the window and Use PrintWindow(,,3) to get the image of background window
OK2        = OK = Restore this ScreenShot
Cancel2    = Cancel = Close the Window Don't Do Anything
ClearAll   = ClearAll = Clean up all saved ScreenShots
OpenDir    = OpenDir = Open the saved screenshots directory
1  = FindText
2  = Gray|GrayDiff|Color|ColorPos|ColorDiff|MultiColor
3  = Capture Image To Text
4  = Capture Image To Text And Find Text Tool
5  = Position|First click RButton\nMove the mouse away\nSecond click RButton
6  = Unbind Window using
7  = Please drag a range with the LButton\nCoordinates are copied to clipboard
8  = Found|Time|ms|Pos|Result|Success|Failed
9  = Success
10 = The Capture Position|Perspective binding window\nRight click to finish capture
11 = Please Set Gray Difference First
12 = Please select the core color first
13 = Please convert the image to black or white first
14 = Can't be used in ColorPos mode, because it can cause position errors
15 = Please set Hotkey and use Hotkey to get ScreenShot first
    )
    Lang:=[], Tip_Text:=[]
    Loop, Parse, s, `n, `r
      if InStr(v:=A_LoopField, "=")
        r:=StrSplit(StrReplace(v,"\n","`n"), "=", "`t ")
        , Lang[r.1 ""]:=r.2, Tip_Text[r.1 ""]:=r.3
    return
  }
}

}  ;// Class End

;================= The End =================

;
Last edited by maleko48 on 19 Apr 2021, 13:38, edited 1 time in total.
User avatar
boiler
Posts: 16925
Joined: 21 Dec 2014, 02:44

Re: Script Help for Menu selection from a Windows taskbar icon

19 Apr 2021, 13:07

You mentioned taskbar icon, so I thought you were referring to the icons to the left that correspond to open windows. I now see that you are referring to the system tray icons, which have different WinTitle information associated with their menus, and they are often different from each other. Often it is ahk_class #32768, so the code could be changed to this:

Code: Select all

CoordMode, Mouse, Screen
CoordMode, Pixel, Screen

^F1::
	MouseGetPos, OrigX, OrigY ; get original mouse position
	MouseMove, 200, A_ScreenHeight - 1
	loop {
		ImageSearch, FoundX, FoundY, 0, A_ScreenHeight - 40, A_ScreenWidth, A_ScreenHeight, PathToMyIconImage.png
		Sleep, 50
		if (A_Index = 100) {
			MsgBox, 8240, Taskbar icon not found, The image of the the taskbar icon could not be found., 3
			return
		}
	} until !ErrorLevel
	Click, R, %FoundX%, %FoundY%
	WinWaitActive, ahk_class #32768
	Send, {Up 3}{Right}{Down 3}{Enter}
	MouseMove, OrigX, OrigY ; move mouse back to original position
return

If your menu does not have the class ahk_class #32768, then use the Window Spy tool to determine what it is and replace it in the code above. Make sure you are getting the info for the menu, not the tray icon itself.
jaaypeso24
Posts: 46
Joined: 23 Jul 2016, 10:54

Re: Script Help for Menu selection from a Windows taskbar icon

19 Apr 2021, 14:07

That last change ended up working! The issue was exactly what you mentioned. Apologies for the confusion as I always just thought they were the same thing (taskbar vs. system tray).

I appreciate the help as I definitely couldn't have gotten that to work just by looking through random forum posts and the help files. Or at least it would have taken me a LOT LONGER.

So thanks for the help
jaaypeso24
Posts: 46
Joined: 23 Jul 2016, 10:54

Re: Script Help for Menu selection from a Windows taskbar icon

21 Apr 2021, 13:09

I wanted to add for anybody in the future who just happens to google search and stumble onto this post that I also figured out another way to setup a macro that can access those system tray icons on the far right of the taskbar, when you need to right click on the icon to get to the menu you want.

Code: Select all

F1::
	Send #b	
	Send, {Right}
	Send, +{F10}
	Sleep 250		
	Send, {Up 4}{Right}{Down 2}{Enter}
	Return
#b sends the Windows+b key which brings up the taskbar and highlights the system icons (starting with hidden icons indicator)
Then +{F10} is the shift+fn10 (which sends a right click") on the current selection.

I had to add a sleep above to get it to work properly, but the rest is just me manually pressing up/down/left/right the number of times I need to navigate my particular menu, but of course you may not need to go up 4, right once, down 2, and then press enter to get to the submenu option you want. hope this helps someone as the community was so helpful to me in learning some new tricks.
User avatar
boiler
Posts: 16925
Joined: 21 Dec 2014, 02:44

Re: Script Help for Menu selection from a Windows taskbar icon

21 Apr 2021, 13:16

Don’t you have to worry about the position of the icon among the other tray icons moving based on what other apps may be running at the time since you’re navigating to a fixed position via keystrokes?
jaaypeso24
Posts: 46
Joined: 23 Jul 2016, 10:54

Re: Script Help for Menu selection from a Windows taskbar icon

21 Apr 2021, 13:21

That's a great point. I see why finding an icon is the preferred method based on that thinking. In my case I have it as the very first icon (outside of the hidden icons folder) so it isn't under the hidden icons folder and stays as a static location even after I restart the computer. But I did have to manually move that icon out of the hidden system icons folder initially otherwise it may jump around and change locations. However, if someone else has it in a different place, or has icons moving around then the above script wouldn't work for them.

So I agree that its a better standard practice to do an image based search because that approach isn't dependent upon the icon location like a mousemove or a more manual approach is. I just was getting a lag with the image search based approach (and every once in a while i'd get an error) so I may need to tinker with it to get it working perfectly everytime. Maybe its something wrong with the image I saved. That was why I was trying to find a more consistent direct approach.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 213 guests