Code style

Code style

#SingleInstance, Force

CoordMode, Tooltip, Screen
CoordMode, Mouse, Screen
Coordmode, Menu, Window
SetControlDelay, -1
SetKeyDelay, -1
Detecthiddenwindows, on
FileEncoding, utf-8

global ConfigPath := A_ScriptDir "\vimd.ini"
global vim := class_vim()
global ini := class_EasyINI(A_ScriptDir "\vimd.ini")
global default_enable_show_info := ini.config.default_enable_show_info
global editor := ini.config.editor
global VIMD_CMD_LIST := []

Menu, Tray, Icon, %A_ScriptDir%\viatc.ico
Menu, Tray, NoStandard
Menu, Tray, Add, 查看热键(&K), <vc_Keymap>
Menu, Tray, Add, 查看插件(&P), <vc_Plugin>
Menu, Tray, Add,
Menu, Tray, Add, 重启(&R), <Reload>
Menu, Tray, Add, 退出(&X), <Exit>
iniWrite, %A_ScriptHwnd%, %A_Temp%\vimd_auto.ini, auto, hwnd

if (!FileExist(ConfigPath))
{
    FileCopy, %ConfigPath%.help.txt, %ConfigPath%
}

if (ini.config.enable_log == 1)
{
    global log := new Logger(A_ScriptDir "\debug.log")
}

if (ini.config.enable_debug == 1)
{
    vim.Debug(true)
}

; 第二个参数为存放描述信息的全局变量名
act := vim.SetAction("VIMD_CMD", "VIMD_CMD_LIST")
act.SetFunction("VIMD_CMD")

CheckPlugin()
CheckHotKey()

; 用于接收来自 cehck.ahk 的信息
OnMessage(0x4a, "ReceiveWMCopyData")

return

CheckPlugin()
{
    ; 检测是否有新增插件
    Loop, %A_ScriptDir%\plugins\*, 2, 0
    {
        IniRead, PluginTime, %A_ScriptDir%\plugins\plugins.ahk, ExtensionsTime, %A_LoopFileName%
        if (PluginTime = "ERROR")
        {
            MsgBox, 发现新插件 %A_LoopFileName%，将自动加载该插件

            if (FileExist(A_ScriptDir "\vimd.exe"))
            {
                Run, %A_ScriptDir%\vimd.exe "%A_ScriptDir%\plugins\check.ahk"
            }
            else
            {
                Run, %A_ScriptDir%\plugins\check.ahk
            }

            IniWrite, 1, %ConfigPath%, plugins, %A_LoopFileName%
            Reload
        }
    }

    for plugin, flag in ini.plugins
        if flag
            vim.LoadPlugin(plugin)
}

CheckHotKey()
{
    for this_key, this_action in ini.global
    {
        this_mode := "normal"
        if RegExMatch(this_action, "\[=[^\[\]]*\]", mode)
        {
            this_mode := Substr(mode, 3, strlen(mode) - 3)
            this_action := RegExReplace(this_action, "\[=[^\[\]]*\]")
        }

        vim.mode(this_mode)
        if RegExMatch(this_action, "^((run)|(key)|(dir)|(tccmd))\|")
        {
            vim.map(this_key, "VIMD_CMD")
            VIMD_CMD_LIST[this_key] := this_action
        }
        else
        {
            vim.map(this_key, this_action)
        }
    }

    for win, flag in ini.exclude
    {
        vim.SetWin(win, win)
        vim.ExcludeWin(win, true)
    }

    for PluginName, Key in ini
    {
        if RegExMatch(PluginName, "i)(config)|(exclude)|(global)|(plugins)")
            continue

        win := vim.SetWin(PluginName, Key.set_class, Key.set_file)
        vim.SetTimeOut(Key.set_time_out, PluginName)
        vim.SetMaxCount(Key.set_max_count, PluginName)
        if (Key.enable_show_info = 1)
        {
            win.SetInfo(true)
        }

        for m, n in Key
        {
            if RegExMatch(m, "i)(set_class)|(set_file)|(set_time_out)|(set_max_count)|(enable_show_info)")
                continue

            this_mode := "normal"
            this_action := n

            if RegExMatch(this_action, "\[=[^\[\]]*\]", mode)
            {
                this_mode := Substr(mode, 3, strlen(mode) - 3)
                this_action := RegExReplace(n, "\[=[^\[\]]*\]")
            }

            vim.mode(this_mode, PluginName)

            if RegExMatch(n, "i)^((run)|(key)|(dir)|(tccmd))\|")
            {
                /*
                示例：
                <c-j>=run|notepad.exe
                */

                vim.map(m, "VIMD_CMD", PluginName)
                VIMD_CMD_LIST[m] := n
            }
            else
            {
                vim.map(m, this_action, PluginName)
            }
        }
    }
}

VIMD_CMD()
{
    obj := GetLastAction()
    if RegExMatch(VIMD_CMD_LIST[obj.keytemp], "i)^(run)\|", m)
    {
        Run, % substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2)
    }
    else if RegExMatch(VIMD_CMD_LIST[obj.keytemp], "i)^(key)\|", m)
    {
        Send, % substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2)
    }
    else if RegExMatch(VIMD_CMD_LIST[obj.keytemp], "i)^(dir)\|", m)
    {
        TC_OpenPath(substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2), false)
    }
    else if RegExMatch(VIMD_CMD_LIST[obj.keytemp], "i)^(tccmd)\|", m)
    {
        TC_Run(substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2))
    }
}

ReceiveWMCopyData(wParam, lParam)
{
    ; 获取 CopyDataStruct 的 lpData 成员.
    StringAddress := NumGet(lParam + 2 * A_PtrSize)
    ; 从结构中复制字符串.
    AHKReturn := StrGet(StringAddress)
    if RegExMatch(AHKReturn, "i)reload")
    {
        Settimer, VIMD_Reload, 500
        return true
    }
}

VIMD_Reload:
    Reload
return

/*
RunAsAdmin()
{
    local params, uacrep
    Loop %0%
        params .= " " (InStr(%A_Index%, " ") ? """" %A_Index% """" : %A_Index%)
    if(A_IsCompiled)
        uacrep := DllCall("shell32\ShellExecute", uint, 0, str, "RunAs", str, A_ScriptFullPath, str, "/r" params, str, A_WorkingDir, int, 1)
    else
        uacrep := DllCall("shell32\ShellExecute", uint, 0, str, "RunAs", str, A_AhkPath, str, "/r """ A_ScriptFullPath """" params, str, A_WorkingDir, int, 1)
    if(uacrep = 42) ;UAC Prompt confirmed, application may run as admin
        ExitApp
    else
        MsgBox 未能获取管理员权限，这可能导致部分功能无法运行。
}
*/

#Include %A_ScriptDir%\core\class_vim.ahk
#Include %A_ScriptDir%\core\VimDConfig.ahk
#Include %A_ScriptDir%\lib\class_EasyINI.ahk
#Include %A_ScriptDir%\lib\acc.ahk
#Include %A_ScriptDir%\lib\ini.ahk
#Include %A_ScriptDir%\lib\gdip.ahk
#Include %A_ScriptDir%\lib\Logger.ahk
#Include %A_ScriptDir%\plugins\plugins.ahk
; 用户自定义配置
#Include *i %A_ScriptDir%\custom.ahk

#SingleInstance, Force

CoordMode, Tooltip, Screen
CoordMode, Mouse, Screen
Coordmode, Menu, Window
SetControlDelay, -1
SetKeyDelay, -1
Detecthiddenwindows, on
FileEncoding, utf-8

global ConfigPath := A_ScriptDir "\vimd.ini"
global vim := class_vim()
global ini := class_EasyINI(A_ScriptDir "\vimd.ini")
global default_enable_show_info := ini.config.default_enable_show_info
global editor := ini.config.editor

Menu, Tray, Icon, %A_ScriptDir%\viatc.ico
Menu, Tray, NoStandard
Menu, Tray, Add, 查看热键(&K), <vc_Keymap>
Menu, Tray, Add, 查看插件(&P), <vc_Plugin>
Menu, Tray, Add,
Menu, Tray, Add, 重启(&R), <Reload>
Menu, Tray, Add, 退出(&X), <Exit>
iniWrite, %A_ScriptHwnd%, %A_Temp%\vimd_auto.ini, auto, hwnd

if (!FileExist(ConfigPath))
{
    FileCopy, %ConfigPath%.help.txt, %ConfigPath%
}

if (ini.config.enable_log == 1)
{
    global log := new Logger(A_ScriptDir "\debug.log")
}

if (ini.config.enable_debug == 1)
{
    vim.Debug(true)
}

; 第二个参数为存放描述信息的全局变量名
act := vim.SetAction("VIMD_CMD", "VIMD_CMD_LIST")
act.SetFunction("VIMD_CMD")

CheckPlugin()
CheckHotKey()

; 用于接收来自 cehck.ahk 的信息
OnMessage(0x4a, "Receive_WM_COPYDATA")

return

CheckPlugin()
{
    ; 检测是否有新增插件
    Loop, %A_ScriptDir%\plugins\*, 2, 0
    {
        IniRead, PluginTime, %A_ScriptDir%\plugins\plugins.ahk, ExtensionsTime, %A_LoopFileName%
        if (PluginTime = "ERROR")
        {
            MsgBox, 发现新插件 %A_LoopFileName%，将自动加载该插件

            if (FileExist(A_ScriptDir "\vimd.exe"))
            {
                Run, %A_ScriptDir%\vimd.exe "%A_ScriptDir%\plugins\check.ahk"
            }
            else
            {
                Run, %A_ScriptDir%\plugins\check.ahk
            }

            IniWrite, 1, %ConfigPath%, plugins, %A_LoopFileName%
            Reload
        }
    }

    for plugin, flag in ini.plugins
        if flag
            vim.LoadPlugin(plugin)
}

CheckHotKey()
{
    global VIMD_CMD_LIST := IsObject(VIMD_CMD_LIST) ? VIMD_CMD_LIST : []

    for this_key, this_action in ini.global
    {
        this_mode := "normal"
        if RegExMatch(this_action, "\[=[^\[\]]*\]", mode)
        {
            this_mode := Substr(mode, 3, strlen(mode) - 3)
            this_action := RegExReplace(this_action, "\[=[^\[\]]*\]")
        }

        vim.mode(this_mode)
        if RegExMatch(this_action, "^((run)|(key)|(dir)|(tccmd))\|")
        {
            vim.map(this_key, "VIMD_CMD")
            VIMD_CMD_LIST[this_key] := this_action
        }
        else
        {
            vim.map(this_key, this_action)
        }
    }

    for win, flag in ini.exclude
    {
        vim.SetWin(win, win)
        vim.ExcludeWin(win, true)
    }

    for PluginName, Key in ini
    {
        if RegExMatch(PluginName, "i)(config)|(exclude)|(global)|(plugins)")
            continue

        win := vim.SetWin(PluginName, Key.set_class, Key.set_file)
        vim.SetTimeOut(Key.set_time_out, PluginName)
        vim.SetMaxCount(Key.set_max_count, PluginName)
        if (Key.enable_show_info = 1)
        {
            win.SetInfo(true)
        }

        for m, n in Key
        {
            if RegExMatch(m, "i)(set_class)|(set_file)|(set_time_out)|(set_max_count)|(enable_show_info)")
                continue

            this_mode := "normal"
            this_action := n

            if RegExMatch(this_action, "\[=[^\[\]]*\]", mode)
            {
                this_mode := Substr(mode, 3, strlen(mode) - 3)
                this_action := RegExReplace(n, "\[=[^\[\]]*\]")
            }

            vim.mode(this_mode, PluginName)

            if RegExMatch(n, "i)^((run)|(key)|(dir)|(tccmd))\|")
            {
                /*
                示例：
                <c-j>=run|notepad.exe
                */

                vim.map(m, "VIMD_CMD", PluginName)
                VIMD_CMD_LIST[m] := n
            }
            else
            {
                vim.map(m, this_action, PluginName)
            }
        }
    }
}

VIMD_CMD()
{
    global VIMD_CMD_LIST
    obj := GetLastAction()
    if RegExMatch(VIMD_CMD_LIST[obj.keytemp], "i)^(run)\|", m)
    {
        Run, % substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2)
    }
    else if RegExMatch(VIMD_CMD_LIST[obj.keytemp], "i)^(key)\|", m)
    {
        Send, % substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2)
    }
    else if RegExMatch(VIMD_CMD_LIST[obj.keytemp], "i)^(dir)\|", m)
    {
        TC_OpenPath(substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2), false)
    }
    else if RegExMatch(VIMD_CMD_LIST[obj.keytemp], "i)^(tccmd)\|", m)
    {
        TC_Run(substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2))
    }
}

Receive_WM_COPYDATA(wParam, lParam)
{
    ; 获取 CopyDataStruct 的 lpData 成员.
    StringAddress := NumGet(lParam + 2 * A_PtrSize)
    ; 从结构中复制字符串.
    AHKReturn := StrGet(StringAddress)
    if RegExMatch(AHKReturn, "i)reload")
    {
        Settimer, VIMD_Reload, 500
        return true
    }
}

VIMD_Reload:
    Reload
return

/*
RunAsAdmin()
{
    local params, uacrep
    Loop %0%
        params .= " " (InStr(%A_Index%, " ") ? """" %A_Index% """" : %A_Index%)
    if(A_IsCompiled)
        uacrep := DllCall("shell32\ShellExecute", uint, 0, str, "RunAs", str, A_ScriptFullPath, str, "/r" params, str, A_WorkingDir, int, 1)
    else
        uacrep := DllCall("shell32\ShellExecute", uint, 0, str, "RunAs", str, A_AhkPath, str, "/r """ A_ScriptFullPath """" params, str, A_WorkingDir, int, 1)
    if(uacrep = 42) ;UAC Prompt confirmed, application may run as admin
        ExitApp
    else
        MsgBox 未能获取管理员权限，这可能导致部分功能无法运行。
}
*/

#Include %A_ScriptDir%\core\class_vim.ahk
#Include %A_ScriptDir%\core\VimDConfig.ahk
#Include %A_ScriptDir%\lib\class_EasyINI.ahk
#Include %A_ScriptDir%\lib\acc.ahk
#Include %A_ScriptDir%\lib\ini.ahk
#Include %A_ScriptDir%\lib\gdip.ahk
#Include %A_ScriptDir%\lib\Logger.ahk
#Include %A_ScriptDir%\plugins\plugins.ahk
; 用户自定义配置
#Include *i %A_ScriptDir%\custom.ahk


TC_Dialog:esc，返回调用者

TotalCommander_Dialog:
;本插件尝试将TotalCommander作为文件打开对话框
; * 默认添加快捷键<lwin>o ,在文件对话框或任意文字编辑界面按下快捷键跳转至TC--TC中选定文件后再次按下快捷键可实现文件打开功能
; * 尝试在打开文件对话框时，自动跳转到TC进行文件选择：#32770，焦点Edit1且内无文字
; * 增加select模式，按下回车可直接选定文件

vim.comment("<OpenTCDialog>","激活TC选择文件,需再次按下快捷键触发对话框打开事件")

;初始化设置：全局快捷键跳转到TC
IniWriteIfNull(ConfigPath,"Global","*<lwin>o","<OpenTCDialog>")

