adding autohotkey

adding autohotkey


Fixed file path in Gui test script.

Fixed file path in Gui test script.

f = %A_Temp%\guitest.png

If (!FileExist(f))
	UrlDownloadToFile, http://i44.tinypic.com/vovc4j.png, %f%

Gui, Add, Text, vC1 Border gButtonClick, Test
Gui, Add, Edit, vC2 ym
Gui, Add, UpDown, vC3 Range5-10, 7
Gui, Add, Pic, vC4 xm Section, %f%
Gui, Add, Button, vC5 ys+10 h20, Click
Gui, Add, CheckBox, vC6 xp+5 yp+30 CheckedGrey, Check
Gui, Add, Radio, vC7, Option 1
Gui, Add, Radio, vC8, Option 2
Gui, Add, DDL, vC9 Section x2, A|B|C||D
Gui, Add, ComboBox, vC10 ys, E||
Gui, Add, ListBox, vC11 ys, F|G||H
Gui, Add, ListView, vC12 Section xm, One|Two|Three
Gui, Add, TreeView, vC13 ys w125
Gui, Add, Hotkey, vC14 Limit4
Gui, Add, DateTime, vC15 xm, 2010
Gui, Add, MonthCal, vC16 Section, 2009
Gui, Add, Slider, vC17 ys Range1-10, 5
Gui, Add, Progress, vC18 -Smooth, 50
Gui, Show, xCenter y100, Example
Return

ButtonClick:
s =
Loop, 18
{
	GuiControlGet, r, , C%A_Index%
	s = %s%C%A_Index%: "%r%"
	GuiControlGet, r, Pos, C%A_Index%
	s = %s% (%rx%, %ry%, %rw%, %rh%)`n
}
Gui, +OwnDialogs
MsgBox, %s%
Return

GuiEscape:
GuiClose:
ExitApp

f = %A_Temp%\guitest.png

If (!FileExist(f))
	UrlDownloadToFile, http://i44.tinypic.com/vovc4j.png, %f%

Gui, Add, Text, vC1 Border gButtonClick, Test
Gui, Add, Edit, vC2 ym
Gui, Add, UpDown, vC3 Range5-10, 7
Gui, Add, Pic, vC4 xm Section, X:\Media\Pictures\what 100.png
Gui, Add, Button, vC5 ys+10 h20, Click
Gui, Add, CheckBox, vC6 xp+5 yp+30 CheckedGrey, Check
Gui, Add, Radio, vC7, Option 1
Gui, Add, Radio, vC8, Option 2
Gui, Add, DDL, vC9 Section x2, A|B|C||D
Gui, Add, ComboBox, vC10 ys, E||
Gui, Add, ListBox, vC11 ys, F|G||H
Gui, Add, ListView, vC12 Section xm, One|Two|Three
Gui, Add, TreeView, vC13 ys w125
Gui, Add, Hotkey, vC14 Limit4
Gui, Add, DateTime, vC15 xm, 2010
Gui, Add, MonthCal, vC16 Section, 2009
Gui, Add, Slider, vC17 ys Range1-10, 5
Gui, Add, Progress, vC18 -Smooth, 50
Gui, Show, xCenter y100, Example
Return

ButtonClick:
s =
Loop, 18
{
	GuiControlGet, r, , C%A_Index%
	s = %s%C%A_Index%: "%r%"
	GuiControlGet, r, Pos, C%A_Index%
	s = %s% (%rx%, %ry%, %rw%, %rh%)`n
}
Gui, +OwnDialogs
MsgBox, %s%
Return

GuiEscape:
GuiClose:
ExitApp


Add S2T

Add S2T

global Arg

Functions:
    @("Help", "帮助信息")
    @("KeyHelp", "置顶的按键帮助信息")
    @("AhkRun", "使用 Ahk 的 Run 运行 `; cmd", true)
    @("CmdRun", "使用 cmd 运行 : cmd", true)
    @("WinRRun", "使用 win + r 运行", true)
    @("Dictionary", "有道词典在线翻译", true)
    @("RunAndDisplay", "使用 cmd 运行，并显示结果", true)
    @("ReloadFiles", "重新加载需要搜索的文件")
    @("Clip", "显示剪切板内容")
    @("Calc", "计算器")
    @("SearchOnBaidu", "使用 Baidu（百度）搜索剪切板或输入内容", true)
    @("SearchOnGoogle", "使用 Google（谷歌）搜索剪切板或输入内容", true)
    @("SearchOnBing", "使用 Bing（必应）搜索剪切板或输入内容", true)
    @("SearchOnTaobao", "使用 Taobao（淘宝）搜索剪切板或输入内容")
    @("SearchOnJingdong", "使用 JD（京东）搜索剪切板或输入内容")
    @("EditConfig", "编辑配置文件")
    @("ClearClipboardFormat", "清除剪切板中文字的格式")
    @("RunClipboard", "使用 ahk 的 Run 运行剪切板内容")
    @("EmptyRecycle", "清空回收站")
    @("Logoff", "注销 登出")
    @("RestartMachine", "重启")
    @("ShutdownMachine", "关机")
    @("SuspendMachine", "挂起 睡眠 待机")
    @("HibernateMachine", "休眠")
    @("TurnMonitorOff", "关闭显示器")
    @("T2S", "将剪切板中的内容繁体转简体")
    @("S2T", "将剪切板中的内容简体转繁体")
    @("ShowIp", "显示 IP")
    @("Calendar", "用浏览器打开万年历")
    @("CleanupRank", "清理命令权重中的无效命令")
    @("ArgTest", "参数测试：ArgTest arg1,arg2,...")

    if (IsLabel("ReservedFunctions"))
    {
        GoSub, ReservedFunctions
    }
