toggle caption lock led for chinese input status

global ChineseLayout := 0

SetCapsLockState, AlwaysOff
+CapsLock::CapsLock

CapsLock::
    Send, {Alt Down}{Shift Down}{Shift Up}{Alt Up}
    ChineseLayout := !ChineseLayout
    If ChineseLayout = 1
        KeyboardLED(4, "on")
    Else
        KeyboardLED(4, "off")
return

/*

    Keyboard LED control for AutoHotkey_L
        http://www.autohotkey.com/forum/viewtopic.php?p=468000#468000

    KeyboardLED(LEDvalue, "Cmd", Kbd)
        LEDvalue  - ScrollLock=1, NumLock=2, CapsLock=4
        Cmd       - on/off/switch
        Kbd       - index of keyboard (probably 0 or 2)

*/

KeyboardLED(LEDvalue, Cmd, Kbd=0)
{
  SetUnicodeStr(fn,"\Device\KeyBoardClass" Kbd)
  h_device:=NtCreateFile(fn,0+0x00000100+0x00000080+0x00100000,1,1,0x00000040+0x00000020,0)

  If Cmd= switch  ;switches every LED according to LEDvalue
   KeyLED:= LEDvalue
  If Cmd= on  ;forces all choosen LED's to ON (LEDvalue= 0 ->LED's according to keystate)
   KeyLED:= LEDvalue | (GetKeyState("ScrollLock", "T") + 2*GetKeyState("NumLock", "T") + 4*GetKeyState("CapsLock", "T"))
  If Cmd= off  ;forces all choosen LED's to OFF (LEDvalue= 0 ->LED's according to keystate)
    {
    LEDvalue:= LEDvalue ^ 7
    KeyLED:= LEDvalue & (GetKeyState("ScrollLock", "T") + 2*GetKeyState("NumLock", "T") + 4*GetKeyState("CapsLock", "T"))
    }

  success := DllCall( "DeviceIoControl"
              ,  "ptr", h_device
              , "uint", CTL_CODE( 0x0000000b     ; FILE_DEVICE_KEYBOARD
                        , 2
                        , 0             ; METHOD_BUFFERED
                        , 0  )          ; FILE_ANY_ACCESS
              , "int*", KeyLED << 16
              , "uint", 4
              ,  "ptr", 0
              , "uint", 0
              ,  "ptr*", output_actual
              ,  "ptr", 0 )

  NtCloseFile(h_device)
  return success
}

CTL_CODE( p_device_type, p_function, p_method, p_access )
{
  Return, ( p_device_type << 16 ) | ( p_access << 14 ) | ( p_function << 2 ) | p_method
}

NtCreateFile(ByRef wfilename,desiredaccess,sharemode,createdist,flags,fattribs)
{
  VarSetCapacity(objattrib,6*A_PtrSize,0)
  VarSetCapacity(io,2*A_PtrSize,0)
  VarSetCapacity(pus,2*A_PtrSize)
  DllCall("ntdll\RtlInitUnicodeString","ptr",&pus,"ptr",&wfilename)
  NumPut(6*A_PtrSize,objattrib,0)
  NumPut(&pus,objattrib,2*A_PtrSize)
  status:=DllCall("ntdll\ZwCreateFile","ptr*",fh,"UInt",desiredaccess,"ptr",&objattrib
                  ,"ptr",&io,"ptr",0,"UInt",fattribs,"UInt",sharemode,"UInt",createdist
                  ,"UInt",flags,"ptr",0,"UInt",0, "UInt")
  return % fh
}

NtCloseFile(handle)
{
  return DllCall("ntdll\ZwClose","ptr",handle)
}

SetUnicodeStr(ByRef out, str_)
{
  VarSetCapacity(out,2*StrPut(str_,"utf-16"))
  StrPut(str_,&out,"utf-16")
}

SetCapsLockState, AlwaysOff
+CapsLock::CapsLock

CapsLock::Send, {Alt Down}{Shift Down}{Shift Up}{Alt Up}
return


Add acceleration

Add acceleration

; Using Keyboard Numpad as a Mouse -- by deguix
; http://www.autohotkey.com

;START OF CONFIG SECTION

#SingleInstance force
#MaxHotkeysPerInterval 500

; Using the keyboard hook to implement the Numpad hotkeys prevents
; them from interfering with the generation of ANSI characters such
; as .  This is because AutoHotkey generates such characters
; by holding down ALT and sending a series of Numpad keystrokes.
; Hook hotkeys are smart enough to ignore such keystrokes.
#UseHook

MouseSpeed = 1
MouseAccelerationSpeed = 1
MouseMaxSpeed = 5

;Mouse wheel speed is also set on Control Panel. As that
;will affect the normal mouse behavior, the real speed of
;these three below are times the normal mouse wheel speed.
MouseWheelSpeed = 1
MouseWheelAccelerationSpeed = 1
MouseWheelMaxSpeed = 5

;END OF CONFIG SECTION

;This is needed or key presses would faulty send their natural
;actions. Like NumPadDiv would send sometimes "/" to the
;screen.
#InstallKeybdHook

repeat = 0

Temp = 0
Temp2 = 0

MouseCurrentAccelerationSpeed = 0
MouseCurrentSpeed = %MouseSpeed%

MouseWheelCurrentAccelerationSpeed = 0
MouseWheelCurrentSpeed = %MouseSpeed%

SetKeyDelay, -1
SetMouseDelay, -1

SetHotkeys( modifier ) {
	; Left hand
	Hotkey, %modifier% & W, MouseLeftUp
	Hotkey, %modifier% & E, MouseUp
	Hotkey, %modifier% & R, MouseRightUp
	Hotkey, %modifier% & S, MouseLeft
	Hotkey, %modifier% & D, MouseDown
	Hotkey, %modifier% & F, MouseRight
	Hotkey, %modifier% & X, MouseLeftDown
	Hotkey, %modifier% & C, MouseDown
	Hotkey, %modifier% & V, MouseRightDown

	; Right hand
	Hotkey, %modifier% & U, MouseLeftUp
	Hotkey, %modifier% & I, MouseUp
	Hotkey, %modifier% & O, MouseRightUp
	Hotkey, %modifier% & J, MouseLeft
	Hotkey, %modifier% & K, MouseDown
	Hotkey, %modifier% & L, MouseRight
	Hotkey, %modifier% & M, MouseLeftDown
	Hotkey, %modifier% & `, , MouseDown
	Hotkey, %modifier% & `. , MouseRightDown

	; Numeric
	Hotkey, %modifier% & 7, MouseLeftUp
	Hotkey, %modifier% & 8, MouseUp
	Hotkey, %modifier% & 9, MouseRightUp
	Hotkey, %modifier% & 4, MouseLeft
	Hotkey, %modifier% & 5, MouseDown
	Hotkey, %modifier% & 6, MouseRight
	Hotkey, %modifier% & 1, MouseLeftDown
	Hotkey, %modifier% & 2, MouseDown
	Hotkey, %modifier% & 3, MouseRightDown

	; Arrows
	Hotkey, %modifier% & Up, MouseUp
	Hotkey, %modifier% & Down, MouseDown
	Hotkey, %modifier% & Left, MouseLeft
	Hotkey, %modifier% & Right, MouseRight
}

SetHotkeys( "CapsLock" )
SetHotkeys( "~LButton" )
SetHotkeys( "~RButton" )
SetHotkeys( "~MButton" )
SetHotkeys( "~XButton1" )
SetHotkeys( "~XButton2" )

return

Move( x, y ) {
	global repeat
	++repeat
	factor := Floor( ( repeat + 1 ) / 2 )
	x := x * factor
	y := y * factor
	MouseMove, x, y, 0, R
}

MouseUp:
	Move( 0, -1 )
	return
MouseDown:
	Move( 0, 1 )
	return
MouseLeft:
	Move( -1, 0 )
	return
MouseRight:
	Move( 1, 0 )
	return
MouseLeftUp:
	Move( -1, -1 )
	return
MouseRightUp:
	Move( 1, -1 )
	return
MouseLeftDown:
	Move( -1, 1 )
	return
MouseRightDown:
	Move( 1, 1 )
	return

If Action <> 0
{
	IfNotInString, A_ThisLabel, %Action%
	{
		MouseCurrentAccelerationSpeed = 0
		MouseCurrentSpeed = %MouseSpeed%
	}
}
StringReplace, Action, A_ThisLabel, *

ButtonAccelerationStart:
If MouseAccelerationSpeed >= 1
{
	If MouseMaxSpeed > %MouseCurrentSpeed%
	{
		Temp = 0.001
		Temp *= %MouseAccelerationSpeed%
		MouseCurrentAccelerationSpeed += %Temp%
		MouseCurrentSpeed += %MouseCurrentAccelerationSpeed%
	}
}

MouseCurrentSpeedToDirection = 1

MouseCurrentSpeedToSide = 0

MouseCurrentSpeedToDirection *= %MouseCurrentSpeed%
MouseCurrentSpeedToSide *= %MouseCurrentSpeed%

Temp = 0

If Action = MouseUp
{
	MouseCurrentSpeedToDirection *= -1
	MouseMove, %MouseCurrentSpeedToSide%, %MouseCurrentSpeedToDirection%, 0, R
}
else if Action = MouseDown
{
	MouseCurrentSpeedToSide *= -1
	MouseMove, %MouseCurrentSpeedToSide%, %MouseCurrentSpeedToDirection%, 0, R
}
else if Action = MouseLeft
{
	MouseCurrentSpeedToSide *= -1
	MouseCurrentSpeedToDirection *= -1

	MouseMove, %MouseCurrentSpeedToDirection%, %MouseCurrentSpeedToSide%, 0, R
}
else if Action = MouseRight
{
	MouseMove, %MouseCurrentSpeedToDirection%, %MouseCurrentSpeedToSide%, 0, R
}
else if Action = MouseLeftUp
{
	Temp = %MouseCurrentSpeedToDirection%
	Temp -= %MouseCurrentSpeedToSide%
	Temp *= -1
	Temp2 = %MouseCurrentSpeedToDirection%
	Temp2 += %MouseCurrentSpeedToSide%
	Temp2 *= -1
	MouseMove, %Temp%, %Temp2%, 0, R
}
else if Action = MouseRightUp
{
	Temp = %MouseCurrentSpeedToDirection%
	Temp += %MouseCurrentSpeedToSide%
	Temp2 = %MouseCurrentSpeedToDirection%
	Temp2 -= %MouseCurrentSpeedToSide%
	Temp2 *= -1
	MouseMove, %Temp%, %Temp2%, 0, R
}
else if Action = MouseLeftDown
{
	Temp = %MouseCurrentSpeedToDirection%
	Temp += %MouseCurrentSpeedToSide%
	Temp *= -1
	Temp2 = %MouseCurrentSpeedToDirection%
	Temp2 -= %MouseCurrentSpeedToSide%
	MouseMove, %Temp%, %Temp2%, 0, R
}
else if Action = MouseRightDown
{
	Temp = %MouseCurrentSpeedToDirection%
	Temp -= %MouseCurrentSpeedToSide%
	Temp2 *= -1
	Temp2 = %MouseCurrentSpeedToDirection%
	Temp2 += %MouseCurrentSpeedToSide%
	MouseMove, %Temp%, %Temp2%, 0, R
}

SetTimer, ButtonAccelerationEnd, 10
return

ButtonAccelerationEnd:
GetKeyState, kstate, %Action%, P
if kstate = D
	Goto ButtonAccelerationStart

SetTimer, ButtonAccelerationEnd, off
MouseCurrentAccelerationSpeed = 0
MouseCurrentSpeed = %MouseSpeed%
Action = 0
return

; Using Keyboard Numpad as a Mouse -- by deguix
; http://www.autohotkey.com

;START OF CONFIG SECTION

#SingleInstance force
#MaxHotkeysPerInterval 500

; Using the keyboard hook to implement the Numpad hotkeys prevents
; them from interfering with the generation of ANSI characters such
; as .  This is because AutoHotkey generates such characters
; by holding down ALT and sending a series of Numpad keystrokes.
; Hook hotkeys are smart enough to ignore such keystrokes.
#UseHook

MouseSpeed = 1
MouseAccelerationSpeed = 1
MouseMaxSpeed = 5

;Mouse wheel speed is also set on Control Panel. As that
;will affect the normal mouse behavior, the real speed of
;these three below are times the normal mouse wheel speed.
MouseWheelSpeed = 1
MouseWheelAccelerationSpeed = 1
MouseWheelMaxSpeed = 5

;END OF CONFIG SECTION

;This is needed or key presses would faulty send their natural
;actions. Like NumPadDiv would send sometimes "/" to the
;screen.
#InstallKeybdHook

Temp = 0
Temp2 = 0

MouseCurrentAccelerationSpeed = 0
MouseCurrentSpeed = %MouseSpeed%

MouseWheelCurrentAccelerationSpeed = 0
MouseWheelCurrentSpeed = %MouseSpeed%

SetKeyDelay, -1
SetMouseDelay, -1