;初始化设置：自动跳转到TC作为文件选择对话框
IniWriteIfNull(ConfigPath,"TotalCommander_Config","AsOpenFileDialog","1")

;读取配置参数，禁用时直接跳过
IniRead,AsOpenFileDialog,%ConfigPath%,TotalCommander_Config,AsOpenFileDialog,1
if AsOpenFileDialog <> 1
	return

;用于记录文件打开对话框所属窗体
global CallerId := 0

;等待OpenFileDialog出现
SetTimer, <CheckFileDialog>, 1000

return

;===============================================

;仅在执行文件选定时，开启select模式
;拷贝normal全部快捷键，并增加回车确认功能
<Select_Mode_TC>:
	vim.mode("select","TTOTAL_CMD")

	if Select_Copyed = 1
		return

	Select_Copyed := 1
	vim.CopyMode("TTOTAL_CMD","normal","select")
	vim.map("<enter>","<TC_Selected>","TTOTAL_CMD")
	vim.map("<esc>","<Return_To_Caller>","TTOTAL_CMD")
	return

;返回调用者
<Return_To_Caller>:
	gosub,<Normal_Mode_TC>
	;未发现可激活的调用窗体时，最小化TC
	if CallerId = 0
	{
		Winminimize,AHK_CLASS TTOTAL_CMD
		sleep,500
		CallerId := WinExist("A")
		if CallerId = 0
			return
	}

	WinActivate,ahk_id %CallerId%
	return

;发现标准打开文件对话框，未记录，焦点控件为Edit1=>记录，并激活TC
<CheckFileDialog>:
{
	WinGetClass, class, A
	if class <> #32770
		return

	ControlGetFocus,ct, ahk_class #32770
	if ct <> Edit1
		return

	;以此排除“另存为”，或其它已经包含文字的对话框
	ControlGetText,str,Edit1,ahk_class #32770
	if StrLen(str) > 0
		return

	id := WinExist("A")
	if id = 0
		return
	if id = %CallerId%
		return

	CallerId := id
	gosub,<FocusTC>
	gosub,<Select_Mode_TC>
	return
}

; * 非TC窗口按下后激活TC窗口
; * TC窗口按下后复制当前选中文件返回原窗口后粘贴
<OpenTCDialog>:
{
	WinGetClass, class, A

	;在Total Commander按下快捷键时，激活调用窗体并执行粘贴操作
	if class = TTOTAL_CMD
	{
		gosub,<TC_Selected>
		return
	}

	if class <> TTOTAL_CMD
	{
		CallerId := WinExist("A")
		if CallerId = 0
			return

		gosub,<FocusTC>
		gosub,<Select_Mode_TC>
		return
	}

	return
}

<TC_Selected>:
{
	vim.mode("normal","TTOTAL_CMD")
	SendPos(2021)
	sleep 500
	files := ""
	Loop, parse, clipboard, `n, `r
		files .= """" A_LoopField  """ "
	clipboard := files

	;未发现可激活的调用窗体时，最小化TC
	if CallerId = 0
	{
		Winminimize,AHK_CLASS TTOTAL_CMD
		sleep,500
		CallerId := WinExist("A")
		if CallerId = 0
			return
	}

	WinActivate,ahk_id %CallerId%
	WinWait,ahk_id %CallerId%
	send, ^v
	send, {Enter}
	return
}

TotalCommander_Dialog:
;本插件尝试将TotalCommander作为文件打开对话框
; * 默认添加快捷键<lwin>o ,在文件对话框或任意文字编辑界面按下快捷键跳转至TC--TC中选定文件后再次按下快捷键可实现文件打开功能
; * 尝试在打开文件对话框时，自动跳转到TC进行文件选择：#32770，焦点Edit1且内无文字
; * 增加select模式，按下回车可直接选定文件

vim.comment("<OpenTCDialog>","激活TC选择文件,需再次按下快捷键触发对话框打开事件")

;初始化设置：全局快捷键跳转到TC
IniWriteIfNull(ConfigPath,"Global","*<lwin>o","<OpenTCDialog>")

;初始化设置：自动跳转到TC作为文件选择对话框
IniWriteIfNull(ConfigPath,"TotalCommander_Config","AsOpenFileDialog","1")

;读取配置参数，禁用时直接跳过
IniRead,AsOpenFileDialog,%ConfigPath%,TotalCommander_Config,AsOpenFileDialog,1
if AsOpenFileDialog <> 1
	return

;用于记录文件打开对话框所属窗体
global CallerId := 0

;等待OpenFileDialog出现
SetTimer, <CheckFileDialog>, 1000

return

;===============================================

;仅在执行文件选定时，开启select模式
;拷贝normal全部快捷键，并增加回车确认功能
<Select_Mode_TC>:
	vim.mode("select","TTOTAL_CMD")

	if Select_Copyed = 1
		return

	Select_Copyed := 1
	vim.CopyMode("TTOTAL_CMD","normal","select")
	vim.map("<enter>","<TC_Selected>","TTOTAL_CMD")
	return

;发现标准打开文件对话框，未记录，焦点控件为Edit1=>记录，并激活TC
<CheckFileDialog>:
{
	WinGetClass, class, A
	if class <> #32770
		return

	ControlGetFocus,ct, ahk_class #32770
	if ct <> Edit1
		return

	;以此排除“另存为”，或其它已经包含文字的对话框
	ControlGetText,str,Edit1,ahk_class #32770
	if StrLen(str) > 0
		return

	id := WinExist("A")
	if id = 0
		return
	if id = %CallerId%
		return

	CallerId := id
	gosub,<FocusTC>
	gosub,<Select_Mode_TC>
	return
}

; * 非TC窗口按下后激活TC窗口
; * TC窗口按下后复制当前选中文件返回原窗口后粘贴
<OpenTCDialog>:
{
	WinGetClass, class, A

	;在Total Commander按下快捷键时，激活调用窗体并执行粘贴操作
	if class = TTOTAL_CMD
	{
		gosub,<TC_Selected>
		return
	}

	if class <> TTOTAL_CMD
	{
		CallerId := WinExist("A")
		if CallerId = 0
			return

		gosub,<FocusTC>
		gosub,<Select_Mode_TC>
		return
	}

	return
}

<TC_Selected>:
{
	vim.mode("normal","TTOTAL_CMD")
	SendPos(2021)
	sleep 500
	files := ""
	Loop, parse, clipboard, `n, `r
		files .= """" A_LoopField  """ "
	clipboard := files

	;未发现可激活的调用窗体时，最小化TC
	if CallerId = 0
	{
		Winminimize,AHK_CLASS TTOTAL_CMD
		sleep,500
		CallerId := WinExist("A")
		if CallerId = 0
			return
	}

	WinActivate,ahk_id %CallerId%
	WinWait,ahk_id %CallerId%
	send, ^v
	send, {Enter}
	return
}


Update work_default.ahk

Update work_default.ahk

; Autohotkey configuration file
; AHK Version v.1.1.30.01
; Franklin Chou (franklin.chou@nelsonmullins.com)
; 22 Mar. 2020
; Tested to work on Lenovo X1 Yoga, Gen. 4

#SingleInstance Force
#Persistent

GLOBAL_DEBUG_MODE := 0
Return

CapsLock::Ctrl
LCtrl::Return
;LCtrl::CapsLock

; DEBUG TOOLS -----------------------------------------------------------------

#c::
  If(GLOBAL_DEBUG_MODE > 0) {
    WinGetTitle, title, A
    MsgBox %GLOBAL_DEBUG_MODE% ;%title%
  }
Return

f12::
  If(GLOBAL_DEBUG_MODE > 0) {
    Reload
  }
Return

#'::
If(GLOBAL_DEBUG_MODE > 0) {
  WinGet windows, List
  Loop %windows% {
    id := windows%A_Index%
    WinGetTitle wt, ahk_id %id%
    r .= wt . "`n"
  }
  MsgBox %r%
}
Return

; TIMEKEEPER ------------------------------------------------------------------

; Shift focus to the timekeeper app
#!e::
  timekeeper_app := WinExist("ahk_class WindowsForms10.Window.8.app.0.262fb3d")
  ;MsgBox %timekeeper_app%
  If(timekeeper_app > 0) {
    WinActivate, ahk_id %timekeeper_app%
  }
Return

; Start the timer on the selected item in the daily view
#IfWinActive ahk_class WindowsForms10.Window.8.app.0.262fb3d
  >+s::
    WinGetActiveTitle, active_title
    match_result := RegExMatch(active_title, "^Entries for")
    drop_down := 100
    If(match_result > 0) {
      WinMove, 100, 100
      MouseMove, 100, 280
      Send {RButton}
      Sleep, 100 ; need to sleep to allow the submenu to come up
      MouseMove, 170, 300 + drop_down
      Send {LButton}
    }
Return

; WORD ------------------------------------------------------------------------
#IfWinActive ahk_class OpusApp
   PrintScreen::AppsKey
Return

; SYMBOL KEYS -----------------------------------------------------------------
>+s::send §

; Autohotkey configuration file
; AHK Version v.1.1.30.01
; Franklin Chou (franklin.chou@nelsonmullins.com)
; 22 Mar. 2020
; Tested to work on Lenovo X1 Yoga, Gen. 4

#SingleInstance Force
#Persistent

GLOBAL_DEBUG_MODE := 0
Return

CapsLock::Ctrl
LCtrl::return
;LCtrl::CapsLock

; DEBUG TOOLS -----------------------------------------------------------------

#c::
  If(GLOBAL_DEBUG_MODE > 0) {
    WinGetTitle, title, A
    MsgBox %GLOBAL_DEBUG_MODE% ;%title%
  }
Return

f12::
  If(GLOBAL_DEBUG_MODE > 0) {
    Reload
  }
Return

#'::
If(GLOBAL_DEBUG_MODE > 0) {
  WinGet windows, List
  Loop %windows% {
    id := windows%A_Index%
    WinGetTitle wt, ahk_id %id%
    r .= wt . "`n"
  }
  MsgBox %r%
}
Return

; TIMEKEEPER ------------------------------------------------------------------

; Shift focus to the timekeeper app
#!e::
  timekeeper_app := WinExist("ahk_class WindowsForms10.Window.8.app.0.262fb3d")
  ;MsgBox %timekeeper_app%
  If(timekeeper_app > 0) {
    WinActivate, ahk_id %timekeeper_app%
  }
Return

; Start the timer on the selected item in the daily view
#IfWinActive ahk_class WindowsForms10.Window.8.app.0.262fb3d
  >+s::
    WinGetActiveTitle, active_title
    match_result := RegExMatch(active_title, "^Entries for")
    drop_down := 100
    If(match_result > 0) {
      WinMove, 100, 100
      MouseMove, 100, 280
      Send {RButton}
      Sleep, 100 ; need to sleep to allow the submenu to come up
      MouseMove, 170, 300 + drop_down
      Send {LButton}
    }
Return

; WORD ------------------------------------------------------------------------
#IfWinActive ahk_class OpusApp
   PrintScreen::AppsKey
Return

; SYMBOL KEYS -----------------------------------------------------------------
>+s::send §


coordinate reseting completely moved to options menu

+ Code Cleared

; AutoHotkey Version: 1.1x
; Language:       English
; Author:         8thSeaOfRhye
;
;                     #####         Parent2Gem.ahk - Version 2       #####
;

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
InitialMode := False ; Initialisation
CoordMode, Mouse, Screen
CurrentCustom := "(g+g)+(g+g)"
LastDDL := 6
CombineMode := True
LastGemPos := 1

TopLeftCornerX := 1590
TopLeftCornerY := 338
BottomRightCornerX := 1436
BottomRightCornerY := 686

ParentStr := "(g+g)+(g+g)"

!V::
	OptionsMenu()
return

