Add tray menu

Add tray menu

#NoEnv
#SingleInstance, Force
#NoTrayIcon

FileEncoding, utf-8
SendMode Input
SetWorkingDir %A_ScriptDir%

; 自动生成的命令文件
global g_SearchFileList := A_ScriptDir . "\SearchFileList.txt"
; 配置文件
global g_ConfFile := A_ScriptDir . "\RunZ.ini"
; 自动写入的配置文件
global g_AutoConfFile := A_ScriptDir . "\RunZ.auto.ini"

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

if (FileExist(g_AutoConfFile ".EasyIni.bak"))
{
    MsgBox, % "发现上次写入配置的备份文件：`n"
        . g_AutoConfFile . ".EasyIni.bak"
        . "`n确定则将其恢复，否则请手动检查文件内容再继续"
    FileMove, % g_AutoConfFile ".EasyIni.bak", % g_AutoConfFile
}
else if (!FileExist(g_AutoConfFile))
{
    FileAppend, % "; 请不要手动修改此文件`n`n[Auto]`n[Rank]`n[History]" , % g_AutoConfFile
}

global g_Conf := class_EasyINI(g_ConfFile)
global g_AutoConf := class_EasyINI(g_AutoConfFile)

; 当前输入命令的参数，数组，为了方便没有添加 g_ 前缀
global Arg
; 不能是 RunZ.ahk 的子串，否则按键绑定会有问题
global g_WindowName := "RunZ "
; 所有命令
global g_Commands
; 当搜索无结果时使用的命令
global g_FallbackCommands
; 编辑框当前内容
global g_CurrentInput
; 当前匹配到的第一条命令
global g_CurrentCommand
; 当前匹配到的所有命令
global g_CurrentCommandList
; 是否启用 TCMatch
global g_EnableTCMatch = TCMatchOn(g_Conf.Config.TCMatchPath)
; 列表第一列的首字母或数字
global g_FirstChar := Asc(g_Conf.Gui.FirstChar)
; 在列表中显示的行数
global g_DisplayRows := g_Conf.Gui.DisplayRows
; 在列表中显示的文字列数（多出的会被截断）
global g_DisplayCols := g_Conf.Gui.DisplayCols
; 命令使用了显示框
global g_UseDisplay
; 历史命令
global g_HistoryCommands
; 运行命令时临时设置，避免因为自身退出无法运行需要提权的软件
global g_DisableAutoExit
; 当前的命令在搜索结果的行数
global g_CurrentLine
; 使用备用的命令
global g_UseFallbackCommands
global g_InputArea := "Edit1"
global g_OutputArea := "Edit3"
global g_CommandArea := "Edit5"

if (g_Conf.Gui.ShowTrayIcon)
{
    Menu, Tray, Icon
    Menu, Tray, NoStandard
    Menu, Tray, Add, 帮助(&H), KeyHelp
    Menu, Tray, Add, 重启(&R), RestartRunZ
    Menu, Tray, Add, 退出(&X), ExitRunZ
}

Menu, Tray, Icon, %A_ScriptDir%\RunZ.ico

if (FileExist(g_SearchFileList))
{
    LoadFiles()
}
else
{
    GoSub, ReloadFiles
}

Gui, Font, % "s" g_Conf.Gui.FontSize, % g_Conf.Gui.FontName
Gui, Add, Edit, % "gProcessInputCommand vSearchArea"
        . " w" g_Conf.Gui.WidgetWidth " h" g_Conf.Gui.EditHeight,
Gui, Add, Edit, w0 h0 ReadOnly,
Gui, Add, Edit, % "ReadOnly vDisplayArea "
        . (g_Conf.Gui.HideDisplayAreaVScroll ? "-VScroll " : "")
        . " w" g_Conf.Gui.WidgetWidth " h" g_Conf.Gui.DisplayAreaHeight
        , % SearchCommand("", true)

if (g_Conf.Gui.ShowCurrentCommand)
{
    Gui, Add, Edit, w0 h0 ReadOnly,
    Gui, Add, Edit, % "ReadOnly"
        . " w" g_Conf.Gui.WidgetWidth " h" g_Conf.Gui.EditHeight,
}

if (g_Conf.Gui.HideTitle)
{
    Gui -Caption
}

Gui, Show, , % g_WindowName

if (g_Conf.Config.WindowAlwaysOnTop)
{
    WinSet, AlwaysOnTop, On, A
}

if (g_Conf.Config.ExitIfInactivate)
{
    OnMessage(0x06, "WM_ACTIVATE")
}

Hotkey, IfWinActive, % g_WindowName
; 如果是 ~enter，有时候会响
Hotkey, enter, RunCurrentCommand

Hotkey, esc, EscFunction
Hotkey, !f4, ExitRunZ

Hotkey, tab, TabFunction
Hotkey, f1, Help
Hotkey, +f1, KeyHelp
Hotkey, f2, EditConfig
Hotkey, ^q, RestartRunZ
Hotkey, ^l, ClearInput
Hotkey, ^d, OpenCurrentFileDir
Hotkey, ^x, DeleteCurrentFile
Hotkey, ^s, ShowCurrentFile
Hotkey, ^r, ReloadFiles
Hotkey, ^h, DisplayHistoryCommands
Hotkey, ^n, IncreaseRank
Hotkey, ^p, DecreaseRank
Hotkey, ^f, NextPage
Hotkey, ^b, PrevPage
Hotkey, ^i, HomeKey
Hotkey, ^o, EndKey
Hotkey, ^j, NextCommand
Hotkey, ^k, PrevCommand
Hotkey, down, NextCommand
Hotkey, up, PrevCommand

; 剩余按键 e g j m t w

Loop, % g_DisplayRows
{
    key := Chr(g_FirstChar + A_Index - 1)
    ; lalt +
    Hotkey, !%key%, RunSelectedCommand
    ; tab +
    Hotkey, ~%key%, RunSelectedCommand
    ; shift +
    Hotkey, ~+%key%, GotoCommand
}

; 用户映射的按键

for key, label in g_Conf.Hotkey
{
    if (label != "Default")
    {
        Hotkey, %key%, %label%
    }
    else
    {
        Hotkey, %key%, Off
    }
}

Hotkey, IfWinActive

for key, label in g_Conf.GlobalHotkey
{
    if (label != "Default")
    {
        Hotkey, %key%, %label%
    }
    else
    {
        Hotkey, %key%, Off
    }
}

if (g_Conf.Config.SaveInputText && g_AutoConf.Auto.InputText != "")
{
    Send, % g_AutoConf.Auto.InputText
}

if (g_Conf.Config.SaveHistory)
{
    g_HistoryCommands := Object()
    LoadHistoryCommands()
}

return

Default:
return

RestartRunZ:
    Reload
return

Test:
    MsgBox Test
return

HomeKey:
    Send, {home}
return

EndKey:
    Send, {End}
return

NextPage:
    ControlFocus, %g_OutputArea%
    Send, {pgdn}
return

PrevPage:
    ControlFocus, %g_OutputArea%
    Send, {pgup}
return

ActivateWindow:
    Gui, Show, , % g_WindowName
return

TabFunction:
    ControlGetFocus, ctrl,
    if (ctrl == g_InputArea)
    {
        ; 定位到一个隐藏编辑框
        ControlFocus, Edit2
    }
    else
    {
        ControlFocus, %g_InputArea%
    }
return

EscFunction:
    ; 如果是后台运行模式，只关闭窗口，不退出程序
    if (g_Conf.Config.RunInBackground)
    {
        Gui, Hide
    }
    else
    {
        GoSub, ExitRunZ
    }
return

NextCommand:
    ChangeCommand(1)
return

PrevCommand:
    ChangeCommand(-1)
return

GotoCommand:
    ControlGetFocus, ctrl,
    if (ctrl == g_InputArea)
    {
        return
    }

    index := Asc(SubStr(A_ThisHotkey, 0, 1)) - g_FirstChar + 1

    if (g_CurrentCommandList[index] != "")
    {
        ChangeCommand(index - 1, true)
    }
return

ChangeCommand(step, resetCurrentLine = false)
{
    ControlGetText, g_CurrentInput, %g_InputArea%

    if (resetCurrentLine || SubStr(g_CurrentInput, 1, 1) != "@")
    {
        g_CurrentLine := 1
    }

    row := g_CurrentCommandList.Length()
    if (row > g_DisplayRows)
    {
        row := g_DisplayRows
    }

    g_CurrentLine := Mod(g_CurrentLine + step, row)
    if (g_CurrentLine == 0)
    {
        g_CurrentLine := row
    }

    ; 重置当前命令
    g_CurrentCommand := g_CurrentCommandList[g_CurrentLine]

    ; 修改输入框内容
    currentChar := Chr(g_FirstChar + g_CurrentLine - 1)
    newInput := "@" currentChar " "

    if (g_UseFallbackCommands)
    {
        if (SubStr(g_CurrentInput, 1, 1) == "@")
        {
            newInput .= SubStr(g_CurrentInput, 4)
        }
        else
        {
            newInput .= g_CurrentInput
        }
    }

    ControlGetText, result, %g_OutputArea%
    result := StrReplace(result, ">| ", " | ")
    if (currentChar == Chr(g_FirstChar))
    {
        result := currentChar ">" SubStr(result, 3)
    }
    else
    {
        result := StrReplace(result, "`n" currentChar " | ", "`n" currentChar ">| ")
    }

    DisplaySearchResult(result)

    ControlSetText, %g_InputArea%, %newInput%
    Send, {end}
}

GuiClose()
{
    if (!g_Conf.Config.RunInBackground)
    {
        GoSub, ExitRunZ
    }
}

ExitRunZ:
    saveConf := false

    if (g_Conf.Config.SaveInputText)
    {
        g_AutoConf.DeleteKey("Auto", "InputText")
        g_AutoConf.AddKey("Auto", "InputText", g_CurrentInput)
        saveConf := true
    }

    if (g_Conf.Config.SaveHistory)
    {
        g_AutoConf.DeleteSection("History")
        g_AutoConf.AddSection("History")

        for index, element in g_HistoryCommands
        {
            if (element != "")
            {
                g_AutoConf.AddKey("History", index, element)
            }
        }

        saveConf := true
    }

    if (g_Conf.Config.AutoRank)
    {
        saveConf := true
    }

    if (saveConf)
    {
        g_AutoConf.Save()

        Loop
        {
            if (!FileExist(g_AutoConfFile))
            {
                MsgBox, 配置文件 %g_AutoConfFile% 写入后丢失，请检查磁盘并点确定来重试
            }
            else
            {
                break
            }
        }

        /*
        应该没有这个问题，备用
        FileGetSize, oldFileSize, %g_AutoConfFile%
        FileCopy, %g_AutoConfFile%, %g_AutoConfFile%.debug
        g_AutoConf.Save()
        ;...
        FileGetSize, newFileSize, %g_AutoConfFile%
        if (oldFileSize - newFileSize >= 50)
        {
            MsgBox, % "配置文件 " g_AutoConfFile
                . "`n减小了 " oldFileSize - newFileSize " 字节"
                . "`n如有疑问请不要退出或重新启动 RunZ，以免配置丢失"
                . "`n配置文件已备份到"
                . "`n" . g_AutoConfFile . ".debug"
        }
        */
    }

    ExitApp
return