return

Help:
    DisplayResult(KeyHelpText() . GetAllFunctions())
return

KeyHelp:
    ToolTip, % KeyHelpText()
return

CmdRun:
    RunWithCmd(Arg)
return

AhkRun:
    Run, %Arg%
return

Clip:
    DisplayResult("剪切板内容长度 " . StrLen(clipboard) . " ：`n`n" . clipboard)
return

EditConfig:
    Run, % g_ConfFile
return

ArgTest:
    Args := StrSplit(Arg, ",")
    result := "共有 " . Args.Length() . " 个参数。`n`n"

    for index, argument in Args
    {
        result .= "第 " . index . " 个参数：" . argument . "`n"
    }

    DisplayResult(result)
return

ShowIp:
    DisplayResult(A_IPAddress1
            . "`r`n" . A_IPAddress2
            . "`r`n" . A_IPAddress3
            . "`r`n" . A_IPAddress4)
return

Dictionary:
    word := Arg == "" ? clipboard : Arg

    url := "http://fanyi.youdao.com/openapi.do?keyfrom=YouDaoCV&key=659600698&"
            . "type=data&doctype=json&version=1.2&q=" UrlEncode(word)

    jsonText := StrReplace(UrlDownloadToString(url), "-phonetic", "_phonetic")

    if (jsonText == "no query")
    {
        DisplayResult("未查到结果")
        return
    }

    parsed := JSON.Load(jsonText)
	result := parsed.query

	if (parsed.basic.uk_phonetic != "" && parsed.basic.us_phonetic != "")
	{
		result .= " UK: [" parsed.basic.uk_phonetic "], US: [" parsed.basic.us_phonetic "]`n"
	}
	else if (parsed.basic.phonetic != "")
	{
		result .= " [" parsed.basic.phonetic "]`n"
	}
    else
    {
        result .= "`n"
    }

	if (parsed.basic.explains.Length() > 0)
	{
		result .= "`n"
		for index, explain in parsed.basic.explains
		{
			result .= "    * " explain "`n"
		}
	}

	if (parsed.web.Length() > 0)
	{
		result .= "`n----`n"

		for i, element in parsed.web
		{
			result .= "`n    * " element.key
			for j, value in element.value
			{
				if (j == 1)
				{
					result .= "`n       "
				}
				else
				{
					result .= "`; "
				}

				result .= value
			}
		}
	}

    DisplayResult(result)
    clipboard := result
return

Calendar:
    Run % "http://www.baidu.com/baidu?wd=%CD%F2%C4%EA%C0%FA"
return

T2S:
    Run, notepad
    clipboard := Kanji_t2s(clipboard)
    Send, ^v
return

S2T:
    Run, notepad
    clipboard := Kanji_s2t(clipboard)
    Send, ^v
return

ClearClipboardFormat:
    clipboard := clipboard
return

SearchOnBaidu:
    word := Arg == "" ? clipboard : Arg

    Run, https://www.baidu.com/s?wd=%word%
return

SearchOnGoogle:
    word := UrlEncode(Arg == "" ? clipboard : Arg)

    Run, https://www.google.com.hk/#newwindow=1&safe=strict&q=%word%
return

SearchOnBing:
    word := Arg == "" ? clipboard : Arg

    Run, http://cn.bing.com/search?q=%word%
return

SearchOnTaobao:
    word := Arg == "" ? clipboard : Arg

    Run, https://s.taobao.com/search?q=%word%
return

SearchOnJingdong:
    word := Arg == "" ? clipboard : Arg

    Run, http://search.jd.com/Search?keyword=%word%&enc=utf-8
return

RunClipboard:
    Run, %clipboard%
return

Calc:
    result := Eval(Arg)
    DisplayResult(result)
    clipboard := result
return

RunAndDisplay:
    DisplayResult(RunAndGetOutput(Arg))
return

WinRRun:
    Send, #r
    Sleep, 100
    Send, %Arg%
    Send, {enter}
return

Logoff:
    Shutdown, 0
return

ShutdownMachine:
    Shutdown, 1
return

RestartMachine:
    Shutdown, 2
return

HibernateMachine:
    ; 参数 #1: 使用 1 代替 0 来进行休眠而不是挂起。
	; 参数 #2: 使用 1 代替 0 来立即挂起而不询问每个应用程序以获得许可。
	; 参数 #3: 使用 1 而不是 0 来禁止所有的唤醒事件。
    DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
return

SuspendMachine:
    DllCall("PowrProf\SetSuspendState", "int", 0, "int", 0, "int", 0)
return

TurnMonitorOff:
	; 关闭显示器:
	SendMessage, 0x112, 0xF170, 2,, Program Manager
	; 0x112 is WM_SYSCOMMAND, 0xF170 is SC_MONITORPOWER.
	; 对上面命令的注释: 使用 -1 代替 2 来打开显示器.
	; 使用 1 代替 2 来激活显示器的节能模式.
return

EmptyRecycle:
    FileRecycleEmpty,
return

global Arg