OptionsMenu() {
	Global ParentStr
	Global ChosenCombine
	Global ParentNewStr
	Global InitialMode
	Global CustomFormula
	Global PGScript
	Global CustomTemp
	Global LastDDL
	Global CurrentCustom
	Global LastDDLTemp
	Global TempReadOnly

	Gui, New,, Options
	GuiHWND := WinExist()

; ################# DDL #####################

	TempReadOnly := ""
	If LastDDL != 6
		TempReadOnly := "readonly"
	Gui, Add, Text,, Choose your desired combine
	Gui, Add, DropDownList, w200 Choose%LastDDL% vChosenCombine gShowCustomField, killgem_amps64-5-gem|killgem_amps64-5-amps|managem_amps256-30_ieee-gem|managem_amps256-30_ieee-amps|universal16c|Custom
	Gui, Add, Text,, Custom Bracket Formula:        Attention! Syntaxerrors may lead to chaos!
	Gui, Add, Edit, w400 r3 vCustomFormula %TempReadOnly%, %CurrentCustom%

; ################# INITMODE ################

	Gui, Add, Text, w400, `n`nIn order to setup the script for your screen-resolution press the following button and follow the instructions`: `n
	Gui, Add, Button, , Setup Script
	Gui, Add, Text,, You have to run this setup each time your screen-resolution changes

;###############Wait For Input ##############

	Gui, Add, Button, default, Ok
	Gui, Show
	WinWaitClose, ahk_id %GuiHWND%
	return

;############### SUBS / Labels #############

	ShowCustomField:
		GuiControlGet, StatusOfDll, , ChosenCombine
		if (StatusOfDll = "custom")
			GuiControl, -readonly, CustomFormula
		else
			GuiControl, +readonly, CustomFormula
	return

	ButtonSetupScript:
		if (InitialMode = False)
			PGScript := RegExReplace(PGScript, "InitialMode := False `; Init", "InitialMode := True  `; Init", , 1)
		FileRead, PGScript, Parent2Gem.ahk
		FileDelete, Parent2Gem.ahk
		MsgBox Place your mouse over the top-left corner of the 12*3 craftingfield and press ENTER
			MouseGetPos, TLCX, TLCY
			PGScript := RegExReplace(PGScript, "TopLeftCornerX := [0-9]+", "TopLeftCornerX := " TLCX, , 1)
			PGScript := RegExReplace(PGScript, "TopLeftCornerY := [0-9]+", "TopLeftCornerY := " TLCY, , 1)
		MsgBox Place your mouse over the bottom-right corner of the 12*3 craftingfield and press ENTER
			MouseGetPos, BRCX, BRCY
			PGScript := RegExReplace(PGScript, "BottomRightCornerX := [0-9]+", "BottomRightCornerX := "BRCX, , 1)
			PGScript := RegExReplace(PGScript, "BottomRightCornerY := [0-9]+", "BottomRightCornerY := "BRCY, , 1)

		FileAppend, %PGScript%, Parent2Gem.ahk

		TopLeftCornerX := TLCX
		TopLeftCornerY := TLCY
		BottomRightCornerX := BRCX
		BottomRightCornerY := BRCY
		MsgBox The Script has been adapted to your screen-resolution. `nRemember to do this whenever your screen-resolution changes!

	return

	ButtonOk:
		Gui, Submit
		if (ChosenCombine = "killgem_amps64-5-gem") {
			ParentNewStr := "((((b+((b+y)+(y+y)))+((b+(b+y))+(b+(b+(b+b)))))+(((b+b)+(b+(y+y)))+(((b+y)+(y+y))+((y+y)+(y+(y+(y+(y+y))))))))+((((b+(b+y))+(b+(y+y)))+((b+(b+y))+(b+(b+(b+(b+b))))))+(((b+(b+y))+(b+(b+(b+b))))+((b+(b+(b+b)))+((b+(b+b))+((b+(b+b))+(b+(b+(b+(b+b))))))))))"
			LastDDL := 1
		}
		if (ChosenCombine = "killgem_amps64-5-amps") {
			ParentNewStr := "((y+y)+(y+(y+y)))"
			LastDDL := 2
		}

		if (ChosenCombine = "managem_amps256-30_ieee-gem") {
			ParentNewStr := "(((((((b+o)+(b+b))+(b+((o+o)+(b+o))))+(((b+o)+(b+b))+((b+b)+(b+(b+(b+(b+b)))))))+((((b+o)+(b+b))+(b+((o+o)+(o+(o+o)))))+((b+((o+o)+(b+o)))+(((o+o)+(b+o))+((o+o)+(o+(o+(o+(o+(o+(o+o)))))))))))+(((((b+o)+(b+b))+(b+((o+o)+(o+(o+o)))))+(((b+o)+(b+b))+((b+b)+(b+(b+(b+(b+b)))))))+((((b+o)+(b+b))+((b+b)+(b+(b+(b+(b+b))))))+(((b+b)+(b+(b+(b+(b+b)))))+((b+(b+(b+(b+b))))+((b+(b+(b+b)))+((b+(b+b))+((b+b)+(b+(b+(b+(b+(b+b)))))))))))))+((((((b+o)+(b+b))+(b+((b+o)+(o+(o+o)))))+(((b+o)+(b+b))+((b+b)+(b+(b+(b+(b+b)))))))+((((b+o)+(b+b))+(b+((b+o)+(o+(o+o)))))+((b+((o+o)+(b+o)))+(((o+o)+(b+o))+((o+(o+o))+(o+(o+(o+(o+(o+(o+o)))))))))))+(((((b+o)+(b+b))+(b+((b+o)+(o+(o+o)))))+((b+((o+o)+(b+o)))+(((b+o)+(o+(o+o)))+((o+(o+o))+(o+(o+(o+(o+(o+(o+o))))))))))+(((b+((o+o)+(b+o)))+((b+(o+o))+((o+o)+(o+(o+(o+(o+(o+o))))))))+((((o+o)+(b+o))+((o+(o+o))+(o+(o+(o+(o+(o+(o+o))))))))+(((o+o)+(o+(o+(o+(o+(o+o))))))+(((o+o)+(o+(o+(o+(o+(o+o))))))+((o+(o+(o+(o+o))))+((o+(o+(o+o)))+((o+(o+o))+((o+(o+o))+(o+(o+(o+(o+(o+(o+(o+o))))))))))))))))))"
			LastDDL := 3
		}

		if (ChosenCombine = "managem_amps256-30_ieee-amps") {
			ParentNewStr := "((((o+o)+(o+o))+((o+o)+(o+(o+(o+o)))))+(((o+o)+(o+(o+(o+o))))+((o+(o+o))+((o+(o+o))+(o+(o+(o+(o+(o+(o+(o+o)))))))))))"
			LastDDL := 4
		}

		if (ChosenCombine = "universal16c") {
			ParentNewStr := "(((((((((g+g)+g)+g)+g)+g)+g)+(g+g))+(g+g))+(((g+g)+g)+(g+g)))"
			LastDDL := 5
		}

		if (ChosenCombine = "Custom") {
			ParentNewStr := CustomFormula
			LastDDL := 6
		}

;		if (ChosenCombine = "") {
;			ParentNewStr := ""
;			LastDDL := 1
;		}

		if (ChosenCombine = "")
			ParentNewStr := ParentStr

		ParentStr := ParentNewStr
		FileRead, PGScript, Parent2Gem.ahk
		FileDelete, Parent2Gem.ahk
		ParentNewStr = ParentStr := "%ParentNewStr%"
		PGScript := RegExReplace(PGScript, "ParentStr := ""[A-Za-z0-9()+]*""", ParentNewStr, , 1)

		CustomTemp = CurrentCustom := "%CustomFormula%"
		if (ChosenCombine = "Custom")
			PGScript := RegExReplace(PGScript, "CurrentCustom := "".*""", CustomTemp, , 1)

		LastDDLTemp = LastDDL := %LastDDL%
		PGScript := RegExReplace(PGScript, "LastDDL := [0-9]*", LastDDLTemp, , 1)

		FileAppend, %PGScript%, Parent2Gem.ahk

		Gui, Destroy
	Return
}
!C::

if (InitialMode = False) {
	MsgBox, You have to adapt the script to your screen-resolution. You will be redirected to the options-menu, where you can hit the "Setup Script"-Button to do this.
	OptionsMenu()
}
else {
	FieldWidth := (BottomRightCornerX - TopLeftCornerX) / 3
	FieldHeight := (BottomRightCornerY - TopLeftCornerY) / 12
	CraftingField := [BottomRightCornerX -(FieldWidth / 2), BottomRightCornerY -(FieldHeight / 2)]

	SetDefaultMouseSpeed, 0
	i := 0
	j := 0
	StkCount := 1
	initPos := [TopLeftCornerX + (FieldWidth / 2), BottomRightCornerY - (FieldHeight * 1.5)]
	StackFields := []
	While i < 12
	{
		while j < 3
		{
			StackFields[StkCount, 1] := initPos[1] + (j * FieldWidth)
			StackFields[StkCount, 2] := initPos[2] - (i * FieldHeight)
			StkCount := StkCount + 1
			j := j + 1
		}
		j := 0
		i := i + 1
	}

	CurrentStk := 0

	OGem() {
		global CraftingField
		Send {Numpad7}
		MouseClick, left, CraftingField[1], CraftingField[2]
	}
	YGem() {
		global CraftingField
		Send {Numpad8}
		MouseClick, left, CraftingField[1], CraftingField[2]
	}
	BGem() {
		global CraftingField
		Send {Numpad1}
		MouseClick, left, CraftingField[1], CraftingField[2]
	}
	RGem() {
		global CraftingField
		Send {Numpad4}
		MouseClick, left, CraftingField[1], CraftingField[2]
	}

	GGem() {
		global CraftingField
		global FieldWidth
		MouseMove, CraftingField[1]-(2*FieldWidth), CraftingField[2]
		send d
	}
	WGem() {
		global CraftingField
		Send {Numpad9}
		MouseClick, left, CraftingField[1], CraftingField[2]
	}

	AddtoStk() {
		global CraftingField
		global CurrentStk
		global StackFields
		if CurrentStk != 0
			{
			Send g
			MouseClickDrag, L, CraftingField[1], CraftingField[2], StackFields[CurrentStk][1], StackFields[CurrentStk][2]
			}
	}

	MovetoStk() {
		global CraftingField
		global CurrentStk
		global StackFields
		CurrentStk := CurrentStk + 1
		MouseClickDrag, L, CraftingField[1], CraftingField[2], StackFields[CurrentStk][1], StackFields[CurrentStk][2]
	}

	PopStk() {
		global CraftingField
		global CurrentStk
		global StackFields
		if CurrentStk > 1
			{
			Send g
			MouseClickDrag, L, StackFields[CurrentStk][1], StackFields[CurrentStk][2], StackFields[CurrentStk - 1][1], StackFields[CurrentStk - 1][2]
			CurrentStk := CurrentStk - 1
			}
	}

	if (CombineMode = True) {
		StrPosEnd := StrLen(ParentStr)
		ElementFound := False
		While ElementFound = False {
			if (SubStr(ParentStr, StrPosEnd, 1) != ")") {
				ElementFound := True
				LastGemPos := StrPosEnd
			}
			StrPosEnd := StrPosEnd - 1
		}
	}

	StrPos := 1
	Parents := []

	While StrPos < StrLen(ParentStr) {
		if (SubStr(ParentStr, StrPos, 1) = "(") {
			if ((SubStr(ParentStr, StrPos - 1, 1) = "(") or (StrPos = 1))
				Parents.Insert(False)
			else
				Parents.Insert(True)
		}

		if (SubStr(ParentStr, StrPos, 1) = ")") {
			if (Parents[Parents.MaxIndex()] = True)
				PopStk()
			Parents.remove(Parents.MaxIndex())
		}

		if (SubStr(ParentStr, StrPos, 1) = "o") {
			OGem()
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
		}

		if (SubStr(ParentStr, StrPos, 1) = "r") {
			RGem()
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
		}

		if (SubStr(ParentStr, StrPos, 1) = "b") {
			BGem()
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
		}

		if (SubStr(ParentStr, StrPos, 1) = "y") {
			YGem()
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
		}
		if (SubStr(ParentStr, StrPos, 1) = "w") {
			WGem()
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
		}
		if ((SubStr(ParentStr, StrPos, 1) = "g") or (SubStr(ParentStr, StrPos, 1) = "k") or (SubStr(ParentStr, StrPos, 1) = "m")) {
			if (LastGemPos != StrPos)
				GGem()
			else
				MouseClickDrag, L, CraftingField[1]-(2*FieldWidth), CraftingField[2], CraftingField[1], CraftingField[2]
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
		}

		if ((SubStr(ParentStr, StrPos, 1) < 10) and (SubStr(ParentStr, StrPos, 1) > 1)) {
			if (SubStr(ParentStr, StrPos + 1, 1) = "o")
				OGem()
			if (SubStr(ParentStr, StrPos + 1, 1) = "y")
				YGem()
			if (SubStr(ParentStr, StrPos + 1, 1) = "b")
				BGem()
			if (SubStr(ParentStr, StrPos + 1, 1) = "r")
				RGem()
			if (SubStr(ParentStr, StrPos + 1, 1) = "r")
				WGem()
			if (SubStr(ParentStr, StrPos + 1, 1) = "g") {
				if (LastGemPos != StrPos + 1)
					GGem()
				else
					MouseClickDrag, L, CraftingField[1]-(2*FieldWidth), CraftingField[2], CraftingField[1], CraftingField[2]
			}
			UCount := 1
			While UCount <= SubStr(ParentStr, StrPos + 1, 1) {
				MouseMove, CraftingField[1], CraftingField[2]
				send u
				UCount := UCount + 1
			}

			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
			StrPos := StrPos + 1
		}

		if (SubStr(ParentStr, StrPos, 1) = "a") {
			MouseClickDrag, L, TopLeftCornerX + (FieldWidth / 2), TopLeftCornerY + (FieldHeight / 2), CraftingField[1], CraftingField[2]
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()

		}
		if (SubStr(ParentStr, StrPos, 1) = "s") {
			MouseClickDrag, L, TopLeftCornerX + (FieldWidth * 1.5), TopLeftCornerY + (FieldHeight / 2), CraftingField[1], CraftingField[2]
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()

		}
		if (SubStr(ParentStr, StrPos, 1) = "d") {
			MouseClickDrag, L, TopLeftCornerX + (FieldWidth * 2.5), TopLeftCornerY + (FieldHeight / 2), CraftingField[1], CraftingField[2]
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()

		}
		StrPos := StrPos + 1
	}
	while CurrentStk > 1 {
		PopStk()
	}
}

Return

; AutoHotkey Version: 1.1x
; Language:       English
; Author:         8thSeaOfRhye
;
;                     #####         Parent2Gem.ahk - Version 2       #####
;
;                     ##### Description of Purpose and Functionality #####
;
; ###            General             ###
; This script translates a String containing the Parenthesis-( i.e. Bracket-)Version of
; a speccing or combining scheme for gemcraft into actual commands for the gems creation.
; Works best in a STANDALONE FLASHPLAYER set to FULLSCREEN.
; It is hopefully easy to use and customize.
; The section which has to be changed is almost right at the top of the following code,
; namely under the command "!C::", and is commented to indicate the exact usage.
;
; The STANDARD HOTKEY is  Alt + c (No shift!!). This corresponds to "!C".
; Check ahkscript.org for Hotkey usage.
;
; CombiningMode is turned on by default. Speccing still works. Suggestion: Don't turn it off...
;
;
; ###  Syntax for the Bracket-Formula ###
;
; Obviously:
; 		r = Red / b = Black / o = orange / y = yellow
;
; Maybe a little less obviously:
;
;		g / k = copy of gem in the BOTTOM-LEFT! corner of the 12*3 craftingfield
;
; Furthermore:   ### New Features ###
;
;		the numerals 2 to 9 followed by any of the above = Corresponding color (or duplicate, respectively), upgraded 1 to 8 times
;
;		Examples: 9o / 2g = Orange upgraded 8 times (grade 9) / Base-gem (BottomLeft corner) upgraded once
;		(Needless to say, the upgrading happens via the "u"-button.)
;
; And:
;
;		a / s / d  =  use (left / middle / right) gem in the top row of the 3*12 craftingfield
;
;		(The order is inspired by the position of the keys on a standard keyboard.
;		 Attention: Those three can't be used in combination with numerals.)

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
InitialMode := False ; Initialisation
CoordMode, Mouse, Screen
CurrentCustom := "(g+g)+(g+g)"
LastDDL := 5
;             I
; #####      V V       																					 #########
; #####       V        INSERT THE SCHEME TO BE COMBINED INBETWEEN THE QUTATION-MARKS IN THE LINE BELOW   #########
ParentStr := "(g+g)+(g+g)"

; #####   						The default example is some random 1024 combine							 #########

!V::
	OptionsMenu()
return

OptionsMenu() {
	Global ParentStr
	Global ChosenCombine
	Global ParentNewStr
	Global ChosenIniMode
	Global IsIniChecked
	Global InitialMode
	Global CustomFormula
	Global PGScript
	Global CustomTemp
	Global LastDDL
	Global CurrentCustom
	Global LastDDLTemp
	Global TempReadOnly

	Gui, New,, Options
	GuiHWND := WinExist()

; ################# DDL ######################
	TempReadOnly := ""
	If LastDDL != 6
		TempReadOnly := "readonly"
	Gui, Add, Text,, Choose your desired combine
	Gui, Add, DropDownList, w200 Choose%LastDDL% vChosenCombine gShowCustomField, killgem_amps64-5-gem|killgem_amps64-5-amps|managem_amps256-30_ieee-gem|managem_amps256-30_ieee-amps|universal16c|Custom
	Gui, Add, Text,, Custom Bracket Formula:        Attention! Syntaxerrors may lead to chaos!
	Gui, Add, Edit, w400 r3 vCustomFormula %TempReadOnly%, %CurrentCustom%

; ################# INITMODE ################

	Gui, Add, Text,, `n`n In order to reset the coordinates check the following option`: `n
	If (InitialMode = False)
		IsIniChecked := ""
	If (InitialMode = True)
		IsIniChecked := "Checked"
	Gui, Add, Checkbox, vChosenIniMode %IsIniChecked%, Initialisation-Mode
	Gui, Add, Text,, If checked, you will be asked for coordinates the next time the CombiningHotkey is pressed.`n CombiningHotkey is Alt C by default.

;###############Wait For Input ##############

	Gui, Add, Button, default, Ok
	Gui, Show
	WinWaitClose, ahk_id %GuiHWND%
	return

;############### SUBS / Labels #############

	ShowCustomField:
		GuiControlGet, StatusOfDll, , ChosenCombine
		if (StatusOfDll = "custom")
			GuiControl, -readonly, CustomFormula
		else
			GuiControl, +readonly, CustomFormula
	return

	ButtonOk:
		Gui, Submit
		if (ChosenCombine = "killgem_amps64-5-gem") {
			ParentNewStr := "((((b+((b+y)+(y+y)))+((b+(b+y))+(b+(b+(b+b)))))+(((b+b)+(b+(y+y)))+(((b+y)+(y+y))+((y+y)+(y+(y+(y+(y+y))))))))+((((b+(b+y))+(b+(y+y)))+((b+(b+y))+(b+(b+(b+(b+b))))))+(((b+(b+y))+(b+(b+(b+b))))+((b+(b+(b+b)))+((b+(b+b))+((b+(b+b))+(b+(b+(b+(b+b))))))))))"
			LastDDL := 1
		}
		if (ChosenCombine = "killgem_amps64-5-amps") {
			ParentNewStr := "((y+y)+(y+(y+y)))"
			LastDDL := 2
		}

		if (ChosenCombine = "managem_amps256-30_ieee-gem") {
			ParentNewStr := "(((((((b+o)+(b+b))+(b+((o+o)+(b+o))))+(((b+o)+(b+b))+((b+b)+(b+(b+(b+(b+b)))))))+((((b+o)+(b+b))+(b+((o+o)+(o+(o+o)))))+((b+((o+o)+(b+o)))+(((o+o)+(b+o))+((o+o)+(o+(o+(o+(o+(o+(o+o)))))))))))+(((((b+o)+(b+b))+(b+((o+o)+(o+(o+o)))))+(((b+o)+(b+b))+((b+b)+(b+(b+(b+(b+b)))))))+((((b+o)+(b+b))+((b+b)+(b+(b+(b+(b+b))))))+(((b+b)+(b+(b+(b+(b+b)))))+((b+(b+(b+(b+b))))+((b+(b+(b+b)))+((b+(b+b))+((b+b)+(b+(b+(b+(b+(b+b)))))))))))))+((((((b+o)+(b+b))+(b+((b+o)+(o+(o+o)))))+(((b+o)+(b+b))+((b+b)+(b+(b+(b+(b+b)))))))+((((b+o)+(b+b))+(b+((b+o)+(o+(o+o)))))+((b+((o+o)+(b+o)))+(((o+o)+(b+o))+((o+(o+o))+(o+(o+(o+(o+(o+(o+o)))))))))))+(((((b+o)+(b+b))+(b+((b+o)+(o+(o+o)))))+((b+((o+o)+(b+o)))+(((b+o)+(o+(o+o)))+((o+(o+o))+(o+(o+(o+(o+(o+(o+o))))))))))+(((b+((o+o)+(b+o)))+((b+(o+o))+((o+o)+(o+(o+(o+(o+(o+o))))))))+((((o+o)+(b+o))+((o+(o+o))+(o+(o+(o+(o+(o+(o+o))))))))+(((o+o)+(o+(o+(o+(o+(o+o))))))+(((o+o)+(o+(o+(o+(o+(o+o))))))+((o+(o+(o+(o+o))))+((o+(o+(o+o)))+((o+(o+o))+((o+(o+o))+(o+(o+(o+(o+(o+(o+(o+o))))))))))))))))))"
			LastDDL := 3
		}

		if (ChosenCombine = "managem_amps256-30_ieee-amps") {
			ParentNewStr := "((((o+o)+(o+o))+((o+o)+(o+(o+(o+o)))))+(((o+o)+(o+(o+(o+o))))+((o+(o+o))+((o+(o+o))+(o+(o+(o+(o+(o+(o+(o+o)))))))))))"
			LastDDL := 4
		}

		if (ChosenCombine = "universal16c") {
			ParentNewStr := "(((((((((g+g)+g)+g)+g)+g)+g)+(g+g))+(g+g))+(((g+g)+g)+(g+g)))"
			LastDDL := 5
		}

		if (ChosenCombine = "Custom") {
			ParentNewStr := CustomFormula
			LastDDL := 6
		}

;		if (ChosenCombine = "") {
;			ParentNewStr := ""
;			LastDDL := 1
;		}

		if (ChosenCombine = "")
			ParentNewStr := ParentStr

		FileRead, PGScript, Parent2Gem.ahk
		FileDelete, Parent2Gem.ahk
		ParentNewStr = ParentStr := "%ParentNewStr%"
		PGScript := RegExReplace(PGScript, "ParentStr := ""[A-Za-z0-9()+]*""", ParentNewStr, , 1)

		CustomTemp = CurrentCustom := "%CustomFormula%"
		if (ChosenCombine = "Custom")
			PGScript := RegExReplace(PGScript, "CurrentCustom := "".*""", CustomTemp, , 1)

		LastDDLTemp = LastDDL := %LastDDL%
		PGScript := RegExReplace(PGScript, "LastDDL := [0-9]*", LastDDLTemp, , 1)

		if ((ChosenIniMode = 0) and (InitialMode = True))
			PGScript := RegExReplace(PGScript, "InitialMode := True  `; Init", "InitialMode := False `; Init", , 1)
		if ((ChosenIniMode = 1) and (InitialMode = False))
			PGScript := RegExReplace(PGScript, "InitialMode := False `; Init", "InitialMode := True  `; Init", , 1)

		FileAppend, %PGScript%, Parent2Gem.ahk
		Gui, Destroy
	Reload
}
!C::