SetHotkeys( modifier ) {
	; Left hand
	Hotkey, %modifier% & W, MouseLeftUp
	Hotkey, %modifier% & E, MouseUp
	Hotkey, %modifier% & R, MouseRightUp
	Hotkey, %modifier% & S, MouseLeft
	Hotkey, %modifier% & D, MouseDown
	Hotkey, %modifier% & F, MouseRight
	Hotkey, %modifier% & X, MouseLeftDown
	Hotkey, %modifier% & C, MouseDown
	Hotkey, %modifier% & V, MouseRightDown

	; Right hand
	Hotkey, %modifier% & U, MouseLeftUp
	Hotkey, %modifier% & I, MouseUp
	Hotkey, %modifier% & O, MouseRightUp
	Hotkey, %modifier% & J, MouseLeft
	Hotkey, %modifier% & K, MouseDown
	Hotkey, %modifier% & L, MouseRight
	Hotkey, %modifier% & M, MouseLeftDown
	Hotkey, %modifier% & `, , MouseDown
	Hotkey, %modifier% & `. , MouseRightDown

	; Numeric
	Hotkey, %modifier% & 7, MouseLeftUp
	Hotkey, %modifier% & 8, MouseUp
	Hotkey, %modifier% & 9, MouseRightUp
	Hotkey, %modifier% & 4, MouseLeft
	Hotkey, %modifier% & 5, MouseDown
	Hotkey, %modifier% & 6, MouseRight
	Hotkey, %modifier% & 1, MouseLeftDown
	Hotkey, %modifier% & 2, MouseDown
	Hotkey, %modifier% & 3, MouseRightDown

	; Arrows
	Hotkey, %modifier% & Up, MouseUp
	Hotkey, %modifier% & Down, MouseDown
	Hotkey, %modifier% & Left, MouseLeft
	Hotkey, %modifier% & Right, MouseRight
}

SetHotkeys( "CapsLock" )
SetHotkeys( "~LButton" )
SetHotkeys( "~RButton" )
SetHotkeys( "~MButton" )
SetHotkeys( "~XButton1" )
SetHotkeys( "~XButton2" )

return

Move( x, y ) {
	MouseMove, x, y, 0, R
}

MouseUp:
	Move( 0, -1 )
	return
MouseDown:
	Move( 0, 1 )
	return
MouseLeft:
	Move( -1, 0 )
	return
MouseRight:
	Move( 1, 0 )
	return
MouseLeftUp:
	Move( -1, -1 )
	return
MouseRightUp:
	Move( 1, -1 )
	return
MouseLeftDown:
	Move( -1, 1 )
	return
MouseRightDown:
	Move( 1, 1 )
	return

If Action <> 0
{
	IfNotInString, A_ThisLabel, %Action%
	{
		MouseCurrentAccelerationSpeed = 0
		MouseCurrentSpeed = %MouseSpeed%
	}
}
StringReplace, Action, A_ThisLabel, *

ButtonAccelerationStart:
If MouseAccelerationSpeed >= 1
{
	If MouseMaxSpeed > %MouseCurrentSpeed%
	{
		Temp = 0.001
		Temp *= %MouseAccelerationSpeed%
		MouseCurrentAccelerationSpeed += %Temp%
		MouseCurrentSpeed += %MouseCurrentAccelerationSpeed%
	}
}

MouseCurrentSpeedToDirection = 1

MouseCurrentSpeedToSide = 0

MouseCurrentSpeedToDirection *= %MouseCurrentSpeed%
MouseCurrentSpeedToSide *= %MouseCurrentSpeed%

Temp = 0

If Action = MouseUp
{
	MouseCurrentSpeedToDirection *= -1
	MouseMove, %MouseCurrentSpeedToSide%, %MouseCurrentSpeedToDirection%, 0, R
}
else if Action = MouseDown
{
	MouseCurrentSpeedToSide *= -1
	MouseMove, %MouseCurrentSpeedToSide%, %MouseCurrentSpeedToDirection%, 0, R
}
else if Action = MouseLeft
{
	MouseCurrentSpeedToSide *= -1
	MouseCurrentSpeedToDirection *= -1

	MouseMove, %MouseCurrentSpeedToDirection%, %MouseCurrentSpeedToSide%, 0, R
}
else if Action = MouseRight
{
	MouseMove, %MouseCurrentSpeedToDirection%, %MouseCurrentSpeedToSide%, 0, R
}
else if Action = MouseLeftUp
{
	Temp = %MouseCurrentSpeedToDirection%
	Temp -= %MouseCurrentSpeedToSide%
	Temp *= -1
	Temp2 = %MouseCurrentSpeedToDirection%
	Temp2 += %MouseCurrentSpeedToSide%
	Temp2 *= -1
	MouseMove, %Temp%, %Temp2%, 0, R
}
else if Action = MouseRightUp
{
	Temp = %MouseCurrentSpeedToDirection%
	Temp += %MouseCurrentSpeedToSide%
	Temp2 = %MouseCurrentSpeedToDirection%
	Temp2 -= %MouseCurrentSpeedToSide%
	Temp2 *= -1
	MouseMove, %Temp%, %Temp2%, 0, R
}
else if Action = MouseLeftDown
{
	Temp = %MouseCurrentSpeedToDirection%
	Temp += %MouseCurrentSpeedToSide%
	Temp *= -1
	Temp2 = %MouseCurrentSpeedToDirection%
	Temp2 -= %MouseCurrentSpeedToSide%
	MouseMove, %Temp%, %Temp2%, 0, R
}
else if Action = MouseRightDown
{
	Temp = %MouseCurrentSpeedToDirection%
	Temp -= %MouseCurrentSpeedToSide%
	Temp2 *= -1
	Temp2 = %MouseCurrentSpeedToDirection%
	Temp2 += %MouseCurrentSpeedToSide%
	MouseMove, %Temp%, %Temp2%, 0, R
}

SetTimer, ButtonAccelerationEnd, 10
return

ButtonAccelerationEnd:
GetKeyState, kstate, %Action%, P
if kstate = D
	Goto ButtonAccelerationStart

SetTimer, ButtonAccelerationEnd, off
MouseCurrentAccelerationSpeed = 0
MouseCurrentSpeed = %MouseSpeed%
Action = 0
return


Delete Effectivity macro - backup.ahk

Delete Effectivity macro - backup.ahk


ctrl, alt, shift

ctrl, alt, shift

; win: #, ctrl: ^, alt: !, shift: +
#z::
!z::
+z::
temp_txt = %userprofile%\git\youdao\word.txt
tempClipboard = %ClipboardAll%
Clipboard =
Send, ^c
ClipWait, 1
FileDelete, %temp_txt%
if (Clipboard != "") {
    FileAppend, %Clipboard%, %temp_txt%
}
Clipboard = %tempClipboard%  ; ClipboardAll no allowed as an output variable
tempClipboard =
return

#z::
temp_txt = %userprofile%\git\youdao\word.txt
tempClipboard = %ClipboardAll%
Clipboard =
Send, ^c
ClipWait, 1
FileDelete, %temp_txt%
if (Clipboard != "") {
    FileAppend, %Clipboard%, %temp_txt%
}
Clipboard = %tempClipboard%  ; ClipboardAll no allowed as an output variable
tempClipboard =
return


Add <WindowMaxNoTitle>

Add <WindowMaxNoTitle>

General:
    Gen_Save_Win := []
    vim.SetAction("<down>", "向下移动")
    vim.SetAction("<up>", "向上移动")
    vim.SetAction("<left>", "向左移动")
    vim.SetAction("<right>", "向右移动")
    vim.SetAction("<home>", "home键")
    vim.SetAction("<end>", "end键")
    vim.SetAction("<Gen_InsertMode>", "插入模式")
    vim.SetAction("<Gen_NormalMode>", "浏览模式")
    vim.SetAction("<Gen_Toggle>", "启用/禁用vim热键(General插件)")
    vim.SetAction("<Reload>", "重新加载")
    vim.SetAction("<WindowMoveDown>", "窗口移动到下方")
    vim.SetAction("<WindowMoveUp>", "窗口移动到上方")
    vim.SetAction("<WindowMoveLeft>", "窗口移动到左侧")
    vim.SetAction("<WindowMoveRight>", "窗口移动到右侧")
    vim.SetAction("<WindowMoveCenter>", "窗口移动到中间")
    vim.SetAction("<WindowMax>", "最大化窗口")
    vim.SetAction("<WindowMaxNoTitle>", "最大化窗口，并且隐藏标题栏")
    vim.SetAction("<WindowMin>", "最小化窗口")
    vim.SetAction("<WindowRestore>", "还原当前窗口")
    vim.SetAction("<FullScreen>", "全屏当前程序")
    vim.SetAction("<NextTab>", "下一个标签")
    vim.SetAction("<PrevTab>", "前一个标签")
    vim.SetAction("<CloseTab>", "关闭当前标签")
    vim.SetAction("<NewTab>", "新建标签")
    vim.SetAction("<ActivateTab1>", "激活第一个标签")
    vim.SetAction("<ActivateTab2>", "激活第二个标签")
    vim.SetAction("<ActivateTab3>", "激活第三个标签")
    vim.SetAction("<ActivateTab4>", "激活第四个标签")
    vim.SetAction("<ActivateTab5>", "激活第五个标签")
    vim.SetAction("<ActivateTab6>", "激活第六个标签")
    vim.SetAction("<ActivateTab7>", "激活第七个标签")
    vim.SetAction("<ActivateTab8>", "激活第八个标签")
    vim.SetAction("<ActivateTab9>", "激活第九个标签")
    vim.SetAction("<ActivateTab0>", "激活最后一个标签")
    vim.SetAction("<pgup>", "上一页")
    vim.SetAction("<pgdn>", "下一页")
    vim.SetAction("<enter>", "回车键")
    vim.SetAction("<space>", "空格键")
    vim.SetAction("<backspace>", "退格键")
    vim.SetAction("<Pass>", "屏蔽按键")
    vim.SetAction("<Media_Next>", "播放下一首")
    vim.SetAction("<Media_Prev>", "播放上一首")
    vim.SetAction("<Media_Play_Pause>", "播放/停止")
    vim.SetAction("<Media_Stop>", "停止播放")
    vim.SetAction("<RemoveToolTip>", "清除屏幕的ToolTip")
    vim.SetAction("<ShowHelp>", "显示所有按键帮助信息")
    vim.SetAction("<ToggleCapsLock>", "切换大小写")
    vim.SetAction("<MouseUp>", "向上移动鼠标")
    vim.SetAction("<MouseDown>", "向下移动鼠标")
    vim.SetAction("<MouseLeft>", "向左移动鼠标")
    vim.SetAction("<MouseRight>", "向右移动鼠标")
    vim.SetAction("<SearchInWeb>", "在网络搜索剪切板内容")
    vim.SetAction("<RunZ>", "运行 RunZ")
    vim.SetAction("<Test>", "测试")

    vim.SetWin("General", "General")
    vim.SetMode("insert", "General")
    vim.map("<Esc>", "<Gen_NormalMode>", "General")
    vim.SetMode("normal", "General")
    vim.map("i", "<Gen_InsertMode>", "General")
    vim.map("0", "<0>", "General")
    vim.map("1", "<1>", "General")
    vim.map("2", "<2>", "General")
    vim.map("3", "<3>", "General")
    vim.map("4", "<4>", "General")
    vim.map("5", "<5>", "General")
    vim.map("6", "<6>", "General")
    vim.map("7", "<7>", "General")
    vim.map("8", "<8>", "General")
    vim.map("9", "<9>", "General")
    vim.map("k", "<up>", "General")
    vim.map("j", "<down>", "General")
    vim.map("k", "<up>", "General")
    vim.map("h", "<left>", "General")
    vim.map("l", "<right>", "General")
    vim.map("zj", "<WindowMoveDown>", "General")
    vim.map("zk", "<WindowMoveUp>", "General")
    vim.map("zh", "<WindowMoveLeft>", "General")
    vim.map("zl", "<WindowMoveRight>", "General")
    vim.map("zc", "<WindowMoveCenter>", "General")
    vim.map("zf", "<fullscreen>", "General")
    vim.map("zm", "<WindowMax>", "General")
    vim.map("zn", "<WindowMin>", "General")
    vim.map("zr", "<WindowRestore>", "General")
    vim.map("t", "<NewTab>", "General")
    vim.map("x", "<CloseTab>", "General")
    vim.map("gn", "<NextTab>", "General")
    vim.map("gp", "<PrevTab>", "General")
    vim.map("g1", "<ActivateTab1>", "General")
    vim.map("g2", "<ActivateTab2>", "General")
    vim.map("g3", "<ActivateTab3>", "General")
    vim.map("g4", "<ActivateTab4>", "General")
    vim.map("g5", "<ActivateTab5>", "General")
    vim.map("g6", "<ActivateTab6>", "General")
    vim.map("g7", "<ActivateTab7>", "General")
    vim.map("g8", "<ActivateTab8>", "General")
    vim.map("g9", "<ActivateTab9>", "General")
    vim.map("g0", "<ActivateTab0>", "General")
    vim.BeforeActionDo("Gen_Before", "General")
return

Gen_Before()
{
    Global vim
    WinGet, MenuID, ID, AHK_CLASS #32768
    If MenuID
        return True
}

<Gen_InsertMode>:
    vim.SetMode("Insert", vim.CheckWin())
    Tooltip, Insert模式, , , 19
    Settimer, cancelTooltip, 1200
return
<Gen_NormalMode>:
    vim.SetMode("Normal", vim.CheckWin())
    Tooltip, Normal模式, , , 19
    Settimer, cancelTooltip, 1200
return
<Gen_Toggle>:
    Gen_Toggle()