GenerateSearchFileList()
{
    FileDelete, %g_SearchFileList%

    searchFileType := g_Conf.Config.SearchFileType

    for dirIndex, dir in StrSplit(g_Conf.Config.SearchFileDir, " | ")
    {
        if (InStr(dir, "A_") == 1)
        {
            searchPath := %dir%
        }
        else
        {
            searchPath := dir
        }

        for extIndex, ext in StrSplit(searchFileType, " | ")
        {
            Loop, Files, %searchPath%\%ext%, R
            {
                if (g_Conf.Config.SearchFileExclude != ""
                        && RegexMatch(A_LoopFileLongPath, g_Conf.Config.SearchFileExclude))
                {
                    continue
                }
                FileAppend, file | %A_LoopFileLongPath%`n, %g_SearchFileList%,
            }
        }
    }
}

ReloadFiles:
    GenerateSearchFileList()

    LoadFiles()
return

ProcessInputCommand:
    ControlGetText, g_CurrentInput, %g_InputArea%

    SearchCommand(g_CurrentInput)
return

SearchCommand(command = "", firstRun = false)
{
    result := ""
    ; 供去重使用
    fullResult := ""
    commandPrefix := SubStr(command, 1, 1)

    if (commandPrefix == ";" || commandPrefix == ":")
    {
        if (commandPrefix == ";")
        {
            g_CurrentCommand := g_FallbackCommands[1]
        }
        else if (commandPrefix == ":")
        {
            g_CurrentCommand := g_FallbackCommands[2]
        }

        g_CurrentCommandList := Object()
        g_CurrentCommandList.Push(g_CurrentCommand)
        result .= Chr(g_FirstChar) ">| " . g_CurrentCommand
        DisplaySearchResult(result)
        return result
    }
    else if (commandPrefix == "@")
    {
        ; 搜索结果被锁定，直接退出
        return
    }
    else if (InStr(command, " ") && g_CurrentCommand != "")
    {
        ; 输入包含空格时锁定搜索结果
        return
    }

    g_CurrentCommandList := Object()

    order := g_FirstChar

    for index, element in g_Commands
    {
        if (InStr(fullResult, element "`n"))
        {
            continue
        }

        splitedElement := StrSplit(element, " | ")

        if (splitedElement[1] == "file")
        {
            SplitPath, % splitedElement[2], , fileDir, , fileNameNoExt

            ; 只搜索和展示不带扩展名的文件名
            elementToSearch := fileNameNoExt
            elementToShow := "file | " . fileNameNoExt

            if (splitedElement.Length() >= 3)
            {
                elementToSearch .= " " . splitedElement[3]
                elementToShow .= "（" . splitedElement[3] . "）"
            }

            elementToShow := SubStr(elementToShow, 1, g_DisplayCols)

            if (g_Conf.Config.SearchFullPath)
            {
                ; TCMatch 在搜索路径时只搜索文件名，强行将 \ 转成空格
                elementToSearch := StrReplace(fileDir, "\", " ") . " " . elementToSearch
            }
        }
        else
        {
            elementToShow := SubStr(element, 1, g_DisplayCols)
            elementToSearch := splitedElement[2]

            if (splitedElement.Length() >= 3)
            {
                elementToSearch .= " " . splitedElement[3]
            }
        }

        if (command == "" || MatchCommand(elementToSearch, command))
        {
            fullResult .= element "`n"
            g_CurrentCommandList.Push(element)

            if (order == g_FirstChar)
            {
                g_CurrentCommand := element
                result .= Chr(order++) . ">| " . elementToShow
            }
            else
            {
                result .= "`n" Chr(order++) . " | " . elementToShow
            }

            if (order - g_FirstChar >= g_DisplayRows)
            {
                break
            }
            ; 第一次运行只加载 function 类型
            if (firstRun && (order - g_FirstChar >= g_DisplayRows - 4))
            {
                result .= "`n`n现有 " g_Commands.Length() " 条命令。"
                result .= "`n`n键入内容 搜索，回车 执行当前命令，Alt + 字母 执行，F1 帮助，Esc 退出。"

                break
            }
        }
    }

    if (result == "")
    {
        g_UseFallbackCommands := true
        g_CurrentCommand := g_FallbackCommands[1]
        g_CurrentCommandList := g_FallbackCommands

        for index, element in g_FallbackCommands
        {
            if (index == 1)
            {
                result .= Chr(g_FirstChar - 1 + index++) . ">| " . element
            }
            else
            {
                result .= "`n"
                result .= Chr(g_FirstChar - 1 + index++) . " | " . element
            }
        }
    }
    else
    {
        g_UseFallbackCommands := false
    }

    result := StrReplace(result, "file | ", "文件 | ")
    result := StrReplace(result, "function | ", "功能 | ")
    result := StrReplace(result, "cmd | ", "命令 | ")

    DisplaySearchResult(result)
    return result
}

DisplaySearchResult(result)
{
    DisplayText(result)

    if (g_CurrentCommandList.Length() == 1 && g_Conf.Config.RunIfOnlyOne)
    {
        RunCommand(g_CurrentCommand)
    }

    if (g_Conf.Gui.ShowCurrentCommand)
    {
        commandToShow := SubStr(g_CurrentCommand, InStr(g_CurrentCommand, " | ") + 3)
        ControlSetText, %g_CommandArea%, %commandToShow%
    }
}

ClearInput:
    ControlSetText, %g_InputArea%,
return

RunCurrentCommand:
    if (GetInputState() == 1)
    {
        Send, {enter}
    }

    if (g_CurrentInput != "")
    {
        RunCommand(g_CurrentCommand)
    }
return

ParseArg:
    commandPrefix := SubStr(g_CurrentInput, 1, 1)

    if (commandPrefix == ";" || commandPrefix == ":")
    {
        Arg := SubStr(g_CurrentInput, 2)
        return
    }
    else if (commandPrefix == "@")
    {
        ; 处理调整过顺序的命令
        Arg := SubStr(g_CurrentInput, 4)
        return
    }

    ; 用空格来判断参数
    if (InStr(g_CurrentInput, " ") && !g_UseFallbackCommands)
    {
        Arg := SubStr(g_CurrentInput, InStr(g_CurrentInput, " ") + 1)
    }
    else
    {
        Arg := g_CurrentInput
    }
return

MatchCommand(Haystack, Needle)
{
    if (g_EnableTCMatch)
    {
        return TCMatch(Haystack, Needle)
    }

    return InStr(Haystack, Needle)
}

RunCommand(originCmd)
{
    GoSub, ParseArg

    g_UseDisplay := false
    g_DisableAutoExit := true

    splitedOriginCmd := StrSplit(originCmd, " | ")
    ; 去掉括号内的注释
    cmd := StrSplit(splitedOriginCmd[2], "（")[1]

    if (splitedOriginCmd[1] == "file")
    {
        if (InStr(cmd, ".lnk"))
        {
            ; 处理 32 位 ahk 运行不了某些 64 位系统 .lnk 的问题
            FileGetShortcut, %cmd%, filePath
            if (!FileExist(filePath))
            {
                filePath := StrReplace(filePath, "C:\Program Files (x86)", "C:\Program Files")
                if (FileExist(filePath))
                {
                    cmd := filePath
                }
            }
        }

        Run, %cmd%
    }
    else if (splitedOriginCmd[1] == "function")
    {
        if (splitedOriginCmd.Length() >= 3)
        {
            Arg := splitedOriginCmd[3]
        }

        if (IsLabel(cmd))
        {
            GoSub, %cmd%
        }
    }
    else if (splitedOriginCmd[1] == "cmd")
    {
        RunWithCmd(cmd)
    }

    if (g_Conf.Config.SaveHistory && cmd != "DisplayHistoryCommands")
    {
        if (splitedOriginCmd.Length() == 2 && Arg != "")
        {
            g_HistoryCommands.InsertAt(1, originCmd " | " Arg)
        }
        else if (originCmd != "")
        {
            g_HistoryCommands.InsertAt(1, originCmd)
        }

        if (g_HistoryCommands.Length() > g_Conf.Config.HistorySize)
        {
            g_HistoryCommands.Pop()
        }
    }

    if (g_Conf.Config.AutoRank)
    {
        IncreaseRank(originCmd)
    }

    g_DisableAutoExit := false

    if (g_Conf.Config.RunOnce && !g_UseDisplay)
    {
        GoSub, EscFunction
    }
}

IncreaseRank(cmd, show = false, inc := 1)
{
    splitedCmd := StrSplit(cmd, " | ")

    if (splitedCmd.Length() >= 3 && splitedCmd[1] == "function")
    {
        ; 去掉参数
        cmd := splitedCmd[1]  " | " splitedCmd[2]
    }

    cmdRank := g_AutoConf.GetValue("Rank", cmd)
    if cmdRank is integer
    {
        g_AutoConf.DeleteKey("Rank", cmd)
        cmdRank += inc
    }
    else
    {
        cmdRank := inc
    }

    if (cmdRank > 0 && cmd != "")
    {
        g_AutoConf.AddKey("Rank", cmd, cmdRank)
    }
    else
    {
        cmdRank := 0
    }

    if (show)
    {
        ToolTip, 调整 %cmd% 的权重到 %cmdRank%
        SetTimer, RemoveToolTip, 800
    }
}

RunSelectedCommand:
    if (SubStr(A_ThisHotkey, 1, 1) == "~")
    {
        ControlGetFocus, ctrl,
        if (ctrl == g_InputArea)
        {
            return
        }
    }

    index := Asc(SubStr(A_ThisHotkey, 0, 1)) - g_FirstChar + 1

    RunCommand(g_CurrentCommandList[index])
return

IncreaseRank:
    if (g_CurrentCommand != "")
    {
        IncreaseRank(g_CurrentCommand, true)
        LoadFiles()
    }
return

DecreaseRank:
    if (g_CurrentCommand != "")
    {
        IncreaseRank(g_CurrentCommand, true, -1)
        LoadFiles()
    }
return

LoadFiles()
{
    g_Commands := Object()
    g_FallbackCommands := Object()

    rankString := ""
    for command, rank in g_AutoConf.Rank
    {
        if (StrLen(command) > 0)
        {
            rankString .= rank "`t" command "`n"
        }
    }

    if (rankString != "")
    {
        Sort, rankString, R N

        Loop, Parse, rankString, `n
        {
            if (A_LoopField == "")
            {
                continue
            }

            g_Commands.Push(StrSplit(A_loopField, "`t")[2])
        }
    }

    for key, value in g_Conf.Command
    {
        if (value != "")
        {
            g_Commands.Push(key . "（" . value "）")
        }
        else
        {
            g_Commands.Push(key)
        }
    }

    if (FileExist(A_ScriptDir "\UserFunctions.ahk"))
    {
        userFunctionLabel := "UserFunctions"
        if (IsLabel(userFunctionLabel))
        {
            GoSub, %userFunctionLabel%
        }
        else
        {
            MsgBox, 未在 %A_ScriptDir%\UserFunctions.ahk 中发现 %userFunctionLabel% 标签，请修改！
        }
    }

    GoSub, Functions

    Loop, Read, %g_SearchFileList%
    {
        g_Commands.Push(A_LoopReadLine)
    }

    if (g_Conf.Config.LoadControlPanelFunctions)
    {
        Loop, Read, %A_ScriptDir%\ControlPanelFunctions.txt
        {
            g_Commands.Push(A_LoopReadLine)
        }
    }
}

DisplayText(text)
{
    textToDisplay := StrReplace(text, "`n", "`r`n")
    ControlSetText, %g_OutputArea%, %textToDisplay%
}

DisplayResult(result)
{
    DisplayText(result)
    g_UseDisplay := true
}

LoadHistoryCommands()
{
    for key, value in g_AutoConf.History
    {
        if (StrLen(value) > 0)
        {
            g_HistoryCommands.Push(value)
        }
    }
}

DisplayHistoryCommands:
    result := ""
    g_CurrentCommandList := Object()
    g_CurrentLine := 1

    for index, element in g_HistoryCommands
    {
        if (index == 1)
        {
            result .= SubStr(Chr(g_FirstChar + index - 1) . ">| " . element, 1, g_DisplayCols) "`n"
            g_CurrentCommand := element
        }
        else
        {
            result .= SubStr(Chr(g_FirstChar + index - 1) . " | " . element, 1, g_DisplayCols) "`n"
        }

        g_CurrentCommandList.Push(element)
    }

    result := StrReplace(result, "file | ", "文件 | ")
    result := StrReplace(result, "function | ", "功能 | ")
    result := StrReplace(result, "cmd | ", "命令 | ")

    DisplayResult(result)
return

@(label, info, fallback = false, key = "")
{
    if (!IsLabel(label))
    {
        MsgBox, 未找到 %label% 标签，请检查 %A_ScriptDir%\UserFunctions.ahk 文件格式！
        return
    }

    g_Commands.Push("function | " . label . "（" . info . "）")
    if (fallback)
    {
        g_FallbackCommands.Push("function | " . label . "（" . info . "）")
    }

    if (key != "")
    {
        Hotkey, %key%, %label%
    }
}

RunAndGetOutput(command)
{
    tempFileName := "RunZ.stdout.log"
    fullCommand = bash -c "%command% &> %tempFileName%"

    if (!FileExist("c:\msys64\usr\bin\bash.exe"))
    {
        fullCommand = %ComSpec% /C "%command% > %tempFileName%"
    }

    RunWait, %fullCommand%, %A_Temp%, Hide
    FileRead, result, %A_Temp%\%tempFileName%
    FileDelete, %A_Temp%\%tempFileName%
    return result
}

RunWithCmd(command)
{
    if (FileExist("c:\msys64\usr\bin\mintty.exe"))
    {
        Run, % "mintty -e sh -c '" command "; read'"
    }
    else
    {
        Run, % ComSpec " /C " command " & pause"
    }
}

OpenPath(filePath)
{
    if (!FileExist(filePath))
    {
        return
    }

    if (FileExist(g_Conf.Config.TCPath))
    {
        TCPath := g_Conf.Config.TCPath
        Run, %TCPath% /O /A /L="%filePath%"
    }
    else
    {
        SplitPath, filePath, , fileDir, ,
        Run, explorer "%fileDir%"
    }
}

GetAllFunctions()
{
    result := ""

    for index, element in g_Commands
    {
        if (InStr(element, "function | ") == 1 and !InStr(result, element "`n"))
        {
            result .= element "`n"
        }
    }

    return result
}

OpenCurrentFileDir:
    filePath := StrSplit(g_CurrentCommand, " | ")[2]
    OpenPath(filePath)
return

DeleteCurrentFile:
    filePath := StrSplit(g_CurrentCommand, " | ")[2]

    if (!FileExist(filePath))
    {
        return
    }

    FileRecycle, % filePath
    GoSub, ReloadFiles
return

ShowCurrentFile:
    clipboard := StrSplit(g_CurrentCommand, " | ")[2]
    ToolTip, % clipboard
    SetTimer, RemoveToolTip, 800
return

RemoveToolTip:
    ToolTip
    SetTimer, RemoveToolTip, Off
return

WM_ACTIVATE(wParam, lParam)
{
    if (g_DisableAutoExit)
    {
        return
    }

    if (wParam >= 1) ; 窗口激活
    {
        return
    }
    else if (wParam <= 0) ; 窗口非激活
    {
        SetTimer, ToExit, 50
    }
}

ToExit:
    if (!WinExist("RunZ.ahk"))
    {
        GoSub, EscFunction
    }

    SetTimer, ToExit, Off
return

KeyHelpText()
{
    return ""
    . "Win + j 显示窗口`n"
    . "键入内容 搜索，回车 执行，Alt + 字母 执行，Esc 退出`n"
    . "按 Tab 后再按 字母或数字 也可执行字母对应功能`n"
    . "按 Tab 后 Shift + 字母或数字 定位到对应功能`n"
    . "Ctrl + j 移动到下一条命令`n"
    . "Ctrl + k 移动到上一条命令`n"
    . "Ctrl + f 翻到下一页`n"
    . "Ctrl + b 翻到上一页`n"
    . "Win  + j 激活窗口`n"
    . "Ctrl + h 显示历史记录`n"
    . "Ctrl + n 可增加当前功能的权重`n"
    . "Ctrl + p 可减少当前功能的权重`n"
    . "Ctrl + l 清除编辑框内容`n"
    . "Ctrl + r 重新创建待搜索文件列表`n"
    . "Ctrl + q 重启`n"
    . "Ctrl + d 用 TC 打开第一个文件所在目录`n"
    . "Ctrl + s 显示并复制当前文件的完整路径`n"
    . "Ctrl + x 删除当前文件`n"
    . "Ctrl + i 移动光标当行首`n"
    . "Ctrl + o 移动光标当行尾`n"
    . "F2       编辑配置文件`n`n"
}

UrlDownloadToString(url)
{
    static whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    whr.Open("GET", url, true)
    whr.Send()
    whr.WaitForResponse()
    return whr.ResponseText
}

; 修改自万年书妖的 Candy 里的 SksSub_UrlEncode 函数，用于转换编码。感谢！
UrlEncode(url, enc = "UTF-8")
{
    enc := trim(enc)
    If enc=
        return url
    formatInteger := A_FormatInteger
    SetFormat, IntegerFast, H
    VarSetCapacity(buff, StrPut(url, enc))
    Loop % StrPut(url, &buff, enc) - 1
    {
        byte := NumGet(buff, A_Index-1, "UChar")
        encoded .= byte > 127 or byte <33 ? "%" Substr(byte, 3) : Chr(byte)
    }
    SetFormat, IntegerFast, %formatInteger%
    return encoded
}

; 0：英文 1：中文
GetInputState(WinTitle = "A")
{
    ControlGet, hwnd, HWND, , , %WinTitle%
    if (A_Cursor = "IBeam")
        return 1
    if (WinActive(WinTitle))
    {
        ptrSize := !A_PtrSize ? 4 : A_PtrSize
        VarSetCapacity(stGTI, cbSize := 4 + 4 + (PtrSize * 6) + 16, 0)
        NumPut(cbSize, stGTI, 0, "UInt")   ;   DWORD   cbSize;
        hwnd := DllCall("GetGUIThreadInfo", Uint, 0, Uint, &stGTI)
                         ? NumGet(stGTI, 8 + PtrSize, "UInt") : hwnd
    }
    return DllCall("SendMessage"
        , UInt, DllCall("imm32\ImmGetDefaultIMEWnd", Uint, hwnd)
        , UInt, 0x0283  ;Message : WM_IME_CONTROL
        , Int, 0x0005  ;wParam  : IMC_GETOPENSTATUS
        , Int, 0)      ;lParam  : 0
}

#include %A_ScriptDir%\Lib\EasyIni.ahk
#include %A_ScriptDir%\Lib\TCMatch.ahk
#include %A_ScriptDir%\Lib\Eval.ahk
#include %A_ScriptDir%\Lib\JSON.ahk
#include %A_ScriptDir%\Lib\Kanji\Kanji.ahk
#include %A_ScriptDir%\Functions.ahk
; 用户自定义命令
#include *i %A_ScriptDir%\UserFunctions.ahk

#NoEnv
#SingleInstance, Force
#NoTrayIcon

FileEncoding, utf-8
SendMode Input
SetWorkingDir %A_ScriptDir%

; 自动生成的命令文件
global g_SearchFileList := A_ScriptDir . "\SearchFileList.txt"
; 配置文件
global g_ConfFile := A_ScriptDir . "\RunZ.ini"
; 自动写入的配置文件
global g_AutoConfFile := A_ScriptDir . "\RunZ.auto.ini"

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

if (FileExist(g_AutoConfFile ".EasyIni.bak"))
{
    MsgBox, % "发现上次写入配置的备份文件：`n"
        . g_AutoConfFile . ".EasyIni.bak"
        . "`n确定则将其恢复，否则请手动检查文件内容再继续"
    FileMove, % g_AutoConfFile ".EasyIni.bak", % g_AutoConfFile
}
else if (!FileExist(g_AutoConfFile))
{
    FileAppend, % "; 请不要手动修改此文件`n`n[Auto]`n[Rank]`n[History]" , % g_AutoConfFile
}

global g_Conf := class_EasyINI(g_ConfFile)
global g_AutoConf := class_EasyINI(g_AutoConfFile)

; 当前输入命令的参数，数组，为了方便没有添加 g_ 前缀
global Arg
; 不能是 RunZ.ahk 的子串，否则按键绑定会有问题
global g_WindowName := "RunZ "
; 所有命令
global g_Commands
; 当搜索无结果时使用的命令
global g_FallbackCommands
; 编辑框当前内容
global g_CurrentInput
; 当前匹配到的第一条命令
global g_CurrentCommand
; 当前匹配到的所有命令
global g_CurrentCommandList
; 是否启用 TCMatch
global g_EnableTCMatch = TCMatchOn(g_Conf.Config.TCMatchPath)
; 列表第一列的首字母或数字
global g_FirstChar := Asc(g_Conf.Gui.FirstChar)
; 在列表中显示的行数
global g_DisplayRows := g_Conf.Gui.DisplayRows
; 在列表中显示的文字列数（多出的会被截断）
global g_DisplayCols := g_Conf.Gui.DisplayCols
; 命令使用了显示框
global g_UseDisplay
; 历史命令
global g_HistoryCommands
; 运行命令时临时设置，避免因为自身退出无法运行需要提权的软件
global g_DisableAutoExit
; 当前的命令在搜索结果的行数
global g_CurrentLine
; 使用备用的命令
global g_UseFallbackCommands
global g_InputArea := "Edit1"
global g_OutputArea := "Edit3"
global g_CommandArea := "Edit5"

if (g_Conf.Gui.ShowTrayIcon)
{
    Menu, Tray, Icon
}

Menu, Tray, Icon, %A_ScriptDir%\RunZ.ico

if (FileExist(g_SearchFileList))
{
    LoadFiles()
}
else
{
    GoSub, ReloadFiles
}

Gui, Font, % "s" g_Conf.Gui.FontSize, % g_Conf.Gui.FontName
Gui, Add, Edit, % "gProcessInputCommand vSearchArea"
        . " w" g_Conf.Gui.WidgetWidth " h" g_Conf.Gui.EditHeight,
Gui, Add, Edit, w0 h0 ReadOnly,
Gui, Add, Edit, % "ReadOnly vDisplayArea "
        . (g_Conf.Gui.HideDisplayAreaVScroll ? "-VScroll " : "")
        . " w" g_Conf.Gui.WidgetWidth " h" g_Conf.Gui.DisplayAreaHeight
        , % SearchCommand("", true)

if (g_Conf.Gui.ShowCurrentCommand)
{
    Gui, Add, Edit, w0 h0 ReadOnly,
    Gui, Add, Edit, % "ReadOnly"
        . " w" g_Conf.Gui.WidgetWidth " h" g_Conf.Gui.EditHeight,
}

if (g_Conf.Gui.HideTitle)
{
    Gui -Caption
}

Gui, Show, , % g_WindowName

if (g_Conf.Config.WindowAlwaysOnTop)
{
    WinSet, AlwaysOnTop, On, A
}

if (g_Conf.Config.ExitIfInactivate)
{
    OnMessage(0x06, "WM_ACTIVATE")
}

Hotkey, IfWinActive, % g_WindowName
; 如果是 ~enter，有时候会响
Hotkey, enter, RunCurrentCommand

Hotkey, esc, EscFunction
Hotkey, !f4, ExitRunZ

Hotkey, tab, TabFunction
Hotkey, f1, Help
Hotkey, +f1, KeyHelp
Hotkey, f2, EditConfig
Hotkey, ^q, RestartRunZ
Hotkey, ^l, ClearInput
Hotkey, ^d, OpenCurrentFileDir
Hotkey, ^x, DeleteCurrentFile
Hotkey, ^s, ShowCurrentFile
Hotkey, ^r, ReloadFiles
Hotkey, ^h, DisplayHistoryCommands
Hotkey, ^n, IncreaseRank
Hotkey, ^p, DecreaseRank
Hotkey, ^f, NextPage
Hotkey, ^b, PrevPage
Hotkey, ^i, HomeKey
Hotkey, ^o, EndKey
Hotkey, ^j, NextCommand
Hotkey, ^k, PrevCommand
Hotkey, down, NextCommand
Hotkey, up, PrevCommand

; 剩余按键 e g j m t w

Loop, % g_DisplayRows
{
    key := Chr(g_FirstChar + A_Index - 1)
    ; lalt +
    Hotkey, !%key%, RunSelectedCommand1
    ; tab +
    Hotkey, ~%key%, RunSelectedCommand2
    ; shift +
    Hotkey, ~+%key%, GotoCommand
}

; 用户映射的按键

for key, label in g_Conf.Hotkey
{
    if (label != "Default")
    {
        Hotkey, %key%, %label%
    }
    else
    {
        Hotkey, %key%, Off
    }
}

Hotkey, IfWinActive

for key, label in g_Conf.GlobalHotkey
{
    if (label != "Default")
    {
        Hotkey, %key%, %label%
    }
    else
    {
        Hotkey, %key%, Off
    }
}

if (g_Conf.Config.SaveInputText && g_AutoConf.Auto.InputText != "")
{
    Send, % g_AutoConf.Auto.InputText
}

if (g_Conf.Config.SaveHistory)
{
    g_HistoryCommands := Object()
    LoadHistoryCommands()
}

return

Default:
return

RestartRunZ:
    Reload
return

Test:
    MsgBox Test
return

HomeKey:
    Send, {home}
return

EndKey:
    Send, {End}
return

NextPage:
    ControlFocus, %g_OutputArea%
    Send, {pgdn}
return

PrevPage:
    ControlFocus, %g_OutputArea%
    Send, {pgup}
return

ActivateWindow:
    Gui, Show, , % g_WindowName
return

TabFunction:
    ControlGetFocus, ctrl,
    if (ctrl == g_InputArea)
    {
        ; 定位到一个隐藏编辑框
        ControlFocus, Edit2
    }
    else
    {
        ControlFocus, %g_InputArea%
    }
return

EscFunction:
    ; 如果是后台运行模式，只关闭窗口，不退出程序
    if (g_Conf.Config.RunInBackground)
    {
        Gui, Hide
    }
    else
    {
        GoSub, ExitRunZ
    }
return

NextCommand:
    ChangeCommand(1)
return

PrevCommand:
    ChangeCommand(-1)
return

GotoCommand:
    ControlGetFocus, ctrl,
    if (ctrl == g_InputArea)
    {
        return
    }

    index := Asc(SubStr(A_ThisHotkey, 0, 1)) - g_FirstChar + 1

    if (g_CurrentCommandList[index] != "")
    {
        ChangeCommand(index - 1, true)
    }
return

ChangeCommand(step, resetCurrentLine = false)
{
    ControlGetText, g_CurrentInput, %g_InputArea%

    if (resetCurrentLine || SubStr(g_CurrentInput, 1, 1) != "@")
    {
        g_CurrentLine := 1
    }

    row := g_CurrentCommandList.Length()
    if (row > g_DisplayRows)
    {
        row := g_DisplayRows
    }

    g_CurrentLine := Mod(g_CurrentLine + step, row)
    if (g_CurrentLine == 0)
    {
        g_CurrentLine := row
    }

    ; 重置当前命令
    g_CurrentCommand := g_CurrentCommandList[g_CurrentLine]

    ; 修改输入框内容
    currentChar := Chr(g_FirstChar + g_CurrentLine - 1)
    newInput := "@" currentChar " "

    if (g_UseFallbackCommands)
    {
        if (SubStr(g_CurrentInput, 1, 1) == "@")
        {
            newInput .= SubStr(g_CurrentInput, 4)
        }
        else
        {
            newInput .= g_CurrentInput
        }
    }

    ControlGetText, result, %g_OutputArea%
    result := StrReplace(result, ">| ", " | ")
    if (currentChar == Chr(g_FirstChar))
    {
        result := currentChar ">" SubStr(result, 3)
    }
    else
    {
        result := StrReplace(result, "`n" currentChar " | ", "`n" currentChar ">| ")
    }

    DisplaySearchResult(result)

    ControlSetText, %g_InputArea%, %newInput%
    Send, {end}
}

GuiClose()
{
    if (!g_Conf.Config.RunInBackground)
    {
        GoSub, ExitRunZ
    }
}

ExitRunZ:
    saveConf := false

    if (g_Conf.Config.SaveInputText)
    {
        g_AutoConf.DeleteKey("Auto", "InputText")
        g_AutoConf.AddKey("Auto", "InputText", g_CurrentInput)
        saveConf := true
    }

    if (g_Conf.Config.SaveHistory)
    {
        g_AutoConf.DeleteSection("History")
        g_AutoConf.AddSection("History")

        for index, element in g_HistoryCommands
        {
            if (element != "")
            {
                g_AutoConf.AddKey("History", index, element)
            }
        }

        saveConf := true
    }

    if (g_Conf.Config.AutoRank)
    {
        saveConf := true
    }

    if (saveConf)
    {
        g_AutoConf.Save()

        Loop
        {
            if (!FileExist(g_AutoConfFile))
            {
                MsgBox, 配置文件 %g_AutoConfFile% 写入后丢失，请检查磁盘并点确定来重试
            }
            else
            {
                break
            }
        }

        /*
        应该没有这个问题，备用
        FileGetSize, oldFileSize, %g_AutoConfFile%
        FileCopy, %g_AutoConfFile%, %g_AutoConfFile%.debug
        g_AutoConf.Save()
        ;...
        FileGetSize, newFileSize, %g_AutoConfFile%
        if (oldFileSize - newFileSize >= 50)
        {
            MsgBox, % "配置文件 " g_AutoConfFile
                . "`n减小了 " oldFileSize - newFileSize " 字节"
                . "`n如有疑问请不要退出或重新启动 RunZ，以免配置丢失"
                . "`n配置文件已备份到"
                . "`n" . g_AutoConfFile . ".debug"
        }
        */
    }

    ExitApp
return

GenerateSearchFileList()
{
    FileDelete, %g_SearchFileList%

    searchFileType := g_Conf.Config.SearchFileType

    for dirIndex, dir in StrSplit(g_Conf.Config.SearchFileDir, " | ")
    {
        if (InStr(dir, "A_") == 1)
        {
            searchPath := %dir%
        }
        else
        {
            searchPath := dir
        }

        for extIndex, ext in StrSplit(searchFileType, " | ")
        {
            Loop, Files, %searchPath%\%ext%, R
            {
                if (g_Conf.Config.SearchFileExclude != ""
                        && RegexMatch(A_LoopFileLongPath, g_Conf.Config.SearchFileExclude))
                {
                    continue
                }
                FileAppend, file | %A_LoopFileLongPath%`n, %g_SearchFileList%,
            }
        }
    }
}

ReloadFiles:
    GenerateSearchFileList()

    LoadFiles()
return

ProcessInputCommand:
    ControlGetText, g_CurrentInput, %g_InputArea%

    SearchCommand(g_CurrentInput)
return

SearchCommand(command = "", firstRun = false)
{
    result := ""
    ; 供去重使用
    fullResult := ""
    commandPrefix := SubStr(command, 1, 1)

    if (commandPrefix == ";" || commandPrefix == ":")
    {
        if (commandPrefix == ";")
        {
            g_CurrentCommand := g_FallbackCommands[1]
        }
        else if (commandPrefix == ":")
        {
            g_CurrentCommand := g_FallbackCommands[2]
        }

        g_CurrentCommandList := Object()
        g_CurrentCommandList.Push(g_CurrentCommand)
        result .= Chr(g_FirstChar) ">| " . g_CurrentCommand
        DisplaySearchResult(result)
        return result
    }
    else if (commandPrefix == "@")
    {
        ; 搜索结果被锁定，直接退出
        return
    }
    else if (InStr(command, " ") && g_CurrentCommand != "")
    {
        ; 输入包含空格时锁定搜索结果
        return
    }

    g_CurrentCommandList := Object()

    order := g_FirstChar

    for index, element in g_Commands
    {
        if (InStr(fullResult, element "`n"))
        {
            continue
        }

        splitedElement := StrSplit(element, " | ")

        if (splitedElement[1] == "file")
        {
            SplitPath, % splitedElement[2], , fileDir, , fileNameNoExt

            ; 只搜索和展示不带扩展名的文件名
            elementToSearch := fileNameNoExt
            elementToShow := "file | " . fileNameNoExt

            if (splitedElement.Length() >= 3)
            {
                elementToSearch .= " " . splitedElement[3]
                elementToShow .= "（" . splitedElement[3] . "）"
            }

            elementToShow := SubStr(elementToShow, 1, g_DisplayCols)

            if (g_Conf.Config.SearchFullPath)
            {
                ; TCMatch 在搜索路径时只搜索文件名，强行将 \ 转成空格
                elementToSearch := StrReplace(fileDir, "\", " ") . " " . elementToSearch
            }
        }
        else
        {
            elementToShow := SubStr(element, 1, g_DisplayCols)
            elementToSearch := splitedElement[2]

            if (splitedElement.Length() >= 3)
            {
                elementToSearch .= " " . splitedElement[3]
            }
        }

        if (command == "" || MatchCommand(elementToSearch, command))
        {
            fullResult .= element "`n"
            g_CurrentCommandList.Push(element)

            if (order == g_FirstChar)
            {
                g_CurrentCommand := element
                result .= Chr(order++) . ">| " . elementToShow
            }
            else
            {
                result .= "`n" Chr(order++) . " | " . elementToShow
            }

            if (order - g_FirstChar >= g_DisplayRows)
            {
                break
            }
            ; 第一次运行只加载 function 类型
            if (firstRun && (order - g_FirstChar >= g_DisplayRows - 4))
            {
                result .= "`n`n现有 " g_Commands.Length() " 条命令。"
                result .= "`n`n键入内容 搜索，回车 执行当前命令，Alt + 字母 执行，F1 帮助，Esc 退出。"

                break
            }
        }
    }

    if (result == "")
    {
        g_UseFallbackCommands := true
        g_CurrentCommand := g_FallbackCommands[1]
        g_CurrentCommandList := g_FallbackCommands

        for index, element in g_FallbackCommands
        {
            if (index == 1)
            {
                result .= Chr(g_FirstChar - 1 + index++) . ">| " . element
            }
            else
            {
                result .= "`n"
                result .= Chr(g_FirstChar - 1 + index++) . " | " . element
            }
        }
    }
    else
    {
        g_UseFallbackCommands := false
    }

    result := StrReplace(result, "file | ", "文件 | ")
    result := StrReplace(result, "function | ", "功能 | ")
    result := StrReplace(result, "cmd | ", "命令 | ")

    DisplaySearchResult(result)
    return result
}

DisplaySearchResult(result)
{
    DisplayText(result)

    if (g_CurrentCommandList.Length() == 1 && g_Conf.Config.RunIfOnlyOne)
    {
        RunCommand(g_CurrentCommand)
    }

    if (g_Conf.Gui.ShowCurrentCommand)
    {
        commandToShow := SubStr(g_CurrentCommand, InStr(g_CurrentCommand, " | ") + 3)
        ControlSetText, %g_CommandArea%, %commandToShow%
    }
}

ClearInput:
    ControlSetText, %g_InputArea%,
return

RunCurrentCommand:
    if (GetInputState() == 1)
    {
        Send, {enter}
    }

    if (g_CurrentInput != "")
    {
        RunCommand(g_CurrentCommand)
    }
return

ParseArg:
    commandPrefix := SubStr(g_CurrentInput, 1, 1)

    if (commandPrefix == ";" || commandPrefix == ":")
    {
        Arg := SubStr(g_CurrentInput, 2)
        return
    }
    else if (commandPrefix == "@")
    {
        ; 处理调整过顺序的命令
        Arg := SubStr(g_CurrentInput, 4)
        return
    }

    ; 用空格来判断参数
    if (InStr(g_CurrentInput, " ") && !g_UseFallbackCommands)
    {
        Arg := SubStr(g_CurrentInput, InStr(g_CurrentInput, " ") + 1)
    }
    else
    {
        Arg := g_CurrentInput
    }
return

MatchCommand(Haystack, Needle)
{
    if (g_EnableTCMatch)
    {
        return TCMatch(Haystack, Needle)
    }

    return InStr(Haystack, Needle)
}

RunCommand(originCmd)
{
    GoSub, ParseArg

    g_UseDisplay := false
    g_DisableAutoExit := true

    splitedOriginCmd := StrSplit(originCmd, " | ")
    ; 去掉括号内的注释
    cmd := StrSplit(splitedOriginCmd[2], "（")[1]

    if (splitedOriginCmd[1] == "file")
    {
        if (InStr(cmd, ".lnk"))
        {
            ; 处理 32 位 ahk 运行不了某些 64 位系统 .lnk 的问题
            FileGetShortcut, %cmd%, filePath
            if (!FileExist(filePath))
            {
                filePath := StrReplace(filePath, "C:\Program Files (x86)", "C:\Program Files")
                if (FileExist(filePath))
                {
                    cmd := filePath
                }
            }
        }

        Run, %cmd%
    }
    else if (splitedOriginCmd[1] == "function")
    {
        if (splitedOriginCmd.Length() >= 3)
        {
            Arg := splitedOriginCmd[3]
        }

        if (IsLabel(cmd))
        {
            GoSub, %cmd%
        }
    }
    else if (splitedOriginCmd[1] == "cmd")
    {
        RunWithCmd(cmd)
    }

    if (g_Conf.Config.SaveHistory && cmd != "DisplayHistoryCommands")
    {
        if (splitedOriginCmd.Length() == 2 && Arg != "")
        {
            g_HistoryCommands.InsertAt(1, originCmd " | " Arg)
        }
        else if (originCmd != "")
        {
            g_HistoryCommands.InsertAt(1, originCmd)
        }

        if (g_HistoryCommands.Length() > g_Conf.Config.HistorySize)
        {
            g_HistoryCommands.Pop()
        }
    }

    if (g_Conf.Config.AutoRank)
    {
        IncreaseRank(originCmd)
    }

    g_DisableAutoExit := false

    if (g_Conf.Config.RunOnce && !g_UseDisplay)
    {
        GoSub, EscFunction
    }
}

IncreaseRank(cmd, show = false, inc := 1)
{
    splitedCmd := StrSplit(cmd, " | ")

    if (splitedCmd.Length() >= 3 && splitedCmd[1] == "function")
    {
        ; 去掉参数
        cmd := splitedCmd[1]  " | " splitedCmd[2]
    }

    cmdRank := g_AutoConf.GetValue("Rank", cmd)
    if cmdRank is integer
    {
        g_AutoConf.DeleteKey("Rank", cmd)
        cmdRank += inc
    }
    else
    {
        cmdRank := inc
    }

    if (cmdRank > 0 && cmd != "")
    {
        g_AutoConf.AddKey("Rank", cmd, cmdRank)
    }
    else
    {
        cmdRank := 0
    }

    if (show)
    {
        ToolTip, 调整 %cmd% 的权重到 %cmdRank%
        SetTimer, RemoveToolTip, 800
    }
}

RunSelectedCommand1:
    index := Asc(SubStr(A_ThisHotkey, 0, 1)) - g_FirstChar + 1

    RunCommand(g_CurrentCommandList[index])
return

RunSelectedCommand2:
    ControlGetFocus, ctrl,
    if (ctrl == g_InputArea)
    {
        return
    }

    index := Asc(A_ThisHotkey) - g_FirstChar + 1

    RunCommand(g_CurrentCommandList[index])
return

IncreaseRank:
    if (g_CurrentCommand != "")
    {
        IncreaseRank(g_CurrentCommand, true)
        LoadFiles()
    }
return

DecreaseRank:
    if (g_CurrentCommand != "")
    {
        IncreaseRank(g_CurrentCommand, true, -1)
        LoadFiles()
    }
return

LoadFiles()
{
    g_Commands := Object()
    g_FallbackCommands := Object()

    rankString := ""
    for command, rank in g_AutoConf.Rank
    {
        if (StrLen(command) > 0)
        {
            rankString .= rank "`t" command "`n"
        }
    }

    if (rankString != "")
    {
        Sort, rankString, R N

        Loop, Parse, rankString, `n
        {
            if (A_LoopField == "")
            {
                continue
            }

            g_Commands.Push(StrSplit(A_loopField, "`t")[2])
        }
    }

    for key, value in g_Conf.Command
    {
        if (value != "")
        {
            g_Commands.Push(key . "（" . value "）")
        }
        else
        {
            g_Commands.Push(key)
        }
    }

    if (FileExist(A_ScriptDir "\UserFunctions.ahk"))
    {
        userFunctionLabel := "UserFunctions"
        if (IsLabel(userFunctionLabel))
        {
            GoSub, %userFunctionLabel%
        }
        else
        {
            MsgBox, 未在 %A_ScriptDir%\UserFunctions.ahk 中发现 %userFunctionLabel% 标签，请修改！
        }
    }

    GoSub, Functions

    Loop, Read, %g_SearchFileList%
    {
        g_Commands.Push(A_LoopReadLine)
    }

    if (g_Conf.Config.LoadControlPanelFunctions)
    {
        Loop, Read, %A_ScriptDir%\ControlPanelFunctions.txt
        {
            g_Commands.Push(A_LoopReadLine)
        }
    }
}

DisplayText(text)
{
    textToDisplay := StrReplace(text, "`n", "`r`n")
    ControlSetText, %g_OutputArea%, %textToDisplay%
}

DisplayResult(result)
{
    DisplayText(result)
    g_UseDisplay := true
}

LoadHistoryCommands()
{
    for key, value in g_AutoConf.History
    {
        if (StrLen(value) > 0)
        {
            g_HistoryCommands.Push(value)
        }
    }
}

DisplayHistoryCommands:
    result := ""
    g_CurrentCommandList := Object()
    g_CurrentLine := 1

    for index, element in g_HistoryCommands
    {
        if (index == 1)
        {
            result .= SubStr(Chr(g_FirstChar + index - 1) . ">| " . element, 1, g_DisplayCols) "`n"
            g_CurrentCommand := element
        }
        else
        {
            result .= SubStr(Chr(g_FirstChar + index - 1) . " | " . element, 1, g_DisplayCols) "`n"
        }

        g_CurrentCommandList.Push(element)
    }

    result := StrReplace(result, "file | ", "文件 | ")
    result := StrReplace(result, "function | ", "功能 | ")
    result := StrReplace(result, "cmd | ", "命令 | ")

    DisplayResult(result)
return

@(label, info, fallback = false, key = "")
{
    if (!IsLabel(label))
    {
        MsgBox, 未找到 %label% 标签，请检查 %A_ScriptDir%\UserFunctions.ahk 文件格式！
        return
    }

    g_Commands.Push("function | " . label . "（" . info . "）")
    if (fallback)
    {
        g_FallbackCommands.Push("function | " . label . "（" . info . "）")
    }

    if (key != "")
    {
        Hotkey, %key%, %label%
    }
}

RunAndGetOutput(command)
{
    tempFileName := "RunZ.stdout.log"
    fullCommand = bash -c "%command% &> %tempFileName%"

    if (!FileExist("c:\msys64\usr\bin\bash.exe"))
    {
        fullCommand = %ComSpec% /C "%command% > %tempFileName%"
    }

    RunWait, %fullCommand%, %A_Temp%, Hide
    FileRead, result, %A_Temp%\%tempFileName%
    FileDelete, %A_Temp%\%tempFileName%
    return result
}

RunWithCmd(command)
{
    if (FileExist("c:\msys64\usr\bin\mintty.exe"))
    {
        Run, % "mintty -e sh -c '" command "; read'"
    }
    else
    {
        Run, % ComSpec " /C " command " & pause"
    }
}

OpenPath(filePath)
{
    if (!FileExist(filePath))
    {
        return
    }

    if (FileExist(g_Conf.Config.TCPath))
    {
        TCPath := g_Conf.Config.TCPath
        Run, %TCPath% /O /A /L="%filePath%"
    }
    else
    {
        SplitPath, filePath, , fileDir, ,
        Run, explorer "%fileDir%"
    }
}

GetAllFunctions()
{
    result := ""

    for index, element in g_Commands
    {
        if (InStr(element, "function | ") == 1 and !InStr(result, element "`n"))
        {
            result .= element "`n"
        }
    }

    return result
}

OpenCurrentFileDir:
    filePath := StrSplit(g_CurrentCommand, " | ")[2]
    OpenPath(filePath)
return

DeleteCurrentFile:
    filePath := StrSplit(g_CurrentCommand, " | ")[2]

    if (!FileExist(filePath))
    {
        return
    }

    FileRecycle, % filePath
    GoSub, ReloadFiles
return

ShowCurrentFile:
    clipboard := StrSplit(g_CurrentCommand, " | ")[2]
    ToolTip, % clipboard
    SetTimer, RemoveToolTip, 800
return

RemoveToolTip:
    ToolTip
    SetTimer, RemoveToolTip, Off
return

WM_ACTIVATE(wParam, lParam)
{
    if (g_DisableAutoExit)
    {
        return
    }

    if (wParam >= 1) ; 窗口激活
    {
        return
    }
    else if (wParam <= 0) ; 窗口非激活
    {
        SetTimer, ToExit, 50
    }
}

ToExit:
    if (!WinExist("RunZ.ahk"))
    {
        GoSub, EscFunction
    }

    SetTimer, ToExit, Off
return

KeyHelpText()
{
    return ""
    . "键入内容 搜索，回车 执行，Alt + 字母 执行，Esc 退出`n"
    . "按 Tab 后再按 字母或数字 也可执行字母对应功能`n"
    . "按 Tab 后 Shift + 字母或数字 定位到对应功能`n"
    . "Ctrl + j 移动到下一条命令`n"
    . "Ctrl + k 移动到上一条命令`n"
    . "Ctrl + f 翻到下一页`n"
    . "Ctrl + b 翻到上一页`n"
    . "Win  + j 激活窗口`n"
    . "Ctrl + h 显示历史记录`n"
    . "Ctrl + n 可增加当前功能的权重`n"
    . "Ctrl + p 可减少当前功能的权重`n"
    . "Ctrl + l 清除编辑框内容`n"
    . "Ctrl + r 重新创建待搜索文件列表`n"
    . "Ctrl + q 重启`n"
    . "Ctrl + d 用 TC 打开第一个文件所在目录`n"
    . "Ctrl + s 显示并复制当前文件的完整路径`n"
    . "Ctrl + x 删除当前文件`n"
    . "Ctrl + i 移动光标当行首`n"
    . "Ctrl + o 移动光标当行尾`n"
    . "F2       编辑配置文件`n`n"
}

UrlDownloadToString(url)
{
    static whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    whr.Open("GET", url, true)
    whr.Send()
    whr.WaitForResponse()
    return whr.ResponseText
}

; 修改自万年书妖的 Candy 里的 SksSub_UrlEncode 函数，用于转换编码。感谢！
UrlEncode(url, enc = "UTF-8")
{
    enc := trim(enc)
    If enc=
        return url
    formatInteger := A_FormatInteger
    SetFormat, IntegerFast, H
    VarSetCapacity(buff, StrPut(url, enc))
    Loop % StrPut(url, &buff, enc) - 1
    {
        byte := NumGet(buff, A_Index-1, "UChar")
        encoded .= byte > 127 or byte <33 ? "%" Substr(byte, 3) : Chr(byte)
    }
    SetFormat, IntegerFast, %formatInteger%
    return encoded
}

; 0：英文 1：中文
GetInputState(WinTitle = "A")
{
    ControlGet, hwnd, HWND, , , %WinTitle%
    if (A_Cursor = "IBeam")
        return 1
    if (WinActive(WinTitle))
    {
        ptrSize := !A_PtrSize ? 4 : A_PtrSize
        VarSetCapacity(stGTI, cbSize := 4 + 4 + (PtrSize * 6) + 16, 0)
        NumPut(cbSize, stGTI, 0, "UInt")   ;   DWORD   cbSize;
        hwnd := DllCall("GetGUIThreadInfo", Uint, 0, Uint, &stGTI)
                         ? NumGet(stGTI, 8 + PtrSize, "UInt") : hwnd
    }
    return DllCall("SendMessage"
        , UInt, DllCall("imm32\ImmGetDefaultIMEWnd", Uint, hwnd)
        , UInt, 0x0283  ;Message : WM_IME_CONTROL
        , Int, 0x0005  ;wParam  : IMC_GETOPENSTATUS
        , Int, 0)      ;lParam  : 0
}

#include %A_ScriptDir%\Lib\EasyIni.ahk
#include %A_ScriptDir%\Lib\TCMatch.ahk
#include %A_ScriptDir%\Lib\Eval.ahk
#include %A_ScriptDir%\Lib\JSON.ahk
#include %A_ScriptDir%\Lib\Kanji\Kanji.ahk
#include %A_ScriptDir%\Functions.ahk
; 用户自定义命令
#include *i %A_ScriptDir%\UserFunctions.ahk


complete code cleaning and optimization

complete code cleaning and optimization

; ===================================================================================
; AHK Version .........: 1.1.24.01
; Version .............: 1.04 (AHK)
; Release Date ........: 2016-09-23
; GitHub ..............: https://github.com/chao-samu/demo-file-renamer
; Author ..............: chao-samu
;------------------------------------------------------------------------------------
; Script Name..........: demo file renamer
; Description .........: Integrate mapname into demofile (*.dem).
;                        Support: TF2, CS 1.6, CS:S and CS:GO
; License..............: MIT License (https://github.com/chao-samu/demo-file-renamer/blob/master/LICENSE)
; ===================================================================================

#NoEnv
#NoTrayIcon
SendMode Input
SetWorkingDir %A_ScriptDir%

;############################### Programm Info ###############################
PrgName := "demo file renamer"
PrgVersion := "1.04 (AHK)"

;############################### OS Detections ###############################
If (A_PtrSize = 4)
{
	BitVersion := "x86"
}
else
{
	BitVersion := "x64"
}

;############################### Functions ###############################
ParsingDemofiles(RenamingMaskNumber, counter_files_quotient)
{
	Loop, Files, *.dem
	{
		counter_prog := counter_files_quotient * A_Index
		GuiControl,, ProgressBar, %counter_prog%
		mapstring := ""
		File := FileOpen(A_LoopFileName, "r")
		while !File.AtEOF
		{
			demofile := File.ReadLine()
			RegExMatch(demofile, "maps[\/\\].+\.bsp", mapstring)
		If mapstring
		{
			File.Close()
			mapstring_formated := Format("{1:s}", mapstring)
			continue
		}
		}
		If (InStr(mapstring_formated, "maps") and InStr(mapstring_formated, "bsp"))
		{
		RegExMatch(mapstring_formated, "(?<=maps[\/\\]).+(?=\.bsp)", Mapname)
		Mapname := Format("{1:s}", Mapname)
			If (InStr(Mapname, "/") or InStr(Mapname, "\"))
			{
				Mapname := RegExReplace(Mapname, ".+[\/\\]", "")
			}
			SplitPath, A_LoopFileName,,,, FileNameNoExt
			If (RenamingMaskNumber = 3) or (RenamingMaskNumber = 4)
			{
				FormatTime, mod_date, %A_LoopFileTimeModified%, yyyy-MM-dd
			}
			RenamingMask := []
			RenamingMask[1] := filelist . A_LoopFileName . "`t" . FileNameNoExt . "_" . Mapname . "." . A_LoopFileExt . "`n"
			RenamingMask[2] := filelist . A_LoopFileName . "`t" . Mapname . "_" . FileNameNoExt . "." . A_LoopFileExt . "`n"
			RenamingMask[3] := filelist . A_LoopFileName . "`t" . mod_date . "_" . Mapname . "_" . FileNameNoExt . "." . A_LoopFileExt . "`n"
			RenamingMask[4] := filelist . A_LoopFileName . "`t" . mod_date . "_" . FileNameNoExt . "_" . Mapname . "." . A_LoopFileExt . "`n"
			filelist := RenamingMask[RenamingMaskNumber]
		}
		else
		{
			filelist_failed := filelist_failed . A_LoopFileName . "`n"
			counter_failed += 1
		}
	}
	return [filelist, filelist_failed, counter_failed]
}

;############################### GUI ###############################
Menu, helpmenu, Add, Help , MenuHelp
Menu, helpmenu, Add
Menu, helpmenu, Add, About, MenuAbout
Menu, topmenu, Add, &Help, :helpmenu
Gui, Menu, topmenu

Gui, Add, Button, x12 y180 w90 h20 , Cancel
Gui, Add, Button, x212 y180 w90 h20 , Start
Gui, Add, Text, x12 y120 w290 h20 vtext_prog, Extracting mapname
Gui, Add, ListBox, x12 y30 w290 h30 vRenamingMaskNumber AltSubmit gpressListBox, OLDNAME_MAPNAME||MAPNAME_OLDNAME|YYYY-MM-DD_MAPNAME_OLDNAME|YYYY-MM-DD_OLDNAME_MAPNAME
Gui, Add, Text, x12 y10 w290 h20 , Choose renaming mask
Gui, Add, Text, x12 y70 w290 h40 vtext_example, Example: `n"samurai-vs-ninja.dem" will be renamed to "samurai-vs-ninja_de_dust2.dem"

Gui, Add, Progress, x12 y140 w290 h10 Backgroundsilver vProgressBar
; Generated using SmartGUI Creator for SciTE
Gui, Show, w323 h221, %PrgName%
return

MenuHelp:
Gui, Help:+owner1
Gui +Disabled
Gui, Help:Add, Text,,
((
What can do this Tool?
This tool was manly made to extract out the mapname of
GoldSrc- and Source Engine demofiles and place it in the name of the demofile itself.

Which kind of demofiles this tool can handle?
Currently this tool support Counter-Strike 1.6, Counter-Strike Source,
Counter-Strike Global Office and Team Fortress 2 demofiles.

How to use?
1. Select your renaming mask you want
2. Press start and select in the following window your folder with the supported demofiles
    (please note, all demofiles with the ending "dem" in this folder will be renamed, subfolder
    are not included).
    In a protected folder (like "ProgramFiles") you have to start this program in admin mode!
3. Press OK and wait until you will hopefully be happy :)
)
Gui, Help:Add, Button, Default, OK
Gui, Help:Show, w450 h240, Help
return

MenuAbout:
Gui, About:+owner1
Gui +Disabled
Gui, About:Add, Link,, %PrgName% - Version %PrgVersion% `n`nTool compiled with: AHK %A_AhkVersion% %BitVersion% `n`nLook for updates:`n<a href="https://github.com/chao-samu">https://github.com/chao-samu</a>`n`nMade by chao-samu
Gui, About:Add, Text, r9 vMeinEdit,
(

:::::::::::::::::::::::::::::::::::::::::This software is provided under the following License:::::::::::::::::::::::::::::::::::::::::
---------------------------------------------------------------------------------------------------------------------------------------------------------------------

The MIT License (MIT)

Copyright (c) 2015 chao-samu

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
)
Gui, About:Add, Button, Default, OK
Gui, About:Show, w540 h490, About
return

HelpButtonOK:
HelpGuiClose:
HelpGuiEscape:
AboutButtonOK:
AboutGuiClose:
AboutGuiEscape:
Gui, 1:-Disabled
Gui Destroy
return

pressListBox:
	Gui, Submit, NoHide
	if (RenamingMaskNumber = 1)
	GuiControl,, text_example, Example: `n"samurai-vs-ninja.dem" will be renamed to "samurai-vs-ninja_de_dust2.dem"
	else if (RenamingMaskNumber = 2)
	GuiControl,, text_example, Example: `n"samurai-vs-ninja.dem" will be renamed to "de_dust2_samurai-vs-ninja.dem"
	else if (RenamingMaskNumber = 3)
	GuiControl,, text_example, Example: `n"samurai-vs-ninja.dem" will be renamed to "2007-05-03_de_dust2_samurai-vs-ninja.dem"
	else
	GuiControl,, text_example, Example: `n"samurai-vs-ninja.dem" will be renamed to "2007-05-03_samurai-vs-ninja_de_dust2.dem"
return

;############################### MAIN Programm ###############################
ButtonStart:
FormatTime, current_time
ParsingDemofiles.Delete(1, 3)
folder_demofiles := ""
filelist := ""
filelist_failed := ""
counter_files := ""
counter_failed := ""
counter_successfully := ""
logfile_counter := 1
GuiControl, Disable, Start
GuiControl, Disable, RenamingMaskNumber
GuiControlGet, RenamingMaskNumber
FileSelectFolder, folder_demofiles,, 0, Please select your folder where your demofiles are. `nAll files with the ending *.dem will be renamed.
if ErrorLevel=0
{
	SetWorkingDir %folder_demofiles%
	Loop, Files, *.dem
	{
		counter_files += 1
	}
	If counter_files
	{
		counter_files_quotient := 100 / counter_files
		ParsingInfo := ParsingDemofiles(RenamingMaskNumber, counter_files_quotient)
		filelist := ParsingInfo[1]
		filelist_failed := ParsingInfo[2]
		counter_failed := ParsingInfo[3]
		GuiControl, Disable, Cancel
		GuiControl,, text_prog, Renaming Files
		Loop, Parse, filelist, `n
		{
			 filelist_array := StrSplit(A_LoopField, A_Tab)
			 Source := filelist_array[1]
			 Destination := filelist_array[2]
			 FileMove, %Source%, %Destination%
		}
		If filelist_failed
		{
			logfile_name := "demo-file-renamer_logfile.txt"
			logfile := "Renaming from " current_time " in " A_WorkingDir " `n`nThe following files aren't renamed because the map wasn't found in the demofile: `n`n" . filelist_failed . "`n`nWhat you can do: `n- Execute the demofile in your game or `n- Open the file in an editor and search for the word ""maps"" `n`nBe sure the demofile is a CS 1.6, CS:S, CS:GO or TF2 demofile."
			IfExist, %A_ScriptDir%\%logfile_name%
			{
			filetrue := "A"
				while filetrue
				{
				logfile_counter +=1
				logfile_name := "demo-file-renamer_logfile(" . logfile_counter . ").txt"
				filetrue := FileExist(A_ScriptDir . "\" . logfile_name)
				}
				FileAppend, %logfile%, %A_ScriptDir%\%logfile_name%
			}
			else
			{
				FileAppend, %logfile%, %A_ScriptDir%\%logfile_name%
			}

			counter_successfully := counter_files - counter_failed
			logfile_path := A_ScriptDir . "\" . logfile_name
			msgbox % counter_successfully " out of " counter_files " files were successfully renamed. `n" "There are " counter_failed " that aren't renamed. `n`nLogfile is generated, please look for further information in logfile: `n" logfile_path
		}
		else
		{
			MsgBox, 0, , All demofiles successfully renamed!
		}
		GuiControl,, ProgressBar, 0
		GuiControl,, text_prog, Extracting mapname
		GuiControl, Enable, RenamingMaskNumber
		GuiControl, Enable, Cancel
		GuiControl, Enable, Start
		return
	}
	else
	{
		MsgBox % "No files found!"
		GuiControl,, ProgressBar, 0
		GuiControl, Enable, RenamingMaskNumber
		GuiControl, Enable, Cancel
		GuiControl, Enable, Start
		return
	}
}
else
{
	GuiControl,, ProgressBar, 0
	GuiControl, Enable, RenamingMaskNumber
	GuiControl, Enable, Start
	return
}

ButtonCancel:
GuiClose:
ExitApp

; ===================================================================================
; AHK Version .........: 1.1.23.01
; Version .............: 1.02 (AHK)
; Release Date ........: 2016-02-10
; GitHub ..............: https://github.com/chao-samu/demo-file-renamer
; Author ..............: chao-samu
;------------------------------------------------------------------------------------
; Script Name..........: demo file renamer
; Description .........: Integrate mapname into demofile (*.dem).
;                        Support: TF2, CS 1.6, CS:S and CS:GO
; License..............: MIT License (https://github.com/chao-samu/demo-file-renamer/blob/master/LICENSE)
; ===================================================================================

#NoEnv
#NoTrayIcon
SendMode Input
SetWorkingDir %A_ScriptDir%
PrgName := "Demo file renamer"
PrgVersion := "1.02 (AHK)"
If (A_PtrSize = 4)
{
	BitVersion := "x86"
}
else
{
	BitVersion := "x64"
}

Menu, helpmenu, Add, Help , MenuHelp
Menu, helpmenu, Add
Menu, helpmenu, Add, About, MenuAbout
Menu, topmenu, Add, &Help, :helpmenu
Gui, Menu, topmenu

Gui, Add, Button, x12 y180 w90 h20 , Cancel
Gui, Add, Button, x212 y180 w90 h20 , Start
Gui, Add, Text, x12 y120 w290 h20 vtext_prog, Extracting mapname
Gui, Add, ListBox, x12 y30 w290 h30 vRenamingMask AltSubmit gpressListBox, OLDNAME_MAPNAME||MAPNAME_OLDNAME|YYYY-MM-DD_MAPNAME_OLDNAME|YYYY-MM-DD_OLDNAME_MAPNAME
Gui, Add, Text, x12 y10 w290 h20 , Choose renaming mask
Gui, Add, Text, x12 y70 w290 h40 vtext_example, Example: `n"samurai-vs-ninja.dem" will be renamed to "samurai-vs-ninja_de_dust2.dem"

Gui, Add, Progress, x12 y140 w290 h10 Backgroundsilver vProgressBar
; Generated using SmartGUI Creator for SciTE
Gui, Show, w323 h221, %PrgName%
return

MenuHelp:
Gui, Help:+owner1
Gui +Disabled
Gui, Help:Add, Text,,
((
What can do this Tool?
This tool was manly made to extract out the mapname of
GoldSrc- and Source Engine demofiles and place it in the name of the demofile itself.

Which kind of demofiles this tool can handle?
Currently this tool support Counter-Strike 1.6, Counter-Strike Source,
Counter-Strike Global Office and Team Fortress 2 demofiles.

How to use?
1. Select your renaming mask you want
2. Press start and select in the following window your folder with the supported demofiles
    (please note, all demofiles with the ending "dem" in this folder will be renamed, subfolder
    are not included).
    In a protected folder (like "ProgramFiles") you have to start this program in admin mode!
3. Press OK and wait until you will hopefully be happy :)
)
Gui, Help:Add, Button, Default, OK
Gui, Help:Show, w450 h230, Help
return

MenuAbout:
Gui, About:+owner1
Gui +Disabled
Gui, About:Add, Link,, %PrgName% - Version %PrgVersion% `n`nTool compiled with: AHK %A_AhkVersion% %BitVersion% `n`nLook for updates:`n<a href="https://github.com/chao-samu">https://github.com/chao-samu</a>`n`nMade by chao-samu
Gui, About:Add, Button, Default, OK
Gui, About:Show, w250 h150, About
return

HelpButtonOK:
HelpGuiClose:
HelpGuiEscape:
AboutButtonOK:
AboutGuiClose:
AboutGuiEscape:
Gui, 1:-Disabled
Gui Destroy
return

pressListBox:
	Gui, Submit, NoHide
	if (RenamingMask = 1)
	GuiControl,, text_example, Example: `n"samurai-vs-ninja.dem" will be renamed to "samurai-vs-ninja_de_dust2.dem"
	else if (RenamingMask = 2)
	GuiControl,, text_example, Example: `n"samurai-vs-ninja.dem" will be renamed to "de_dust2_samurai-vs-ninja.dem"
	else if (RenamingMask = 3)
	GuiControl,, text_example, Example: `n"samurai-vs-ninja.dem" will be renamed to "2007-05-03_de_dust2_samurai-vs-ninja.dem"
	else
	GuiControl,, text_example, Example: `n"samurai-vs-ninja.dem" will be renamed to "2007-05-03_samurai-vs-ninja_de_dust2.dem"
return

ButtonStart:
FormatTime, current_time
folder_demofiles := ""
filelist := ""
filelist_failed := ""
counter_files := ""
counter_failed := ""
counter_successfully := ""
logfile_counter := 1
GuiControl, Disable, Start
GuiControl, Disable, RenamingMask
GuiControlGet, RenamingMask
FileSelectFolder, folder_demofiles,, 0, Please select your folder where your demofiles are. `nAll files with the ending *.dem will be renamed.
if ErrorLevel=0
{
	SetWorkingDir %folder_demofiles%
	Loop, Files, *.dem
	{
		counter_files += 1
	}
	If counter_files ;not empty or zero
	{
		counter_files_quotient := 100 / counter_files

		if (RenamingMask = 1)
		{
			Loop, Files, *.dem
			{
				counter_prog := counter_files_quotient * A_Index
				GuiControl,, ProgressBar, %counter_prog%
				FileRead, demofile, %A_LoopFileName%
				RegExMatch(demofile, "maps[\/\\].+\.bsp", mapstring)
				mapstring := Format("{1:s}", mapstring)
				If (InStr(mapstring, "maps") and InStr(mapstring, "bsp"))
				{
					RegExMatch(mapstring, "(?<=maps[\/\\]).+(?=\.bsp)", Mapname)
					Mapname := Format("{1:s}", Mapname)
					If (InStr(Mapname, "/") or InStr(Mapname, "\"))
					{
						Mapname := RegExReplace(Mapname, ".+[\/\\]", "")
					}
					SplitPath, A_LoopFileName,,,, FileNameNoExt
					filelist := filelist . A_LoopFileName . "`t" . FileNameNoExt . "_" . Mapname . "." . A_LoopFileExt . "`n"
				}
				else
				{
					filelist_failed := filelist_failed . A_LoopFileName . "`n"
					counter_failed += 1
				}
			}
		}
		else if (RenamingMask = 2)
		{
			Loop, Files, *.dem
			{
				counter_prog := counter_files_quotient * A_Index
				GuiControl,, ProgressBar, %counter_prog%
				FileRead, demofile, %A_LoopFileName%
				RegExMatch(demofile, "maps[\/\\].+\.bsp", mapstring)
				mapstring := Format("{1:s}", mapstring)
				If (InStr(mapstring, "maps") and InStr(mapstring, "bsp"))
				{
					RegExMatch(mapstring, "(?<=maps[\/\\]).+(?=\.bsp)", Mapname)
					Mapname := Format("{1:s}", Mapname)
					If (InStr(Mapname, "/") or InStr(Mapname, "\"))
					{
						Mapname := RegExReplace(Mapname, ".+[\/\\]", "")
					}
					SplitPath, A_LoopFileName,,,, FileNameNoExt
					filelist := filelist . A_LoopFileName . "`t" . Mapname . "_" .  FileNameNoExt . "." . A_LoopFileExt . "`n"
				}
				else
				{
					filelist_failed := filelist_failed . A_LoopFileName . "`n"
					counter_failed += 1
				}
			}
		}
		else if (RenamingMask = 3)
		{
			Loop, Files, *.dem
			{
				counter_prog := counter_files_quotient * A_Index
				GuiControl,, ProgressBar, %counter_prog%
				FileRead, demofile, %A_LoopFileName%
				RegExMatch(demofile, "maps[\/\\].+\.bsp", mapstring)
				mapstring := Format("{1:s}", mapstring)
				If (InStr(mapstring, "maps") and InStr(mapstring, "bsp"))
				{
					RegExMatch(mapstring, "(?<=maps[\/\\]).+(?=\.bsp)", Mapname)
					Mapname := Format("{1:s}", Mapname)
					If (InStr(Mapname, "/") or InStr(Mapname, "\"))
					{
						Mapname := RegExReplace(Mapname, ".+[\/\\]", "")
					}
					SplitPath, A_LoopFileName,,,, FileNameNoExt
					FormatTime, mod_date, %A_LoopFileTimeModified%, yyyy-MM-dd
					filelist := filelist . A_LoopFileName . "`t" . mod_date . "_" . Mapname . "_" . FileNameNoExt . "." . A_LoopFileExt . "`n"
				}
				else
				{
					filelist_failed := filelist_failed . A_LoopFileName . "`n"
					counter_failed += 1
				}
			}
		}
		else
		{
			Loop, Files, *.dem
			{
				counter_prog := counter_files_quotient * A_Index
				GuiControl,, ProgressBar, %counter_prog%
				FileRead, demofile, %A_LoopFileName%
				RegExMatch(demofile, "maps[\/\\].+\.bsp", mapstring)
				mapstring := Format("{1:s}", mapstring)
				If (InStr(mapstring, "maps") and InStr(mapstring, "bsp"))
				{
					RegExMatch(mapstring, "(?<=maps[\/\\]).+(?=\.bsp)", Mapname)
					Mapname := Format("{1:s}", Mapname)
					If (InStr(Mapname, "/") or InStr(Mapname, "\"))
					{
						Mapname := RegExReplace(Mapname, ".+[\/\\]", "")
					}
					SplitPath, A_LoopFileName,,,, FileNameNoExt
					FormatTime, mod_date, %A_LoopFileTimeModified%, yyyy-MM-dd
					filelist := filelist . A_LoopFileName . "`t" . mod_date . "_" . FileNameNoExt . "_" . Mapname . "." . A_LoopFileExt . "`n"
				}
				else
				{
					filelist_failed := filelist_failed . A_LoopFileName . "`n"
					counter_failed += 1
				}
			}
		}
		GuiControl, Disable, Cancel
		GuiControl,, text_prog, Renaming Files
		Loop, Parse, filelist, `n
		{
			 filelist_array := StrSplit(A_LoopField, A_Tab)
			 Source :=  filelist_array[1]
			 Destination :=  filelist_array[2]
			 FileMove, %Source%, %Destination%
		}
		If filelist_failed
		{
			logfile_name := "Demofile_renamer_logfile.txt"
			logfile := "Renaming from " current_time " in " A_WorkingDir " `n`nThe following files aren't renamed because the map wasn't found in the demofile: `n`n" . filelist_failed . "`n`nWhat you can do: `n- Execute the demofile in your game or `n- Open the file in an editor and search for the word ""maps"" `n`nBe sure the demofile is a CS 1.6, CS:S, CS:GO or TF2 demofile."

			IfExist, %A_ScriptDir%\%logfile_name%
			{
			filetrue := "A"
				while (filetrue <> "")
				{
				logfile_counter +=1
				logfile_name := "Demofile_renamer_logfile(" . logfile_counter . ").txt"
				filetrue := FileExist(logfile_name)
				}
				FileAppend, %logfile%, %A_ScriptDir%\%logfile_name%
			}
			else
			{
				FileAppend, %logfile%, %A_ScriptDir%\%logfile_name%
			}

			counter_successfully := counter_files - counter_failed
			logfile_path := A_ScriptDir . "\" . logfile_name
			msgbox % counter_successfully " out of " counter_files " files were successfully renamed. `n" "There are " counter_failed " that aren't renamed. `n`nLogfile is generated, please look for further information in logfile: `n" logfile_path
		}
		else
		{
			MsgBox, 0, , All demofiles successfully renamed!
		}
		GuiControl,, ProgressBar, 0
		GuiControl,, text_prog, Extracting mapname
		GuiControl, Enable, RenamingMask
		GuiControl, Enable, Cancel
		GuiControl, Enable, Start
		return
	}
	else
	{
		MsgBox % "No files found!"
		GuiControl,, ProgressBar, 0
		GuiControl, Enable, RenamingMask
		GuiControl, Enable, Cancel
		GuiControl, Enable, Start
		return
	}
}
else
{
	GuiControl,, ProgressBar, 0
	GuiControl, Enable, RenamingMask
	GuiControl, Enable, Start
	return
}

ButtonCancel:
GuiClose:
ExitApp


Remove invalid comment

Remove invalid comment

FileEncoding, UTF-8 ; This file needs to be saved/encoded with "UTF-8 with BOM"

; Use Swedish characters on US-English keyboard
![:: Send, å
!+{:: Send, Å
!':: Send, ä
!+':: Send, Ä
!;:: Send, ö
!+;:: Send, Ö

; HHKB settings to mimic macOS behavior on Windows
LWin::LCtrl  ; this one is better to use SharpKeys for, as it is unreliable here
<^Right:: Send, {End}
<^Left:: Send, {Home}
<^Up:: Send, {PgUp}
<^Down:: Send, {PgDn}
<+^Right:: Send, {LShift down}{End}{LShift up}
<+^Left:: Send, {LShift down}{Home}{LShift up}
<+^Up:: Send, {LShift down}{PgUp}{LShift up}
<+^Down:: Send, {LShift down}{PgDn}{LShift up}

; Windows laptop
AppsKey:: Send, {RWin}

FileEncoding, UTF-8 ; This file needs to be saved/encoded with "UTF-8 with BOM"

; Use Swedish characters on US-English keyboard
![:: Send, å
!+{:: Send, Å
!':: Send, ä
!+':: Send, Ä
!;:: Send, ö
!+;:: Send, Ö  ; does not work

; HHKB settings to mimic macOS behavior on Windows
LWin::LCtrl  ; this one is better to use SharpKeys for, as it is unreliable here
<^Right:: Send, {End}
<^Left:: Send, {Home}
<^Up:: Send, {PgUp}
<^Down:: Send, {PgDn}
<+^Right:: Send, {LShift down}{End}{LShift up}
<+^Left:: Send, {LShift down}{Home}{LShift up}
<+^Up:: Send, {LShift down}{PgUp}{LShift up}
<+^Down:: Send, {LShift down}{PgDn}{LShift up}

; Windows laptop
AppsKey:: Send, {RWin}


cfg/ahk: use meta+n for Japanese

cfg/ahk: use meta+n for Japanese

;Control key Ctrl- ^
;Alt key Alt- !
;Shift key Shift- +
;Windows key Win- #

#Persistent
#SingleInstance Force
DetectHiddenWindows, On
DetectHiddenText, On
SetTitleMatchMode, RegEx ;match titles and classes using regular expressions
SetTitleMatchMode Slow ;match titles and classes using regular expressions
CoordMode, Mouse, Screen
CoordMode, ToolTip, Screen

;detect cygwin
global CygPath
CygPath = C:\Program Files (x86)\cygwin
IfNotExist %CygPath%
    CygPath = C:\Cygwin
IfNotExist %CygPath%
    CygPath = C:\Cygwin64

;detect browser
global BrowserPath
BrowserPath = C:\Program Files (x86)\Mozilla Firefox\firefox.exe
IfNotExist %BrowserPath%
    BrowserPath = "C:\Users\rr-\AppData\Local\Google\Chrome\Application\chrome.exe"

;disable windows+l
RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\Microsoft\Windows\CurrentVersion\Policies\System, DisableLockWorkstation, 1

;activate/run a program
FRun(window, path, folder)
{
    if (!window or !WinExist(window))
    {
        Run, %path%, %folder%
    }
    else
    {
        WinShow
        WinActivate
    }
    return
}

return

;replace stuff in clipboard when it changes
OnClipboardChange:
{
    if (A_EventInfo == 1) and (SubStr(clipboard, 1, 7) == "http://")
    {
        StringReplace, clipboard, clipboard, [, `%5b, All
        StringReplace, clipboard, clipboard, \, `%5c, All
        StringReplace, clipboard, clipboard, ], `%5d, All
    }
    return
}

#If FileExist(CygPath)
    ;cygwin - activate/run
    #Enter::
    {
        Run, %CygPath%\bin\mintty.exe --title "Terminal" --class "mintty_thetty" --exec /bin/zsh -i -l, %CygPath%
        return
    }
    +^![::
    {
        Run, %CygPath%\bin\mintty.exe --title "Terminal" --class "mintty_thetty" --exec /bin/zsh -i -l, %CygPath%
        return
    }
    ^![::
    {
        if (!WinExist("ahk_class mintty_thetty"))
        {
            Run, %CygPath%\bin\mintty.exe --title "Terminal" --class "mintty_thetty" --exec /bin/zsh -i -l, %CygPath%
            WinWait ahk_class mintty_thetty
        }
        else
        {
            WinShow
            WinActivate
        }
        return
    }

    ;ssh to cyclone - activate/run
    +^!]::
    {
        Run, %CygPath%\bin\mintty.exe --title "Remote terminal" --class mintty_ssh --exec /bin/ssh cyclone, %CygPath%/bin
        return
    }
    ^!]::
    {
        if (!WinExist("ahk_class mintty_ssh"))
        {
            Run, %CygPath%\bin\mintty.exe --title "Remote terminal" --class mintty_ssh --exec /bin/ssh cyclone, %CygPath%/bin
            WinWait ahk_class mintty_ssh
        }
        else
        {
            WinShow
            WinActivate
        }
        return
    }

    ;text editor - activate/run
    +^!N::
    {
        IfWinExist, ahk_class Vim
        {
            WinShow
            WinActivate
        }
        else
        {
            Run, %CygPath%\bin\mintty.exe --class "Vim" --exec /bin/zsh -l -i -c /bin/vim, %CygPath%/bin
            WinWait, ahk_class Vim
        }
        return
    }

    ;vifm - activate/run
    #e::
    {
        IfWinExist, ahk_class Vifm
        {
            WinShow
            WinActivate
        }
        else
        {
            Run, %CygPath%\bin\mintty.exe --window max --class "Vifm" --exec /bin/zsh -l -i -c vifm, %CygPath%/bin
            WinWait, ahk_class Vifm
        }
        return
    }

    ;vifm - just run
    +#e::
    {
        Run, %CygPath%\bin\mintty.exe --window max --class "Vifm" --exec /bin/zsh -l -i -c vifm, %CygPath%/bin
        return
    }

;browser
#If FileExist(BrowserPath)
    ;web browser - activate/run
    ^!;::
        if WinExist("Mozilla Firefox")
        {
            WinShow
            WinActivate
            Send, !d
        }
        else if WinExist("Vimperator")
        {
            WinShow
            WinActivate
            Send, !d
        }
        else if WinExist("ahk_class Chrome_WidgetWin_1")
        {
            WinActivate
            ControlFocus, Chrome_OmniboxView1
            SendInput, {Home}+{End}
        }
        else
        {
            IfExist %BrowserPath%
                Run, %BrowserPath%
        }
        return

;adobe products
#IfWinActive ahk_group adobe
    ~LAlt::return
    LAlt UP::Send {Escape}
#IfWinActive
#IfWinActive ahk_class illustrator
+wheelup::
    send {Ctrl Down}{=}{Ctrl Up}
    return
+wheeldown::
    send {Ctrl Down}-{Ctrl Up}
    return
#IfWinActive

;close active window
#q::
    ActiveHwnd := WinExist("A")
    WinClose
    return

;fullscreen
#f::
    WinGet MX, MinMax, A
    if MX
        WinRestore A
    else
        WinMaximize A
    return

;restore active window
#s::
    ActiveHwnd := WinExist("A")
    PostMessage 0x112, 0xf120 ;WM_SYSCOMMAND, SC_RESTORE
    return

;minimize active window
#w::
    if WinActive("WTW$")
    {
        WinHide
    }
    else if WinActive("Buddy List")
    {
        WinHide
    }
    else
    {
        ActiveHwnd := WinExist("A")
        PostMessage 0x112, 0xF020 ;WM_SYSCOMMAND, SC_MINIMIZE
    }
    return

;set active window as always on top
#a::WinSet, AlwaysOnTop, Toggle, A

;transparency
AddTransparency(delta)
{
    WinGet, Transparency, Transparent, A
    if ! Transparency
        Transparency = 255
    Transparency := Transparency + delta
    if Transparency <= 10
    {
        WinSet, Transparent, 10, A
    }
    else if Transparency >= 255
    {
        WinSet, Transparent, 255, A
        WinSet, Transparent, OFF, A
    }
    else
    {
        WinSet, Transparent, %Transparency%, A
    }
    return
}
#WheelUp::AddTransparency(12)
#WheelDown::AddTransparency(-12)
#z::AddTransparency(-12)
+#z::AddTransparency(12)

;music
#x::Send {Volume_Up}
+#x::Volume_Down
#c::Send {Media_Next}
+#c::Media_Prev
#v::Send {Media_Play_Pause}

;screenshots
+#i::Run, %CygPath%\bin\zsh.exe -i -l -c 'shot -w -i --output=Z:/', , Hide
#i::Run, %CygPath%\bin\zsh.exe -i -l -c 'shot -i --output=Z:/', , Hide

;reload autohotkey
!F12::Reload

#n::
{
    SetFormat, Integer, H
    Locale1=0x4150415
    Locale2=0x4110411
    WinGet, WinID,, A
    ThreadID:=DllCall("GetWindowThreadProcessId", "Int", WinID, "Int", "0")
    InputLocaleID:=DllCall("GetKeyboardLayout", "Int", ThreadID)
    if(InputLocaleID=Locale1)
        SendMessage, 0x50,, % Locale2,, A
    else if(InputLocaleID=Locale2)
        SendMessage, 0x50,, % Locale1,, A
    return
}

;Control key Ctrl- ^
;Alt key Alt- !
;Shift key Shift- +
;Windows key Win- #

#Persistent
#SingleInstance Force
DetectHiddenWindows, On
DetectHiddenText, On
SetTitleMatchMode, RegEx ;match titles and classes using regular expressions
SetTitleMatchMode Slow ;match titles and classes using regular expressions
CoordMode, Mouse, Screen
CoordMode, ToolTip, Screen

;detect cygwin
global CygPath
CygPath = C:\Program Files (x86)\cygwin
IfNotExist %CygPath%
    CygPath = C:\Cygwin
IfNotExist %CygPath%
    CygPath = C:\Cygwin64

;detect browser
global BrowserPath
BrowserPath = C:\Program Files (x86)\Mozilla Firefox\firefox.exe
IfNotExist %BrowserPath%
    BrowserPath = "C:\Users\rr-\AppData\Local\Google\Chrome\Application\chrome.exe"

;disable windows+l
RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\Microsoft\Windows\CurrentVersion\Policies\System, DisableLockWorkstation, 1

;activate/run a program
FRun(window, path, folder)
{
    if (!window or !WinExist(window))
    {
        Run, %path%, %folder%
    }
    else
    {
        WinShow
        WinActivate
    }
    return
}

return

;replace stuff in clipboard when it changes
OnClipboardChange:
{
    if (A_EventInfo == 1) and (SubStr(clipboard, 1, 7) == "http://")
    {
        StringReplace, clipboard, clipboard, [, `%5b, All
        StringReplace, clipboard, clipboard, \, `%5c, All
        StringReplace, clipboard, clipboard, ], `%5d, All
    }
    return
}

#If FileExist(CygPath)
    ;cygwin - activate/run
    #Enter::
    {
        Run, %CygPath%\bin\mintty.exe --title "Terminal" --class "mintty_thetty" --exec /bin/zsh -i -l, %CygPath%
        return
    }
    +^![::
    {
        Run, %CygPath%\bin\mintty.exe --title "Terminal" --class "mintty_thetty" --exec /bin/zsh -i -l, %CygPath%
        return
    }
    ^![::
    {
        if (!WinExist("ahk_class mintty_thetty"))
        {
            Run, %CygPath%\bin\mintty.exe --title "Terminal" --class "mintty_thetty" --exec /bin/zsh -i -l, %CygPath%
            WinWait ahk_class mintty_thetty
        }
        else
        {
            WinShow
            WinActivate
        }
        return
    }

    ;ssh to cyclone - activate/run
    +^!]::
    {
        Run, %CygPath%\bin\mintty.exe --title "Remote terminal" --class mintty_ssh --exec /bin/ssh cyclone, %CygPath%/bin
        return
    }
    ^!]::
    {
        if (!WinExist("ahk_class mintty_ssh"))
        {
            Run, %CygPath%\bin\mintty.exe --title "Remote terminal" --class mintty_ssh --exec /bin/ssh cyclone, %CygPath%/bin
            WinWait ahk_class mintty_ssh
        }
        else
        {
            WinShow
            WinActivate
        }
        return
    }

    ;text editor - activate/run
    +^!N::
    {
        IfWinExist, ahk_class Vim
        {
            WinShow
            WinActivate
        }
        else
        {
            Run, %CygPath%\bin\mintty.exe --class "Vim" --exec /bin/zsh -l -i -c /bin/vim, %CygPath%/bin
            WinWait, ahk_class Vim
        }
        return
    }

    ;vifm - activate/run
    #e::
    {
        IfWinExist, ahk_class Vifm
        {
            WinShow
            WinActivate
        }
        else
        {
            Run, %CygPath%\bin\mintty.exe --window max --class "Vifm" --exec /bin/zsh -l -i -c vifm, %CygPath%/bin
            WinWait, ahk_class Vifm
        }
        return
    }

    ;vifm - just run
    +#e::
    {
        Run, %CygPath%\bin\mintty.exe --window max --class "Vifm" --exec /bin/zsh -l -i -c vifm, %CygPath%/bin
        return
    }

;browser
#If FileExist(BrowserPath)
    ;web browser - activate/run
    ^!;::
        if WinExist("Mozilla Firefox")
        {
            WinShow
            WinActivate
            Send, !d
        }
        else if WinExist("Vimperator")
        {
            WinShow
            WinActivate
            Send, !d
        }
        else if WinExist("ahk_class Chrome_WidgetWin_1")
        {
            WinActivate
            ControlFocus, Chrome_OmniboxView1
            SendInput, {Home}+{End}
        }
        else
        {
            IfExist %BrowserPath%
                Run, %BrowserPath%
        }
        return

;adobe products
#IfWinActive ahk_group adobe
    ~LAlt::return
    LAlt UP::Send {Escape}
#IfWinActive
#IfWinActive ahk_class illustrator
+wheelup::
    send {Ctrl Down}{=}{Ctrl Up}
    return
+wheeldown::
    send {Ctrl Down}-{Ctrl Up}
    return
#IfWinActive

;close active window
#q::
    ActiveHwnd := WinExist("A")
    WinClose
    return

;fullscreen
#f::
    WinGet MX, MinMax, A
    if MX
        WinRestore A
    else
        WinMaximize A
    return

;restore active window
#s::
    ActiveHwnd := WinExist("A")
    PostMessage 0x112, 0xf120 ;WM_SYSCOMMAND, SC_RESTORE
    return

;minimize active window
#w::
    if WinActive("WTW$")
    {
        WinHide
    }
    else if WinActive("Buddy List")
    {
        WinHide
    }
    else
    {
        ActiveHwnd := WinExist("A")
        PostMessage 0x112, 0xF020 ;WM_SYSCOMMAND, SC_MINIMIZE
    }
    return

;set active window as always on top
#a::WinSet, AlwaysOnTop, Toggle, A

;transparency
AddTransparency(delta)
{
    WinGet, Transparency, Transparent, A
    if ! Transparency
        Transparency = 255
    Transparency := Transparency + delta
    if Transparency <= 10
    {
        WinSet, Transparent, 10, A
    }
    else if Transparency >= 255
    {
        WinSet, Transparent, 255, A
        WinSet, Transparent, OFF, A
    }
    else
    {
        WinSet, Transparent, %Transparency%, A
    }
    return
}
#WheelUp::AddTransparency(12)
#WheelDown::AddTransparency(-12)
#z::AddTransparency(-12)
+#z::AddTransparency(12)

;music
#x::Send {Volume_Up}
+#x::Volume_Down
#c::Send {Media_Next}
+#c::Media_Prev
#v::Send {Media_Play_Pause}

;screenshots
+#i::Run, %CygPath%\bin\zsh.exe -i -l -c 'shot -w -i --output=Z:/', , Hide
#i::Run, %CygPath%\bin\zsh.exe -i -l -c 'shot -i --output=Z:/', , Hide

;reload autohotkey
!F12::Reload

#j::
{
    SetFormat, Integer, H
    Locale1=0x4150415
    Locale2=0x4110411
    WinGet, WinID,, A
    ThreadID:=DllCall("GetWindowThreadProcessId", "Int", WinID, "Int", "0")
    InputLocaleID:=DllCall("GetKeyboardLayout", "Int", ThreadID)
    if(InputLocaleID=Locale1)
        SendMessage, 0x50,, % Locale2,, A
    else if(InputLocaleID=Locale2)
        SendMessage, 0x50,, % Locale1,, A
    return
}


TC_Dialog:自动跳转条件排除含有密码、password等内容的对话框

TotalCommander_Dialog:
;本插件尝试将TotalCommander作为文件打开对话框
; * 默认添加快捷键<lwin>o ,在文件对话框或任意文字编辑界面按下快捷键跳转至TC--TC中选定文件后再次按下快捷键可实现文件打开功能
; * 尝试在打开文件对话框时，自动跳转到TC进行文件选择：#32770，焦点Edit1且内无文字,对话框内不含密码、password等内容
; * 增加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

;未发现TC路径时自动禁用该功能
if StrLen(TCPath) = 0
	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

	;排除含有密码、password等内容的对话框
	WinGetText,str,ahk_class #32770
	IfInString,str,密码
		return
	IfInString,str,password
		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

;未发现TC路径时自动禁用该功能
if StrLen(TCPath) = 0
	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
}


[map] printscreen -> app_option

[map] printscreen -> app_option

; 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

CapsLock::Ctrl
LCtrl::CapsLock

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

; 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

CapsLock::Ctrl
LCtrl::CapsLock