Functions:
    @("Help", "帮助信息")
    @("KeyHelp", "置顶的按键帮助信息")
    @("AhkRun", "使用 Ahk 的 Run 运行 `; cmd", true)
    @("CmdRun", "使用 cmd 运行 : cmd", true)
    @("WinRRun", "使用 win + r 运行", true)
    @("Dictionary", "有道词典在线翻译", true)
    @("RunAndDisplay", "使用 cmd 运行，并显示结果", true)
    @("ReloadFiles", "重新加载需要搜索的文件")
    @("Clip", "显示剪切板内容")
    @("Calc", "计算器")
    @("SearchOnBaidu", "使用 Baidu（百度）搜索剪切板或输入内容", true)
    @("SearchOnGoogle", "使用 Google（谷歌）搜索剪切板或输入内容", true)
    @("SearchOnBing", "使用 Bing（必应）搜索剪切板或输入内容", true)
    @("SearchOnTaobao", "使用 Taobao（淘宝）搜索剪切板或输入内容")
    @("SearchOnJingdong", "使用 JD（京东）搜索剪切板或输入内容")
    @("EditConfig", "编辑配置文件")
    @("ClearClipboardFormat", "清除剪切板中文字的格式")
    @("RunClipboard", "使用 ahk 的 Run 运行剪切板内容")
    @("EmptyRecycle", "清空回收站")
    @("LogOff", "注销 登出")
    @("RestartMachine", "重启")
    @("ShutdownMachine", "关机")
    @("SuspendMachine", "挂起 睡眠 待机")
    @("HibernateMachine", "休眠")
    @("TurnMonitorOff", "关闭显示器")
    @("T2S", "将剪切板中的内容繁体转简体")
    @("ShowIp", "显示 IP")
    @("Calendar", "用浏览器打开万年历")
    @("CleanupRank", "清理命令权重中的无效命令")
    @("ArgTest", "参数测试：ArgTest arg1,arg2,...")

    if (IsLabel("ReservedFunctions"))
    {
        GoSub, ReservedFunctions
    }
return

Help:
    DisplayResult(KeyHelpText() . GetAllFunctions())
return

KeyHelp:
    ToolTip, % KeyHelpText()
return

CmdRun:
    RunWithCmd(Arg)
return

AhkRun:
    Run, %Arg%
return

Clip:
    DisplayResult("剪切板内容长度 " . StrLen(clipboard) . " ：`n`n" . clipboard)
return

EditConfig:
    Run, % g_ConfFile
return

ArgTest:
    Args := StrSplit(Arg, ",")
    result := "共有 " . Args.Length() . " 个参数。`n`n"

    for index, argument in Args
    {
        result .= "第 " . index . " 个参数：" . argument . "`n"
    }

    DisplayResult(result)
return

ShowIp:
    DisplayResult(A_IPAddress1
            . "`r`n" . A_IPAddress2
            . "`r`n" . A_IPAddress3
            . "`r`n" . A_IPAddress4)
return

Dictionary:
    word := Arg == "" ? clipboard : Arg

    url := "http://fanyi.youdao.com/openapi.do?keyfrom=YouDaoCV&key=659600698&"
            . "type=data&doctype=json&version=1.2&q=" UrlEncode(word)

    jsonText := StrReplace(UrlDownloadToString(url), "-phonetic", "_phonetic")

    if (jsonText == "no query")
    {
        DisplayResult("未查到结果")
        return
    }

    parsed := JSON.Load(jsonText)
	result := parsed.query

	if (parsed.basic.uk_phonetic != "" && parsed.basic.us_phonetic != "")
	{
		result .= " UK: [" parsed.basic.uk_phonetic "], US: [" parsed.basic.us_phonetic "]`n"
	}
	else if (parsed.basic.phonetic != "")
	{
		result .= " [" parsed.basic.phonetic "]`n"
	}
    else
    {
        result .= "`n"
    }

	if (parsed.basic.explains.Length() > 0)
	{
		result .= "`n"
		for index, explain in parsed.basic.explains
		{
			result .= "    * " explain "`n"
		}
	}

	if (parsed.web.Length() > 0)
	{
		result .= "`n----`n"

		for i, element in parsed.web
		{
			result .= "`n    * " element.key
			for j, value in element.value
			{
				if (j == 1)
				{
					result .= "`n       "
				}
				else
				{
					result .= "`; "
				}

				result .= value
			}
		}
	}

    DisplayResult(result)
    clipboard := result
return

Calendar:
    Run % "http://www.baidu.com/baidu?wd=%CD%F2%C4%EA%C0%FA"
return

T2S:
    Run, notepad
    clipboard := Kanji_t2s(clipboard)
    Send, ^v
return

ClearClipboardFormat:
    clipboard := clipboard
return

SearchOnBaidu:
    word := Arg == "" ? clipboard : Arg

    Run, https://www.baidu.com/s?wd=%word%
return

SearchOnGoogle:
    word := UrlEncode(Arg == "" ? clipboard : Arg)

    Run, https://www.google.com.hk/#newwindow=1&safe=strict&q=%word%
return

SearchOnBing:
    word := Arg == "" ? clipboard : Arg

    Run, http://cn.bing.com/search?q=%word%
return

SearchOnTaobao:
    word := Arg == "" ? clipboard : Arg

    Run, https://s.taobao.com/search?q=%word%
return

SearchOnJingdong:
    word := Arg == "" ? clipboard : Arg

    Run, http://search.jd.com/Search?keyword=%word%&enc=utf-8