CombineMode := True
LastGemPos := 1

TopLeftCornerX := 1590 				;  ####### ENTER THE COORDINATES OF THE 3*12 CRAFTINGFIELD ON YOUR SCREEN #########
TopLeftCornerY := 338				;	###### If you don't know how to obtain those values, you'd better  ########
BottomRightCornerX := 1436			;    ##### ask somebody. They don't have to be really precise.     #######
BottomRightCornerY := 686			;	  #### AND THAT'S IT! The script should work for you now!  ######

if (InitialMode = True) {
	FileRead, PGScript, Parent2Gem.ahk
	FileDelete, Parent2Gem.ahk
	MsgBox Place your mouse over the top-left corner of the 12*3 craftingfield and press ENTER
		MouseGetPos, TLCX, TLCY
		PGScript := RegExReplace(PGScript, "TopLeftCornerX := [0-9]+", "TopLeftCornerX := " TLCX, , 1)
		PGScript := RegExReplace(PGScript, "TopLeftCornerY := [0-9]+", "TopLeftCornerY := " TLCY, , 1)
	MsgBox Place your mouse over the bottom-right corner of the 12*3 craftingfield and press ENTER
		MouseGetPos, BRCX, BRCY
		PGScript := RegExReplace(PGScript, "BottomRightCornerX := [0-9]+", "BottomRightCornerX := "BRCX, , 1)
		PGScript := RegExReplace(PGScript, "BottomRightCornerY := [0-9]+", "BottomRightCornerY := "BRCY, , 1)
		PGScript := RegExReplace(PGScript, "InitialMode := True  `; Init", "InitialMode := False `; Init", , 1)
	FileAppend, %PGScript%, Parent2Gem.ahk

	MsgBox The Script has been initialised and will be reloaded!

	Reload
}
	else {
	FieldWidth := (BottomRightCornerX - TopLeftCornerX) / 3
	FieldHeight := (BottomRightCornerY - TopLeftCornerY) / 12
	CraftingField := [BottomRightCornerX -(FieldWidth / 2), BottomRightCornerY -(FieldHeight / 2)]

	SetDefaultMouseSpeed, 0
	i := 0
	j := 0
	StkCount := 1
	initPos := [TopLeftCornerX + (FieldWidth / 2), BottomRightCornerY - (FieldHeight * 1.5)]
	StackFields := []
	While i < 12
	{
		while j < 3
		{
			StackFields[StkCount, 1] := initPos[1] + (j * FieldWidth)
			StackFields[StkCount, 2] := initPos[2] - (i * FieldHeight)
			StkCount := StkCount + 1
			j := j + 1
		}
		j := 0
		i := i + 1
	}

	; For FieldNum, FieldValue in StackFields
	;	MsgBox % " Coordinates of Stack-Field #" . FieldNum .  ": " . FieldValue[1] . FieldValue[2]

	CurrentStk := 0

	OGem() {
		global CraftingField
		Send {Numpad7}
		MouseClick, left, CraftingField[1], CraftingField[2]
	}
	YGem() {
		global CraftingField
		Send {Numpad8}
		MouseClick, left, CraftingField[1], CraftingField[2]
	}
	BGem() {
		global CraftingField
		Send {Numpad1}
		MouseClick, left, CraftingField[1], CraftingField[2]
	}
	RGem() {
		global CraftingField
		Send {Numpad4}
		MouseClick, left, CraftingField[1], CraftingField[2]
	}

	GGem() {
		global CraftingField
		global FieldWidth
		MouseMove, CraftingField[1]-(2*FieldWidth), CraftingField[2]
		send d
	}
	WGem() {
		global CraftingField
		Send {Numpad9}
		MouseClick, left, CraftingField[1], CraftingField[2]
	}

	AddtoStk() {
		global CraftingField
		global CurrentStk
		global StackFields
		if CurrentStk != 0
			{
			Send g
			MouseClickDrag, L, CraftingField[1], CraftingField[2], StackFields[CurrentStk][1], StackFields[CurrentStk][2]
			}
	}

	MovetoStk() {
		global CraftingField
		global CurrentStk
		global StackFields
		CurrentStk := CurrentStk + 1
		MouseClickDrag, L, CraftingField[1], CraftingField[2], StackFields[CurrentStk][1], StackFields[CurrentStk][2]
	}

	PopStk() {
		global CraftingField
		global CurrentStk
		global StackFields
		if CurrentStk > 1
			{
			Send g
			MouseClickDrag, L, StackFields[CurrentStk][1], StackFields[CurrentStk][2], StackFields[CurrentStk - 1][1], StackFields[CurrentStk - 1][2]
			CurrentStk := CurrentStk - 1
			}
	}

	if (CombineMode = True) {
		StrPosEnd := StrLen(ParentStr)
		ElementFound := False
		While ElementFound = False {
			if (SubStr(ParentStr, StrPosEnd, 1) != ")") {
				ElementFound := True
				LastGemPos := StrPosEnd
			}
			StrPosEnd := StrPosEnd - 1
		}
	}

	StrPos := 1
	Parents := []

	While StrPos < StrLen(ParentStr) {
		if (SubStr(ParentStr, StrPos, 1) = "(") {
			if ((SubStr(ParentStr, StrPos - 1, 1) = "(") or (StrPos = 1))
				Parents.Insert(False)
			else
				Parents.Insert(True)
		}

		if (SubStr(ParentStr, StrPos, 1) = ")") {
			if (Parents[Parents.MaxIndex()] = True)
				PopStk()
			Parents.remove(Parents.MaxIndex())
		}

		if (SubStr(ParentStr, StrPos, 1) = "o") {
			OGem()
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
		}

		if (SubStr(ParentStr, StrPos, 1) = "r") {
			RGem()
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
		}

		if (SubStr(ParentStr, StrPos, 1) = "b") {
			BGem()
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
		}

		if (SubStr(ParentStr, StrPos, 1) = "y") {
			YGem()
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
		}
		if (SubStr(ParentStr, StrPos, 1) = "w") {
			WGem()
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
		}
		if ((SubStr(ParentStr, StrPos, 1) = "g") or (SubStr(ParentStr, StrPos, 1) = "k") or (SubStr(ParentStr, StrPos, 1) = "m")) {
			if (LastGemPos != StrPos)
				GGem()
			else
				MouseClickDrag, L, CraftingField[1]-(2*FieldWidth), CraftingField[2], CraftingField[1], CraftingField[2]
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
		}

		if ((SubStr(ParentStr, StrPos, 1) < 10) and (SubStr(ParentStr, StrPos, 1) > 1)) {
			if (SubStr(ParentStr, StrPos + 1, 1) = "o")
				OGem()
			if (SubStr(ParentStr, StrPos + 1, 1) = "y")
				YGem()
			if (SubStr(ParentStr, StrPos + 1, 1) = "b")
				BGem()
			if (SubStr(ParentStr, StrPos + 1, 1) = "r")
				RGem()
			if (SubStr(ParentStr, StrPos + 1, 1) = "r")
				WGem()
			if (SubStr(ParentStr, StrPos + 1, 1) = "g") {
				if (LastGemPos != StrPos + 1)
					GGem()
				else
					MouseClickDrag, L, CraftingField[1]-(2*FieldWidth), CraftingField[2], CraftingField[1], CraftingField[2]
			}
			UCount := 1
			While UCount <= SubStr(ParentStr, StrPos + 1, 1) {
				MouseMove, CraftingField[1], CraftingField[2]
				send u
				UCount := UCount + 1
			}

			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()
			StrPos := StrPos + 1
		}

		if (SubStr(ParentStr, StrPos, 1) = "a") {
			MouseClickDrag, L, TopLeftCornerX + (FieldWidth / 2), TopLeftCornerY + (FieldHeight / 2), CraftingField[1], CraftingField[2]
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()

		}
		if (SubStr(ParentStr, StrPos, 1) = "s") {
			MouseClickDrag, L, TopLeftCornerX + (FieldWidth * 1.5), TopLeftCornerY + (FieldHeight / 2), CraftingField[1], CraftingField[2]
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()

		}
		if (SubStr(ParentStr, StrPos, 1) = "d") {
			MouseClickDrag, L, TopLeftCornerX + (FieldWidth * 2.5), TopLeftCornerY + (FieldHeight / 2), CraftingField[1], CraftingField[2]
			if (SubStr(ParentStr, StrPos - 1, 1) = "(")
				MovetoStk()
			else
				AddtoStk()

		}
		StrPos := StrPos + 1
	}
	while CurrentStk > 1 {
		PopStk()
	}
}

Return


Update mac.ahk

Update mac.ahk

SetCapsLockState AlwaysOff

+CapsLock::CapsLock

; Unified MacOS like copy paste
!x::
  IfWinActive, Hyper
    Send ^+x
  else
    Send ^x
Return

!c::
  IfWinActive, Hyper
    Send ^+c
  else
    Send ^c
Return

!v::
  IfWinActive, Hyper
    Send ^+v
  else
    Send ^v
Return

; Reuse system wide navigation
CapsLock & b::Send {Left}
CapsLock & f::Send {Right}
CapsLock & p::Send {Up}
CapsLock & n::Send {Down}
CapsLock & a::Send {Home}
CapsLock & e::Send {End}

CapsLock & c::Send ^c
CapsLock & u::Send ^u
CapsLock & d::Send ^d
CapsLock & w::Send ^w
CapsLock & v::Send ^v

CapsLock & h::Send ^h
CapsLock & j::Send ^j
CapsLock & k::Send ^k
CapsLock & l::Send ^l

CapsLock & 1::Send ^1
CapsLock & 2::Send ^2
CapsLock & 3::Send ^3
CapsLock & 4::Send ^4
CapsLock & 5::Send ^5
CapsLock & 6::Send ^6
CapsLock & 7::Send ^7
CapsLock & 8::Send ^8
CapsLock & 9::Send ^9
CapsLock & 0::Send ^0