return
Gen_Toggle()
{
    Global vim, Gen_Save_Win
    WinGetClass, c, A
    WinGet, f, ProcessPath, ahk_class %c%
    WinName:=vim.CheckWin()
    If not Gen_Save_Win[c]
    {
        If Strlen(winName) And IsObject(vim.GetWin(winName))
        {
            MsgBox, , VimDesktop, 当前窗口 [ %winName% ] 已经拥有Vim模式`n不允许替换为通用(General)模式！
            return
        }
    }
    winObj := vim.GetWin(c)
    If not Isobject(winObj)
    {
        vim.copy("General", c, c, f)
        Gen_Save_Win[c] := True
        Tooltip, 复制VIMD热键到当前窗口成功, , , 19
    }
    Else
    {
        if vim.Toggle(c)
            Tooltip, 激活当前窗口的VIMD热键, , , 19
        else
            Tooltip, 取消当前窗口的VIMD热键, , , 19
    }
    Settimer, cancelTooltip, 1200
}
cancelTooltip:
    Tooltip, , , , 19
return
<reload>:
    reload
return
<Exit>:
    ExitApp
return
<down>:
    send, {down}
return
<up>:
    send, {up}
return
<left>:
    send, {left}
return
<right>:
    send, {right}
return
<home>:
    send, {home}
return
<end>:
    send, {end}
return
<pgup>:
    send, {pgup}
return
<pgdn>:
    send, {pgdn}
return
<enter>:
    send, {enter}
return
<space>:
    send, {space}
return
<backspace>:
    send, {backspace}
return
<Media_Next>:
    send, {Media_Next}
return
<Media_Prev>:
    send, {Media_Prev}
return
<Media_Stop>:
    send, {Media_Stop}
return
<Media_Play_Pause>:
    send, {Media_Play_Pause}
return

<WindowMoveDown>:
    WindowPadMove("0, +1, 1.0, 0.5")
Return
<WindowMoveUp>:
    WindowPadMove("0, -1, 1.0, 0.5")
Return
<WindowMoveLeft>:
    WindowPadMove("-1, 0, 0.5, 1.0")
Return
<WindowMoveRight>:
    WindowPadMove("+1, 0, 0.5, 1.0")
Return
<WindowMoveCenter>:
    WindowPadMove("0, 0, 0.5, 0.7")
return
<WindowMax>:
    WinMaximize, A
return
<WindowMaxNoTitle>:
    WinMaximize, A
    WinSet, Style, -0xc00000, A
return
<WindowMin>:
    WinMinimize, A
return
<WindowRestore>:
    WinRestore, A
return

; 全屏当前程序
<FullScreen>:
    FullScreen()
return
FullScreen() {
    WinGet, windowID, ID, A
    WindowState := FullScreenID[windowID]
    If Strlen(windowState) = 0
        WindowState := 0
    If WindowState
    {
        WinSet, Style, ^0xC40000, ahk_id %WindowID%
        Loop, Parse, windowState, `,
        {
            If A_Index = 2
                WinPosX := A_LoopField
            If A_Index = 3
                WinPosY := A_LoopField
            If A_Index = 4
                WindowWidth := A_LoopField
            If A_Index = 5
                WindowHeight := A_LoopField
        }
        WinMove, ahk_id %WindowID%, , WinPosX, WinPosY, WindowWidth, WindowHeight
        WindowState := 0
    }
    Else
    {
        WinGetPos, WinPosX, WinPosY, WindowWidth, WindowHeight, ahk_id %WindowID%
        WinSet, Style, ^0xC40000, ahk_id %WindowID%
        WinMove, ahk_id %WindowID%, , 0, 0, A_ScreenWidth, A_ScreenHeight
        WindowState := 1 ", " WinPosX ", " WinPosY ", " WindowWidth ", " WindowHeight
        ;Msgbox 再按一下刚刚的热键退出全屏
    }
    FullScreenID[windowID] := WindowState
}

;====================================================================================
;
; WindowPad.ahk
; Version: 0.4
; Last Updated: 11/5/2009
;
; This file contains functions which are useful for manipulating and moving windows.
; This is a stripped down version of WindowPad v.1.56 by Lexikos.
; Downloaded from http://www.autohotkey.com/forum/topic21703.html
;

WindowPadMove(P)
{
    StringSplit, P, P, `, , %A_Space%%A_Tab%
    ; Params: 1:dirX, 2:dirY, 3:widthFactor, 4:heightFactor, 5:window

    if P1 =
        P1 = R
    if P2 =
        P2 = R

    WindowPad_WinExist(P5)

    if !WinExist()
        return

    ; Determine width/height factors.
    if (P1 or P2) {
        ; to a side
        widthFactor := P3+0 ? P3 : (P1 ? 0.5 : 1.0)
        heightFactor := P4+0 ? P4 : (P2 ? 0.5 : 1.0)
    } else {
        ; to center
        widthFactor  := P3+0 ? P3 : 1.0
        heightFactor := P4+0 ? P4 : 1.0
    }

    ; Move the window!
    MoveWindowInDirection(P1, P2, widthFactor, heightFactor)
}

MaximizeToggle(P)
{
    WindowPad_WinExist(P)

    WinGet, state, MinMax
    if state
        WinRestore
    else
        WinMaximize
}

; Does the grunt work of the script.
MoveWindowInDirection(sideX, sideY, widthFactor, heightFactor)
{
    WinGetPos, x, y, w, h

    hwnd:=WinExist()
    if (can_restore := GetWindowProperty(hwnd, "wpHasRestorePos"))
    {   ; Window has restore info. Check if it is where we last put it.
        last_x := GetWindowProperty(hwnd, "wpLastX")
        last_y := GetWindowProperty(hwnd, "wpLastY")
        last_w := GetWindowProperty(hwnd, "wpLastW")
        last_h := GetWindowProperty(hwnd, "wpLastH")
    }
    if (can_restore && last_x = x && last_y = y && last_w = w && last_h = h)
    {   ; Window is where we last put it. Check if user wants to restore.
        if SubStr(sideX, 1, 1) = "R"
        {   ; Restore on X-axis.
            restore_x := GetWindowProperty(hwnd, "wpRestoreX")
            restore_w := GetWindowProperty(hwnd, "wpRestoreW")
            StringTrimLeft, sideX, sideX, 1
        }
        if SubStr(sideY, 1, 1) = "R"
        {   ; Restore on Y-axis.
            restore_y := GetWindowProperty(hwnd, "wpRestoreY")
            restore_h := GetWindowProperty(hwnd, "wpRestoreH")
            StringTrimLeft, sideY, sideY, 1
        }
        if (restore_x != "" || restore_y != "")
        {   ; If already at the "restored" size and position, do the normal thing instead.
            if ((restore_x = x || restore_x = "") && (restore_y = y || restore_y = "")
                && (restore_w = w || restore_w = "") && (restore_h = h || restore_h = ""))
            {
                restore_x =
                restore_y =
                restore_w =
                restore_h =
            }
        }
    }
    else
    {   ; Next time user requests the window be "restored" use this position and size.
        SetWindowProperty(hwnd, "wpHasRestorePos", true)
        SetWindowProperty(hwnd, "wpRestoreX", x)
        SetWindowProperty(hwnd, "wpRestoreY", y)
        SetWindowProperty(hwnd, "wpRestoreW", w)
        SetWindowProperty(hwnd, "wpRestoreH", h)

        if SubStr(sideX, 1, 1) = "R"
            StringTrimLeft, sideX, sideX, 1
        if SubStr(sideY, 1, 1) = "R"
            StringTrimLeft, sideY, sideY, 1
    }

    ; If no direction specified, restore or only switch monitors.
    if (sideX+0 = "" && restore_x = "")
        restore_x := x, restore_w := w
    if (sideY+0 = "" && restore_y = "")
        restore_y := y, restore_h := h

    ; Determine which monitor contains the center of the window.
    m := GetMonitorAt(x+w/2, y+h/2)

    ; Get work area of active monitor.
    gosub CalcMonitorStats
    ; Calculate possible new position for window.
    gosub CalcNewSizeAndPosition

    ; If the window is already there,
    if (newx ", " newy ", " neww ", " newh) = (x ", " y ", " w ", " h)
    {   ; ..move to the next monitor along instead.

        if (sideX or sideY)
        {   ; Move in the direction of sideX or sideY.
            SysGet, monB, Monitor, %m% ; get bounds of entire monitor (vs. work area)
            x := (sideX=0) ? (x+w/2) : (sideX>0 ? monBRight : monBLeft) + sideX
            y := (sideY=0) ? (y+h/2) : (sideY>0 ? monBBottom : monBTop) + sideY
            newm := GetMonitorAt(x, y, m)
        }
        else
        {   ; Move to center (Numpad5)
            newm := m+1
            SysGet, mon, MonitorCount
            if (newm > mon)
                newm := 1
        }

        if (newm != m)
        {
            m := newm
            ; Move to opposite side of monitor (left of a monitor is another monitor's right edge)
            sideX *= -1
            sideY *= -1
            ; Get new monitor's work area.
            gosub CalcMonitorStats
        }
        else
        {
            ; No monitor to move to, alternate size of window instead.
            if sideX
                widthFactor /= 2
            else if sideY
                heightFactor /= 2
            else
                widthFactor *= 1.5
            gosub CalcNewSizeAndPosition
        }

        ; Calculate new position for window.
        gosub CalcNewSizeAndPosition
    }

    ; Restore before resizing...
    WinGet, state, MinMax
    if state
        WinRestore

    WinDelay := A_WinDelay
    SetWinDelay, 0

    ; Move the window!
    WinMove, , , newx, newy, neww, newh

    ; For console windows and other windows which have size restrictions, check
    ; that the window was actually resized. If not, reposition based on actual size.
    WinGetPos, newx, newy, realw, realh
    if (neww != realw || newh != realh)
    {
        neww := realw
        newh := realh
        gosub CalcNewPosition
        if ((newm = "" || newm = m) && (newx ", " newy ", " realw ", " realh)=(x ", " y ", " w ", " h))
        {
            if sideX
                neww //= 2
            else if sideY
                newh //= 2
            else
                neww := Round(neww*1.5)
            ; Size first, since the window size will probably be restricted in some way.
            WinMove, , , , , neww, newh
            WinGetPos, , , neww, newh
            gosub CalcNewPosition
        }
        WinMove, , , newx, newy
    }

    ; Explorer uses WM_EXITSIZEMOVE to detect when a user finishes moving a window
    ; in order to save the position for next time. May also be used by other apps.
    PostMessage, 0x232

    SetWinDelay, WinDelay

    ; Remember where we put it, to detect if the user moves it.
    SetWindowProperty(hwnd, "wpLastX", newx)
    SetWindowProperty(hwnd, "wpLastY", newy)
    SetWindowProperty(hwnd, "wpLastW", neww)
    SetWindowProperty(hwnd, "wpLastH", newh)
    return

CalcNewSizeAndPosition:
    ; Calculate new size.
    if (IsResizable()) {
        neww := restore_w != "" ? restore_w : Round(monWidth * widthFactor)
        newh := restore_h != "" ? restore_h : Round(monHeight * heightFactor)
    } else {
        neww := w
        newh := h
    }
CalcNewPosition:
    ; Calculate new position.
    newx := restore_x != "" ? restore_x : Round(monLeft + (sideX+1) * (monWidth  - neww)/2)
    newy := restore_y != "" ? restore_y : Round(monTop  + (sideY+1) * (monHeight - newh)/2)
    return

CalcMonitorStats:
    ; Get work area (excludes taskbar-reserved space.)
    SysGet, mon, MonitorWorkArea, %m%
    monWidth  := monRight - monLeft
    monHeight := monBottom - monTop
    return
}

; Get/set window property. type should be int, uint or float.
GetWindowProperty(hwnd, property_name, type="int") {
    return DllCall("GetProp", "uint", hwnd, "str", property_name, type)
}
SetWindowProperty(hwnd, property_name, data, type="int") {
    return DllCall("SetProp", "uint", hwnd, "str", property_name, type, data)
}

; Get the index of the monitor containing the specified x and y co-ordinates.
GetMonitorAt(x, y, default=1)
{
    SysGet, m, MonitorCount
    ; Iterate through all monitors.
    Loop, %m%
    {
        ; Check if the window is on this monitor.
        SysGet, Mon, Monitor, %A_Index%
        if (x >= MonLeft && x <= MonRight && y >= MonTop && y <= MonBottom)
            return A_Index
    }

    return default
}

IsResizable()
{
    WinGetClass, Class
    if Class = Chrome_XPFrame
        return true
    if Class = ConsoleWindowClass
        return false
    WinGet, Style, Style
    return (Style & 0x40000) ; WS_SIZEBOX
}

WindowPad_WinExist(WinTitle)
{
    if WinTitle = P
        return WinPreviouslyActive()
    if WinTitle = M
    {
        MouseGetPos, , , win
        return WinExist("ahk_id " win)
    }
    return WinExist(WinTitle!="" ? WinTitle : "A")
}

; Note: This may not work properly with always-on-top windows. (Needs testing)
WinPreviouslyActive()
{
    active := WinActive("A")
    WinGet, win, List

    ; Find the active window.
    ; (Might not be win1 if there are always-on-top windows?)
    Loop, %win%
        if (win%A_Index% = active)
        {
            if (A_Index < win)
                N := A_Index+1

            ; hack for PSPad: +1 seems to get the document (child!) window, so do +2
            ifWinActive, ahk_class TfPSPad
                N += 1

            break
        }

    ; Use WinExist to set Last Found Window (for consistency with WinActive())
    return WinExist("ahk_id " . win%N%)
}

;
; Switch without moving/resizing (relative to screen)
;
WindowScreenMove(P)
{
    SetWinDelay, 0

    StringSplit, P, P, `, , %A_Space%%A_Tab%
    ; 1:Next|Prev|Num, 2:Window

    WindowPad_WinExist(P2)

    WinGet, state, MinMax
    if state = 1
        WinRestore

    WinGetPos, x, y, w, h

    ; Determine which monitor contains the center of the window.
    ms := GetMonitorAt(x+w/2, y+h/2)

    SysGet, mc, MonitorCount

    ; Determine which monitor to move to.
    if P1 in , N, Next
    {
        md := ms+1
        if (md > mc)
            md := 1
    }
    else if P1 in P, Prev, Previous
    {
        md := ms-1
        if (md < 1)
            md := mc
    }
    else if P1 is integer
        md := P1

    if (md=ms or (md+0)="" or md<1 or md>mc)
        return

    ; Get source and destination work areas (excludes taskbar-reserved space.)
    SysGet, ms, MonitorWorkArea, %ms%
    SysGet, md, MonitorWorkArea, %md%
    msw := msRight - msLeft, msh := msBottom - msTop
    mdw := mdRight - mdLeft, mdh := mdBottom - mdTop

    ; Calculate new size.
    if (IsResizable()) {
        w := Round(w*(mdw/msw))
        h := Round(h*(mdh/msh))
    }

    ; Move window, using resolution difference to scale co-ordinates.
    WinMove, , , mdLeft + (x-msLeft)*(mdw/msw), mdTop + (y-msTop)*(mdh/msh), w, h

    if state = 1
        WinMaximize
}

;
; "Gather" windows on a specific screen.
;
GatherWindows(md=1)
{
    global ProcessGatherExcludeList

    SetWinDelay, 0

    ; List all visible windows.
    WinGet, win, List

    ; Copy bounds of all monitors to an array.
    SysGet, mc, MonitorCount
    Loop, %mc%
        SysGet, mon%A_Index%, MonitorWorkArea, %A_Index%

    if md = M
    {
        ; Special exception for 'M', since the desktop window
        ; spreads across all screens.
        CoordMode, Mouse, Screen
        MouseGetPos, x, y
        md := GetMonitorAt(x, y, 0)
    }
    else if md is not integer
    {
        ; Support A, P and WinTitle.
        ; (Gather at screen containing specified window.)
        WindowPad_WinExist(md)
        WinGetPos, x, y, w, h
        md := GetMonitorAt(x+w/2, y+h/2, 0)
    }
    if (md<1 or md>mc)
        return

    ; Destination monitor
    mdx := mon%md%Left
    mdy := mon%md%Top
    mdw := mon%md%Right - mdx
    mdh := mon%md%Bottom - mdy

    Loop, %win%
    {
        ; If this window matches the GatherExclude group, don't touch it.
        if (WinExist("ahk_group GatherExclude ahk_id " . win%A_Index%))
            continue

        ; Set Last Found Window.
        if (!WinExist("ahk_id " . win%A_Index%))
            continue

        WinGet, procname, ProcessName
        ; Check process (program) exclusion list.
        if procname in %ProcessGatherExcludeList%
            continue

        WinGetPos, x, y, w, h

        ; Determine which monitor this window is on.
        xc := x+w/2, yc := y+h/2
        ms := 0
        Loop, %mc%
            if (xc >= mon%A_Index%Left && xc <= mon%A_Index%Right
                && yc >= mon%A_Index%Top && yc <= mon%A_Index%Bottom)
            {
                ms := A_Index
                break
            }
        ; If already on destination monitor, skip this window.
        if (ms = md)
            continue

        WinGet, state, MinMax
        if (state = 1) {
            WinRestore
            WinGetPos, x, y, w, h
        }

        if ms
        {
            ; Source monitor
            msx := mon%ms%Left
            msy := mon%ms%Top
            msw := mon%ms%Right - msx
            msh := mon%ms%Bottom - msy

            ; If the window is resizable, scale it by the monitors' resolution difference.
            if (IsResizable()) {
                w *= (mdw/msw)
                h *= (mdh/msh)
            }

            ; Move window, using resolution difference to scale co-ordinates.
            WinMove, , , mdx + (x-msx)*(mdw/msw), mdy + (y-msy)*(mdh/msh), w, h
        }
        else
        {
            ; Window not on any monitor, move it to center.
            WinMove, , , mdx + (mdw-w)/2, mdy + (mdh-h)/2
        }

        if state = 1
            WinMaximize
    }
}

GetLastMinimizedWindow()
{
    WinGet, w, List

    Loop %w%
    {
        wi := w%A_Index%
        WinGet, m, MinMax, ahk_id %wi%
        if m = -1 ; minimized
        {
            lastFound := wi
            break
        }
    }

    return "ahk_id " . (lastFound ? lastFound : 0)
}

;================================== 功能代码 :由北风一叶提供
;下一个标签
<NextTab>:
    send ^{tab}
return

;上一个标签
<PrevTab>:
    send ^+{tab}
return

;关闭当前标签
<CloseTab>:
    send ^{w}
return

;新建标签
<NewTab>:
    send ^{t}
return

;激活第一个标签
<ActivateTab1>:
    send ^{1}
return

;激活第二个标签
<ActivateTab2>:
    send ^{2}
return

;激活第三个标签
<ActivateTab3>:
    send ^{3}
return

;激活第四个标签
<ActivateTab4>:
    send ^{4}
return

;激活第五个标签
<ActivateTab5>:
    send ^{5}
return

;激活第六个标签
<ActivateTab6>:
    send ^{6}
return

;激活第七个标签
<ActivateTab7>:
    send ^{7}
return

;激活第八个标签
<ActivateTab8>:
    send ^{8}
return

;激活第九个标签
<ActivateTab9>:
    send ^{8}^{tab}
return

;激活最后一个标签
<ActivateTab0>:
    send ^{9}
return

;清除 ToolTip 计时器
<RemoveToolTip>:
    Global showToolTipStatus

    SetTimer, <RemoveToolTip>, Off
    ToolTip
    showToolTipStatus := false
return

;进入、退出模式时显示提示
DisplayMode(ahk_class_name, mode_name)
{
    Global vim
    Global showToolTipStatus

    ToolTip, 进入 %mode_name% 模式
    showToolTipStatus := true

    SetTimer, <RemoveToolTip>, 500
}

ShowHelp()
{
    Global vim

    modeObj := vim.GetMode(vim.LastFoundWin)

    np := "help`n"
    np .= "=====================`n"

    for i, k in modeObj.keymapList
    {
        if (i >= 0 && i <= 9)
        {
            Continue
        }

        act := vim.GetAction(modeObj.GetKeyMap(i))
        if (act.Type = 1)
        {
            ActionDescList := act.Comment
            np .= i "`t"  %ActionDescList%[i] "`n"
        }
        else
        {
            np .= i "`t" act.Comment "`n"
        }
    }

    MouseGetPos, posx, posy, A
    posx += 40
    posy += 40
    Tooltip, %np%, %posx%, %posy%
}

<ShowHelp>:
    Global showToolTipStatus

    if (!showToolTipStatus)
    {
        ShowHelp()
    }
    else
    {
        ToolTip
    }

    showToolTipStatus := !showToolTipStatus
return

<ToggleCapsLock>:
    GetKeyState, CapsLockState, CapsLock, T
    if CapsLockState = D
        SetCapsLockState, AlwaysOff
    else
        SetCapsLockState, AlwaysOn
return

<MouseUp>:
    MouseMove, 0, -10, 0, R
return

<MouseDown>:
    MouseMove, 0, 10, 0, R
return

<MouseLeft>:
    MouseMove, -10, 0, 0, R
return

<MouseRight>:
    MouseMove, 10, 0, 0, R
return

<SearchInWeb>:
    Run, https://www.baidu.com/s?wd=%clipboard%
return

<Test>:
    Msgbox, 测试
return

SwitchIME(dwLayout)
{
    HKL := DllCall("LoadKeyboardLayout", Str, dwLayout, UInt, 1)
    ControlGetFocus, ctl, A
    SendMessage, 0x50, 0, HKL, %ctl%, A
}

<SwitchToEngIME>:
    ; 下方代码可只保留一个
    SwitchIME(0x04090409) ; 英语(美国) 美式键盘
    SwitchIME(0x08040804) ; 中文(中国) 简体中文-美式键盘
return

<SwitchToEngIMEAndEsc>:
    Send, {esc}
    ; 下方代码可只保留一个
    SwitchIME(0x04090409) ; 英语(美国) 美式键盘
    SwitchIME(0x08040804) ; 中文(中国) 简体中文-美式键盘
return

<RunZ>:
    RunZPath := A_ScriptDir "\..\RunZ\RunZ.ahk"
    if (ini.config.runz_dir != "")
    {
        RunZPath := ini.config.runz_dir "\RunZ.ahk"
    }

    if (!FileExist(RunZPath))
    {
        return
    }

    if (FileExist(A_ScriptDir "\vimd.exe"))
    {
        Run, %A_ScriptDir%\vimd.exe "%RunZPath%"
    }
    else
    {
        Run, "%RunZPath%"
    }
return

General:
    Gen_Save_Win := []
    vim.SetAction("<down>", "向下移动")
    vim.SetAction("<up>", "向上移动")
    vim.SetAction("<left>", "向左移动")
    vim.SetAction("<right>", "向右移动")
    vim.SetAction("<home>", "home键")
    vim.SetAction("<end>", "end键")
    vim.SetAction("<Gen_InsertMode>", "插入模式")
    vim.SetAction("<Gen_NormalMode>", "浏览模式")
    vim.SetAction("<Gen_Toggle>", "启用/禁用vim热键(General插件)")
    vim.SetAction("<Reload>", "重新加载")
    vim.SetAction("<WindowMoveDown>", "窗口移动到下方")
    vim.SetAction("<WindowMoveUp>", "窗口移动到上方")
    vim.SetAction("<WindowMoveLeft>", "窗口移动到左侧")
    vim.SetAction("<WindowMoveRight>", "窗口移动到右侧")
    vim.SetAction("<WindowMoveCenter>", "窗口移动到中间")
    vim.SetAction("<WindowMax>", "最大化窗口")
    vim.SetAction("<WindowMin>", "最小化窗口")
    vim.SetAction("<WindowRestore>", "还原当前窗口")
    vim.SetAction("<FullScreen>", "全屏当前程序")
    vim.SetAction("<NextTab>", "下一个标签")
    vim.SetAction("<PrevTab>", "前一个标签")
    vim.SetAction("<CloseTab>", "关闭当前标签")
    vim.SetAction("<NewTab>", "新建标签")
    vim.SetAction("<ActivateTab1>", "激活第一个标签")
    vim.SetAction("<ActivateTab2>", "激活第二个标签")
    vim.SetAction("<ActivateTab3>", "激活第三个标签")
    vim.SetAction("<ActivateTab4>", "激活第四个标签")
    vim.SetAction("<ActivateTab5>", "激活第五个标签")
    vim.SetAction("<ActivateTab6>", "激活第六个标签")
    vim.SetAction("<ActivateTab7>", "激活第七个标签")
    vim.SetAction("<ActivateTab8>", "激活第八个标签")
    vim.SetAction("<ActivateTab9>", "激活第九个标签")
    vim.SetAction("<ActivateTab0>", "激活最后一个标签")
    vim.SetAction("<pgup>", "上一页")
    vim.SetAction("<pgdn>", "下一页")
    vim.SetAction("<enter>", "回车键")
    vim.SetAction("<space>", "空格键")
    vim.SetAction("<backspace>", "退格键")
    vim.SetAction("<Pass>", "屏蔽按键")
    vim.SetAction("<Media_Next>", "播放下一首")
    vim.SetAction("<Media_Prev>", "播放上一首")
    vim.SetAction("<Media_Play_Pause>", "播放/停止")
    vim.SetAction("<Media_Stop>", "停止播放")
    vim.SetAction("<RemoveToolTip>", "清除屏幕的ToolTip")
    vim.SetAction("<ShowHelp>", "显示所有按键帮助信息")
    vim.SetAction("<ToggleCapsLock>", "切换大小写")
    vim.SetAction("<MouseUp>", "向上移动鼠标")
    vim.SetAction("<MouseDown>", "向下移动鼠标")
    vim.SetAction("<MouseLeft>", "向左移动鼠标")
    vim.SetAction("<MouseRight>", "向右移动鼠标")
    vim.SetAction("<SearchInWeb>", "在网络搜索剪切板内容")
    vim.SetAction("<RunZ>", "运行 RunZ")
    vim.SetAction("<Test>", "测试")

    vim.SetWin("General", "General")
    vim.SetMode("insert", "General")
    vim.map("<Esc>", "<Gen_NormalMode>", "General")
    vim.SetMode("normal", "General")
    vim.map("i", "<Gen_InsertMode>", "General")
    vim.map("0", "<0>", "General")
    vim.map("1", "<1>", "General")
    vim.map("2", "<2>", "General")
    vim.map("3", "<3>", "General")
    vim.map("4", "<4>", "General")
    vim.map("5", "<5>", "General")
    vim.map("6", "<6>", "General")
    vim.map("7", "<7>", "General")
    vim.map("8", "<8>", "General")
    vim.map("9", "<9>", "General")
    vim.map("k", "<up>", "General")
    vim.map("j", "<down>", "General")
    vim.map("k", "<up>", "General")
    vim.map("h", "<left>", "General")
    vim.map("l", "<right>", "General")
    vim.map("zj", "<WindowMoveDown>", "General")
    vim.map("zk", "<WindowMoveUp>", "General")
    vim.map("zh", "<WindowMoveLeft>", "General")
    vim.map("zl", "<WindowMoveRight>", "General")
    vim.map("zc", "<WindowMoveCenter>", "General")
    vim.map("zf", "<fullscreen>", "General")
    vim.map("zm", "<WindowMax>", "General")
    vim.map("zn", "<WindowMin>", "General")
    vim.map("zr", "<WindowRestore>", "General")
    vim.map("t", "<NewTab>", "General")
    vim.map("x", "<CloseTab>", "General")
    vim.map("gn", "<NextTab>", "General")
    vim.map("gp", "<PrevTab>", "General")
    vim.map("g1", "<ActivateTab1>", "General")
    vim.map("g2", "<ActivateTab2>", "General")
    vim.map("g3", "<ActivateTab3>", "General")
    vim.map("g4", "<ActivateTab4>", "General")
    vim.map("g5", "<ActivateTab5>", "General")
    vim.map("g6", "<ActivateTab6>", "General")
    vim.map("g7", "<ActivateTab7>", "General")
    vim.map("g8", "<ActivateTab8>", "General")
    vim.map("g9", "<ActivateTab9>", "General")
    vim.map("g0", "<ActivateTab0>", "General")
    vim.BeforeActionDo("Gen_Before", "General")
return

Gen_Before()
{
    Global vim
    WinGet, MenuID, ID, AHK_CLASS #32768
    If MenuID
        return True
}

<Gen_InsertMode>:
    vim.SetMode("Insert", vim.CheckWin())
    Tooltip, Insert模式, , , 19
    Settimer, cancelTooltip, 1200
return
<Gen_NormalMode>:
    vim.SetMode("Normal", vim.CheckWin())
    Tooltip, Normal模式, , , 19
    Settimer, cancelTooltip, 1200
return
<Gen_Toggle>:
    Gen_Toggle()
return
Gen_Toggle()
{
    Global vim, Gen_Save_Win
    WinGetClass, c, A
    WinGet, f, ProcessPath, ahk_class %c%
    WinName:=vim.CheckWin()
    If not Gen_Save_Win[c]
    {
        If Strlen(winName) And IsObject(vim.GetWin(winName))
        {
            MsgBox, , VimDesktop, 当前窗口 [ %winName% ] 已经拥有Vim模式`n不允许替换为通用(General)模式！
            return
        }
    }
    winObj := vim.GetWin(c)
    If not Isobject(winObj)
    {
        vim.copy("General", c, c, f)
        Gen_Save_Win[c] := True
        Tooltip, 复制VIMD热键到当前窗口成功, , , 19
    }
    Else
    {
        if vim.Toggle(c)
            Tooltip, 激活当前窗口的VIMD热键, , , 19
        else
            Tooltip, 取消当前窗口的VIMD热键, , , 19
    }
    Settimer, cancelTooltip, 1200
}
cancelTooltip:
    Tooltip, , , , 19
return
<reload>:
    reload
return
<Exit>:
    ExitApp
return
<down>:
    send, {down}
return
<up>:
    send, {up}
return
<left>:
    send, {left}
return
<right>:
    send, {right}
return
<home>:
    send, {home}
return
<end>:
    send, {end}
return
<pgup>:
    send, {pgup}
return
<pgdn>:
    send, {pgdn}
return
<enter>:
    send, {enter}
return
<space>:
    send, {space}
return
<backspace>:
    send, {backspace}
return
<Media_Next>:
    send, {Media_Next}
return
<Media_Prev>:
    send, {Media_Prev}
return
<Media_Stop>:
    send, {Media_Stop}
return
<Media_Play_Pause>:
    send, {Media_Play_Pause}
return

<WindowMoveDown>:
    WindowPadMove("0, +1, 1.0, 0.5")
Return
<WindowMoveUp>:
    WindowPadMove("0, -1, 1.0, 0.5")
Return
<WindowMoveLeft>:
    WindowPadMove("-1, 0, 0.5, 1.0")
Return
<WindowMoveRight>:
    WindowPadMove("+1, 0, 0.5, 1.0")
Return
<WindowMoveCenter>:
    WindowPadMove("0, 0, 0.5, 0.7")
return
<WindowMax>:
    WinMaximize, A
return
<WindowMin>:
    WinMinimize, A
return
<WindowRestore>:
    WinRestore, A
return

; 全屏当前程序
<FullScreen>:
    FullScreen()
return
FullScreen() {
    WinGet, windowID, ID, A
    WindowState := FullScreenID[windowID]
    If Strlen(windowState) = 0
        WindowState := 0
    If WindowState
    {
        WinSet, Style, ^0xC40000, ahk_id %WindowID%
        Loop, Parse, windowState, `,
        {
            If A_Index = 2
                WinPosX := A_LoopField
            If A_Index = 3
                WinPosY := A_LoopField
            If A_Index = 4
                WindowWidth := A_LoopField
            If A_Index = 5
                WindowHeight := A_LoopField
        }
        WinMove, ahk_id %WindowID%, , WinPosX, WinPosY, WindowWidth, WindowHeight
        WindowState := 0
    }
    Else
    {
        WinGetPos, WinPosX, WinPosY, WindowWidth, WindowHeight, ahk_id %WindowID%
        WinSet, Style, ^0xC40000, ahk_id %WindowID%
        WinMove, ahk_id %WindowID%, , 0, 0, A_ScreenWidth, A_ScreenHeight
        WindowState := 1 ", " WinPosX ", " WinPosY ", " WindowWidth ", " WindowHeight
        ;Msgbox 再按一下刚刚的热键退出全屏
    }
    FullScreenID[windowID] := WindowState
}

;====================================================================================
;
; WindowPad.ahk
; Version: 0.4
; Last Updated: 11/5/2009
;
; This file contains functions which are useful for manipulating and moving windows.
; This is a stripped down version of WindowPad v.1.56 by Lexikos.
; Downloaded from http://www.autohotkey.com/forum/topic21703.html
;

WindowPadMove(P)
{
    StringSplit, P, P, `, , %A_Space%%A_Tab%
    ; Params: 1:dirX, 2:dirY, 3:widthFactor, 4:heightFactor, 5:window

    if P1 =
        P1 = R
    if P2 =
        P2 = R

    WindowPad_WinExist(P5)

    if !WinExist()
        return

    ; Determine width/height factors.
    if (P1 or P2) {
        ; to a side
        widthFactor := P3+0 ? P3 : (P1 ? 0.5 : 1.0)
        heightFactor := P4+0 ? P4 : (P2 ? 0.5 : 1.0)
    } else {
        ; to center
        widthFactor  := P3+0 ? P3 : 1.0
        heightFactor := P4+0 ? P4 : 1.0
    }

    ; Move the window!
    MoveWindowInDirection(P1, P2, widthFactor, heightFactor)
}

MaximizeToggle(P)
{
    WindowPad_WinExist(P)

    WinGet, state, MinMax
    if state
        WinRestore
    else
        WinMaximize
}

; Does the grunt work of the script.
MoveWindowInDirection(sideX, sideY, widthFactor, heightFactor)
{
    WinGetPos, x, y, w, h

    hwnd:=WinExist()
    if (can_restore := GetWindowProperty(hwnd, "wpHasRestorePos"))
    {   ; Window has restore info. Check if it is where we last put it.
        last_x := GetWindowProperty(hwnd, "wpLastX")
        last_y := GetWindowProperty(hwnd, "wpLastY")
        last_w := GetWindowProperty(hwnd, "wpLastW")
        last_h := GetWindowProperty(hwnd, "wpLastH")
    }
    if (can_restore && last_x = x && last_y = y && last_w = w && last_h = h)
    {   ; Window is where we last put it. Check if user wants to restore.
        if SubStr(sideX, 1, 1) = "R"
        {   ; Restore on X-axis.
            restore_x := GetWindowProperty(hwnd, "wpRestoreX")
            restore_w := GetWindowProperty(hwnd, "wpRestoreW")
            StringTrimLeft, sideX, sideX, 1
        }
        if SubStr(sideY, 1, 1) = "R"
        {   ; Restore on Y-axis.
            restore_y := GetWindowProperty(hwnd, "wpRestoreY")
            restore_h := GetWindowProperty(hwnd, "wpRestoreH")
            StringTrimLeft, sideY, sideY, 1
        }
        if (restore_x != "" || restore_y != "")
        {   ; If already at the "restored" size and position, do the normal thing instead.
            if ((restore_x = x || restore_x = "") && (restore_y = y || restore_y = "")
                && (restore_w = w || restore_w = "") && (restore_h = h || restore_h = ""))
            {
                restore_x =
                restore_y =
                restore_w =
                restore_h =
            }
        }
    }
    else
    {   ; Next time user requests the window be "restored" use this position and size.
        SetWindowProperty(hwnd, "wpHasRestorePos", true)
        SetWindowProperty(hwnd, "wpRestoreX", x)
        SetWindowProperty(hwnd, "wpRestoreY", y)
        SetWindowProperty(hwnd, "wpRestoreW", w)
        SetWindowProperty(hwnd, "wpRestoreH", h)

        if SubStr(sideX, 1, 1) = "R"
            StringTrimLeft, sideX, sideX, 1
        if SubStr(sideY, 1, 1) = "R"
            StringTrimLeft, sideY, sideY, 1
    }

    ; If no direction specified, restore or only switch monitors.
    if (sideX+0 = "" && restore_x = "")
        restore_x := x, restore_w := w
    if (sideY+0 = "" && restore_y = "")
        restore_y := y, restore_h := h

    ; Determine which monitor contains the center of the window.
    m := GetMonitorAt(x+w/2, y+h/2)

    ; Get work area of active monitor.
    gosub CalcMonitorStats
    ; Calculate possible new position for window.
    gosub CalcNewSizeAndPosition

    ; If the window is already there,
    if (newx ", " newy ", " neww ", " newh) = (x ", " y ", " w ", " h)
    {   ; ..move to the next monitor along instead.

        if (sideX or sideY)
        {   ; Move in the direction of sideX or sideY.
            SysGet, monB, Monitor, %m% ; get bounds of entire monitor (vs. work area)
            x := (sideX=0) ? (x+w/2) : (sideX>0 ? monBRight : monBLeft) + sideX
            y := (sideY=0) ? (y+h/2) : (sideY>0 ? monBBottom : monBTop) + sideY
            newm := GetMonitorAt(x, y, m)
        }
        else
        {   ; Move to center (Numpad5)
            newm := m+1
            SysGet, mon, MonitorCount
            if (newm > mon)
                newm := 1
        }

        if (newm != m)
        {
            m := newm
            ; Move to opposite side of monitor (left of a monitor is another monitor's right edge)
            sideX *= -1
            sideY *= -1
            ; Get new monitor's work area.
            gosub CalcMonitorStats
        }
        else
        {
            ; No monitor to move to, alternate size of window instead.
            if sideX
                widthFactor /= 2
            else if sideY
                heightFactor /= 2
            else
                widthFactor *= 1.5
            gosub CalcNewSizeAndPosition
        }

        ; Calculate new position for window.
        gosub CalcNewSizeAndPosition
    }

    ; Restore before resizing...
    WinGet, state, MinMax
    if state
        WinRestore

    WinDelay := A_WinDelay
    SetWinDelay, 0

    ; Move the window!
    WinMove, , , newx, newy, neww, newh

    ; For console windows and other windows which have size restrictions, check
    ; that the window was actually resized. If not, reposition based on actual size.
    WinGetPos, newx, newy, realw, realh
    if (neww != realw || newh != realh)
    {
        neww := realw
        newh := realh
        gosub CalcNewPosition
        if ((newm = "" || newm = m) && (newx ", " newy ", " realw ", " realh)=(x ", " y ", " w ", " h))
        {
            if sideX
                neww //= 2
            else if sideY
                newh //= 2
            else
                neww := Round(neww*1.5)
            ; Size first, since the window size will probably be restricted in some way.
            WinMove, , , , , neww, newh
            WinGetPos, , , neww, newh
            gosub CalcNewPosition
        }
        WinMove, , , newx, newy
    }

    ; Explorer uses WM_EXITSIZEMOVE to detect when a user finishes moving a window
    ; in order to save the position for next time. May also be used by other apps.
    PostMessage, 0x232

    SetWinDelay, WinDelay

    ; Remember where we put it, to detect if the user moves it.
    SetWindowProperty(hwnd, "wpLastX", newx)
    SetWindowProperty(hwnd, "wpLastY", newy)
    SetWindowProperty(hwnd, "wpLastW", neww)
    SetWindowProperty(hwnd, "wpLastH", newh)
    return

CalcNewSizeAndPosition:
    ; Calculate new size.
    if (IsResizable()) {
        neww := restore_w != "" ? restore_w : Round(monWidth * widthFactor)
        newh := restore_h != "" ? restore_h : Round(monHeight * heightFactor)
    } else {
        neww := w
        newh := h
    }
CalcNewPosition:
    ; Calculate new position.
    newx := restore_x != "" ? restore_x : Round(monLeft + (sideX+1) * (monWidth  - neww)/2)
    newy := restore_y != "" ? restore_y : Round(monTop  + (sideY+1) * (monHeight - newh)/2)
    return

CalcMonitorStats:
    ; Get work area (excludes taskbar-reserved space.)
    SysGet, mon, MonitorWorkArea, %m%
    monWidth  := monRight - monLeft
    monHeight := monBottom - monTop
    return
}

; Get/set window property. type should be int, uint or float.
GetWindowProperty(hwnd, property_name, type="int") {
    return DllCall("GetProp", "uint", hwnd, "str", property_name, type)
}
SetWindowProperty(hwnd, property_name, data, type="int") {
    return DllCall("SetProp", "uint", hwnd, "str", property_name, type, data)
}

; Get the index of the monitor containing the specified x and y co-ordinates.
GetMonitorAt(x, y, default=1)
{
    SysGet, m, MonitorCount
    ; Iterate through all monitors.
    Loop, %m%
    {
        ; Check if the window is on this monitor.
        SysGet, Mon, Monitor, %A_Index%
        if (x >= MonLeft && x <= MonRight && y >= MonTop && y <= MonBottom)
            return A_Index
    }

    return default
}

IsResizable()
{
    WinGetClass, Class
    if Class = Chrome_XPFrame
        return true
    if Class = ConsoleWindowClass
        return false
    WinGet, Style, Style
    return (Style & 0x40000) ; WS_SIZEBOX
}

WindowPad_WinExist(WinTitle)
{
    if WinTitle = P
        return WinPreviouslyActive()
    if WinTitle = M
    {
        MouseGetPos, , , win
        return WinExist("ahk_id " win)
    }
    return WinExist(WinTitle!="" ? WinTitle : "A")
}

; Note: This may not work properly with always-on-top windows. (Needs testing)
WinPreviouslyActive()
{
    active := WinActive("A")
    WinGet, win, List

    ; Find the active window.
    ; (Might not be win1 if there are always-on-top windows?)
    Loop, %win%
        if (win%A_Index% = active)
        {
            if (A_Index < win)
                N := A_Index+1

            ; hack for PSPad: +1 seems to get the document (child!) window, so do +2
            ifWinActive, ahk_class TfPSPad
                N += 1

            break
        }

    ; Use WinExist to set Last Found Window (for consistency with WinActive())
    return WinExist("ahk_id " . win%N%)
}

;
; Switch without moving/resizing (relative to screen)
;
WindowScreenMove(P)
{
    SetWinDelay, 0

    StringSplit, P, P, `, , %A_Space%%A_Tab%
    ; 1:Next|Prev|Num, 2:Window

    WindowPad_WinExist(P2)

    WinGet, state, MinMax
    if state = 1
        WinRestore

    WinGetPos, x, y, w, h

    ; Determine which monitor contains the center of the window.
    ms := GetMonitorAt(x+w/2, y+h/2)

    SysGet, mc, MonitorCount

    ; Determine which monitor to move to.
    if P1 in , N, Next
    {
        md := ms+1
        if (md > mc)
            md := 1
    }
    else if P1 in P, Prev, Previous
    {
        md := ms-1
        if (md < 1)
            md := mc
    }
    else if P1 is integer
        md := P1

    if (md=ms or (md+0)="" or md<1 or md>mc)
        return

    ; Get source and destination work areas (excludes taskbar-reserved space.)
    SysGet, ms, MonitorWorkArea, %ms%
    SysGet, md, MonitorWorkArea, %md%
    msw := msRight - msLeft, msh := msBottom - msTop
    mdw := mdRight - mdLeft, mdh := mdBottom - mdTop

    ; Calculate new size.
    if (IsResizable()) {
        w := Round(w*(mdw/msw))
        h := Round(h*(mdh/msh))
    }

    ; Move window, using resolution difference to scale co-ordinates.
    WinMove, , , mdLeft + (x-msLeft)*(mdw/msw), mdTop + (y-msTop)*(mdh/msh), w, h

    if state = 1
        WinMaximize
}

;
; "Gather" windows on a specific screen.
;
GatherWindows(md=1)
{
    global ProcessGatherExcludeList

    SetWinDelay, 0

    ; List all visible windows.
    WinGet, win, List

    ; Copy bounds of all monitors to an array.
    SysGet, mc, MonitorCount
    Loop, %mc%
        SysGet, mon%A_Index%, MonitorWorkArea, %A_Index%

    if md = M
    {
        ; Special exception for 'M', since the desktop window
        ; spreads across all screens.
        CoordMode, Mouse, Screen
        MouseGetPos, x, y
        md := GetMonitorAt(x, y, 0)
    }
    else if md is not integer
    {
        ; Support A, P and WinTitle.
        ; (Gather at screen containing specified window.)
        WindowPad_WinExist(md)
        WinGetPos, x, y, w, h
        md := GetMonitorAt(x+w/2, y+h/2, 0)
    }
    if (md<1 or md>mc)
        return

    ; Destination monitor
    mdx := mon%md%Left
    mdy := mon%md%Top
    mdw := mon%md%Right - mdx
    mdh := mon%md%Bottom - mdy

    Loop, %win%
    {
        ; If this window matches the GatherExclude group, don't touch it.
        if (WinExist("ahk_group GatherExclude ahk_id " . win%A_Index%))
            continue

        ; Set Last Found Window.
        if (!WinExist("ahk_id " . win%A_Index%))
            continue

        WinGet, procname, ProcessName
        ; Check process (program) exclusion list.
        if procname in %ProcessGatherExcludeList%
            continue

        WinGetPos, x, y, w, h

        ; Determine which monitor this window is on.
        xc := x+w/2, yc := y+h/2
        ms := 0
        Loop, %mc%
            if (xc >= mon%A_Index%Left && xc <= mon%A_Index%Right
                && yc >= mon%A_Index%Top && yc <= mon%A_Index%Bottom)
            {
                ms := A_Index
                break
            }
        ; If already on destination monitor, skip this window.
        if (ms = md)
            continue

        WinGet, state, MinMax
        if (state = 1) {
            WinRestore
            WinGetPos, x, y, w, h
        }

        if ms
        {
            ; Source monitor
            msx := mon%ms%Left
            msy := mon%ms%Top
            msw := mon%ms%Right - msx
            msh := mon%ms%Bottom - msy

            ; If the window is resizable, scale it by the monitors' resolution difference.
            if (IsResizable()) {
                w *= (mdw/msw)
                h *= (mdh/msh)
            }

            ; Move window, using resolution difference to scale co-ordinates.
            WinMove, , , mdx + (x-msx)*(mdw/msw), mdy + (y-msy)*(mdh/msh), w, h
        }
        else
        {
            ; Window not on any monitor, move it to center.
            WinMove, , , mdx + (mdw-w)/2, mdy + (mdh-h)/2
        }

        if state = 1
            WinMaximize
    }
}

GetLastMinimizedWindow()
{
    WinGet, w, List

    Loop %w%
    {
        wi := w%A_Index%
        WinGet, m, MinMax, ahk_id %wi%
        if m = -1 ; minimized
        {
            lastFound := wi
            break
        }
    }

    return "ahk_id " . (lastFound ? lastFound : 0)
}

;================================== 功能代码 :由北风一叶提供
;下一个标签
<NextTab>:
    send ^{tab}
return

;上一个标签
<PrevTab>:
    send ^+{tab}
return

;关闭当前标签
<CloseTab>:
    send ^{w}
return

;新建标签
<NewTab>:
    send ^{t}
return

;激活第一个标签
<ActivateTab1>:
    send ^{1}
return

;激活第二个标签
<ActivateTab2>:
    send ^{2}
return

;激活第三个标签
<ActivateTab3>:
    send ^{3}
return

;激活第四个标签
<ActivateTab4>:
    send ^{4}
return

;激活第五个标签
<ActivateTab5>:
    send ^{5}
return

;激活第六个标签
<ActivateTab6>:
    send ^{6}
return

;激活第七个标签
<ActivateTab7>:
    send ^{7}
return

;激活第八个标签
<ActivateTab8>:
    send ^{8}
return

;激活第九个标签
<ActivateTab9>:
    send ^{8}^{tab}
return

;激活最后一个标签
<ActivateTab0>:
    send ^{9}
return

;清除 ToolTip 计时器
<RemoveToolTip>:
    Global showToolTipStatus

    SetTimer, <RemoveToolTip>, Off
    ToolTip
    showToolTipStatus := false
return

;进入、退出模式时显示提示
DisplayMode(ahk_class_name, mode_name)
{
    Global vim
    Global showToolTipStatus

    ToolTip, 进入 %mode_name% 模式
    showToolTipStatus := true

    SetTimer, <RemoveToolTip>, 500
}

ShowHelp()
{
    Global vim

    modeObj := vim.GetMode(vim.LastFoundWin)

    np := "help`n"
    np .= "=====================`n"

    for i, k in modeObj.keymapList
    {
        if (i >= 0 && i <= 9)
        {
            Continue
        }

        act := vim.GetAction(modeObj.GetKeyMap(i))
        if (act.Type = 1)
        {
            ActionDescList := act.Comment
            np .= i "`t"  %ActionDescList%[i] "`n"
        }
        else
        {
            np .= i "`t" act.Comment "`n"
        }
    }

    MouseGetPos, posx, posy, A
    posx += 40
    posy += 40
    Tooltip, %np%, %posx%, %posy%
}

<ShowHelp>:
    Global showToolTipStatus

    if (!showToolTipStatus)
    {
        ShowHelp()
    }
    else
    {
        ToolTip
    }

    showToolTipStatus := !showToolTipStatus
return

<ToggleCapsLock>:
    GetKeyState, CapsLockState, CapsLock, T
    if CapsLockState = D
        SetCapsLockState, AlwaysOff
    else
        SetCapsLockState, AlwaysOn
return

<MouseUp>:
    MouseMove, 0, -10, 0, R
return

<MouseDown>:
    MouseMove, 0, 10, 0, R
return

<MouseLeft>:
    MouseMove, -10, 0, 0, R
return

<MouseRight>:
    MouseMove, 10, 0, 0, R
return

<SearchInWeb>:
    Run, https://www.baidu.com/s?wd=%clipboard%
return

<Test>:
    Msgbox, 测试
return

SwitchIME(dwLayout)
{
    HKL := DllCall("LoadKeyboardLayout", Str, dwLayout, UInt, 1)
    ControlGetFocus, ctl, A
    SendMessage, 0x50, 0, HKL, %ctl%, A
}

<SwitchToEngIME>:
    ; 下方代码可只保留一个
    SwitchIME(0x04090409) ; 英语(美国) 美式键盘
    SwitchIME(0x08040804) ; 中文(中国) 简体中文-美式键盘
return

<SwitchToEngIMEAndEsc>:
    Send, {esc}
    ; 下方代码可只保留一个
    SwitchIME(0x04090409) ; 英语(美国) 美式键盘
    SwitchIME(0x08040804) ; 中文(中国) 简体中文-美式键盘
return

<RunZ>:
    RunZPath := A_ScriptDir "\..\RunZ\RunZ.ahk"
    if (ini.config.runz_dir != "")
    {
        RunZPath := ini.config.runz_dir "\RunZ.ahk"
    }

    if (!FileExist(RunZPath))
    {
        return
    }

    if (FileExist(A_ScriptDir "\vimd.exe"))
    {
        Run, %A_ScriptDir%\vimd.exe "%RunZPath%"
    }
    else
    {
        Run, "%RunZPath%"
    }
return


Fixing autohotkey script name

Fixing autohotkey script name

files/autohotkey_scripts/7. Dial Plan Page - One Area Code.ahk


Update EditFile()

Update EditFile()

VimDConfig:
    vim.SetPlugin("VimDConfig", "Array", "0.1", "VimDesktop的配置界面")
    vim.SetAction("<VimDConfig_Plugin>", "显示 VimDesktop 插件信息")
    vim.SetAction("<VimDConfig_Keymap>", "显示 VimDesktop 热键信息")
    vim.SetAction("<VimDConfig_EditConfig>", "打开 VimDesktop 配置文件")
return

<VimDConfig_Plugin>:
    GUI, VimDConfig_plugin:Destroy
    GUI, VimDConfig_plugin:Default
    GUI, VimDConfig_plugin:Font, s10, Microsoft YaHei

    GUI, VimDConfig_plugin:Add, GroupBox, x10 y460 w170 h70, 过滤 &F
    GUI, VimDConfig_plugin:Add, Edit, x20 y490 gsearch_plugin v_search

    GUI, VimDConfig_plugin:Add, GroupBox, x190 y10 w650 h520, 动作 &A
    GUI, VimDConfig_plugin:Add, ListView, glistview x200 y35 w630 h482 grid altsubmit, 序号|动作|描述（双击进入文件）

    LV_ModifyCol(1, "center")
    LV_ModifyCol(2, "left 250")
    LV_ModifyCol(3, "left 320")

    ; 先创建右边的 ListView，再创建左边的 ListView，否则 LV_Modify 时会出问题。
    GUI, VimDConfig_plugin:Add, GroupBox, x10 y10 w170 h440, 插件 &P
    GUI, VimDConfig_plugin:Add, ListView, x20 y35 w150 h400 grid altsubmit gVimDConfig_LoadActions, 名称

    for plugin, obj in vim.PluginList
        LV_Add("", plugin)

    LV_Modify(1, "Select")

    GUI, VimDConfig_plugin:Show
return

<VimDConfig_Keymap>:
    menu, VimDConfig_keymap_menu, add
    menu, VimDConfig_keymap_menu, add, &Exit, VimDConfig_keymap_exit

    GUI, VimDConfig_keymap:Destroy
    GUI, VimDConfig_keymap:Default
    GUI, VimDConfig_keymap:Font, s10, Microsoft YaHei

    GUI, VimDConfig_keymap:Add, GroupBox, x10 y10 w200 h269, 插件 &P
    GUI, VimDConfig_keymap:Add, ListBox, x20 y35 w180 R12 center gVimDConfig_keymap_loadmodelist

    GUI, VimDConfig_keymap:Add, GroupBox, x10 y290 w200 h135, 模式 &M
    GUI, VimDConfig_keymap:Add, ListBox, x20 y315 w180 R5 center gVimDConfig_keymap_loadhotkey

    GUI, VimDConfig_keymap:Add, GroupBox, x10 y435 w200 h61, 过滤 &F
    GUI, VimDConfig_keymap:Add, Edit, gsearch_keymap v_search x20 y460 w180 h25

    GUI, VimDConfig_keymap:Add, GroupBox, x225 y10 w650 h486, 映射 &K
    GUI, VimDConfig_keymap:Add, Listview, glistview x235 y36 w630 h450 grid, 热键|动作（双击定位，右键双击编辑）|描述

    LV_ModifyCol(1, "left 100")
    LV_ModifyCol(2, "left 250")
    LV_ModifyCol(3, "left 259")

    VimDConfig_keymap_loadwinlist()
    VimDConfig_keymap_loadhotkey(VimDConfig_keymap_loadmodelist(thiswin))

    GUI, VimDConfig_keymap:Show
    ControlFocus, Edit1, A
return

<VimDConfig_EditConfig>:
    Run, %A_ScriptDir%\vimd.ini
return

VimDConfig_LoadActions:
    If A_GuiEvent = I
    {
        if not InStr(ErrorLevel, "S", true)
        {
            return
        }

        GUI, VimDConfig_plugin:ListView, sysListview322
        LV_GetText(plugin, A_EventInfo)
        GUI, VimDConfig_plugin:Default
        GUI, VimDConfig_plugin:ListView, sysListview321
        idx := 1
        LV_Delete()

        global current_plugin := ""
        for action, type in vim.ActionFromPlugin
        {
            If type = %plugin%
            {
                Desc := vim.GetAction(action)
                LV_Add("", idx, action, Desc.Comment)
                current_plugin .= idx "`t" action "`t" Desc.Comment "`n"
                idx++
            }
        }
    }

    ControlFocus, Edit1, A
return

VimDConfig_keymap_exit:
{
    GUI, VimDConfig_keymap:Destroy
    return
}

VimDConfig_keymap_loadwinlist()
{
    global vim
    list := "|全局"
    GUI, VimDConfig_keymap:Default
    for win, obj in vim.WinList
    {
        if vim.ExcludeWinList[win]
        {
            continue
        }

        ; Convert class name TTOTAL_CMD to plugin name TotalCommander
        if (win = "TTOTAL_CMD")
        {
            win := "TotalCommander"
        }
        list .= "|" win
    }
    GuiControl, , ListBox1, %list%
}

VimDConfig_keymap_loadmodelist:
    VimDConfig_keymap_loadmodelist()
    GUI, VimDConfig_keymap:Default
    LV_delete()
    GuiControl, Choose, ListBox2, |normal
    ControlFocus, Edit1, A
return

VimDConfig_keymap_loadmodelist(win = "")
{
    global vim
    GUI, VimDConfig_keymap:Default
    If not strlen(win)
        ControlGet, win, Choice, , ListBox1
    If win = 全局
        winObj := vim.GetWin()
    Else
        winObj := vim.GetWin(win)
    for mode, obj in winObj.modeList
        mlist .= "|" mode
    GuiControl, , ListBox2, %mlist%
    return win
}

VimDConfig_keymap_loadhotkey:
    GUI, VimDConfig_keymap:Default
    ControlGet, win, Choice, , ListBox1
    win := RegExMatch(win, "^全局$") ? "" : win

    ; Convert plugin name TotalCommander to class name TTOTAL_CMD
    if (win = "TotalCommander")
    {
        win := "TTOTAL_CMD"
    }

    ControlGet, mode, Choice, , ListBox2
    VimDConfig_keymap_loadhotkey(win, mode)
return

VimDConfig_keymap_loadhotkey(win, mode = "")
{
    global vim
    global current_keymap := ""
    If strlen(mode)
    {
        winObj  := vim.GetWin(win)
        modeobj := winObj.modeList[mode]
    }
    Else
        modeobj := vim.GetMode(win)
    GUI, VimDConfig_keymap:Default
    LV_delete()
    for key, i in modeobj.keymapList
    {
        ; Type = 1 : Function
        if (vim.GetAction(i).Type = 1)
        {
            ActionDescList := vim.GetAction(i).Comment
            actionDesc := StrSplit(%ActionDescList%[key], "|")
            LV_ADD("", Key, actionDesc[1], actionDesc[2])
            current_keymap .= Key "`t" actionDesc[1] "`t" actionDesc[2] "`n"
        }
        else
        {
            LV_Add("", RegExReplace(Key, "<S-(.*)>", "$1"), i, vim.GetAction(i).Comment)
            current_keymap .= Key "`t" i "`t" vim.GetAction(i).Comment "`n"
        }
    }
}

listview:
    if A_GuiEvent = DoubleClick
    {
        ;~ ToolTip You double-clicked row number %A_EventInfo%.
        LV_GetText(SelectedAction, A_EventInfo, 2)
        LV_GetText(SelectedDesc, A_EventInfo, 3)
        SearchFileForEdit(SelectedAction, SelectedDesc, false)
    }
    else if A_GuiEvent = R
    {
        LV_GetText(SelectedAction, A_EventInfo, 2)
        LV_GetText(SelectedDesc, A_EventInfo, 3)
        SearchFileForEdit(SelectedAction, SelectedDesc, true)
    }
return

SearchFileForEdit(Action, Desc, EditKeyMapping)
{
    IsUserCmd := RegExMatch(Action, "^(run|key|dir|tccmd|wshkey)$")
    if (IsUserCmd || EditKeyMapping)
    {
        SearchLine := "=" Action
        if (IsUserCmd || Action == "function")
        {
            SearchLine := Action "|" Desc
        }

        Loop, Read, %A_ScriptDir%\vimd.ini
        {
            if (InStr(A_LoopReadLine, SearchLine))
            {
                EditFile(A_ScriptDir "\vimd.ini", A_Index)
                return
            }
        }

        EditFile(A_ScriptDir "\vimd.ini")
        return
    }

    label := Action ":"
    if (Action == "function")
    {
        label := Desc
    }

    Loop, %A_ScriptDir%\plugins\*.ahk, , 1
    {
        Loop, Read, %A_LoopFileFullPath%
        {
            if (InStr(A_LoopReadLine, label) == 1)
            {
                EditFile(A_LoopFileFullPath, A_Index)
                return
            }
        }
    }

    Loop, %A_ScriptDir%\core\*.ahk, , 1
    {
        Loop, Read, %A_LoopFileFullPath%
        {
            if (InStr(A_LoopReadLine, label) = 1)
            {
                EditFile(A_LoopFileFullPath, A_Index)
                return
            }
        }
    }
}

EditFile(editPath, line := 1)
{
    editorArgs := {}
    editorArgs["notepad"] := "/g $line $file"
    editorArgs["notepad2"] := "/g $line $file"
    editorArgs["sublime_text"] := "$file:$line"
    editorArgs["vim"] := "+$line $file"
    editorArgs["gvim"] := "--remote-silent-tab +$line $file"
    editorArgs["everedit"] := "-n$line $file"
    editorArgs["notepad++"] := "-n$line $file"
    editorArgs["EmEditor"] := "-l $line $file"
    editorArgs["uedit32"] := "$file/$line"
    editorArgs["Editplus"] := "$file -cursor $line"
    editorArgs["textpad"] := "$file($line)"
    editorArgs["pspad"] := "$file /$line"
    editorArgs["ConTEXT"] := "$file /g1:$line"
    editorArgs["scite"] := "$file -goto:$line"

    Global editor

    If not FileExist(editor)
    {
        MsgBox, 请配置 vimd.ini 中 [config] 中的 editor ，并重启 vimd ！
        return
    }

    ; 根据编辑器 exe 名称获取打开参数
    SplitPath, editor, , , OutExtension, OutNameNoExt
    args := editorArgs[OutNameNoExt]
    StringReplace, args, args, $line, %line%
    StringReplace, args, args, $file, "%editPath%"
    target := editor " " args

    run, %target%
}

search_keymap:
    global current_keymap
    search_to_display(current_keymap)
return

search_plugin:
    global current_plugin
    search_to_display(current_plugin)
return

search_to_display(lines)
{
    Gui Submit, nohide
    GuiControlGet, OutputVar, , _search

    text := StrSplit(lines, "`n")

    LV_Delete() ; 清理不掉，第二次加载后，都成了重复的了，不知道怎么处理
    GuiControl, -Redraw, listview ; 重新启用重绘 (上面把它禁用了)
    for k, v in text
    {
        if v =
            continue
        if Instr(v, OutputVar)
        {
            list := StrSplit(v, "`t")
            LV_Add("", list[1], list[2], list[3])
        }
    }
    GuiControl, +Redraw, listview ; 重新启用重绘 (上面把它禁用了)
}

VimDConfig:
    vim.SetPlugin("VimDConfig", "Array", "0.1", "VimDesktop的配置界面")
    vim.SetAction("<VimDConfig_Plugin>", "显示 VimDesktop 插件信息")
    vim.SetAction("<VimDConfig_Keymap>", "显示 VimDesktop 热键信息")
    vim.SetAction("<VimDConfig_EditConfig>", "打开 VimDesktop 配置文件")
return

<VimDConfig_Plugin>:
    GUI, VimDConfig_plugin:Destroy
    GUI, VimDConfig_plugin:Default
    GUI, VimDConfig_plugin:Font, s10, Microsoft YaHei

    GUI, VimDConfig_plugin:Add, GroupBox, x10 y460 w170 h70, 过滤 &F
    GUI, VimDConfig_plugin:Add, Edit, x20 y490 gsearch_plugin v_search

    GUI, VimDConfig_plugin:Add, GroupBox, x190 y10 w650 h520, 动作 &A
    GUI, VimDConfig_plugin:Add, ListView, glistview x200 y35 w630 h482 grid altsubmit, 序号|动作|描述（双击进入文件）

    LV_ModifyCol(1, "center")
    LV_ModifyCol(2, "left 250")
    LV_ModifyCol(3, "left 320")

    ; 先创建右边的 ListView，再创建左边的 ListView，否则 LV_Modify 时会出问题。
    GUI, VimDConfig_plugin:Add, GroupBox, x10 y10 w170 h440, 插件 &P
    GUI, VimDConfig_plugin:Add, ListView, x20 y35 w150 h400 grid altsubmit gVimDConfig_LoadActions, 名称

    for plugin, obj in vim.PluginList
        LV_Add("", plugin)

    LV_Modify(1, "Select")

    GUI, VimDConfig_plugin:Show
return

<VimDConfig_Keymap>:
    menu, VimDConfig_keymap_menu, add
    menu, VimDConfig_keymap_menu, add, &Exit, VimDConfig_keymap_exit

    GUI, VimDConfig_keymap:Destroy
    GUI, VimDConfig_keymap:Default
    GUI, VimDConfig_keymap:Font, s10, Microsoft YaHei

    GUI, VimDConfig_keymap:Add, GroupBox, x10 y10 w200 h269, 插件 &P
    GUI, VimDConfig_keymap:Add, ListBox, x20 y35 w180 R12 center gVimDConfig_keymap_loadmodelist

    GUI, VimDConfig_keymap:Add, GroupBox, x10 y290 w200 h135, 模式 &M
    GUI, VimDConfig_keymap:Add, ListBox, x20 y315 w180 R5 center gVimDConfig_keymap_loadhotkey

    GUI, VimDConfig_keymap:Add, GroupBox, x10 y435 w200 h61, 过滤 &F
    GUI, VimDConfig_keymap:Add, Edit, gsearch_keymap v_search x20 y460 w180 h25

    GUI, VimDConfig_keymap:Add, GroupBox, x225 y10 w650 h486, 映射 &K
    GUI, VimDConfig_keymap:Add, Listview, glistview x235 y36 w630 h450 grid, 热键|动作（双击定位，右键双击编辑）|描述

    LV_ModifyCol(1, "left 100")
    LV_ModifyCol(2, "left 250")
    LV_ModifyCol(3, "left 259")

    VimDConfig_keymap_loadwinlist()
    VimDConfig_keymap_loadhotkey(VimDConfig_keymap_loadmodelist(thiswin))

    GUI, VimDConfig_keymap:Show
    ControlFocus, Edit1, A
return

<VimDConfig_EditConfig>:
    Run, %A_ScriptDir%\vimd.ini
return

VimDConfig_LoadActions:
    If A_GuiEvent = I
    {
        if not InStr(ErrorLevel, "S", true)
        {
            return
        }

        GUI, VimDConfig_plugin:ListView, sysListview322
        LV_GetText(plugin, A_EventInfo)
        GUI, VimDConfig_plugin:Default
        GUI, VimDConfig_plugin:ListView, sysListview321
        idx := 1
        LV_Delete()

        global current_plugin := ""
        for action, type in vim.ActionFromPlugin
        {
            If type = %plugin%
            {
                Desc := vim.GetAction(action)
                LV_Add("", idx, action, Desc.Comment)
                current_plugin .= idx "`t" action "`t" Desc.Comment "`n"
                idx++
            }
        }
    }

    ControlFocus, Edit1, A
return

VimDConfig_keymap_exit:
{
    GUI, VimDConfig_keymap:Destroy
    return
}

VimDConfig_keymap_loadwinlist()
{
    global vim
    list := "|全局"
    GUI, VimDConfig_keymap:Default
    for win, obj in vim.WinList
    {
        if vim.ExcludeWinList[win]
        {
            continue
        }

        ; Convert class name TTOTAL_CMD to plugin name TotalCommander
        if (win = "TTOTAL_CMD")
        {
            win := "TotalCommander"
        }
        list .= "|" win
    }
    GuiControl, , ListBox1, %list%
}

VimDConfig_keymap_loadmodelist:
    VimDConfig_keymap_loadmodelist()
    GUI, VimDConfig_keymap:Default
    LV_delete()
    GuiControl, Choose, ListBox2, |normal
    ControlFocus, Edit1, A
return

VimDConfig_keymap_loadmodelist(win = "")
{
    global vim
    GUI, VimDConfig_keymap:Default
    If not strlen(win)
        ControlGet, win, Choice, , ListBox1
    If win = 全局
        winObj := vim.GetWin()
    Else
        winObj := vim.GetWin(win)
    for mode, obj in winObj.modeList
        mlist .= "|" mode
    GuiControl, , ListBox2, %mlist%
    return win
}

VimDConfig_keymap_loadhotkey:
    GUI, VimDConfig_keymap:Default
    ControlGet, win, Choice, , ListBox1
    win := RegExMatch(win, "^全局$") ? "" : win

    ; Convert plugin name TotalCommander to class name TTOTAL_CMD
    if (win = "TotalCommander")
    {
        win := "TTOTAL_CMD"
    }

    ControlGet, mode, Choice, , ListBox2
    VimDConfig_keymap_loadhotkey(win, mode)
return

VimDConfig_keymap_loadhotkey(win, mode = "")
{
    global vim
    global current_keymap := ""
    If strlen(mode)
    {
        winObj  := vim.GetWin(win)
        modeobj := winObj.modeList[mode]
    }
    Else
        modeobj := vim.GetMode(win)
    GUI, VimDConfig_keymap:Default
    LV_delete()
    for key, i in modeobj.keymapList
    {
        ; Type = 1 : Function
        if (vim.GetAction(i).Type = 1)
        {
            ActionDescList := vim.GetAction(i).Comment
            actionDesc := StrSplit(%ActionDescList%[key], "|")
            LV_ADD("", Key, actionDesc[1], actionDesc[2])
            current_keymap .= Key "`t" actionDesc[1] "`t" actionDesc[2] "`n"
        }
        else
        {
            LV_Add("", RegExReplace(Key, "<S-(.*)>", "$1"), i, vim.GetAction(i).Comment)
            current_keymap .= Key "`t" i "`t" vim.GetAction(i).Comment "`n"
        }
    }
}

listview:
    if A_GuiEvent = DoubleClick
    {
        ;~ ToolTip You double-clicked row number %A_EventInfo%.
        LV_GetText(SelectedAction, A_EventInfo, 2)
        LV_GetText(SelectedDesc, A_EventInfo, 3)
        SearchFileForEdit(SelectedAction, SelectedDesc, false)
    }
    else if A_GuiEvent = R
    {
        LV_GetText(SelectedAction, A_EventInfo, 2)
        LV_GetText(SelectedDesc, A_EventInfo, 3)
        SearchFileForEdit(SelectedAction, SelectedDesc, true)
    }
return

SearchFileForEdit(Action, Desc, EditKeyMapping)
{
    IsUserCmd := RegExMatch(Action, "^(run|key|dir|tccmd|wshkey)$")
    if (IsUserCmd || EditKeyMapping)
    {
        SearchLine := "=" Action
        if (IsUserCmd || Action == "function")
        {
            SearchLine := Action "|" Desc
        }

        Loop, Read, %A_ScriptDir%\vimd.ini
        {
            if (InStr(A_LoopReadLine, SearchLine))
            {
                EditFile(A_ScriptDir "\vimd.ini", A_Index)
                return
            }
        }

        EditFile(A_ScriptDir "\vimd.ini")
        return
    }

    label := Action ":"
    if (Action == "function")
    {
        label := Desc
    }

    Loop, %A_ScriptDir%\plugins\*.ahk, , 1
    {
        Loop, Read, %A_LoopFileFullPath%
        {
            if (InStr(A_LoopReadLine, label) == 1)
            {
                EditFile(A_LoopFileFullPath, A_Index)
                return
            }
        }
    }

    Loop, %A_ScriptDir%\core\*.ahk, , 1
    {
        Loop, Read, %A_LoopFileFullPath%
        {
            if (InStr(A_LoopReadLine, label) = 1)
            {
                EditFile(A_LoopFileFullPath, A_Index)
                return
            }
        }
    }
}

EditFile(editPath, line := 1)
{
    editorArgs := {}
    editorArgs["notepad"] := "/g $line $file"
    editorArgs["notepad2"] := "/g $line $file"
    editorArgs["sublime_text"] := "$file:$line"
    editorArgs["vim"] := "+$line $file"
    editorArgs["gvim"] := "--remote-silent-tab +$line $file"
    editorArgs["everedit"] := "-n$line $file"
    editorArgs["notepad++"] := "-n$line $file"
    editorArgs["EmEditor"] := "-l $line $file"
    editorArgs["uedit32"] := "$file/$line"
    editorArgs["Editplus"] := "$file -cursor $line"
    editorArgs["textpad"] := "$file($line)"
    editorArgs["pspad"] := "$file /$line"
    editorArgs["ConTEXT"] := "$file /g1:$line"
    editorArgs["scite"] := "$file -goto:$line"

    Global editor

    If not FileExist(editor)
    {
        MsgBox, 请配置 vimd.ini 中 [config] 中的 editor ，并重启 vimd ！
        return
    }

    ; 根据编辑器 exe 名称获取打开参数
    SplitPath, editor, , , OutExtension, OutNameNoExt
    args := editorArgs[OutNameNoExt]
    StringReplace, args, args, $line, %line%
    StringReplace, args, args, $file, "%editPath%"
    target := editor " " args
    if (OutExtension = "sh" || OutExtension = "zsh")
    {
        target := "sh.exe " target
    }

    run, %target%
}

search_keymap:
    global current_keymap
    search_to_display(current_keymap)
return

search_plugin:
    global current_plugin
    search_to_display(current_plugin)
return

search_to_display(lines)
{
    Gui Submit, nohide
    GuiControlGet, OutputVar, , _search

    text := StrSplit(lines, "`n")

    LV_Delete() ; 清理不掉，第二次加载后，都成了重复的了，不知道怎么处理
    GuiControl, -Redraw, listview ; 重新启用重绘 (上面把它禁用了)
    for k, v in text
    {
        if v =
            continue
        if Instr(v, OutputVar)
        {
            list := StrSplit(v, "`t")
            LV_Add("", list[1], list[2], list[3])
        }
    }
    GuiControl, +Redraw, listview ; 重新启用重绘 (上面把它禁用了)
}


定时（每 2 秒）检查一次配置文件是否有改动，如有则重新加载配置文件

定时（每 2 秒）检查一次配置文件是否有改动，如有则重新加载配置文件

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

VimdRun()
{
    ConfigPath := A_ScriptDir "\conf\vimd.ini"
    IniRead, CustomConfigPath, %ConfigPath%, config, custom_config_path
    if (FileExist(A_ScriptDir "\conf\" CustomConfigPath))
    {
        ConfigPath := A_ScriptDir "\conf\" CustomConfigPath
    }

    vim := class_vim()
    VIMD_CMD_LIST := []

    ; 给 check.ahk 使用
    IniWrite, %A_ScriptHwnd%, %A_Temp%\vimd_auto.ini, auto, hwnd

    if (!FileExist(ConfigPath))
    {
        FileCopy, %A_ScriptDir%\conf\vimd.ini.help.txt, %ConfigPath%
    }

    ini := class_EasyINI(ConfigPath)
    default_enable_show_info := ini.config.default_enable_show_info
    editor := ini.config.editor

    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")

    ; 定时检查配置文件更新
    SetTimer, WatchConfigFile, 2000
}

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)
    {
        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

WatchConfigFile:
    FileGetTime, newConfigFileModifyTime, %ConfigPath%

    if (lastConfigFileModifyTime != "" && lastConfigFileModifyTime != newConfigFileModifyTime)
    {
        GoSub, VIMD_Reload
    }
    lastConfigFileModifyTime := newConfigFileModifyTime
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

VimdRun()
{
    ConfigPath := A_ScriptDir "\conf\vimd.ini"
    IniRead, CustomConfigPath, %ConfigPath%, config, custom_config_path
    if (FileExist(A_ScriptDir "\conf\" CustomConfigPath))
    {
        ConfigPath := A_ScriptDir "\conf\" CustomConfigPath
    }

    vim := class_vim()
    VIMD_CMD_LIST := []

    ; 给 check.ahk 使用
    IniWrite, %A_ScriptHwnd%, %A_Temp%\vimd_auto.ini, auto, hwnd

    if (!FileExist(ConfigPath))
    {
        FileCopy, %A_ScriptDir%\conf\vimd.ini.help.txt, %ConfigPath%
    }

    ini := class_EasyINI(ConfigPath)
    default_enable_show_info := ini.config.default_enable_show_info
    editor := ini.config.editor

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


implemented autohotkey command to upload script

WinActivate ahk_exe hackmud_win.exe
Send {Raw}#
Send up script {Enter}
Exit

^j::
   SendInput, #up test_script{enter}
Return


FIX: loop wasn't necessary

FIX: loop wasn't necessary

; default environment
DetectHiddenWindows, off
SetControlDelay, 20

; modified environment
#NoEnv
#NoTrayIcon
DetectHiddenText, off
SetTitleMatchMode, 2

; variables
winTitleIE = - Internet Explorer ahk_class IEFrame ahk_exe iexplore.exe
winTitleAddons = Manage Add-ons ahk_class #32770 ahk_exe iexplore.exe
winTitleEnable = Enable add-on ahk_class #32770 ahk_exe iexplore.exe

Process, Exist, iexplore.exe
if !ErrorLevel = 0 {
  procExists = 1
  WinActivate,%winTitleIE%
} else {
  procExists = 0
  Run, iexplore, , , pid
;  WinWait, ahk_pid %pid%, Address Bar, 60  ;too quick
;  WinActivate, ahk_pid %pid%, , 10
  WinWait, %winTitleIE%, , 60
  WinActivate, %winTitleIE%, , 60
  Send {ALT Down}x{ALT Up}m
  Sleep 250
}

Send {TAB 2}QTTabBar{ALT Down}e{ALT Up}
Sleep 1000

IfWinActive, %winTitleEnable%
{
  Send {ENTER}
  Send {ALT Down}l{ALT Up}
  CloseIE()
  sleep 10000
  Return
}
IfWinActive, %winTitleAddons%
{
  Send {ALT Down}l{ALT Up}
  CloseIE()
}

CloseIE()
{
  if procExists = 1
  {
    WinActivate,%winTitleIE%,
    Send, ^w
  }
  else
  {
    WinClose, ahk_exe iexplore.exe
  }
}

; File Explorer
Run, explorer
WinWait, ahk_exe explorer.exe, , 60
WinActivate, ahk_exe explorer.exe
Sleep 500
SetKeyDelay 50
Send {ALT}
Send {V}
Send {Y}
Send {DOWN 2}
Send {SPACE}
Send {ALT down}{F4}

; default environment
DetectHiddenWindows, off
SetControlDelay, 20

; modified environment
#NoEnv
#NoTrayIcon
DetectHiddenText, off
SetTitleMatchMode, 2

; variables
winTitleIE = - Internet Explorer ahk_class IEFrame ahk_exe iexplore.exe
winTitleAddons = Manage Add-ons ahk_class #32770 ahk_exe iexplore.exe
winTitleEnable = Enable add-on ahk_class #32770 ahk_exe iexplore.exe

Process, Exist, iexplore.exe
if !ErrorLevel = 0 {
  procExists = 1
  WinActivate,%winTitleIE%
} else {
  procExists = 0
  Run, iexplore, , , pid
;  WinWait, ahk_pid %pid%, Address Bar, 60  ;too quick
;  WinActivate, ahk_pid %pid%, , 10
  WinWait, %winTitleIE%, , 60
  WinActivate, %winTitleIE%, , 60
  Sleep 1000
}

Loop {
  Send {ALT Down}x{ALT Up}m
  IfWinExist, %winTitleAddons%
  {
    WinActivate
    break
  }
  Sleep 150
}

Send {TAB 2}QTTabBar{ALT Down}e{ALT Up}
Sleep 1000

IfWinActive, %winTitleEnable%
{
  Send {ENTER}
  Send {ALT Down}l{ALT Up}
  CloseIE()
  sleep 10000
  Return
}
IfWinActive, %winTitleAddons%
{
  Send {ALT Down}l{ALT Up}
  CloseIE()
}

CloseIE()
{
  if procExists = 1
  {
    WinActivate,%winTitleIE%,
    Send, ^w
  }
  else
  {
    WinClose, ahk_exe iexplore.exe
  }
}

; File Explorer
Run, explorer
WinWait, ahk_exe explorer.exe, , 60
WinActivate, ahk_exe explorer.exe
Sleep 500
SetKeyDelay 50
Send {ALT}
Send {V}
Send {Y}
Send {DOWN 2}
Send {SPACE}
Send {ALT down}{F4}


Added a shortcut to keep a window on top

#NoTrayIcon
#Persistent
#SingleInstance force
#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.

;;*******************************************************
; CUSTOM SHORTCUTS
;*******************************************************

;-------------------------------------------------------
; Replace default calculator
;-------------------------------------------------------
^NumpadEnter::Run "C:\Program Files (x86)\Moffsoft FreeCalc\MoffFreeCalc.exe"
;-------------------------------------------------------

;-------------------------------------------------------
; Call Listary
;-------------------------------------------------------
; With Alt + Space
!Space::Send !+^{=}
; With the down button of the mouse
XButton1::Send !+^{)}
;-------------------------------------------------------

;-------------------------------------------------------
; Switch between the desktops
;-------------------------------------------------------
; With the up button of the mouse
^XButton1:: switchDesktop() ;
XButton2:: switchDesktop() ;

; Function to switch between the desktops
switchedDesktop := false
switchDesktop()
{
	global switchedDesktop
    if switchedDesktop
    {
        SendEvent ^#{Right}
        switchedDesktop := false
    }
    else
    {
        SendEvent ^#{Left}
        switchedDesktop := true
    }
}
;-------------------------------------------------------