return

RunClipboard:
    Run, %clipboard%
return

Calc:
    result := Eval(Arg)
    DisplayResult(result)
    clipboard := result
return

RunAndDisplay:
    DisplayResult(RunAndGetOutput(Arg))
return

WinRRun:
    Send, #r
    Sleep, 100
    Send, %Arg%
    Send, {enter}
return

LogOff:
    Shutdown, 0
return

ShutdownMachine:
    Shutdown, 1
return

RestartMachine:
    Shutdown, 2
return

HibernateMachine:
    ; 参数 #1: 使用 1 代替 0 来进行休眠而不是挂起。
	; 参数 #2: 使用 1 代替 0 来立即挂起而不询问每个应用程序以获得许可。
	; 参数 #3: 使用 1 而不是 0 来禁止所有的唤醒事件。
    DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
return

SuspendMachine:
    DllCall("PowrProf\SetSuspendState", "int", 0, "int", 0, "int", 0)
return

TurnMonitorOff:
	; 关闭显示器:
	SendMessage, 0x112, 0xF170, 2,, Program Manager
	; 0x112 is WM_SYSCOMMAND, 0xF170 is SC_MONITORPOWER.
	; 对上面命令的注释: 使用 -1 代替 2 来打开显示器.
	; 使用 1 代替 2 来激活显示器的节能模式.
return

EmptyRecycle:
    FileRecycleEmpty,
return


Fix ChangeCommand

Fix ChangeCommand

#NoEnv
#SingleInstance, Force
#NoTrayIcon

FileEncoding, utf-8
SendMode Input

; 自动生成的命令文件
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

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

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, % "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, % "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

; 如果是后台运行模式，Esc 键只关闭窗口，不退出程序
Hotkey, esc, EscFunction
Hotkey, !f4, ExitRunZ

Hotkey, tab, TabFunction
Hotkey, f1, Help
Hotkey, f2, EditConfig
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 q t w n p

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

Test:
    MsgBox Test
return

HomeKey:
    Send, {home}
return

EndKey:
    Send, {End}
return

NextPage:
    ControlFocus, Edit2
    Send, {pgdn}
return

PrevPage:
    ControlFocus, Edit2
    Send, {pgup}
return

ActivateWindow:
    Gui, Show, , % g_WindowName
return

TabFunction:
    ControlGetFocus, ctrl,
    if (ctrl == "Edit1")
    {
        ControlFocus, Edit2
    }
    else
    {
        ControlFocus, Edit1
    }
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 == "Edit1")
    {
        return
    }

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

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

ChangeCommand(step, resetCurrentLine = false)
{
    ControlGetText, g_CurrentInput, Edit1

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

    g_CurrentLine := Mod(g_CurrentLine + step, g_CurrentCommandList.Length())
    if (g_CurrentLine == 0)
    {
        g_CurrentLine := g_CurrentCommandList.Length()
    }

    ; 重置当前命令
    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, Edit2
    result := StrReplace(result, ">| ", " | ")
    result := StrReplace(result, currentChar " | ", currentChar ">| ")
    DisplaySearchResult(result)

    ControlSetText, Edit1, %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
        {
            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, Edit1

    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.Push(g_CurrentCommand)
        result .= "a | " . 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)
    {
        ControlSetText, Edit3, %g_CurrentCommand%
    }
}

ClearInput:
    ControlSetText, Edit1,
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
        {
            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)
    {
        g_AutoConf.AddKey("Rank", cmd, cmdRank)
    }
    else
    {
        cmdRank := 0
    }

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

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

    RunCommand(g_CurrentCommandList[index])
return

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

    index := Asc(SubStr(A_ThisHotkey, 2, 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
    {
        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, Edit2, %textToDisplay%
}

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

LoadHistoryCommands()
{
    for key, value in g_AutoConf.History
    {
        if (value != "")
        {
            g_HistoryCommands.Push(value)
        }
    }
}

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

    for index, element in g_HistoryCommands
    {
        result .= Chr(g_FirstChar + index - 1) . " | " . element "`n"

        if (index == 1)
        {
            g_CurrentCommand := element
        }

        g_CurrentCommandList.Push(element)
    }

    DisplayResult(result)
return

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

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

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, ExitRunZ
    }

    SetTimer, ToExit, Off
return

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

; 自动生成的命令文件
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

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

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, % "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, % "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

; 如果是后台运行模式，Esc 键只关闭窗口，不退出程序
Hotkey, esc, EscFunction
Hotkey, !f4, ExitRunZ

Hotkey, tab, TabFunction
Hotkey, f1, Help
Hotkey, f2, EditConfig
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 q t w n p

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

Test:
    MsgBox Test
return

HomeKey:
    Send, {home}
return

EndKey:
    Send, {End}
return

NextPage:
    ControlFocus, Edit2
    Send, {pgdn}
return

PrevPage:
    ControlFocus, Edit2
    Send, {pgup}
return

ActivateWindow:
    Gui, Show, , % g_WindowName
return

TabFunction:
    ControlGetFocus, ctrl,
    if (ctrl == "Edit1")
    {
        ControlFocus, Edit2
    }
    else
    {
        ControlFocus, Edit1
    }
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 == "Edit1")
    {
        return
    }

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

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