!n::Send ^n
!w::Send ^w
!t::Send ^t
!r::Send ^r
!s::Send ^s
!l::Send ^l
!a::Send ^a
!f::Send ^f
!z::Send ^z
!q::Send !{F4}

!+t::Send ^+t

; To Mac Command Left Click
!LButton::
  SendEvent ^{LButton down}
  KeyWait AppsKey  ; Prevents keyboard auto-repeat from repeating the mouse click.
  SendEvent ^{LButton up}
return

SetCapsLockState AlwaysOff

!x::
  IfWinActive, Hyper
    Send ^+x
  else
    Send ^x
Return

!c::
  IfWinActive, Hyper
    Send ^+c
  else
    Send ^c
Return

!v::
  IfWinActive, Hyper
    Send ^+v
  else
    Send ^v
Return

CapsLock & b::Send {Left}
CapsLock & f::Send {Right}
CapsLock & p::Send {Up}
CapsLock & n::Send {Down}
CapsLock & a::Send {Home}
CapsLock & e::Send {End}

CapsLock & c::Send ^c
CapsLock & u::Send ^u
CapsLock & d::Send ^d
CapsLock & w::Send ^w
CapsLock & v::Send ^v

CapsLock & h::Send ^h
CapsLock & j::Send ^j
CapsLock & k::Send ^k
CapsLock & l::Send ^l

CapsLock & 1::Send ^1
CapsLock & 2::Send ^2
CapsLock & 3::Send ^3
CapsLock & 4::Send ^4
CapsLock & 5::Send ^5
CapsLock & 6::Send ^6
CapsLock & 7::Send ^7
CapsLock & 8::Send ^8
CapsLock & 9::Send ^9
CapsLock & 0::Send ^0

!n::Send ^n
!w::Send ^w
!t::Send ^t
!r::Send ^r
!s::Send ^s
!l::Send ^l
!a::Send ^a
!f::Send ^f
!z::Send ^z


[chore] cleanup

[chore] cleanup

; Autohotkey configuration file
; AHK Version v.1.1.32.00
; Franklin Chou (franklin.chou@nelsonmullins.com)
; 14 Apr. 2020
; Tested to work on Lenovo X1 Yoga, Gen. 4

#SingleInstance Force
#Persistent

GLOBAL_DEBUG_MODE := 0
Return

CapsLock::Ctrl
LCtrl::Return
; LCtrl::CapsLock

; DEBUG TOOLS -----------------------------------------------------------------

#c::
  If(GLOBAL_DEBUG_MODE > 0) {
    ; WinGetClass, title, A
    WinGetActiveTitle, title
    MsgBox %title%
  }
Return

f12::
  If(GLOBAL_DEBUG_MODE > 0) {
    Reload
  }
Return

; SYSTEM ----------------------------------------------------------------------

; Access different windows of the same group
!`::
  WinGet, process_name, ProcessName, A ; get the active window's process name
  process_windows := GetWindowsOfProcess(process_name)

  n_process_windows := process_windows.Length()

  index := 1 ; AHK arrays are 1 indexed
  While(GetKeyState("Alt", "P")) {
    If (GetKeyState("``", "P")) {
      If (index < n_process_windows) {
        index := index + 1
      } Else {
        index := 1
      }
      active_id := process_windows[index]
      WinActivate, ahk_id %active_id%
    }
  }
  index := ""
  process_windows := ""
  n_process_windows := ""
Return

; Get the window ids of all the processes under that process name
GetWindowsOfProcess(process_name) {
  ids := Array()
  WinGet, window_ids, List ; get the IDs for all running windows
  Loop %window_ids% {
    id := window_ids%A_Index%
    WinGetTitle, title, ahk_id %id%
    WinGet, a_process_name, ProcessName, ahk_id %id%
    ; only include windows with visible title
    If (title && a_process_name = process_name) {
      ids.Push(id)
    }
  }
  Return, ids
}

; utility to get selected text (if any)
GetSelectedText() {
  temp := ClipboardAll
  Clipboard := ""
  Send ^c
  ClipWait, 0, 1
  selection := Clipboard
  Clipboard := temp
  Return, selection
}

; TIMEKEEPER ------------------------------------------------------------------

; Shift focus to the timekeeper app
#!e::
  timekeeper_app := WinExist("ahk_class WindowsForms10.Window.8.app.0.262fb3d")
  If(timekeeper_app > 0) {
    WinActivate, ahk_id %timekeeper_app%
  } Else {
    Run, DTE.exe, C:\Program Files (x86)\DTEAxiom
  }
Return

; Start the timer on the selected item in the daily view
#IfWinActive ahk_class WindowsForms10.Window.8.app.0.262fb3d
  >+s::
    WinGetActiveTitle, active_title
    selected := GetSelectedText()
    is_releasable := RegExMatch(selected, "Ready to be released|Timer still running")
    ; match weekly view, 1 application window
    If (is_releasable && RegExMatch(active_title, "DTE Axiom") > 0) {
      WinMove, 0, 0
      MouseMove, 100, 460
      DTEAppContextClick(4, 460)
    ; match monthly view, 2 application windows
    ; in this view, Ctrl + C does NOT copy the selected text
    ; so `is_releasable` is useless
    } Else If(RegExMatch(active_title, "^Entries for") > 0) {
      WinMove, 0, 0
      ; when figuring out how low to get the mouse to move aim for the area
      ; of the menu bar that says "Drag a column header here..."
      MouseMove, 100, 280
      DTEAppContextClick(4, 280)
    } Else {
      MsgBox Select releasable entry
      Return
    }
    is_releasable := ""
    selected := ""
Return

; click the item in the DTE context menu that is `item_position` from the top
; with the starting position of `initial_mouse` (y-axis offset)
DTEAppContextClick(item_position, initial_mouse) {
    ; each item in the dropdown is approximately 25 pixels
    drop_down := 25
    Send {RButton}
    Sleep, 10 ; sleep to allow submenu time to come up
    MouseMove, 170, (initial_mouse + 20) + drop_down * item_position
    Send {LButton}
}

; MSOFFICE --------------------------------------------------------------------

; Let the print screen key open the application options key (for spell check)
; Word and Outlook
#If WinActive("ahk_class OpusApp") || WinActive("ahk_class rctrl_renwnd32")
  PrintScreen::AppsKey
Return

; This ridiculous keymapping is care of Lenovo
; which maps F12 to some bloatware keyboard manager utility
#If WinActive("ahk_class OpusApp") || WinActive("ahk_class XLMAIN")
  F12::
    Send {F12}
Return

; WORD ONLY -------------------------------------------------------------------

; Cycle through types of markup
#If WinActive("ahk_class OpusApp")
  >+m::
    Send !r
    Sleep, 10
    Send td
    Send {Down}
    Send {Enter}
Return

; Bring up the tab stop modification dialogue
#If WinActive("ahk_class OpusApp")
  >+t::
    Send !h
    Send pg
    Send !t
Return

; Autohotkey configuration file
; AHK Version v.1.1.32.00
; Franklin Chou (franklin.chou@nelsonmullins.com)
; 14 Apr. 2020
; Tested to work on Lenovo X1 Yoga, Gen. 4

#SingleInstance Force
#Persistent

GLOBAL_DEBUG_MODE := 0
Return

CapsLock::Ctrl
LCtrl::Return
; LCtrl::CapsLock

; DEBUG TOOLS -----------------------------------------------------------------

#c::
  If(GLOBAL_DEBUG_MODE > 0) {
    ; WinGetClass, title, A
    WinGetActiveTitle, title
    MsgBox %title%
  }
Return

f12::
  If(GLOBAL_DEBUG_MODE > 0) {
    Reload
  }
Return

; SYSTEM ----------------------------------------------------------------------

; Access different windows of the same group
!`::
  WinGet, process_name, ProcessName, A ; get the active window's process name
  process_windows := GetWindowsOfProcess(process_name)

  n_process_windows := process_windows.Length()

  index := 1 ; AHK arrays are 1 indexed
  While(GetKeyState("Alt", "P")) {
    If (GetKeyState("``", "P")) {
      If (index < n_process_windows) {
        index := index + 1
      } Else {
        index := 1
      }
      active_id := process_windows[index]
      WinActivate, ahk_id %active_id%
    }
  }

  index := ""
  process_windows := ""
  n_process_windows := ""
Return

; Get the window ids of all the processes under that process name
GetWindowsOfProcess(process_name) {
  ids := Array()
  WinGet, window_ids, List ; get the IDs for all running windows
  Loop %window_ids% {
    id := window_ids%A_Index%
    WinGetTitle, title, ahk_id %id%
    WinGet, a_process_name, ProcessName, ahk_id %id%
    ; only include windows with visible title
    If (title && a_process_name = process_name) {
      ids.Push(id)
    }
  }
  Return, ids
}

; utility to get selected text (if any)
GetSelectedText() {
  temp := ClipboardAll
  Clipboard := ""
  Send ^c
  ClipWait, 0, 1
  selection := Clipboard
  Clipboard := temp
  Return, selection
}

; TIMEKEEPER ------------------------------------------------------------------

; Shift focus to the timekeeper app
#!e::
  timekeeper_app := WinExist("ahk_class WindowsForms10.Window.8.app.0.262fb3d")
  If(timekeeper_app > 0) {
    WinActivate, ahk_id %timekeeper_app%
  } Else {
    Run, DTE.exe, C:\Program Files (x86)\DTEAxiom
  }
Return

; Start the timer on the selected item in the daily view
#IfWinActive ahk_class WindowsForms10.Window.8.app.0.262fb3d
  >+s::
    WinGetActiveTitle, active_title
    selected := GetSelectedText()
    is_releasable := RegExMatch(selected, "Ready to be released|Timer still running")
    MsgBox %selected%
    ; match weekly view, 1 application window
    If (is_releasable && RegExMatch(active_title, "DTE Axiom") > 0) {
      WinMove, 0, 0
      MouseMove, 100, 460
      DTEAppContextClick(4, 460)
    ; match monthly view, 2 application windows
    ; in this view, Ctrl + C does NOT copy the selected text
    ; so `is_releasable` is useless
    } Else If(RegExMatch(active_title, "^Entries for") > 0) {
      WinMove, 0, 0
      ; when figuring out how low to get the mouse to move aim for the area
      ; of the menu bar that says "Drag a column header here..."
      MouseMove, 100, 280
      DTEAppContextClick(4, 280)
    } Else {
      MsgBox Select releasable entry
      Return
    }
    is_releasable := ""
    selected := ""
Return

; click the item in the DTE context menu that is `item_position` from the top
; with the starting position of `initial_mouse` (y-axis offset)
DTEAppContextClick(item_position, initial_mouse) {
    ; each item in the dropdown is approximately 25 pixels
    drop_down := 25
    Send {RButton}
    Sleep, 10 ; sleep to allow submenu time to come up
    MouseMove, 170, (initial_mouse + 20) + drop_down * item_position
    Send {LButton}
}

; MSOFFICE --------------------------------------------------------------------

; Let the print screen key open the application options key (for spell check)
; Word and Outlook
#If WinActive("ahk_class OpusApp") || WinActive("ahk_class rctrl_renwnd32")
  PrintScreen::AppsKey
Return

; This ridiculous keymapping is care of Lenovo
; which maps F12 to some bloatware keyboard manager utility
#If WinActive("ahk_class OpusApp") || WinActive("ahk_class XLMAIN")
  F12::
    Send {F12}
Return

; WORD ONLY -------------------------------------------------------------------

; Cycle through types of markup
#If WinActive("ahk_class OpusApp")
  >+m::
    Send !r
    Sleep, 10
    Send td
    Send {Down}
    Send {Enter}
Return

; Bring up the tab stop modification dialogue
#If WinActive("ahk_class OpusApp")
  >+t::
    Send !h
    Send pg
    Send !t
Return


Create 19. Speech Recognition Page - No Options.ahk

templates/autohotkey_scripts/19. Speech Recognition Page - No Options.ahk


v2.32

; -----------------------------------------------------------------------------------------
; Clicker Heroes Sw1ft Bot
; by Sw1ftb
; -----------------------------------------------------------------------------------------

#Persistent
#NoEnv
#InstallKeybdHook

#Include %A_ScriptDir%
#Include ch_bot_lib.ahk

SetControlDelay, -1

scriptName=CH Sw1ft Bot
scriptVersion=2.32
minLibVersion=1.31

script := scriptName . " v" . scriptVersion

; -----------------------------------------------------------------------------------------
; -- Mandatory Configuration
; -----------------------------------------------------------------------------------------

irisLevel := 1029 ; try to keep your Iris within 1001 levels of your optimal zone

; Clicker Heroes Ancients Optimizer @ http://s3-us-west-2.amazonaws.com/clickerheroes/ancientssoul.html

; Use the optimizer to set the optimal level and time:
optimalLevel := 2000
speedRunTime := 29 ; minutes (usually between 28 and 30 minutes)

; In the Heroes tab you can verify that you are using the optimal ranger.
gildedRanger := 6 ; the number of your main guilded ranger
; 1:Dread Knight, 2:Atlas, 3:Terra, 4:Phthalo, 5:Banana, 6:Lilin, 7:Cadmia, 8:Alabaster, 9:Astraea

; -----------------------------------------------------------------------------------------
; -- Optional Settings
; -----------------------------------------------------------------------------------------

; (Steam only) Want to run borderless fullscreen?
; 1. In Clicker Heroes, turn on the "Full Screen" option.
; 2. Change "fullScreenOption" to "true" in the ch_bot_lib.ahk file.
; 3. Reload with Alt+F5.

; -- Speed run ----------------------------------------------------------------------------

; If the script starts on the 2nd ranger too early (before lvl 100) or too late (after lvl 200), adjust this setting.
firstStintAdjustment := 0 ; Add or remove time (in seconds) to or from the first hero.

activateSkillsAtStart := true ; usually needed in the late game to get going after ascending

hybridMode := false ; chain a deep run when the speed run finish

ascDownClicks := 26 ; # of down clicks needed to get the ascension button center:ish (after a full speed run)

autoAscend := false ; Warning! Set to true will both salvage relics and ascend without any user intervention!
autoAscendDelay := 10 ; warning timer (in seconds) before ascending

saveBeforeAscending := false ; autosave the game

; If you run the Steam client with autoAscend, you can screenshot every relic you salvage!
screenShotRelics := false

; -- Deep run -----------------------------------------------------------------------------

deepRunTime := 60 ; minutes

clickableHuntDelay := 15 ; hunt for a clickable every 15s
stopHuntThreshold := 30 ; stop hunt when this many minutes remain of a deep run

; Number of gilds to move over at a time
reGildCount := 100 ; don't set this higher than 100 if you plan on moving gilds during a deep run
reGildRanger := gildedRanger + 1

; -- Init run -----------------------------------------------------------------------------

; The assistant will automatically try to set the correct initDownClicks and yLvlInit settings.
; It will also assist with Iris level recommendations.
useConfigurationAssistant := true

; A list of clicks needed to scroll down 4 heroes at a time, starting from the top.
initDownClicks := [0,0,0,0,0,0]

; This y coordinate is supposed to keep itself inside the top lvl up button when scrolling down according to the above "clicking pattern".
yLvlInit := 000

; Manual configuration (if not using the assistant):
; 1. Ascend with a "clickable" available.
; 2. Click Alt+F1 (the script should pick up the clickable).
; 3. Scroll down to the bottom. What ranger is last?
; 4. From the list below, pick the matching settings:

; Astraea      [6,5,6,5,6,3], 241 (Iris > 2010)
; Alabaster    [6,6,5,6,6,3], 259 (Iris > 1760)
; Cadmia       [6,6,6,6,6,3], 240 (Iris > 1510)
; Lilin        [6,6,6,6,6,3], 285 (Iris > 1260)
; Banana       [6,7,6,7,6,3], 240 (Iris > 1010)
; Phthalo      [6,7,7,6,7,3], 273 (Iris > 760)
; Terra        [7,7,7,7,7,3], 240 (Iris > 510)
; Atlas        [7,7,7,8,7,3], 273 (Iris > 260)
; Dread Knight [7,8,7,8,7,4], 257

; E.g. if Phthalo is last, you set initDownClicks to [6,7,7,6,7,3] and yLvlInit to 273.
; In this case your Iris level should be somewhere between 760 and 1010.

; 5. Now click Alt+F2 (the script should level up and upgrade all heroes from Cid to Frostleaf).

; If some heroes where missed, make sure you have picked the suggested setting for your Iris level.
; If you are close to one of these Iris irisThresholds, you should move above it with some margin.
; E.g if your Iris is at 489, you should level it to at least 529, pick the setting for Terra,
; reload the script (Alt+F5), ascend with a clickable and try Alt+F2 again.

; -- Look & Feel --------------------------------------------------------------------------

; true or false
global playNotificationSounds := true
global playWarningSounds := true
global showSplashTexts := true ; Note that some splash texts will always be shown
global showProgressBar := true

; Splash text window position
xSplash := A_ScreenWidth // 2 - wSplash // 2 ; centered
ySplash := A_ScreenHeight // 2 - 40

; Progress bar position
xProgressBar := 20
yProgressBar := 20

; If you run with a dual/tripple monitor setup, you can move windows
; right or left by adding or subtracting A_ScreenWidth from the x-parameters.

; Left monitor example:
; xSplash := A_ScreenWidth // 2 - wSplash // 2 - A_ScreenWidth
; xProgressBar := 20 - A_ScreenWidth

; -- Skill Combos -------------------------------------------------------------------------

; 1 - Clickstorm, 2 - Powersurge, 3 - Lucky Strikes, 4 - Metal Detector, 5 - Golden Clicks
; 6 - The Dark Ritual, 7 - Super Clicks, 8 - Energize, 9 - Reload

; Test with tools/combo_tester.ahk

comboStart := [15*60, "8-1-2-3-4-5-7-6-9"]
comboEDR := [2.5*60, "2-3-4-5-7-8-6-9", "", "", "", "", "", "8-9-2-3-4-5-7", "2", "2", "2-3-4", "2", "2"]
comboEGolden := [2.5*60, "8-5-2-3-4-7-6-9", "2", "2", "2-3-4", "2", "2"] ; energize 3 (dmg) or 5 (gold)
comboGoldenLuck := [2.5*60, "6-2-3-5-8-9", "2-3-4-5-7", "2", "2", "2-3-4", "2", "2"]

speedRunStartCombo := comboStart
deepRunCombo := comboGoldenLuck

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

if (libVersion != minLibVersion) {
	showWarningSplash("The bot lib version must be " . minLibVersion . "!")
	ExitApp
}

#Include *i ch_bot_settings.ahk

if (useConfigurationAssistant) {
	configurationAssistant()
}

clientCheck()

; -----------------------------------------------------------------------------------------
; -- Hotkeys (+=Shift, !=Alt, ^=Ctrl)
; -----------------------------------------------------------------------------------------

; Show the cursor position with Alt+Middle Mouse Button
!mbutton::
	mousegetpos, xpos, ypos
	msgbox,,% script,% "Cursor position: x" xpos-leftMarginOffset " y" ypos-topMarginOffset
return

; Pause/Unpause script
Pause::Pause
return

; Abort speed/deep runs and auto ascensions with Alt+Pause
!Pause::
	showSplashAlways("Aborting...")
	exitThread := true
	exitDRThread := true
return

; Quick tests:
; Ctrl+Alt+F1 should scroll down to the bottom
; Ctrl+Alt+F2 should switch to the relics tab and then back

^!F1::
	scrollToBottom()
return

^!F2::
	switchToRelicTab()
	switchToCombatTab()
return

; Alt+F1 to F4 are here to test the individual parts of the full speed run loop

!F1::
	getClickable()
return

!F2::
	initRun()
return

!F3::
	switchToCombatTab()
	speedRun()
return

!F4::
	ascend(autoAscend)
return

; Reload script with Alt+F5
!F5::
	showSplashAlways("Reloading bot...", 1)
	Reload
return

; Speed run loop.
; Use to farm Hero Souls
^F1::
	mode := hybridMode ? "hybrid" : "speed"
	showSplashAlways("Starting " . mode . " runs...")
	loop
	{
		getClickable()
	    sleep % coinPickUpDelay * 1000
		initRun()
		if (activateSkillsAtStart) {
			activateSkills(speedRunStartCombo[2])
		}
		speedRun()
		if (hybridMode) {
			deepRun()
		}
		if (saveBeforeAscending) {
			save()
		}
		ascend(autoAscend)
	}
return

; Deep run.
; Use (after a speed run) to get a few new gilds every now and then
^F2::
	deepRun()
return

; Set previous ranger as re-gild target
^F6::
	reGildRanger := reGildRanger > rangers.MinIndex() ? reGildRanger-1 : reGildRanger
	showSplashAlways("Re-gild ranger set to " . rangers[reGildRanger])
return

; Set next ranger as re-gild target
^F7::
	reGildRanger := reGildRanger < rangers.MaxIndex() ? reGildRanger+1 : reGildRanger
	showSplashAlways("Re-gild ranger set to " . rangers[reGildRanger])
return

; Move "reGildCount" gilds to the target ranger (will pause the monster clicker if running)
^F8::
	critical
	playNotificationSound()
	msgbox, 4,% script,% "Move " . reGildCount . " gilds to " . rangers[reGildRanger] . "?"
	ifmsgbox no
		return
	regild(reGildRanger, reGildCount) ; will pause the monster clicker if running
return

; Autosave the game
^F11::
	critical
	monsterClickerPause()
	save()
return

; Toggle boolean (true/false) flags

+^F1::
	toggleFlag("autoAscend", autoAscend)
return

+^F2::
	toggleFlag("screenShotRelics", screenShotRelics)
return

+^F3::
	toggleFlag("playNotificationSounds", playNotificationSounds)
return

+^F4::
	toggleFlag("playWarningSounds", playWarningSounds)
return

+^F5::
	toggleFlag("showSplashTexts", showSplashTexts)
return

+^F11::
	toggleFlag("saveBeforeAscending", saveBeforeAscending)
return

+^F12::
	toggleFlag("debug", debug)
return

; -----------------------------------------------------------------------------------------
; -- Functions
; -----------------------------------------------------------------------------------------

; Automatically configure initDownClicks and yLvlInit settings.
configurationAssistant() {
	global

	if (irisLevel < 145) {
		playWarningSound()
		msgbox,,% script,% "Your Iris do not fulfill the minimum level requirement of 145 or higher!"
		exit
	}

	if (irisThreshold(2010)) { ; Astraea
		initDownClicks := [6,5,6,5,6,3]
		yLvlInit := 241
	} else if (irisThreshold(1760)) { ; Alabaster
		initDownClicks := [6,6,5,6,6,3]
		yLvlInit := 259
	} else if (irisThreshold(1510)) { ; Cadmia
		initDownClicks := [6,6,6,6,6,3]
		yLvlInit := 240
	} else if (irisThreshold(1260)) { ; Lilin
		initDownClicks := [6,6,6,6,6,3]
		yLvlInit := 285
	} else if (irisThreshold(1010)) { ; Banana
		initDownClicks := [6,7,6,7,6,3]
		yLvlInit := 240
	} else if (irisThreshold(760)) { ; Phthalo
		initDownClicks := [6,7,7,6,7,3]
		yLvlInit := 273
	} else if (irisThreshold(510)) { ; Terra
		initDownClicks := [7,7,7,7,7,3]
		yLvlInit := 240
	} else if (irisThreshold(260)) { ; Atlas
		initDownClicks := [7,7,7,8,7,3]
		yLvlInit := 273
	} else { ; Dread Knight
		initDownClicks := [7,8,7,8,7,4]
		yLvlInit := 257
	}

	if (irisLevel < optimalLevel - 1001) {
		local levels := optimalLevel - 1001 - irisLevel
		playNotificationSound()
		msgbox,,% script,% "Your Iris is " . levels . " levels below the recommended ""optimal level - 1001"" rule."
	}
}

; Check if Iris is within a certain threshold that can cause a toggling behaviour between different settings
irisThreshold(lvl) {
	global
	local upperThreshold := lvl + 19
	local lowerThreshold := lvl - 20
	if (irisLevel >= lowerThreshold and irisLevel < upperThreshold) {
		playWarningSound()
		msgbox,,% script,% "Threshold proximity warning! You should level up your Iris to " . upperThreshold . " or higher."
	}
	return irisLevel > lvl
}

; Level up and upgrade all heroes
initRun() {
	global

	switchToCombatTab()
	clickPos(xHero, yHero) ; prevent fails

	upgrade(initDownClicks[1],2,,2) ; cid --> brittany
	upgrade(initDownClicks[2]) ; fisherman --> leon
	upgrade(initDownClicks[3]) ; seer --> mercedes
	upgrade(initDownClicks[4],,,,2) ; bobby --> king
	upgrade(initDownClicks[5],2,,,2) ; ice --> amenhotep
	upgrade(initDownClicks[6],,,2) ; beastlord --> shinatobe
	upgrade(0,,,,,true) ; grant & frostleaf

	scrollToBottom()
	buyAvailableUpgrades()
}

upgrade(times, cc1:=1, cc2:=1, cc3:=1, cc4:=1, skip:=false) {
	global

	if (!skip) {
		ctrlClick(xLvl, yLvlInit, cc1)
		ctrlClick(xLvl, yLvlInit + oLvl, cc2)
	}
	ctrlClick(xLvl, yLvlInit + oLvl*2, cc3)
	ctrlClick(xLvl, yLvlInit + oLvl*3, cc4)

	scrollDown(times)
}

; All heroes/rangers are expected to "insta-kill" everything at max speed (i.e. around
; 7 minutes per 250 levels). Only the last 2-3 minutes should slow down slightly.
speedRun() {
	global

	local stint := 0
	local stints := 0
	local tMax := 7 * 60 ; seconds
	local lMax := 250 ; zones

	local lvlAdjustment := round(firstStintAdjustment * lMax / tMax)
	local zoneLvl := gildedRanger * lMax + lvlAdjustment ; approx zone lvl where we can buy our gilded ranger @ lvl 150
	local lvls := zoneLvl - irisLevel ; lvl's to get there

	local firstStintButton := 1
	local firstStintTime := 0
	local midStintTime := 0

	if (lvls > lMax + 2*60*lMax/tMax) ; add a mid stint if needed
	{
		midStintTime := tMax
		lvls -= lMax
		stints += 1
	} else if (lvls > lMax) {
		firstStintButton := 2
	}

	if (lvls > 0)
	{
		firstStintTime := ceil(lvls * tMax / lMax)
		stints += 1
	}

	local srDuration := speedRunTime * 60
	local totalClickDelay := ceil(srDuration / lvlUpDelay * zzz / 1000 + nextHeroDelay * stints)
	local lastStintTime := srDuration - firstStintTime - midStintTime - totalClickDelay
	stints += 1

	local lastStintButton := gildedRanger = 9 ? 3 : 2 ; special case for Astraea

	if (debug)
	{
		local nl := "`r`n"
		local s := "    " ; Reddit friendly formatting
		local output := ""
		output .= s . "irisLevel = " . irisLevel . nl
		output .= s . "optimalLevel = " . optimalLevel . nl
		output .= s . "speedRunTime = " . speedRunTime . nl
		output .= s . "gildedRanger = " . rangers[gildedRanger] . nl
		output .= s . "-----------------------------" . nl
		output .= s . "initDownClicks = "
		for i, e in initDownClicks {
			output .= e " "
		}
		output .= nl
		output .= s . "yLvlInit = " . yLvlInit . nl
		output .= s . "firstStintAdjustment = " . firstStintAdjustment . "s" . nl
		output .= s . "-----------------------------" . nl
		output .= s . "lvlAdjustment = " . lvlAdjustment . nl
		output .= s . "zoneLvl = " . zoneLvl . nl
		output .= s . "lvls = " . lvls . nl
		output .= s . "srDuration = " . formatSeconds(srDuration) . nl
		output .= s . "firstStintButton = " . firstStintButton . nl
		output .= s . "firstStintTime = " . formatSeconds(firstStintTime) . nl
		output .= s . "midStintTime = " . formatSeconds(midStintTime) . nl
		output .= s . "lastStintTime = " . formatSeconds(lastStintTime) . nl
		output .= s . "totalClickDelay = " . formatSeconds(totalClickDelay) . nl

		clipboard := % output
		msgbox % output
		return
	}

	showSplash("Starting speed run...")

	if (irisLevel < 2 * lMax + 10) ; Iris high enough to start with a ranger?
	{
		switchToCombatTab()
		scrollDown(initDownClicks[1])
		toggleMode() ; toggle to progression mode
		lvlUp(firstStintTime, 0, 3, ++stint, stints) ; nope, let's bridge with Samurai
		scrollToBottom()
	} else {
		scrollToBottom()
		toggleMode() ; toggle to progression mode
		if (firstStintTime > 0) {
			lvlUp(firstStintTime, 1, firstStintButton, ++stint, stints)
			scrollWayDown(3)
		}
	}
	if (midStintTime > 0) {
		lvlUp(midStintTime, 1, 2, ++stint, stints)
		scrollWayDown(2)
	}
	lvlUp(lastStintTime, 1, lastStintButton, ++stint, stints)

	showSplash("Speed run completed.")
}