ChangeCommand(step)
{
    ControlGetText, g_CurrentInput, Edit1

    if (SubStr(g_CurrentInput, 1, 1) != "@")
    {
        g_CurrentLine := g_CurrentCommandList.Length() >= 2 ? 2 : 1
    }
    else if (g_CurrentLine + step <= g_CurrentCommandList.Length() && g_CurrentLine + step >= 1)
    {
        g_CurrentLine += step
    }
    else
    {
        return
    }

    ; 重置当前命令
    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, Edit2
    result := StrReplace(result, ">| ", " | ")
    result := StrReplace(result, currentChar " | ", currentChar ">| ")
    DisplaySearchResult(result)

    ControlSetText, Edit1, %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
        {
            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, Edit1

    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.Push(g_CurrentCommand)
        result .= "a | " . 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)
    {
        ControlSetText, Edit3, %g_CurrentCommand%
    }
}

ClearInput:
    ControlSetText, Edit1,
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
        {
            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)
    {
        g_AutoConf.AddKey("Rank", cmd, cmdRank)
    }
    else
    {
        cmdRank := 0
    }

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

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

    RunCommand(g_CurrentCommandList[index])
return

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

    index := Asc(SubStr(A_ThisHotkey, 2, 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
    {
        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, Edit2, %textToDisplay%
}

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

LoadHistoryCommands()
{
    for key, value in g_AutoConf.History
    {
        if (value != "")
        {
            g_HistoryCommands.Push(value)
        }
    }
}

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

    for index, element in g_HistoryCommands
    {
        result .= Chr(g_FirstChar + index - 1) . " | " . element "`n"

        if (index == 1)
        {
            g_CurrentCommand := element
        }

        g_CurrentCommandList.Push(element)
    }

    DisplayResult(result)
return

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

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

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, ExitRunZ
    }

    SetTimer, ToExit, Off
return

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


try fix autohotkey control stuck issue again

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

SetKeyDelay , 30, 30 ; first is delay between keypresses, and second is press duration

#WinActivateForce
DetectHiddenWindows, On

;#MaxHotkeysPerInterval 200

; https://stackoverflow.com/questions/49009176/autohotkey-causing-control-key-to-get-stuck
; https://www.autohotkey.com/docs/commands/_MenuMaskKey.htm
#MenuMaskKey vkFF

return() {
    For Each, Modifier in ["Shift","LWin","RWin","Alt","LControl", "RControl"]
        ; If GetKeyState(Modifier) And !GetKeyState(Modifier,"P")
        If GetKeyState(Modifier)
            Send, {%Modifier% Up}
    Exit
}

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

SetKeyDelay , 30, 30 ; first is delay between keypresses, and second is press duration

#WinActivateForce
DetectHiddenWindows, On

;#MaxHotkeysPerInterval 200

; https://stackoverflow.com/questions/49009176/autohotkey-causing-control-key-to-get-stuck
; https://www.autohotkey.com/docs/commands/_MenuMaskKey.htm
#MenuMaskKey vkFF

Return() {
    For Each, Modifier in ["Shift","LWin","RWin","Alt","LControl", "RControl"]
        If GetKeyState(Modifier) And !GetKeyState(Modifier,"P")
            Send, {%Modifier% Up}
    Exit
}


Add acceleration menu toggle

Add acceleration menu toggle

; JKLmouse for AutoHotkey by Michael Geary
; http://www.jklmouse.com/ - documentation
; http://unlicense.org/ - public domain statement

#SingleInstance force

SetRegView, 64

version := "0.2x"

; Use either the embedded icon in a compiled .exe,
; or a separate .ico file when running the .ahk script.
iconPath := RegExReplace( A_ScriptFullPath, "i).ahk$", ".ico" )

regKeySettings := "Software\JKLmouse"

; TODO: protect against invalid registry string
accelerate := RegReadValue( "Accelerate", 1 )
keysLeft := RegReadValue( "KeysLeft", "ESDF" )
keysRight := RegReadValue( "KeysRight", "IJKL" )

keyMap := ""

keyMaps :=
(join
{
	Arrows: "Up~Up Down~Down Left~Left Right~Right",
	NumPad: "7~UpLeft 8~Up 9~UpRight 4~Left 5~Down 6~Right 1~DownLeft 2~Down 3~DownRight",
	IJKL: "U~UpLeft I~Up O~UpRight J~Left K~Down L~Right M~DownLeft ,~Down .~DownRight",
	HJKL: "H~Left J~Down K~Up L~Right",
	ESDF: "W~UpLeft E~Up R~UpRight S~Left D~Down F~Right X~DownLeft C~Down V~DownRight",
	WASD: "Q~UpLeft W~Up E~UpRight A~Left S~Down D~Right Z~DownLeft X~Down C~DownRight"
}
)

; Set up the tray icon and menu
Menu, Tray, Icon, %iconPath%
Menu, Tray, Tip, JKLmouse
Menu, Tray, Add
Menu, Tray, Add, Left Hand: ESDF, MenuESDF
Menu, Tray, Add, Left Hand: WASD, MenuWASD
Menu, Tray, Add
Menu, Tray, Add, Right Hand: IJKL, MenuIJKL
Menu, Tray, Add, Right Hand: HJKL, MenuHJKL
Menu, Tray, Add
Menu, Tray, Add, Acceleration, MenuAccelerate
Menu, Tray, Add
Menu, Tray, Add, About JKLmouse, MenuAbout
Menu, Tray, Add, JKLmouse Website, MenuWebsite

if( accelerate )
	Menu, Tray, Check, Acceleration
Menu, Tray, Check, Left Hand: %keysLeft%
Menu, Tray, Check, Right Hand: %keysRight%

; Display tray balloon
; TODO: more useful content?
; TODO: display this only during an install
TrayTip JKLmouse, The Automatic Keyboard Mouse

; Remove forced delay between triggered mouse events.
; TODO: experiment with this when accelerated
SetMouseDelay, -1

; Hotkey repeat count for acceleration
repeat := 0

SetAllKeyMaps()

;MsgBox % keyMap

SetAllKeys( true )

return

; Read a string value from our settings registry key, or return otherwise if not present
RegReadValue( name, otherwise ) {
	global regKeySettings
	value := ""
	RegRead, value, HKCU, %regKeySettings%, %name%
	if( ErrorLevel )
		return %otherwise%
	return %value%
}

; Write a dword value to our settings registry key
RegWriteDword( name, value ) {
	RegWriteValue( name, value, "REG_DWORD" )
}

; Write a string value to our settings registry key
RegWriteString( name, value ) {
	RegWriteValue( name, value, "REG_SZ" )
}

; Write a value of a specific type to our settings registry key
RegWriteValue( name, value, type ) {
	global regKeySettings
	RegWrite, %type%, HKCU, %regKeySettings%, %name%, %value%
}

; TODO: refactor SetKeysLeft() and SetKeysRight()!

SetKeysLeft( keys ) {
	global keysLeft
	if( keys = keysLeft )
		return
	Menu, Tray, Uncheck, Left Hand: %keysLeft%
	keysLeft := keys
	Menu, Tray, Check, Left Hand: %keysLeft%
	RegWriteString( "KeysLeft", keysLeft )
	ReloadAllKeys()
}

SetKeysRight( keys ) {
	global keysRight
	if( keys = keysRight )
		return
	Menu, Tray, Uncheck, Right Hand: %keysRight%
	keysRight := keys
	Menu, Tray, Check, Right Hand: %keysRight%
	RegWriteString( "KeysRight", keysRight )
	ReloadAllKeys()
}

; Load the entire set of key maps for all arrow pads and all modifiers
SetAllKeyMaps() {
	global keyMap, keysLeft, keysRight
	keyMap := ""
	SetKeyMap( "Arrows", "NumPad", keysLeft, keysRight )
}

; Load the specified key maps for all modifiers
SetKeyMap( keys* ) {
	global keyMap, keyMaps
    for index, value in keys
        keyMap .= keyMaps[value] . " "
    return SubStr( str, 1, -StrLen(sep) )
}

; Turn off existing key maps, reparse and reload new key maps
ReloadAllKeys() {
	SetAllKeys( false )
	SetAllKeyMaps()
	SetAllKeys( true )
}

; Set up or remove all hotkeys for all modifier keys
SetAllKeys( on ) {
	; Each of these modifier keys enables the same set of JKLmouse hotkeys
	SetKeys( on, "CapsLock" )
	SetKeys( on, "~LButton" )
	SetKeys( on, "~RButton" )
	SetKeys( on, "~MButton" )
	SetKeys( on, "~XButton1" )
	SetKeys( on, "~XButton2" )
}

; Set up or remove all the hotkeys for a specific modifier key
SetKeys( on, mod ) {
	global keyMap
	Loop, Parse, keyMap, %A_Space%
	{
		StringSplit map, A_LoopField, ~
		SetKey( on, mod, map1, "Mouse" . map2 )
	}
}

; Set up or remove one hotkey by combining the modifier and key names.
; Take the specified action on key down,
; and always stop acceleration on key up.
SetKey( on, mod, key, action ) {
	keydown = %mod% & %key%
	if( on ) {
		Hotkey, %keydown%, %action%, On
		Hotkey, %keydown% UP, StopAcceleration, On
	}
	else {
		Hotkey, %keydown%, %action%, Off
		Hotkey, %keydown% UP, StopAcceleration, Off
	}
}

; Move the mouse the specifed x and y distances, both scaled by the
; mouse acceleration factor calculated from the key repeat count.
Move( x, y ) {
	global accelerate, repeat
	++repeat
	factor := accelerate ? Floor( ( repeat + 1 ) / 2 ) : 1
	x := x * factor
	y := y * factor
	MouseMove, x, y, 0, R
}

;ArrayJoin( sep, ary ) {
;    for index, value in ary
;		MsgBox % index
;        ;str .= value . sep
;	MsgBox % str
;    return SubStr( str, 1, -StrLen(sep) )
;}

ToggleAccelerate() {
	global accelerate
	accelerate := ! accelerate
	RegWriteDword( "Accelerate", accelerate )
	action := accelerate ? "Check" : "Uncheck"
	Menu, Tray, %action%, Acceleration
}

; Handle the keydown for each of the mouse movement directions
; TODO: Maybe a way to simplify this?
MouseUp:
	Move( 0, -1 )
	return
MouseDown:
	Move( 0, 1 )
	return
MouseLeft:
	Move( -1, 0 )
	return
MouseRight:
	Move( 1, 0 )
	return
MouseUpLeft:
	Move( -1, -1 )
	return
MouseUpRight:
	Move( 1, -1 )
	return
MouseDownLeft:
	Move( -1, 1 )
	return
MouseDownRight:
	Move( 1, 1 )
	return

; Handle the keyup for all hotkeys
StopAcceleration:
	repeat = 0
	return

; Handle the About menu item
MenuAbout:
	MsgBox, 0x2040, JKLmouse by Geary Labs, JKLmouse version %version%`nAutoHotkey version %A_AhkVersion%
	return

; Handle the Website menu item
MenuWebsite:
	Run, http://www.jklmouse.com/
	return

MenuESDF:
	setKeysLeft( "ESDF" )
	return

MenuWASD:
	setKeysLeft( "WASD" )
	return

MenuIJKL:
	setKeysRight( "IJKL" )
	return

MenuHJKL:
	setKeysRight( "HJKL" )
	return

MenuAccelerate:
	toggleAccelerate()
	return

; JKLmouse for AutoHotkey by Michael Geary
; http://www.jklmouse.com/ - documentation
; http://unlicense.org/ - public domain statement

#SingleInstance force

SetRegView, 64

version := "0.2x"

; Use either the embedded icon in a compiled .exe,
; or a separate .ico file when running the .ahk script.
iconPath := RegExReplace( A_ScriptFullPath, "i).ahk$", ".ico" )

regKeySettings := "Software\JKLmouse"

; TODO: protect against invalid registry string
keysLeft := RegStringRead( "KeysLeft", "ESDF" )
keysRight := RegStringRead( "KeysRight", "IJKL" )

keyMap := ""

keyMaps :=
(join
{
	Arrows: "Up~Up Down~Down Left~Left Right~Right",
	NumPad: "7~UpLeft 8~Up 9~UpRight 4~Left 5~Down 6~Right 1~DownLeft 2~Down 3~DownRight",
	IJKL: "U~UpLeft I~Up O~UpRight J~Left K~Down L~Right M~DownLeft ,~Down .~DownRight",
	HJKL: "H~Left J~Down K~Up L~Right",
	ESDF: "W~UpLeft E~Up R~UpRight S~Left D~Down F~Right X~DownLeft C~Down V~DownRight",
	WASD: "Q~UpLeft W~Up E~UpRight A~Left S~Down D~Right Z~DownLeft X~Down C~DownRight"
}
)

; Set up the tray icon and menu
Menu, Tray, Icon, %iconPath%
Menu, Tray, Tip, JKLmouse
Menu, Tray, Add
Menu, Tray, Add, Left Hand: ESDF, MenuESDF
Menu, Tray, Add, Left Hand: WASD, MenuWASD
Menu, Tray, Add
Menu, Tray, Add, Right Hand: IJKL, MenuIJKL
Menu, Tray, Add, Right Hand: HJKL, MenuHJKL
Menu, Tray, Add
Menu, Tray, Add, About JKLmouse, MenuAbout
Menu, Tray, Add, JKLmouse Website, MenuWebsite

Menu, Tray, Check, Left Hand: %keysLeft%
Menu, Tray, Check, Right Hand: %keysRight%

; Display tray balloon
; TODO: more useful content?
; TODO: display this only during an install
TrayTip JKLmouse, The Automatic Keyboard Mouse

; Remove forced delay between triggered mouse events.
; TODO: experiment with this when accelerated
SetMouseDelay, -1

; Hotkey repeat count for acceleration
repeat := 0

SetAllKeyMaps()

;MsgBox % keyMap

SetAllKeys( true )

return

; Read a string value from our settings registry key, or return otherwise if not present
RegStringRead( name, otherwise ) {
	global regKeySettings
	value := ""
	RegRead, value, HKEY_CURRENT_USER, %regKeySettings%, %name%
	if( ErrorLevel )
		return %otherwise%
	return %value%
}

; Write a string value to our settings registry key
RegStringWrite( name, value ) {
	global regKeySettings
	RegWrite, REG_SZ, HKEY_CURRENT_USER, %regKeySettings%, %name%, %value%
}

; TODO: refactor SetKeysLeft() and SetKeysRight()!

SetKeysLeft( keys ) {
	global keysLeft
	if( keys = keysLeft )
		return
	Menu, Tray, Uncheck, Left Hand: %keysLeft%
	keysLeft := keys
	Menu, Tray, Check, Left Hand: %keysLeft%
	RegStringWrite( "KeysLeft", keysLeft )
	ReloadAllKeys()
}

SetKeysRight( keys ) {
	global keysRight
	if( keys = keysRight )
		return
	Menu, Tray, Uncheck, Right Hand: %keysRight%
	keysRight := keys
	Menu, Tray, Check, Right Hand: %keysRight%
	RegStringWrite( "KeysRight", keysRight )
	ReloadAllKeys()
}

; Load the entire set of key maps for all arrow pads and all modifiers
SetAllKeyMaps() {
	global keyMap, keysLeft, keysRight
	keyMap := ""
	SetKeyMap( "Arrows", "NumPad", keysLeft, keysRight )
}

; Load the specified key maps for all modifiers
SetKeyMap( keys* ) {
	global keyMap, keyMaps
    for index, value in keys
        keyMap .= keyMaps[value] . " "
    return SubStr( str, 1, -StrLen(sep) )
}

; Turn off existing key maps, reparse and reload new key maps
ReloadAllKeys() {
	SetAllKeys( false )
	SetAllKeyMaps()
	SetAllKeys( true )
}

; Set up or remove all hotkeys for all modifier keys
SetAllKeys( on ) {
	; Each of these modifier keys enables the same set of JKLmouse hotkeys
	SetKeys( on, "CapsLock" )
	SetKeys( on, "~LButton" )
	SetKeys( on, "~RButton" )
	SetKeys( on, "~MButton" )
	SetKeys( on, "~XButton1" )
	SetKeys( on, "~XButton2" )
}

; Set up or remove all the hotkeys for a specific modifier key
SetKeys( on, mod ) {
	global keyMap
	Loop, Parse, keyMap, %A_Space%
	{
		StringSplit map, A_LoopField, ~
		SetKey( on, mod, map1, "Mouse" . map2 )
	}
}

; Set up or remove one hotkey by combining the modifier and key names.
; Take the specified action on key down,
; and always stop acceleration on key up.
SetKey( on, mod, key, action ) {
	keydown = %mod% & %key%
	if( on ) {
		Hotkey, %keydown%, %action%, On
		Hotkey, %keydown% UP, StopAcceleration, On
	}
	else {
		Hotkey, %keydown%, %action%, Off
		Hotkey, %keydown% UP, StopAcceleration, Off
	}
}

; Move the mouse the specifed x and y distances, both scaled by the
; mouse acceleration factor calculated from the key repeat count.
Move( x, y ) {
	global repeat
	++repeat
	factor := Floor( ( repeat + 1 ) / 2 )
	x := x * factor
	y := y * factor
	MouseMove, x, y, 0, R
}

;ArrayJoin( sep, ary ) {
;    for index, value in ary
;		MsgBox % index
;        ;str .= value . sep
;	MsgBox % str
;    return SubStr( str, 1, -StrLen(sep) )
;}

; Handle the keydown for each of the mouse movement directions
; TODO: Maybe a way to simplify this?
MouseUp:
	Move( 0, -1 )
	return
MouseDown:
	Move( 0, 1 )
	return
MouseLeft:
	Move( -1, 0 )
	return
MouseRight:
	Move( 1, 0 )
	return
MouseUpLeft:
	Move( -1, -1 )
	return
MouseUpRight:
	Move( 1, -1 )
	return
MouseDownLeft:
	Move( -1, 1 )
	return
MouseDownRight:
	Move( 1, 1 )
	return

; Handle the keyup for all hotkeys
StopAcceleration:
	repeat = 0
	return

; Handle the About menu item
MenuAbout:
	MsgBox, 0x2040, JKLmouse by Geary Labs, JKLmouse version %version%`nAutoHotkey version %A_AhkVersion%
	return

; Handle the Website menu item
MenuWebsite:
	Run, http://www.jklmouse.com/
	return

MenuESDF:
	setKeysLeft( "ESDF" )
	return

MenuWASD:
	setKeysLeft( "WASD" )
	return

MenuIJKL:
	setKeysRight( "IJKL" )
	return

MenuHJKL:
	setKeysRight( "HJKL" )
	return


Use SendLevel, 1 instead of WshShell

Use SendLevel, 1 instead of WshShell

global ConfigPath
global vim
global ini
global default_enable_show_info
global editor
global VIMD_CMD_LIST
global WshShell

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

    ; 给 check.ahk 使用
    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")
}

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|wshkey|function)\|")
        {
            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|wshkey|function)\|")
            {
                /*
                示例：
                <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)^(function)\|", m)
    {
        splitedCommand:= StrSplit(substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2), "|")
        functionName := splitedCommand[1]
        if (IsFunc(functionName))
        {
            ; 简单起见只支持一个参数，需要更多函数的话请自行切割字符串
            %functionName%(splitedCommand[2])
        }
        else
        {
            MsgBox, %functionName% 函数不存在！
        }
    }
    else if RegExMatch(VIMD_CMD_LIST[obj.keytemp], "i)^(tccmd)\|", m)
    {
        TC_Run(substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2))
    }
    else if RegExMatch(VIMD_CMD_LIST[obj.keytemp], "i)^(wshkey)\|", m)
    {
        /*
        if (!WshShell)
        {
            WshShell := ComObjCreate("WScript.Shell")
        }

        WshShell.SendKeys(substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2))
        */

        SendLevel, 1
        Send, % 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 未能获取管理员权限，这可能导致部分功能无法运行。
}
*/

global ConfigPath
global vim
global ini
global default_enable_show_info
global editor
global VIMD_CMD_LIST
global WshShell

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

    ; 给 check.ahk 使用
    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")
}

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|wshkey|function)\|")
        {
            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|wshkey|function)\|")
            {
                /*
                示例：
                <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)^(function)\|", m)
    {
        splitedCommand:= StrSplit(substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2), "|")
        functionName := splitedCommand[1]
        if (IsFunc(functionName))
        {
            ; 简单起见只支持一个参数，需要更多函数的话请自行切割字符串
            %functionName%(splitedCommand[2])
        }
        else
        {
            MsgBox, %functionName% 函数不存在！
        }
    }
    else if RegExMatch(VIMD_CMD_LIST[obj.keytemp], "i)^(tccmd)\|", m)
    {
        TC_Run(substr(VIMD_CMD_LIST[obj.keytemp], strlen(m1) + 2))
    }
    else if RegExMatch(VIMD_CMD_LIST[obj.keytemp], "i)^(wshkey)\|", m)
    {
        if (!WshShell)
        {
            WshShell := ComObjCreate("WScript.Shell")
        }

        WshShell.SendKeys(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 未能获取管理员权限，这可能导致部分功能无法运行。
}
*/