deepRun() {
	global

	exitDRThread := false

	local drDuration := deepRunTime * 60
	local button := gildedRanger = 9 ? 3 : 2 ; special case for Astraea
	local y := yLvl + oLvl * (button - 1)

	showSplash("Starting deep run...")

	startMouseMonitoring()
	startProgress("Deep Run Progress", 0, drDuration // barUpdateDelay)
	monsterClickerOn()

	local comboDelay := deepRunCombo[1]
	local comboIndex := 2
	local stopHuntIndex := drDuration - stopHuntThreshold * 60
	local t := 0

	loop % drDuration
	{
		if (exitDRThread) {
			monsterClickerOff()
			stopProgress()
			stopMouseMonitoring()
			showSplashAlways("Deep run aborted!")
			exit
		}
		clickPos(xMonster, yMonster)
		if (mod(t, comboDelay) = 0) {
			activateSkills(deepRunCombo[comboIndex])
			comboIndex := comboIndex < deepRunCombo.MaxIndex() ? comboIndex+1 : 2
		}
		if (mod(t, lvlUpDelay) = 0) {
			ctrlClick(xLvl, y, 1, 0)
		}
		if (mod(t, clickableHuntDelay) = 0 and t < stopHuntIndex) {
			getClickable()
		}
		t += 1
		updateProgress(t // barUpdateDelay, drDuration - t)
		sleep 1000
	}

	monsterClickerOff()
	stopProgress()
	stopMouseMonitoring()

	showSplash("Deep run ended.")
	sleep 1000
}

monsterClickerOn() {
	send {shift down}{f1 down}{f1 up}{shift up}
}

monsterClickerPause() {
	send {shift down}{f2 down}{f2 up}{shift up}
}

monsterClickerOff() {
	send {shift down}{pause down}{pause up}{shift up}
}

lvlUp(seconds, buyUpgrades, button, stint, stints) {
	global

	exitThread := false
	local y := yLvl + oLvl * (button - 1)
	local title := "Speed Run Progress (" . stint . "/" . stints . ")"

	startMouseMonitoring()
	startProgress(title, 0, seconds // barUpdateDelay)

	if (buyUpgrades) {
		ctrlClick(xLvl, y)
		buyAvailableUpgrades()
	}
	maxClick(xLvl, y)

	local t := 0

	loop % seconds
	{
		if (exitThread) {
			stopProgress()
			stopMouseMonitoring()
			showSplashAlways("Speed run aborted!")
			exit
		}
		if (mod(t, lvlUpDelay) = 0) {
			ctrlClick(xLvl, y)
		}
		t += 1
		updateProgress(t // barUpdateDelay, seconds - t)
		sleep 1000
	}
	stopProgress()
	stopMouseMonitoring()
}

ascend(autoYes:=false) {
	global
	exitThread := false
	local extraClicks := 6
	local y := yAsc - extraClicks * buttonSize

	if (autoYes) {
		showWarningSplash(autoAscendDelay . " seconds till ASCENSION! (Abort with Alt+Pause)", autoAscendDelay)
		if (exitThread) {
			showSplashAlways("Ascension aborted!")
			exit
		}
	} else {
		playWarningSound()
		msgbox, 260,% script,Salvage Junk Pile & Ascend? ; default no
		ifmsgbox no
			exit
	}

	salvageJunkPile() ; must salvage junk relics before ascending

	switchToCombatTab()
	scrollDown(ascDownClicks)
	sleep % zzz * 2

	; Scrolling is not an exact science, hence we click above, center and below
	loop % 2 * extraClicks + 1
	{
		clickPos(xAsc, y)
		y += buttonSize
	}
	sleep % zzz * 4
	clickPos(xYes, yYes)
	sleep % zzz * 2
}

salvageJunkPile() {
	global

	switchToRelicTab()
	if (autoAscend && screenShotRelics) {
		clickPos(xRelic, yRelic) ; focus
		screenShot()
		clickPos(xRelic+100, yRelic) ; remove focus
	}
	clickPos(xSalvageJunk, ySalvageJunk)
	sleep % zzz * 4
	clickPos(xDestroyYes, yDestroyYes)
	sleep % zzz * 2
}

buyAvailableUpgrades() {
	global
	clickPos(xBuy, yBuy)
	sleep % zzz * 3
}

; Move "gildCount" gilds to given ranger
regild(ranger, gildCount) {
	global
	monsterClickerPause()
	switchToCombatTab()
	scrollToBottom()

	clickPos(xGilded, yGilded)
	sleep % zzz * 2

	ControlSend,, {shift down}, % winName
	clickPos(rangerPositions[ranger].x, rangerPositions[ranger].y, gildCount)
	sleep % 1000 * gildCount/100*5
	ControlSend,, {shift up}, % winName

	clickPos(xGildedClose, yGildedClose)
	sleep % zzz * 2
}

; Toggle between farm and progression modes
toggleMode() {
	global
	ControlSend,, {a down}{a up}, % winName
	sleep % zzz
}

activateSkills(skills) {
	global
	clickPos(xHero, yHero) ; prevent fails
	loop,parse,skills,-
	{
		ControlSend,,% A_LoopField, % winName
		sleep 100
	}
	sleep 1000
}

startMouseMonitoring() {
	setTimer, checkMousePosition, 250
}

stopMouseMonitoring() {
	setTimer, checkMousePosition, off
}

; -----------------------------------------------------------------------------------------
; -- Subroutines
; -----------------------------------------------------------------------------------------

; Safety zone around the in-game tabs (that triggers an automatic script pause when breached)
checkMousePosition:
	MouseGetPos,,, window
	if (window = WinExist(winName)) {
		WinActivate
		MouseGetPos, x, y

		xL := getAdjustedX(xSafetyZoneL)
		xR := getAdjustedX(xSafetyZoneR)
		yT := getAdjustedY(ySafetyZoneT)
		yB := getAdjustedY(ySafetyZoneB)

		if (x > xL && x < xR && y > yT && y < yB) {
			playNotificationSound()
			msgbox,,% script,Click safety pause engaged. Continue?
		}
	}
return

; -----------------------------------------------------------------------------------------
; Clicker Heroes Sw1ft Bot
; by Sw1ftb
; -----------------------------------------------------------------------------------------

#Persistent
#NoEnv
#InstallKeybdHook

#Include %A_ScriptDir%
#Include ch_bot_lib.ahk

SetControlDelay, -1

scriptName=CH Sw1ft Bot
scriptVersion=2.31
minLibVersion=1.31

script := scriptName . " v" . scriptVersion

; -----------------------------------------------------------------------------------------
; -- Mandatory Configuration
; -----------------------------------------------------------------------------------------

irisLevel := 1029 ; try to keep your Iris within 1001 levels of your optimal zone

; Clicker Heroes Ancients Optimizer @ http://s3-us-west-2.amazonaws.com/clickerheroes/ancientssoul.html

; Use the optimizer to set the optimal level and time:
optimalLevel := 2000
speedRunTime := 29 ; minutes (usually between 28 and 30 minutes)

; In the Heroes tab you can verify that you are using the optimal ranger.
gildedRanger := 6 ; the number of your main guilded ranger
; 1:Dread Knight, 2:Atlas, 3:Terra, 4:Phthalo, 5:Banana, 6:Lilin, 7:Cadmia, 8:Alabaster, 9:Astraea

; -----------------------------------------------------------------------------------------
; -- Optional Settings
; -----------------------------------------------------------------------------------------

; (Steam only) Want to run borderless fullscreen?
; 1. In Clicker Heroes, turn on the "Full Screen" option.
; 2. Change "fullScreenOption" to "true" in the ch_bot_lib.ahk file.
; 3. Reload with Alt+F5.

; -- Speed run ----------------------------------------------------------------------------

; If the script starts on the 2nd ranger too early (before lvl 100) or too late (after lvl 200), adjust this setting.
firstStintAdjustment := 0 ; Add or remove time (in seconds) to or from the first hero.

activateSkillsAtStart := true ; usually needed in the late game to get going after ascending

hybridMode := false ; chain a deep run when the speed run finish

ascDownClicks := 26 ; # of down clicks needed to get the ascension button center:ish (after a full speed run)

autoAscend := false ; Warning! Set to true will both salvage relics and ascend without any user intervention!
autoAscendDelay := 10 ; warning timer (in seconds) before ascending

saveBeforeAscending := false ; autosave the game

; If you run the Steam client with autoAscend, you can screenshot every relic you salvage!
screenShotRelics := false

; -- Deep run -----------------------------------------------------------------------------

deepRunTime := 60 ; minutes

clickableHuntDelay := 15 ; hunt for a clickable every 15s
stopHuntThreshold := 30 ; stop hunt when this many minutes remain of a deep run

; Number of gilds to move over at a time
reGildCount := 100 ; don't set this higher than 100 if you plan on moving gilds during a deep run
reGildRanger := gildedRanger + 1

; -- Init run -----------------------------------------------------------------------------

; The assistant will automatically try to set the correct initDownClicks and yLvlInit settings.
; It will also assist with Iris level recommendations.
useConfigurationAssistant := true

; A list of clicks needed to scroll down 4 heroes at a time, starting from the top.
initDownClicks := [0,0,0,0,0,0]

; This y coordinate is supposed to keep itself inside the top lvl up button when scrolling down according to the above "clicking pattern".
yLvlInit := 000

; Manual configuration (if not using the assistant):
; 1. Ascend with a "clickable" available.
; 2. Click Alt+F1 (the script should pick up the clickable).
; 3. Scroll down to the bottom. What ranger is last?
; 4. From the list below, pick the matching settings:

; Astraea      [6,5,6,5,6,3], 241 (Iris > 2010)
; Alabaster    [6,6,5,6,6,3], 259 (Iris > 1760)
; Cadmia       [6,6,6,6,6,3], 240 (Iris > 1510)
; Lilin        [6,6,6,6,6,3], 285 (Iris > 1260)
; Banana       [6,7,6,7,6,3], 240 (Iris > 1010)
; Phthalo      [6,7,7,6,7,3], 273 (Iris > 760)
; Terra        [7,7,7,7,7,3], 240 (Iris > 510)
; Atlas        [7,7,7,8,7,3], 273 (Iris > 260)
; Dread Knight [7,8,7,8,7,4], 257

; E.g. if Phthalo is last, you set initDownClicks to [6,7,7,6,7,3] and yLvlInit to 273.
; In this case your Iris level should be somewhere between 760 and 1010.

; 5. Now click Alt+F2 (the script should level up and upgrade all heroes from Cid to Frostleaf).

; If some heroes where missed, make sure you have picked the suggested setting for your Iris level.
; If you are close to one of these Iris irisThresholds, you should move above it with some margin.
; E.g if your Iris is at 489, you should level it to at least 529, pick the setting for Terra,
; reload the script (Alt+F5), ascend with a clickable and try Alt+F2 again.

; -- Look & Feel --------------------------------------------------------------------------

; true or false
global playNotificationSounds := true
global playWarningSounds := true
global showSplashTexts := true ; Note that some splash texts will always be shown
global showProgressBar := true

; Splash text window position
xSplash := A_ScreenWidth // 2 - wSplash // 2 ; centered
ySplash := A_ScreenHeight // 2 - 40

; Progress bar position
xProgressBar := 20
yProgressBar := 20

; If you run with a dual/tripple monitor setup, you can move windows
; right or left by adding or subtracting A_ScreenWidth from the x-parameters.

; Left monitor example:
; xSplash := A_ScreenWidth // 2 - wSplash // 2 - A_ScreenWidth
; xProgressBar := 20 - A_ScreenWidth

; -- Skill Combos -------------------------------------------------------------------------

; 1 - Clickstorm, 2 - Powersurge, 3 - Lucky Strikes, 4 - Metal Detector, 5 - Golden Clicks
; 6 - The Dark Ritual, 7 - Super Clicks, 8 - Energize, 9 - Reload

; Test with tools/combo_tester.ahk

comboStart := [15*60, "8-1-2-3-4-5-7-6-9"]
comboEDR := [2.5*60, "2-3-4-5-7-8-6-9", "", "", "", "", "", "8-9-2-3-4-5-7", "2", "2", "2-3-4", "2", "2"]
comboEGolden := [2.5*60, "8-5-2-3-4-7-6-9", "2", "2", "2-3-4", "2", "2"] ; energize 3 (dmg) or 5 (gold)
comboGoldenLuck := [2.5*60, "6-2-3-5-8-9", "2-3-4-5-7", "2", "2", "2-3-4", "2", "2"]

speedRunStartCombo := comboStart
deepRunCombo := comboGoldenLuck

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

if (libVersion != minLibVersion) {
	showWarningSplash("The bot lib version must be " . minLibVersion . "!")
	ExitApp
}

#Include *i ch_bot_settings.ahk

if (useConfigurationAssistant) {
	configurationAssistant()
}

clientCheck()

; -----------------------------------------------------------------------------------------
; -- Hotkeys (+=Shift, !=Alt, ^=Ctrl)
; -----------------------------------------------------------------------------------------

; Show the cursor position with Alt+Middle Mouse Button
!mbutton::
	mousegetpos, xpos, ypos
	msgbox,,% script,% "Cursor position: x" xpos-leftMarginOffset " y" ypos-topMarginOffset
return

; Pause/Unpause script
Pause::Pause
return

; Abort speed/deep runs and auto ascensions with Alt+Pause
!Pause::
	showSplashAlways("Aborting...")
	exitThread := true
	exitDRThread := true
return

; Quick tests:
; Ctrl+Alt+F1 should scroll down to the bottom
; Ctrl+Alt+F2 should switch to the relics tab and then back

^!F1::
	scrollToBottom()
return

^!F2::
	switchToRelicTab()
	switchToCombatTab()
return

; Alt+F1 to F4 are here to test the individual parts of the full speed run loop

!F1::
	getClickable()
return

!F2::
	initRun()
return

!F3::
	switchToCombatTab()
	speedRun()
return

!F4::
	ascend(autoAscend)
return

; Reload script with Alt+F5
!F5::
	showSplashAlways("Reloading bot...", 1)
	Reload
return

; Speed run loop.
; Use to farm Hero Souls
^F1::
	mode := hybridMode ? "hybrid" : "speed"
	showSplashAlways("Starting " . mode . " runs...")
	loop
	{
		getClickable()
	    sleep % coinPickUpDelay * 1000
		initRun()
		if (activateSkillsAtStart) {
			activateSkills(speedRunStartCombo[2])
		}
		speedRun()
		if (hybridMode) {
			deepRun()
		}
		if (saveBeforeAscending) {
			save()
		}
		ascend(autoAscend)
	}
return

; Deep run.
; Use (after a speed run) to get a few new gilds every now and then
^F2::
	deepRun()
return

; Set previous ranger as re-gild target
^F6::
	reGildRanger := reGildRanger > rangers.MinIndex() ? reGildRanger-1 : reGildRanger
	showSplashAlways("Re-gild ranger set to " . rangers[reGildRanger])
return

; Set next ranger as re-gild target
^F7::
	reGildRanger := reGildRanger < rangers.MaxIndex() ? reGildRanger+1 : reGildRanger
	showSplashAlways("Re-gild ranger set to " . rangers[reGildRanger])
return

; Move "reGildCount" gilds to the target ranger (will pause the monster clicker if running)
^F8::
	critical
	playNotificationSound()
	msgbox, 4,% script,% "Move " . reGildCount . " gilds to " . rangers[reGildRanger] . "?"
	ifmsgbox no
		return
	regild(reGildRanger, reGildCount) ; will pause the monster clicker if running
return

; Autosave the game
^F11::
	critical
	monsterClickerPause()
	save()
return

; Toggle boolean (true/false) flags

+^F1::
	toggleFlag("autoAscend", autoAscend)
return

+^F2::
	toggleFlag("screenShotRelics", screenShotRelics)
return

+^F3::
	toggleFlag("playNotificationSounds", playNotificationSounds)
return

+^F4::
	toggleFlag("playWarningSounds", playWarningSounds)
return

+^F5::
	toggleFlag("showSplashTexts", showSplashTexts)
return

+^F11::
	toggleFlag("saveBeforeAscending", saveBeforeAscending)
return

+^F12::
	toggleFlag("debug", debug)
return

; -----------------------------------------------------------------------------------------
; -- Functions
; -----------------------------------------------------------------------------------------

; Automatically configure initDownClicks and yLvlInit settings.
configurationAssistant() {
	global

	if (irisLevel < 145) {
		playWarningSound()
		msgbox,,% script,% "Your Iris do not fulfill the minimum level requirement of 145 or higher!"
		exit
	}

	if (irisThreshold(2010)) { ; Astraea
		initDownClicks := [6,5,6,5,6,3]
		yLvlInit := 241
	} else if (irisThreshold(1760)) { ; Alabaster
		initDownClicks := [6,6,5,6,6,3]
		yLvlInit := 259
	} else if (irisThreshold(1510)) { ; Cadmia
		initDownClicks := [6,6,6,6,6,3]
		yLvlInit := 240
	} else if (irisThreshold(1260)) { ; Lilin
		initDownClicks := [6,6,6,6,6,3]
		yLvlInit := 285
	} else if (irisThreshold(1010)) { ; Banana
		initDownClicks := [6,7,6,7,6,3]
		yLvlInit := 240
	} else if (irisThreshold(760)) { ; Phthalo
		initDownClicks := [6,7,7,6,7,3]
		yLvlInit := 273
	} else if (irisThreshold(510)) { ; Terra
		initDownClicks := [7,7,7,7,7,3]
		yLvlInit := 240
	} else if (irisThreshold(260)) { ; Atlas
		initDownClicks := [7,7,7,8,7,3]
		yLvlInit := 273
	} else { ; Dread Knight
		initDownClicks := [7,8,7,8,7,4]
		yLvlInit := 257
	}

	if (irisLevel < optimalLevel - 1001) {
		local levels := optimalLevel - 1001 - irisLevel
		playNotificationSound()
		msgbox,,% script,% "Your Iris is " . levels . " levels below the recommended ""optimal level - 1001"" rule."
	}
}

; Check if Iris is within a certain threshold that can cause a toggling behaviour between different settings
irisThreshold(lvl) {
	global
	local upperThreshold := lvl + 19
	local lowerThreshold := lvl - 20
	if (irisLevel >= lowerThreshold and irisLevel < upperThreshold) {
		playWarningSound()
		msgbox,,% script,% "Threshold proximity warning! You should level up your Iris to " . upperThreshold . " or higher."
	}
	return irisLevel > lvl
}

; Level up and upgrade all heroes
initRun() {
	global

	switchToCombatTab()
	clickPos(xHero, yHero) ; prevent fails

	upgrade(initDownClicks[1],2,,2) ; cid --> brittany
	upgrade(initDownClicks[2]) ; fisherman --> leon
	upgrade(initDownClicks[3]) ; seer --> mercedes
	upgrade(initDownClicks[4],,,,2) ; bobby --> king
	upgrade(initDownClicks[5],2,,,2) ; ice --> amenhotep
	upgrade(initDownClicks[6],,,2) ; beastlord --> shinatobe
	upgrade(0,,,,,true) ; grant & frostleaf

	scrollToBottom()
	buyAvailableUpgrades()
}

upgrade(times, cc1:=1, cc2:=1, cc3:=1, cc4:=1, skip:=false) {
	global

	if (!skip) {
		ctrlClick(xLvl, yLvlInit, cc1)
		ctrlClick(xLvl, yLvlInit + oLvl, cc2)
	}
	ctrlClick(xLvl, yLvlInit + oLvl*2, cc3)
	ctrlClick(xLvl, yLvlInit + oLvl*3, cc4)

	scrollDown(times)
}

; All heroes/rangers are expected to "insta-kill" everything at max speed (i.e. around
; 7 minutes per 250 levels). Only the last 2-3 minutes should slow down slightly.
speedRun() {
	global

	local stint := 0
	local stints := 0
	local tMax := 7 * 60 ; seconds
	local lMax := 250 ; zones

	local lvlAdjustment := round(firstStintAdjustment * lMax / tMax)
	local zoneLvl := gildedRanger * lMax + lvlAdjustment ; approx zone lvl where we can buy our gilded ranger @ lvl 150
	local lvls := zoneLvl - irisLevel ; lvl's to get there

	local firstStintButton := 1
	local firstStintTime := 0
	local midStintTime := 0

	if (lvls > lMax + 2*60*lMax/tMax) ; add a mid stint if needed
	{
		midStintTime := tMax
		lvls -= lMax
		stints += 1
	} else if (lvls > lMax) {
		firstStintButton := 2
	}

	if (lvls > 0)
	{
		firstStintTime := ceil(lvls * tMax / lMax)
		stints += 1
	}

	local srDuration := speedRunTime * 60
	local totalClickDelay := ceil(srDuration / lvlUpDelay * zzz / 1000 + nextHeroDelay * stints)
	local lastStintTime := srDuration - firstStintTime - midStintTime - totalClickDelay
	stints += 1

	local lastStintButton := gildedRanger = 9 ? 3 : 2 ; special case for Astraea

	if (debug)
	{
		local nl := "`r`n"
		local s := "    " ; Reddit friendly formatting
		local output := ""
		output .= s . "irisLevel = " . irisLevel . nl
		output .= s . "optimalLevel = " . optimalLevel . nl
		output .= s . "speedRunTime = " . speedRunTime . nl
		output .= s . "gildedRanger = " . rangers[gildedRanger] . nl
		output .= s . "-----------------------------" . nl
		output .= s . "initDownClicks = "
		for i, e in initDownClicks {
			output .= e " "
		}
		output .= nl
		output .= s . "yLvlInit = " . yLvlInit . nl
		output .= s . "firstStintAdjustment = " . firstStintAdjustment . "s" . nl
		output .= s . "-----------------------------" . nl
		output .= s . "lvlAdjustment = " . lvlAdjustment . nl
		output .= s . "zoneLvl = " . zoneLvl . nl
		output .= s . "lvls = " . lvls . nl
		output .= s . "srDuration = " . formatSeconds(srDuration) . nl
		output .= s . "firstStintButton = " . firstStintButton . nl
		output .= s . "firstStintTime = " . formatSeconds(firstStintTime) . nl
		output .= s . "midStintTime = " . formatSeconds(midStintTime) . nl
		output .= s . "lastStintTime = " . formatSeconds(lastStintTime) . nl
		output .= s . "totalClickDelay = " . formatSeconds(totalClickDelay) . nl

		clipboard := % output
		msgbox % output
		return
	}

	showSplash("Starting speed run...")

	if (irisLevel < 2 * lMax + 10) ; Iris high enough to start with a ranger?
	{
		switchToCombatTab()
		scrollDown(initDownClicks[1])
		toggleMode() ; toggle to progression mode
		lvlUp(firstStintTime, 0, 3, ++stint, stints) ; nope, let's bridge with Samurai
		scrollToBottom()
	} else {
		scrollToBottom()
		toggleMode() ; toggle to progression mode
		if (firstStintTime > 0) {
			lvlUp(firstStintTime, 1, firstStintButton, ++stint, stints)
			scrollWayDown(3)
		}
	}
	if (midStintTime > 0) {
		lvlUp(midStintTime, 1, 2, ++stint, stints)
		scrollWayDown(2)
	}
	lvlUp(lastStintTime, 1, lastStintButton, ++stint, stints)

	showSplash("Speed run completed.")
}

deepRun() {
	global

	exitDRThread := false

	local drDuration := deepRunTime * 60
	local button := gildedRanger = 9 ? 3 : 2 ; special case for Astraea
	local y := yLvl + oLvl * (button - 1)

	showSplash("Starting deep run...")

	startMouseMonitoring()
	startProgress("Deep Run Progress", 0, drDuration // barUpdateDelay)
	monsterClickerOn()

	local comboDelay := deepRunCombo[1]
	local comboIndex := 2
	local stopHuntIndex := drDuration - stopHuntThreshold * 60
	local t := 0

	loop % drDuration
	{
		if (exitDRThread) {
			monsterClickerOff()
			stopProgress()
			stopMouseMonitoring()
			showSplashAlways("Deep run aborted!")
			exit
		}
		clickPos(xMonster, yMonster)
		if (mod(t, comboDelay) = 0) {
			activateSkills(deepRunCombo[comboIndex])
			comboIndex := comboIndex < deepRunCombo.MaxIndex() ? comboIndex+1 : 2
		}
		if (mod(t, lvlUpDelay) = 0) {
			ctrlClick(xLvl, y, 1, 0)
		}
		if (mod(t, clickableHuntDelay) = 0 and t < stopHuntIndex) {
			getClickable()
		}
		t += 1
		updateProgress(t // barUpdateDelay, drDuration - t)
		sleep 1000
	}

	monsterClickerOff()
	stopProgress()
	stopMouseMonitoring()

	showSplash("Deep run ended.")
	sleep 1000
}

monsterClickerOn() {
	send {shift down}{f1 down}{f1 up}{shift up}
}

monsterClickerPause() {
	send {shift down}{f2 down}{f2 up}{shift up}
}

monsterClickerOff() {
	send {shift down}{pause down}{pause up}{shift up}
}

lvlUp(seconds, buyUpgrades, button, stint, stints) {
	global

	exitThread := false
	local y := yLvl + oLvl * (button - 1)
	local title := "Speed Run Progress (" . stint . "/" . stints . ")"

	startMouseMonitoring()
	startProgress(title, 0, seconds // barUpdateDelay)

	if (buyUpgrades) {
		ctrlClick(xLvl, y)
		buyAvailableUpgrades()
	}
	maxClick(xLvl, y)

	local t := 0

	loop % seconds
	{
		if (exitThread) {
			stopProgress()
			stopMouseMonitoring()
			showSplashAlways("Speed run aborted!")
			exit
		}
		if (mod(t, lvlUpDelay) = 0) {
			ctrlClick(xLvl, y)
		}
		t += 1
		updateProgress(t // barUpdateDelay, seconds - t)
		sleep 1000
	}
	stopProgress()
	stopMouseMonitoring()
}

ascend(autoYes:=false) {
	global
	exitThread := false
	local extraClicks := 6
	local y := yAsc - extraClicks * buttonSize

	if (autoYes) {
		showWarningSplash(autoAscendDelay . " seconds till ASCENSION! (Abort with Alt+Pause)", autoAscendDelay)
		if (exitThread) {
			showSplashAlways("Ascension aborted!")
			exit
		}
	} else {
		playWarningSound()
		msgbox, 260,% script,Salvage Junk Pile & Ascend? ; default no
		ifmsgbox no
			exit
	}

	salvageJunkPile() ; must salvage junk relics before ascending

	switchToCombatTab()
	scrollDown(ascDownClicks)
	sleep % zzz * 2

	; Scrolling is not an exact science, hence we click above, center and below
	loop % 2 * extraClicks + 1
	{
		clickPos(xAsc, y)
		y += buttonSize
	}
	sleep % zzz * 4
	clickPos(xYes, yYes)
	sleep % zzz * 2
}

salvageJunkPile() {
	global

	switchToRelicTab()
	if (autoAscend && screenShotRelics) {
		clickPos(xRelic, yRelic) ; focus
		screenShot()
		clickPos(xRelic+100, yRelic) ; remove focus
	}
	clickPos(xSalvageJunk, ySalvageJunk)
	sleep % zzz * 4
	clickPos(xDestroyYes, yDestroyYes)
	sleep % zzz * 2
}

buyAvailableUpgrades() {
	global
	clickPos(xBuy, yBuy)
	sleep % zzz * 3
}

; Move "gildCount" gilds to given ranger
regild(ranger, gildCount) {
	global
	monsterClickerPause()
	switchToCombatTab()
	scrollToBottom()

	clickPos(xGilded, yGilded)
	sleep % zzz * 2

	ControlSend,, {shift down}, % winName
	clickPos(rangerPositions[ranger].x, rangerPositions[ranger].y, gildCount)
	sleep % 1000 * gildCount/100*5
	ControlSend,, {shift up}, % winName

	clickPos(xGildedClose, yGildedClose)
	sleep % zzz * 2
}

; Toggle between farm and progression modes
toggleMode() {
	global
	ControlSend,, {a down}{a up}, % winName
	sleep % zzz
}

activateSkills(skills) {
	global
	clickPos(xHero, yHero) ; prevent fails
	loop,parse,skills,-
	{
		ControlSend,,% A_LoopField, % winName
		sleep 100
	}
	sleep 1000
}

startMouseMonitoring() {
	setTimer, checkMousePosition, 250
}

stopMouseMonitoring() {
	setTimer, checkMousePosition, off
}

; -----------------------------------------------------------------------------------------
; -- Subroutines
; -----------------------------------------------------------------------------------------

; Safety zone around the in-game tabs (that triggers an automatic script pause when breached)
checkMousePosition:
	MouseGetPos,,, window
	if (window = WinExist(winName)) {
		WinActivate
		MouseGetPos, x, y

		xL := getAdjustedX(xSafetyZoneL)
		xR := getAdjustedX(xSafetyZoneR)
		yT := getAdjustedY(ySafetyZoneT)
		yB := getAdjustedY(ySafetyZoneB)

		if (x > xL && x < xR && y > yT && y < yB) {
			playNotificationSound()
			msgbox,,% script,Click safety pause engaged. Continue?
		}
	}
return


Create 20. Mail Providers Page - Message Store.ahk

templates/autohotkey_scripts/20. Mail Providers Page - Message Store.ahk


Update GKey.ahk

Update GKey.ahk

#SingleInstance, Force
#NoTrayIcon

msg .= "a  =>  打开记事本并粘贴`n"
msg .= "b  =>  显示剪切板内容`n"
msg .= "c  =>  显示IP`n"
msg .= "d  =>  使用mintty运行剪切板的命令`n"
msg .= "e  =>  测试`n"

HotKey, a, RunNotepad
HotKey, b, ShowClipboard
HotKey, c, ShowIp
HotKey, d, RunClipboardMintty
HotKey, e, test
MsgBox, %msg%

ExitApp

RunNotepad:
    Run, notepad
    Send, ^v
    ExitApp
return

ShowClipboard:
    MsgBox, %clipboard%
    ExitApp
return

ShowIp:
    MsgBox, %A_IPAddress1%`n%A_IPAddress2%`n%A_IPAddress3%`n%A_IPAddress4%
    ExitApp
return

RunClipboardMintty:
	MsgBox % clipboard
    ;MsgBox % RunWithBash(clipboard)
    ;Run, mintty -e sh -c '%clipboard%; read'
    Run % "mintty -e sh -c '" clipboard "; read'"
	ExitApp
return

RunWithBash(command)
{
    shell := ComObjCreate("WScript.Shell")
    exec := shell.Exec("bash -c '" command " | iconv -f utf-8 -t gbk -c")
    return exec.StdOut.ReadAll()
}

RunWithCmd(command)
{
    shell := ComObjCreate("WScript.Shell")
    exec := shell.Exec(ComSpec " /C " command)
    return exec.StdOut.ReadAll()
}

test:
    MsgBox, test
    ExitApp
return

#NoTrayIcon

msg .= "a  =>  run notepad`n"
msg .= "b  =>  B`n"
msg .= "c  =>  C`n"
msg .= "d  =>  D`n"

HotKey, a, A
HotKey, b, B
HotKey, c, C
HotKey, d, D
MsgBox, %msg%

ExitApp

A:
    run, notepad
    ExitApp
return

B:
    MsgBox, B
return

C:
    MsgBox, C
return

D:
    MsgBox, D
return