Update qemu_swap.ahk to map CapsLock to ScrollLock

#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.
Capslock::ScrollLock

class Config
{
   static sHost := "10.3.1.2"
   static iPort := 666
   static iSleep := 200

   static DEBUG := 0
   static WSAVersion := (2<<8) | 2 ; version 2.2
}

class SizeOf
{
   static sockaddr_in := 16
   static addrinfo := A_Is64bitOS ? 48  : 32
   static WSADATA  := A_Is64bitOS ? 400 : 396
}

class Offset
{
   class addrinfo
   {
      static ai_flags     := 0
      static ai_family    := 4
      static ai_socktype  := 8
      static ai_protocol  := 12
      static ai_addrlen   := 16
      static ai_canonname := A_Is64bitOS ? 24 : 20
      static ai_addr      := A_Is64bitOS ? 32 : 24
      static ai_next      := A_Is64bitOS ? 40 : 28
   }

   class sockaddr_in
   {
      static sin_family := 0
      static sin_port   := 2
      static in_addr    := 4
      static sin_zero   := 8
   }
}

class Const
{
   static AF_INET := 2

   static SOCK_STREAM := 1

   static IPPROTO_TCP := 6

   static FORMAT_MESSAGE_FROM_SYSTEM    := 0x1000
   static FORMAT_MESSAGE_IGNORE_INSERTS := 0x200
}

VarDump(ByRef pVar, iLen)
{
   sDump := ""
   iIter := 0
   while (iIter < iLen)
   {
      sDump := sDump . Format(" {:02x}", NumGet(pVar + 0, iIter, "UChar"))
      iIter++
   }
   return SubStr(sDump, 1)
}

StrJoin(ByRef aStr, sSep)
{
   sResult := ""
   For _, sVal in aStr
      sResult := sResult . ", " . sVal
   return SubStr(sResult, 2)
}

DllCallCheck(aParams*)
{
   iResult := DllCall(aParams*)
   if (ErrorLevel != 0)
   {
      MsgBox % Format("Invocation({:}) failed with ErrorLevel({:})", StrJoin(aParams, ", "), ErrorLevel)
   }
   else if (Config.DEBUG)
   {
      MsgBox % Format("Invocation({:}) returned({:})", StrJoin(aParams, ", "), iResult)
   }
   return iResult
}

GetError(iErrorId:=-1)
{
   VarSetCapacity(sMessage, 1024, 0)

   if (iErrorId == -1)
      iErrorId := DllCallCheck("Ws2_32\WSAGetLastError")

   iFlags := Const.FORMAT_MESSAGE_FROM_SYSTEM | Const.FORMAT_MESSAGE_IGNORE_INSERTS
   iResult := DllCallCheck("FormatMessage"
                    ,"UInt", iFlags      ; dwFlags
                    ,"UInt", 0           ; lpSource
                    ,"UInt", iErrorId    ; dwMessageID
                    ,"UInt", 0           ; dwLanguageID
                    ,"Ptr", &sMessage    ; lpBuffer
                    ,"UInt", 1024        ; nSize
                    ,"Ptr", 0)           ; Arguments

   if (iResult == 0)
      return iErrorId

   return sMessage
}

CleanExit(iStatus, pAddrinfo:=-1, iSocket:=-1)
{
   if (iSocket >= 0)
      DllCallCheck("Ws2_32\closesocket", "UInt", iSocket)
   if (pAddrinfo >= 0)
      DllCallCheck("Ws2_32\freeaddrinfo", "Ptr", pAddrinfo)
   DllCallCheck("Ws2_32\WSACleanup")

   Exit, iStatus
}

WSAStartup()
{
   VarSetCapacity(wsaData, SizeOf.WSADATA)
   iResult := DllCallCheck("Ws2_32\WSAStartup", "UShort", Config.WSAVersion, "Ptr", &wsaData)

   if (iResult != 0)
   {
      MsgBox % Format("WSAStartup failed with error: {:}", GetError())
      CleanExit(2)
   }

   return iResult
}

ResolveName(ByRef sHost, iPort)
{
   sPort := Format("{:d}", iPort)

   VarSetCapacity(aiHints, SizeOf.addrinfo, 0)
   NumPut(Const.AF_INET,     aiHints, Offset.ai_family)
   NumPut(Const.SOCK_STREAM, aiHints, Offset.ai_socktype)
   NumPut(Const.IPPROTO_TCP, aiHints, Offset.ai_protocol)

   VarSetCapacity(ppAddrinfo, A_PtrSize, 0)
   result := DllCallCheck("Ws2_32\GetAddrInfo"
                    ,"UPtr", &sHost       ; pNodeName
                    ,"UPtr", &sPort       ; pServiceName
                    ,"UPtr", &aiHints     ; pHints
                    ,"UPtr", &ppAddrinfo) ; pResult

   pAddrinfo := NumGet(ppAddrinfo, 0, "UPtr")

   if (result != 0)
   {
      MsgBox % Format("Can't resolve name({:}) with error: {:}", host, GetError())
      CleanExit(1, pAddrinfo)
   }

   return pAddrinfo
}

CreateSocket(pAddrinfo)
{
   iFamily   := NumGet(pAddrinfo + 0, Offset.addrinfo.ai_family)
   iSockType := NumGet(pAddrinfo + 0, Offset.addrinfo.ai_socktype)
   iProtocol := NumGet(pAddrinfo + 0, Offset.addrinfo.ai_protocol)

   iSocket := DllCallCheck("Ws2_32\socket", "Int", iFamily, "Int", iSockType, "Int", iProtocol)
   if (iSocket < 0)
   {
      MsgBox % Format("Can't create socket with family({:}), type({:}), protocol({:}): {:}", iFamily, iSockType, iProtocol, GetError())
   }

   return iSocket
}

Connect(iSocket, pAddrinfo)
{
   pSockaddr    := NumGet(pAddrinfo + 0, Offset.addrinfo.ai_addr)
   iSockaddrLen := NumGet(pAddrinfo + 0, Offset.addrinfo.ai_addrlen)

   iResult := DllCallCheck("Ws2_32\connect", "UInt", iSocket, "Ptr", pSockaddr, "UInt", iSockaddrLen)
   if (iResult < 0)
   {
      iPort_net  := NumGet(pSockaddr + 0, Offset.sockaddr_in.sin_port, "UShort")
      iPort_host := DllCallCheck("Ws2_32\ntohs", "UShort", iPort_net)

      iAddr := NumGet(pSockaddr + 0, 4)
      sAddr := DllCallCheck("Ws2_32\inet_ntoa", "UInt", iAddr, "Str")
      MsgBox % Format("Can't connect to host({:}) on port({:d}): {:}", sAddr, iPort_host, GetError())
   }

   return iResult
}

Main()
{
   Sleep, Config.iSleep
   WSAStartup()

   pAddrinfo := ResolveName(Config.sHost, Config.iPort)
   pIter := pAddrinfo
   iSocket := -1

   while (pIter != 0) {
      iSocket := CreateSocket(pIter)
      if (iSocket >= 0)
      {
         if (Connect(iSocket, pIter) >= 0)
            break
         else
            DllCallCheck("Ws2_32\closesocket", "UInt", iSocket)
      }

      pIter := NumGet(pIter + 0, Offset.addrinfo.ai_next, "UPtr")
   }

   if (pIter == 0)
   {
      MsgBox % Format("Could not connect to any host: {:}", GetError())
      CleanExit(3, pAddrinfo)
   }

   CleanExit(0, pAddrinfo, iSocket)
}

!`::
   Main()

#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.

class Config
{
   static sHost := "10.3.1.2"
   static iPort := 666

   static DEBUG := 0
   static WSAVersion := (2<<8) | 2 ; version 2.2
}

class SizeOf
{
   static sockaddr_in := 16
   static addrinfo := A_Is64bitOS ? 48  : 32
   static WSADATA  := A_Is64bitOS ? 400 : 396
}

class Offset
{
   class addrinfo
   {
      static ai_flags     := 0
      static ai_family    := 4
      static ai_socktype  := 8
      static ai_protocol  := 12
      static ai_addrlen   := 16
      static ai_canonname := A_Is64bitOS ? 24 : 20
      static ai_addr      := A_Is64bitOS ? 32 : 24
      static ai_next      := A_Is64bitOS ? 40 : 28
   }

   class sockaddr_in
   {
      static sin_family := 0
      static sin_port   := 2
      static in_addr    := 4
      static sin_zero   := 8
   }
}

class Const
{
   static AF_INET := 2

   static SOCK_STREAM := 1

   static IPPROTO_TCP := 6

   static FORMAT_MESSAGE_FROM_SYSTEM    := 0x1000
   static FORMAT_MESSAGE_IGNORE_INSERTS := 0x200
}

VarDump(ByRef pVar, iLen)
{
   sDump := ""
   iIter := 0
   while (iIter < iLen)
   {
      sDump := sDump . Format(" {:02x}", NumGet(pVar + 0, iIter, "UChar"))
      iIter++
   }
   return SubStr(sDump, 1)
}

StrJoin(ByRef aStr, sSep)
{
   sResult := ""
   For _, sVal in aStr
      sResult := sResult . ", " . sVal
   return SubStr(sResult, 2)
}

DllCallCheck(aParams*)
{
   iResult := DllCall(aParams*)
   if (ErrorLevel != 0)
   {
      MsgBox % Format("Invocation({:}) failed with ErrorLevel({:})", StrJoin(aParams, ", "), ErrorLevel)
   }
   else if (Config.DEBUG)
   {
      MsgBox % Format("Invocation({:}) returned({:})", StrJoin(aParams, ", "), iResult)
   }
   return iResult
}

GetError(iErrorId:=-1)
{
   VarSetCapacity(sMessage, 1024, 0)

   if (iErrorId == -1)
      iErrorId := DllCallCheck("Ws2_32\WSAGetLastError")

   iFlags := Const.FORMAT_MESSAGE_FROM_SYSTEM | Const.FORMAT_MESSAGE_IGNORE_INSERTS
   iResult := DllCallCheck("FormatMessage"
                    ,"UInt", iFlags      ; dwFlags
                    ,"UInt", 0           ; lpSource
                    ,"UInt", iErrorId    ; dwMessageID
                    ,"UInt", 0           ; dwLanguageID
                    ,"Ptr", &sMessage    ; lpBuffer
                    ,"UInt", 1024        ; nSize
                    ,"Ptr", 0)           ; Arguments

   if (iResult == 0)
      return iErrorId

   return sMessage
}

CleanExit(iStatus, pAddrinfo:=-1, iSocket:=-1)
{
   if (iSocket >= 0)
      DllCallCheck("Ws2_32\closesocket", "UInt", iSocket)
   if (pAddrinfo >= 0)
      DllCallCheck("Ws2_32\freeaddrinfo", "Ptr", pAddrinfo)
   DllCallCheck("Ws2_32\WSACleanup")

   Exit, iStatus
}

WSAStartup()
{
   VarSetCapacity(wsaData, SizeOf.WSADATA)
   iResult := DllCallCheck("Ws2_32\WSAStartup", "UShort", Config.WSAVersion, "Ptr", &wsaData)

   if (iResult != 0)
   {
      MsgBox % Format("WSAStartup failed with error: {:}", GetError())
      CleanExit(2)
   }

   return iResult
}

ResolveName(ByRef sHost, iPort)
{
   sPort := Format("{:d}", iPort)

   VarSetCapacity(aiHints, SizeOf.addrinfo, 0)
   NumPut(Const.AF_INET,     aiHints, Offset.ai_family)
   NumPut(Const.SOCK_STREAM, aiHints, Offset.ai_socktype)
   NumPut(Const.IPPROTO_TCP, aiHints, Offset.ai_protocol)

   VarSetCapacity(ppAddrinfo, A_PtrSize, 0)
   result := DllCallCheck("Ws2_32\GetAddrInfo"
                    ,"UPtr", &sHost       ; pNodeName
                    ,"UPtr", &sPort       ; pServiceName
                    ,"UPtr", &aiHints     ; pHints
                    ,"UPtr", &ppAddrinfo) ; pResult

   pAddrinfo := NumGet(ppAddrinfo, 0, "UPtr")

   if (result != 0)
   {
      MsgBox % Format("Can't resolve name({:}) with error: {:}", host, GetError())
      CleanExit(1, pAddrinfo)
   }

   return pAddrinfo
}

CreateSocket(pAddrinfo)
{
   iFamily   := NumGet(pAddrinfo + 0, Offset.addrinfo.ai_family)
   iSockType := NumGet(pAddrinfo + 0, Offset.addrinfo.ai_socktype)
   iProtocol := NumGet(pAddrinfo + 0, Offset.addrinfo.ai_protocol)

   iSocket := DllCallCheck("Ws2_32\socket", "Int", iFamily, "Int", iSockType, "Int", iProtocol)
   if (iSocket < 0)
   {
      MsgBox % Format("Can't create socket with family({:}), type({:}), protocol({:}): {:}", iFamily, iSockType, iProtocol, GetError())
   }

   return iSocket
}

Connect(iSocket, pAddrinfo)
{
   pSockaddr    := NumGet(pAddrinfo + 0, Offset.addrinfo.ai_addr)
   iSockaddrLen := NumGet(pAddrinfo + 0, Offset.addrinfo.ai_addrlen)

   iResult := DllCallCheck("Ws2_32\connect", "UInt", iSocket, "Ptr", pSockaddr, "UInt", iSockaddrLen)
   if (iResult < 0)
   {
      iPort_net  := NumGet(pSockaddr + 0, Offset.sockaddr_in.sin_port, "UShort")
      iPort_host := DllCallCheck("Ws2_32\ntohs", "UShort", iPort_net)

      iAddr := NumGet(pSockaddr + 0, 4)
      sAddr := DllCallCheck("Ws2_32\inet_ntoa", "UInt", iAddr, "Str")
      MsgBox % Format("Can't connect to host({:}) on port({:d}): {:}", sAddr, iPort_host, GetError())
   }

   return iResult
}

Main()
{
   WSAStartup()

   pAddrinfo := ResolveName(Config.sHost, Config.iPort)
   pIter := pAddrinfo
   iSocket := -1

   while (pIter != 0) {
      iSocket := CreateSocket(pIter)
      if (iSocket >= 0)
      {
         if (Connect(iSocket, pIter) >= 0)
            break
         else
            DllCallCheck("Ws2_32\closesocket", "UInt", iSocket)
      }

      pIter := NumGet(pIter + 0, Offset.addrinfo.ai_next, "UPtr")
   }

   if (pIter == 0)
   {
      MsgBox % Format("Could not connect to any host: {:}", GetError())
      CleanExit(3, pAddrinfo)
   }

   CleanExit(0, pAddrinfo, iSocket)
}

!`::
   Main()


Remove search button in VimDConfig

Remove search button in VimDConfig

VimDConfig:
    vim.SetPlugin("VimDConfig", "Array", "0.1", "VimDesktop的配置界面")
    vim.SetAction("<vc_plugin>", "显示 VimDesktop 插件信息")
    vim.SetAction("<vc_keymap>", "显示 VimDesktop 热键信息")
return

<vc_plugin>:
{
    GUI, VimDConfig_plugin:Destroy
    GUI, VimDConfig_plugin:Default
    GUI, VimDConfig_plugin:Font, s10, Microsoft YaHei
    GUI, VimDConfig_plugin:Add, ListView, x10 y10 w150 h400 grid altsubmit gVimDConfig_LoadActions, 插件
    for plugin, obj in vim.pluginlist
        LV_Add("", plugin)
    GUI, VimDConfig_plugin:Add, ListView, glistview x170 y10 w650 h400 grid altsubmit, 序号|动作|描述（双击进入文件）

    GUI, VimDConfig_plugin:Add, Text, x180 h25, 搜索：
    GUI, VimDConfig_plugin:Font, s10, Microsoft YaHei
    GUI, VimDConfig_plugin:Add, Edit, gsearch_plugin v_search x+10 w120 h25

    LV_ModifyCol(1, "center")
    LV_ModifyCol(2, "left 250")
    LV_ModifyCol(3, "left 400")
    GUI, VimDConfig_plugin:Show
    return
}

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

        GUI, VimDConfig_plugin:ListView, sysListview321
        LV_GetText(plugin, A_EventInfo)
        GUI, VimDConfig_plugin:Default
        GUI, VimDConfig_plugin:ListView, sysListview322
        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++
            }
        }
    }
    return
}

<vc_keymap>:
{
    menu, VimDConfig_keymap_menu, add
    ;menu, VimDConfig_keymap_menu, deleteall
    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 w300 h270, 窗口(&Q)
    GUI, VimDConfig_keymap:Add, ListBox, x20 y36 w180 R12 center gVimDConfig_keymap_loadmodelist

    GUI, VimDConfig_keymap:Add, GroupBox, x10 y290  w200 h140, 模式(&M)
    GUI, VimDConfig_keymap:Add, ListBox, x20 y316  w180 R5 center gVimDConfig_keymap_loadhotkey

    GUI, VimDConfig_keymap:Add, GroupBox, x225 y10 w650 h420, 热键定义（双击进入对应文件，右键双击修改键映射）(&V)
    GUI, VimDConfig_keymap:Add, Listview, glistview x235 y36 w630 h380 grid, 热键|动作|描述
    GUI, VimDConfig_keymap:Font, s12, Microsoft YaHei
    GUI, VimDConfig_keymap:Add, Text, x230 h25, 搜索：
    GUI, VimDConfig_keymap:Font, s10, Microsoft YaHei
    GUI, VimDConfig_keymap:Add, Edit, gsearch_keymap v_search x+10 w120 h25

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

    VimDConfig_keymap_loadwinlist()
    VimDConfig_keymap_loadhotkey(VimDConfig_keymap_loadmodelist(thiswin))

    GUI, VimDConfig_keymap:show
    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
        }
        list .= "|" win
    }
    GuiControl, , ListBox1, %list%
}

VimDConfig_keymap_loadmodelist:
    VimDConfig_keymap_loadmodelist()
    GUI, VimDConfig_keymap:Default
    LV_delete()
    GuiControl, Choose, ListBox2, |normal
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
    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("", Key, 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

ToMatch(str)
{
    str := RegExReplace(str,"\+|\?|\.|\*|\{|\}|\(|\)|\||\^|\$|\[|\]|\\","\$0")
    Return RegExReplace(str,"\s","\s")
}

SearchFileForEdit(Action, Desc, EditKeyMapping)
{
    if (Action = "key" || Action = "run" || EditKeyMapping)
    {
        SearchLine := "=" Action

        if (Action = "key" || Action = "run") {
            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 ":"
    funcMatch := ToMatch(Action) "\s*\(\)"
    FileEncoding,
    Loop, %A_ScriptDir%\plugins\*.ahk, , 1
    {
        Loop, Read, %A_LoopFileFullPath%
        {
            if (A_LoopReadLine = label || RegExMatch(A_LoopReadLine, funcMatch))
            {
                EditFile(A_LoopFileFullPath, A_Index)
                return
            }
        }
    }

    Loop, %A_ScriptDir%\core\*.ahk, , 1
    {
        Loop, Read, %A_LoopFileFullPath%
        {
            if (A_LoopReadLine = label || RegExMatch(A_LoopReadLine, funcMatch))
            {
                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")
    {
        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 ; 重新启用重绘 (上面把它禁用了)
}

VimDConfig:
    vim.SetPlugin("VimDConfig", "Array", "0.1", "VimDesktop的配置界面")
    vim.SetAction("<vc_plugin>", "显示 VimDesktop 插件信息")
    vim.SetAction("<vc_keymap>", "显示 VimDesktop 热键信息")
return

<vc_plugin>:
{
    GUI, VimDConfig_plugin:Destroy
    GUI, VimDConfig_plugin:Default
    GUI, VimDConfig_plugin:Font, s10, Microsoft YaHei
    GUI, VimDConfig_plugin:Add, ListView, x10 y10 w150 h400 grid altsubmit gVimDConfig_LoadActions, 插件
    for plugin, obj in vim.pluginlist
        LV_Add("", plugin)
    GUI, VimDConfig_plugin:Add, ListView, glistview x170 y10 w650 h400 grid altsubmit, 序号|动作|描述（双击进入文件）

    GUI, VimDConfig_plugin:Add, Text, x180 h25, 搜索：
    GUI, VimDConfig_plugin:Font, s10, Microsoft YaHei
    GUI, VimDConfig_plugin:Add, Edit, v_search x+10 w120 h25
    GUI, VimDConfig_plugin:Add, Button, gsearch_keymap x+15 w50 h25 Default, 搜索

    LV_ModifyCol(1, "center")
    LV_ModifyCol(2, "left 250")
    LV_ModifyCol(3, "left 400")
    GUI, VimDConfig_plugin:Show
    return
}

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

        GUI, VimDConfig_plugin:ListView, sysListview321
        LV_GetText(plugin, A_EventInfo)
        GUI, VimDConfig_plugin:Default
        GUI, VimDConfig_plugin:ListView, sysListview322
        idx := 1
        LV_Delete()
        for action, type in vim.ActionFromPlugin
        {
            If type = %plugin%
            {
                Desc := vim.GetAction(action)
                LV_Add("", idx, action, Desc.Comment)
                idx++
            }
        }
    }
    return
}

<vc_keymap>:
{
    menu, VimDConfig_keymap_menu, add
    ;menu, VimDConfig_keymap_menu, deleteall
    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 w300 h270, 窗口(&Q)
    GUI, VimDConfig_keymap:Add, ListBox, x20 y36 w180 R12 center gVimDConfig_keymap_loadmodelist

    GUI, VimDConfig_keymap:Add, GroupBox, x10 y290  w200 h140, 模式(&M)
    GUI, VimDConfig_keymap:Add, ListBox, x20 y316  w180 R5 center gVimDConfig_keymap_loadhotkey

    GUI, VimDConfig_keymap:Add, GroupBox, x225 y10 w650 h420, 热键定义（双击进入对应文件，右键双击修改键映射）(&V)
    GUI, VimDConfig_keymap:Add, Listview, glistview x235 y36 w630 h380 grid, 热键|动作|描述
    GUI, VimDConfig_keymap:Font, s12, Microsoft YaHei
    GUI, VimDConfig_keymap:Add, Text, x230 h25, 搜索：
    GUI, VimDConfig_keymap:Font, s10, Microsoft YaHei
    GUI, VimDConfig_keymap:Add, Edit, v_search x+10 w120 h25
    GUI, VimDConfig_keymap:Add, Button, gsearch_keymap x+15 w50 h25 Default, 搜索

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

    VimDConfig_keymap_loadwinlist()
    VimDConfig_keymap_loadhotkey(VimDConfig_keymap_loadmodelist(thiswin))

    GUI, VimDConfig_keymap:show
    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
        }
        list .= "|" win
    }
    GuiControl, , ListBox1, %list%
}

VimDConfig_keymap_loadmodelist:
    VimDConfig_keymap_loadmodelist()
    GUI, VimDConfig_keymap:Default
    LV_delete()
    GuiControl, Choose, ListBox2, |normal
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
    ControlGet, mode, Choice, , ListBox2
    VimDConfig_keymap_loadhotkey(win, mode)
return

VimDConfig_keymap_loadhotkey(win, mode = "")
{
    global vim
    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])
        }
        else
        {
            LV_Add("", Key, i, vim.GetAction(i).Comment)
        }
    }
}

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

ToMatch(str)
{
    str := RegExReplace(str,"\+|\?|\.|\*|\{|\}|\(|\)|\||\^|\$|\[|\]|\\","\$0")
    Return RegExReplace(str,"\s","\s")
}

SearchFileForEdit(Action, Desc, EditKeyMapping)
{
    if (Action = "key" || Action = "run" || EditKeyMapping)
    {
        SearchLine := "=" Action

        if (Action = "key" || Action = "run") {
            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 ":"
    funcMatch := ToMatch(Action) "\s*\(\)"
    FileEncoding,
    Loop, %A_ScriptDir%\plugins\*.ahk, , 1
    {
        Loop, Read, %A_LoopFileFullPath%
        {
            if (A_LoopReadLine = label || RegExMatch(A_LoopReadLine, funcMatch))
            {
                EditFile(A_LoopFileFullPath, A_Index)
                return
            }
        }
    }

    Loop, %A_ScriptDir%\core\*.ahk, , 1
    {
        Loop, Read, %A_LoopFileFullPath%
        {
            if (A_LoopReadLine = label || RegExMatch(A_LoopReadLine, funcMatch))
            {
                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")
    {
        target := "sh.exe " target
    }

    run, %target%
}

search_keymap:
    Gui Submit, nohide
    GuiControlGet, OutputVar, , _search
    if OutputVar =
    {
        ; TODO 适配 plugin 窗口
        LV_Delete() ; 清理不掉，第二次加载后，都成了重复的了，不知道怎么处理
        LV_ModifyCol(1, "left 100")
        LV_ModifyCol(2, "left 250")
        LV_ModifyCol(3, "left 400")

        VimDConfig_keymap_loadHotkey(VimDConfig_keymap_loadmodelist(thiswin))
        return
    }

    Loop % LV_GetCount()
    {
        LV_GetText(Text_1, A_Index, 1)
        LV_GetText(Text_2, A_Index, 2)
        LV_GetText(Text_3, A_Index, 3)
        if InStr(Text_1, OutputVar) or InStr(Text_2, OutputVar) or InStr(Text_3, OutputVar) ;搜索全部
        {
            LV_GetText(Text_1, A_Index,1)
            LV_GetText(Text_2, A_Index,2)
            LV_GetText(Text_3, A_Index,3)
            match = %Text_1%---%Text_2%---%Text_3%
            zmatch .= match "`n"
        }
    }

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

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

    match =
    zmatch =
    OutputVar =
return


Fix EditFile bug

Fix EditFile bug

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, %ConfigPath%
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, %ConfigPath%
        {
            if (InStr(A_LoopReadLine, SearchLine))
            {
                EditFile(ConfigPath, A_Index)
                return
            }
        }

        EditFile(ConfigPath)
        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, 请配置 %ConfigPath% 中 [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, %ConfigPath%
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, %ConfigPath%
        {
            if (InStr(A_LoopReadLine, SearchLine))
            {
                EditFile(%ConfigPath%, A_Index)
                return
            }
        }

        EditFile(%ConfigPath%)
        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, 请配置 %ConfigPath% 中 [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 ; 重新启用重绘 (上面把它禁用了)
}


AutoHotkey: Working on both computers finally

; Startup script for Autohotkey scripts that I want to run on system startup.
;
; Instructions:
;   Right click this .ahk file and hit create shortcut
;   Add the StartupScript.ahk to windows startup
;       Can be done with the registry by adding a string value to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run with the location of this file.
; Running 'Startup.reg' should work as well

; Using %A_AppData% instead of %A_UserName% because that returns TScheffert but
; my directory is tscheffert

; #include C:\Users\%A_UserName%\AutoHotkey\PhotoshopHotkeys.ahk
#include %A_AppData%\..\..\AutoHotkey\MusicControls.ahk
#include %A_AppData%\..\..\AutoHotkey\OutlookHotkeys.ahk
#include %A_AppData%\..\..\AutoHotkey\PhotoshopHotkeys.ahk

; Startup script for Autohotkey scripts that I want to run on system startup.
;
; Instructions:
;   Right click this .ahk file and hit create shortcut
;   Add the StartupScript.ahk to windows startup
;       Can be done with the registry by adding a string value to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run with the location of this file.
; Running 'Startup.reg' should work as well

; #include C:\Users\%A_UserName%\AutoHotkey\PhotoshopHotkeys.ahk
#include C:\Users\%A_UserName%\AutoHotkey\MusicControls.ahk
#include C:\Users\%A_UserName%\AutoHotkey\OutlookHotkeys.ahk
#include C:\Users\%A_UserName%\AutoHotkey\PhotoshopHotkeys.ahk


Fixing slight problems with my interpreter


update version metadata

update version metadata

; Webapp.ahk
; -------------------------------------------------------
; "Webapps made easy!"
; Library for developing web-based apps with AutoHotkey.
; Released under the MIT License
; More info here: https://github.com/joedf/Webapp.ahk
; -------------------------------------------------------
;
; AutoHotkey Tested Version: 1.1.31.01
; Dev Platform:   Windows 10 x64
; Author:         Joe DF  |  http://joedf.ahkscript.org  |  joedf@ahkscript.org
; Date:           22:14 2019/12/11
; Revision:       3

#NoEnv
SetWorkingDir %A_ScriptDir%

; https://autohotkey.com/board/topic/62512-permanently-turn-off-that-annoying-hotkey-limit/
#MaxHotkeysPerInterval 500
#UseHook

__Webapp_jsonf := "webapp.json"
FileRead,data,%__Webapp_jsonf%
j:=JSON_ToObj(data)

try {
	__Webapp_Name := __Webapp_DefaultVar(j.name,"My App")
	__Webapp_Width := __Webapp_DefaultVar(j.width,640)
	__Webapp_height := __Webapp_DefaultVar(j.height,480)
	__Webapp_protocol := __Webapp_DefaultVar(j.protocol,"app")
	__Webapp_Nav_sounds := __Webapp_DefaultVar(j.Nav_sounds,0)
	__Webapp_FullScreen := __Webapp_DefaultVar(j.fullscreen,0)
	__Webapp_DPI_Aware := __Webapp_DefaultVar(j.DPI_Aware,1)
	__Webapp_ZoomLevel := __Webapp_DefaultVar(j.ZoomLevel,100)
	__Webapp_AllowZoomLevelChange := __Webapp_DefaultVar(j.AllowZoomLevelChange,1)
	__Webapp_protocol_call := __Webapp_DefaultVar(j.protocol_call,"app_call")
		if !IsFunc(__Webapp_protocol_call)
			throw "Function Name '" . __Webapp_protocol_call . "' does not exist."
		__Webapp_protocol_call:=Func(__Webapp_protocol_call)
	__Webapp_NavComplete_call := __Webapp_DefaultVar(j.NavComplete_call,"app_page")
		if !IsFunc(__Webapp_NavComplete_call)
			throw "Function Name '" . __Webapp_NavComplete_call . "' does not exist."
		__Webapp_NavComplete_call:=Func(__Webapp_NavComplete_call)
	__Webapp_html_url := __Webapp_DefaultVar(j.html_url,"index.html")
		if !FileExist(__Webapp_html_url)
			throw "File '" . __Webapp_html_url . "' does not exist."
		__Webapp_html_url := getFileFullPath(__Webapp_html_url)
} catch e {
	err:= e . "`nPlease verify the '" . __Webapp_jsonf . "' file."
	if (A_LastError)
		err .= "`n" . Trim(GetErrorMessage(A_LastError),"`r`n") . "`nA_LastError = " . A_LastError
	ErrorExit(err)
}

OnExit,__Webapp_GuiClose
Gui __Webapp_:New
Gui __Webapp_:Margin, 0, 0
if (!__Webapp_DPI_Aware)
	Gui __Webapp_:-DPIScale
Gui __Webapp_:+LastFound +Resize +Hwnd__Webapp_GuiHwnd

; Register Messages
OnMessage(WM_KEYDOWN := 0x100, "gui_KeyDown", 2)
if (!__Webapp_AllowZoomLevelChange) {
	OnMessage(WM_MOUSEWHEEL = 0x20A, "gui_WheelScroll")

	Hotkey, IfWinActive, ahk_id %__Webapp_GuiHwnd%
		Hotkey, ^WheelDown, __Webapp_DoNothing
		Hotkey, ^WheelUp, __Webapp_DoNothing
	Hotkey, If
}

Gui __Webapp_:Add, ActiveX, v__Webapp_wb w%__Webapp_Width% h%__Webapp_height%, Shell.Explorer
SetWBClientSite()
__Webapp_wb.silent := true ;Surpress JS Error boxes
;__Webapp_wb.Navigate("about:<!DOCTYPE html><meta http-equiv='X-UA-Compatible' content='IE=edge'>")
__Webapp_wb.Navigate("file://" . __Webapp_html_url)

if (InStr(__Webapp_Nav_sounds,"false") || __Webapp_Nav_sounds==0) {
	; Thanks MrBubbles
	; https://autohotkey.com/boards/viewtopic.php?p=117029#p117029
	DllCall("urlmon\CoInternetSetFeatureEnabled"
			,"Int",  21 ; FEATURE_DISABLE_NAVIGATION_SOUNDS
			,"UInt", 0x00000002 ; SET_FEATURE_ON_PROCESS
			,"Int", 1)
}

ComObjConnect(__Webapp_wb, __Webapp_wb_events)
__Webapp_w := __Webapp_wb.Document.parentWindow
__Webapp_wf := Func("JS_AHK")
__Webapp_w.AHK := __Webapp_wf
;Wait for IE to load the page, before we connect the event handlers
while __Webapp_wb.readystate != 4 or __Webapp_wb.busy
	sleep 10

Gui __Webapp_:Show, w%__Webapp_Width% h%__Webapp_height%, %__Webapp_Name%
Gui __Webapp_:Default
GroupAdd, __Webapp_windows, ahk_id %__Webapp_GuiHwnd%

setZoomLevel( __Webapp_ZoomLevel )

if (__Webapp_FullScreen) {
	setFullscreen(__Webapp_FullScreen)
}
goto,__Webapp_AppStart
return

~LButton:: ;//cheap fix to reattach JS_AHK
gosub,__Webapp_JS_AHK_Attach
return

__Webapp_JS_AHK_Attach:
	 __Webapp_wb.Document.parentWindow.AHK := __Webapp_wf
return

__Webapp_GuiSize:
	GuiControl, __Webapp_:Move, __Webapp_wb, W%A_GuiWidth% H%A_GuiHeight%
return

__Webapp_GuiEscape:
	MsgBox 0x34, Webapp.ahk, Are you sure you want to quit?
	IfMsgBox No
		return
__Webapp_GuiClose:
	;make sure taskbar is back on exit
	WinShow, ahk_class Shell_TrayWnd
	WinShow, Start ahk_class Button
	Gui __Webapp_:Destroy
	ExitApp
return

__Webapp_DoNothing:
return

class __Webapp_wb_events
{
	;for more events and other, see http://msdn.microsoft.com/en-us/library/aa752085

	 ;blocked all navigation, we want our own stuff happening
	NavigateComplete2(wb, NewURL) {
		; wb.Stop() ;not needed in this one.
	}
	DownloadComplete(wb, NewURL) {
		wb.Stop()
	}
	DocumentComplete(wb, NewURL) {
		global __Webapp_NavComplete_call
		__Webapp_NavComplete_call.call(NewURL)
		wb.Stop()
	}
	NavigateError(wb, NewURL) {
		wb.Stop()
	}

	BeforeNavigate2(wb, NewURL)
	{
		wb.Stop() ;blocked all navigation, we want our own stuff happening

		global __Webapp_protocol
		global __Webapp_protocol_call

		;parse the url
		if (__Webapp_protocol == "*") ;if * then all goes to the function call, ie #nofilter ;)
			__Webapp_protocol_call.call(NewURL)
		else {
			if (InStr(NewURL,__Webapp_protocol "://")==1) { ;if url starts with "myapp://"
				what := SubStr(NewURL,Strlen(__Webapp_protocol)+4) ;get stuff after "myapp://"
				__Webapp_protocol_call.call(what)
			}
		}
		;else do nothing
	}
}

/* Autoconnect inputs by Phatricko - https://autohotkey.com/boards/viewtopic.php?p=102421#p102421
loop % wb.document.getElementsByTagName("input").length{
    ;ComObjConnect needs a unique variable for each iteration for all to work
    button%a_index% := wb.document.getElementsByTagName("input")[A_Index-1]
    id := button%a_index%.id
    ComObjConnect(button%a_index%, id . "_")
}
*/

__Webapp_DefaultVar(a,b) {
	if Instr(a,"false",false)
		return false
	if !StrLen(a)
		return b
	return a
}

;javascript:AHK('Func') --> Func()
JS_AHK(func, prms*) {
	wb := getDOM()
	; Stop navigation prior to calling the function, in case it uses Exit.
	wb.Stop()
	return %func%(prms*)
}

getWindow() {
	wb := getDOM()
	return wb.document.parentWindow
}

getDOM(){
	global __Webapp_wb
	return __Webapp_wb
}

setAppName(n) {
	global __Webapp_Name
	__Webapp_Name := __Webapp_DefaultVar(n,"My App")
	Gui, __Webapp_:Show, , %__Webapp_Name%
}

setFullscreen(bool) {
	global __Webapp_GuiHwnd
	global __Webapp_Width
	global __Webapp_height
	global __Webapp_FullScreen

	if (bool) {
		;Save old GUI values
		WinGetPos,nFS_x,nFS_y,__Webapp_Width,__Webapp_height,ahk_id %__Webapp_GuiHwnd%

		;Set New GUI Values
		SysGet, caption, 31
		SysGet, borderH, 32
		SysGet, borderV, 33
		FS_x := 0 - (borderH)
		FS_y := 0 - (caption) - (borderV)
		FS_w := A_ScreenWidth + (borderH*2)
		FS_h := A_ScreenHeight + (caption) + (borderV*2)

		;hide taskbar
		;WinSet,AlwaysOnTop,On,ahk_id %__Webapp_GuiHwnd%
		WinHide, ahk_class Shell_TrayWnd
		WinHide, Start ahk_class Button

		WinMove,ahk_id %__Webapp_GuiHwnd%,,%FS_x%,%FS_y%,%FS_w%,%FS_h%
		WinActivate,ahk_id %__Webapp_GuiHwnd% ;avoid bug
		__Webapp_FullScreen:=true ;FULLSCREEN = TRUE
	} else {
		nFS_x := (A_ScreenWidth//2) - (__Webapp_Width//2)
		nFS_y := (A_ScreenHeight//2) - (__Webapp_height//2)
		nFS_w := __Webapp_Width
		nFS_h := __Webapp_height
		WinMove,ahk_id %__Webapp_GuiHwnd%,,%nFS_x%,%nFS_y%,%nFS_w%,%nFS_h%

		;show taskbar
		;WinSet,AlwaysOnTop,Off,ahk_id %__Webapp_GuiHwnd%
		WinShow, ahk_class Shell_TrayWnd
		WinShow, Start ahk_class Button

		WinActivate,ahk_id %__Webapp_GuiHwnd% ;avoid bug
		__Webapp_FullScreen:=false ;FULLSCREEN = FALSE
	}
}

setZoomLevel(z) {
	global __Webapp_DPI_Aware

	; https://stackoverflow.com/a/738254/883015
	OLECMDID_OPTICAL_ZOOM := 63
	OLECMDID_OPTICAL_GETZOOMRANGE := 64
	OLECMDEXECOPT_DONTPROMPTUSER :=  2 ;?  https://social.msdn.microsoft.com/Forums/ie/en-US/21d2bc41-d182-4af6-81e9-6e06793058b9
	wb := getDOM()

	if (__Webapp_DPI_Aware) {
		DPI_Scale := A_ScreenDPI/96
		z := z * DPI_Scale
	}

	; ensure INT
	z := z & 0xFFFFFFFF

	wb.ExecWB( OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, z, 0)
}

ErrorExit(errMsg) {
	MsgBox 16, Webapp.ahk, %errMsg%
	ExitApp 1
}

;{ other stuff

GetErrorMessage(error_code="") {
	VarSetCapacity(buf, 1024) ; Probably won't exceed 1024 chars.
	if DllCall("FormatMessage", "uint", 0x1200, "ptr", 0, "int", error_code!=""
		? error_code : A_LastError, "uint", 1024, "str", buf, "uint", 1024, "ptr", 0)
	return buf
}

getFileFullPath(f) {
	Loop, Files, %f%
	{
		if (A_LoopFileLongPath)
			return A_LoopFileLongPath
	}
}

/*  Complex workaround to override "Active scripting" setting
 *  and ensure scripts can run within the WebBrowser control.
 */

global WBClientSite

SetWBClientSite()
{
	interfaces := {
	(Join,
		IOleClientSite: [0,3,1,0,1,0]
		IServiceProvider: [3]
		IInternetSecurityManager: [1,1,3,4,8,7,3,3]
	)}
	unkQI      := RegisterCallback("WBClientSite_QI", "Fast")
	unkAddRef  := RegisterCallback("WBClientSite_AddRef", "Fast")
	unkRelease := RegisterCallback("WBClientSite_Release", "Fast")
	WBClientSite := {_buffers: bufs := {}}, bufn := 0,
	for name, prms in interfaces
	{
		bufn += 1
		bufs.SetCapacity(bufn, (4 + prms.MaxIndex()) * A_PtrSize)
		buf := bufs.GetAddress(bufn)
		NumPut(unkQI,       buf + 1*A_PtrSize)
		NumPut(unkAddRef,   buf + 2*A_PtrSize)
		NumPut(unkRelease,  buf + 3*A_PtrSize)
		for i, prmc in prms
			NumPut(RegisterCallback("WBClientSite_" name, "Fast", prmc+1, i), buf + (3+i)*A_PtrSize)
		NumPut(buf + A_PtrSize, buf + 0)
		WBClientSite[name] := buf
	}
	wb := getDOM()
	if pOleObject := ComObjQuery(wb, "{00000112-0000-0000-C000-000000000046}")
	{   ; IOleObject::SetClientSite
		DllCall(NumGet(NumGet(pOleObject+0)+3*A_PtrSize), "ptr"
			, pOleObject, "ptr", WBClientSite.IOleClientSite, "uint")
		ObjRelease(pOleObject)
	}
}

WBClientSite_QI(p, piid, ppvObject)
{
	static IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"
	static IID_IOleClientSite := "{00000118-0000-0000-C000-000000000046}"
	static IID_IServiceProvider := "{6d5140c1-7436-11ce-8034-00aa006009fa}"
	iid := _String4GUID(piid)
	if (iid = IID_IOleClientSite || iid = IID_IUnknown)
	{
		NumPut(WBClientSite.IOleClientSite, ppvObject+0)
		return 0 ; S_OK
	}
	if (iid = IID_IServiceProvider)
	{
		NumPut(WBClientSite.IServiceProvider, ppvObject+0)
		return 0 ; S_OK
	}
	NumPut(0, ppvObject+0)
	return 0x80004002 ; E_NOINTERFACE
}

WBClientSite_AddRef(p)
{
	return 1
}

WBClientSite_Release(p)
{
	return 1
}

WBClientSite_IOleClientSite(p, p1="", p2="", p3="")
{
	if (A_EventInfo = 3) ; GetContainer
	{
		NumPut(0, p1+0) ; *ppContainer := NULL
		return 0x80004002 ; E_NOINTERFACE
	}
	return 0x80004001 ; E_NOTIMPL
}

WBClientSite_IServiceProvider(p, pguidService, piid, ppvObject)
{
	static IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"
	static IID_IInternetSecurityManager := "{79eac9ee-baf9-11ce-8c82-00aa004ba90b}"
	if (_String4GUID(pguidService) = IID_IInternetSecurityManager)
	{
		iid := _String4GUID(piid)
		if (iid = IID_IInternetSecurityManager || iid = IID_IUnknown)
		{
			NumPut(WBClientSite.IInternetSecurityManager, ppvObject+0)
			return 0 ; S_OK
		}
		NumPut(0, ppvObject+0)
		return 0x80004002 ; E_NOINTERFACE
	}
	NumPut(0, ppvObject+0)
	return 0x80004001 ; E_NOTIMPL
}

WBClientSite_IInternetSecurityManager(p, p1="", p2="", p3="", p4="", p5="", p6="", p7="", p8="")
{
	if (A_EventInfo = 5) ; ProcessUrlAction
	{
		if (p2 = 0x1400) ; dwAction = URLACTION_SCRIPT_RUN
		{
			NumPut(0, p3+0)  ; *pPolicy := URLPOLICY_ALLOW
			return 0 ; S_OK
		}
	}
	return 0x800C0011 ; INET_E_DEFAULT_ACTION
}

_String4GUID(pGUID)
{
	VarSetCapacity(String,38*2)
	DllCall("ole32\StringFromGUID2", "ptr", pGUID, "str", String, "int", 39)
	Return	String
}

/*  Fix keyboard shortcuts in WebBrowser control.
 *  References:
 *    http://www.autohotkey.com/community/viewtopic.php?p=186254#p186254
 *    http://msdn.microsoft.com/en-us/library/ms693360
 */

gui_KeyDown(wParam, lParam, nMsg, hWnd) {
	global __Webapp_AllowZoomLevelChange

	wb := getDOM()

	if (Chr(wParam) ~= "[A-Z]" || wParam = 0x74) ; Disable Ctrl+O/L/F/N and F5.
		return

	; joedf: optionally disable ctrl zooming
	if (!__Webapp_AllowZoomLevelChange) {
		if(GetKeyState("CTRL") && (wParam=187 || wParam=189)) ;CTRL+ CTRL-
			return
	}

	pipa := ComObjQuery(wb, "{00000117-0000-0000-C000-000000000046}")
	VarSetCapacity(kMsg, 48), NumPut(A_GuiY, NumPut(A_GuiX
	, NumPut(A_EventInfo, NumPut(lParam, NumPut(wParam
	, NumPut(nMsg, NumPut(hWnd, kMsg)))), "uint"), "int"), "int")
	Loop 2
	r := DllCall(NumGet(NumGet(1*pipa)+5*A_PtrSize), "ptr", pipa, "ptr", &kMsg)
	; Loop to work around an odd tabbing issue (it's as if there
	; is a non-existent element at the end of the tab order).
	until wParam != 9 || wb.Document.activeElement != ""
	ObjRelease(pipa)
	if r = 0 ; S_OK: the message was translated to an accelerator.
		return 0
}

gui_WheelScroll(wParam, lParam) {
	if(GET_KEYSTATE_WPARAM(wParam)==8)
		return 1
}

GET_KEYSTATE_WPARAM(wparam) {
	return (wparam & 0xFFFF)
}

;}

;-----end-----

; Webapp.ahk
; -------------------------------------------------------
; "Webapps made easy!"
; Library for developing web-based apps with AutoHotkey.
; Released under the MIT License
; More info here: https://github.com/joedf/Webapp.ahk
; -------------------------------------------------------
;
; AutoHotkey Tested Version: 1.1.24.03
; Dev Platform:   Windows 10 x64
; Author:         Joe DF  |  http://joedf.ahkscript.org  |  joedf@ahkscript.org
; Date:           15:40 2016/11/19
; Revision:       2

#NoEnv
SetWorkingDir %A_ScriptDir%

; https://autohotkey.com/board/topic/62512-permanently-turn-off-that-annoying-hotkey-limit/
#MaxHotkeysPerInterval 500
#UseHook

__Webapp_jsonf := "webapp.json"
FileRead,data,%__Webapp_jsonf%
j:=JSON_ToObj(data)

try {
	__Webapp_Name := __Webapp_DefaultVar(j.name,"My App")
	__Webapp_Width := __Webapp_DefaultVar(j.width,640)
	__Webapp_height := __Webapp_DefaultVar(j.height,480)
	__Webapp_protocol := __Webapp_DefaultVar(j.protocol,"app")
	__Webapp_Nav_sounds := __Webapp_DefaultVar(j.Nav_sounds,0)
	__Webapp_FullScreen := __Webapp_DefaultVar(j.fullscreen,0)
	__Webapp_DPI_Aware := __Webapp_DefaultVar(j.DPI_Aware,1)
	__Webapp_ZoomLevel := __Webapp_DefaultVar(j.ZoomLevel,100)
	__Webapp_AllowZoomLevelChange := __Webapp_DefaultVar(j.AllowZoomLevelChange,1)
	__Webapp_protocol_call := __Webapp_DefaultVar(j.protocol_call,"app_call")
		if !IsFunc(__Webapp_protocol_call)
			throw "Function Name '" . __Webapp_protocol_call . "' does not exist."
		__Webapp_protocol_call:=Func(__Webapp_protocol_call)
	__Webapp_NavComplete_call := __Webapp_DefaultVar(j.NavComplete_call,"app_page")
		if !IsFunc(__Webapp_NavComplete_call)
			throw "Function Name '" . __Webapp_NavComplete_call . "' does not exist."
		__Webapp_NavComplete_call:=Func(__Webapp_NavComplete_call)
	__Webapp_html_url := __Webapp_DefaultVar(j.html_url,"index.html")
		if !FileExist(__Webapp_html_url)
			throw "File '" . __Webapp_html_url . "' does not exist."
		__Webapp_html_url := getFileFullPath(__Webapp_html_url)
} catch e {
	err:= e . "`nPlease verify the '" . __Webapp_jsonf . "' file."
	if (A_LastError)
		err .= "`n" . Trim(GetErrorMessage(A_LastError),"`r`n") . "`nA_LastError = " . A_LastError
	ErrorExit(err)
}

OnExit,__Webapp_GuiClose
Gui __Webapp_:New
Gui __Webapp_:Margin, 0, 0
if (!__Webapp_DPI_Aware)
	Gui __Webapp_:-DPIScale
Gui __Webapp_:+LastFound +Resize +Hwnd__Webapp_GuiHwnd

; Register Messages
OnMessage(WM_KEYDOWN := 0x100, "gui_KeyDown", 2)
if (!__Webapp_AllowZoomLevelChange) {
	OnMessage(WM_MOUSEWHEEL = 0x20A, "gui_WheelScroll")

	Hotkey, IfWinActive, ahk_id %__Webapp_GuiHwnd%
		Hotkey, ^WheelDown, __Webapp_DoNothing
		Hotkey, ^WheelUp, __Webapp_DoNothing
	Hotkey, If
}

Gui __Webapp_:Add, ActiveX, v__Webapp_wb w%__Webapp_Width% h%__Webapp_height%, Shell.Explorer
SetWBClientSite()
__Webapp_wb.silent := true ;Surpress JS Error boxes
;__Webapp_wb.Navigate("about:<!DOCTYPE html><meta http-equiv='X-UA-Compatible' content='IE=edge'>")
__Webapp_wb.Navigate("file://" . __Webapp_html_url)

if (InStr(__Webapp_Nav_sounds,"false") || __Webapp_Nav_sounds==0) {
	; Thanks MrBubbles
	; https://autohotkey.com/boards/viewtopic.php?p=117029#p117029
	DllCall("urlmon\CoInternetSetFeatureEnabled"
			,"Int",  21 ; FEATURE_DISABLE_NAVIGATION_SOUNDS
			,"UInt", 0x00000002 ; SET_FEATURE_ON_PROCESS
			,"Int", 1)
}

ComObjConnect(__Webapp_wb, __Webapp_wb_events)
__Webapp_w := __Webapp_wb.Document.parentWindow
__Webapp_wf := Func("JS_AHK")
__Webapp_w.AHK := __Webapp_wf
;Wait for IE to load the page, before we connect the event handlers
while __Webapp_wb.readystate != 4 or __Webapp_wb.busy
	sleep 10

Gui __Webapp_:Show, w%__Webapp_Width% h%__Webapp_height%, %__Webapp_Name%
Gui __Webapp_:Default
GroupAdd, __Webapp_windows, ahk_id %__Webapp_GuiHwnd%

setZoomLevel( __Webapp_ZoomLevel )

if (__Webapp_FullScreen) {
	setFullscreen(__Webapp_FullScreen)
}
goto,__Webapp_AppStart
return

~LButton:: ;//cheap fix to reattach JS_AHK
gosub,__Webapp_JS_AHK_Attach
return

__Webapp_JS_AHK_Attach:
	 __Webapp_wb.Document.parentWindow.AHK := __Webapp_wf
return

__Webapp_GuiSize:
	GuiControl, __Webapp_:Move, __Webapp_wb, W%A_GuiWidth% H%A_GuiHeight%
return

__Webapp_GuiEscape:
	MsgBox 0x34, Webapp.ahk, Are you sure you want to quit?
	IfMsgBox No
		return
__Webapp_GuiClose:
	;make sure taskbar is back on exit
	WinShow, ahk_class Shell_TrayWnd
	WinShow, Start ahk_class Button
	Gui __Webapp_:Destroy
	ExitApp
return

__Webapp_DoNothing:
return

class __Webapp_wb_events
{
	;for more events and other, see http://msdn.microsoft.com/en-us/library/aa752085

	 ;blocked all navigation, we want our own stuff happening
	NavigateComplete2(wb, NewURL) {
		; wb.Stop() ;not needed in this one.
	}
	DownloadComplete(wb, NewURL) {
		wb.Stop()
	}
	DocumentComplete(wb, NewURL) {
		global __Webapp_NavComplete_call
		__Webapp_NavComplete_call.call(NewURL)
		wb.Stop()
	}
	NavigateError(wb, NewURL) {
		wb.Stop()
	}

	BeforeNavigate2(wb, NewURL)
	{
		wb.Stop() ;blocked all navigation, we want our own stuff happening

		global __Webapp_protocol
		global __Webapp_protocol_call

		;parse the url
		if (__Webapp_protocol == "*") ;if * then all goes to the function call, ie #nofilter ;)
			__Webapp_protocol_call.call(NewURL)
		else {
			if (InStr(NewURL,__Webapp_protocol "://")==1) { ;if url starts with "myapp://"
				what := SubStr(NewURL,Strlen(__Webapp_protocol)+4) ;get stuff after "myapp://"
				__Webapp_protocol_call.call(what)
			}
		}
		;else do nothing
	}
}

/* Autoconnect inputs by Phatricko - https://autohotkey.com/boards/viewtopic.php?p=102421#p102421
loop % wb.document.getElementsByTagName("input").length{
    ;ComObjConnect needs a unique variable for each iteration for all to work
    button%a_index% := wb.document.getElementsByTagName("input")[A_Index-1]
    id := button%a_index%.id
    ComObjConnect(button%a_index%, id . "_")
}
*/

__Webapp_DefaultVar(a,b) {
	if Instr(a,"false",false)
		return false
	if !StrLen(a)
		return b
	return a
}

;javascript:AHK('Func') --> Func()
JS_AHK(func, prms*) {
	wb := getDOM()
	; Stop navigation prior to calling the function, in case it uses Exit.
	wb.Stop()
	return %func%(prms*)
}

getWindow() {
	wb := getDOM()
	return wb.document.parentWindow
}

getDOM(){
	global __Webapp_wb
	return __Webapp_wb
}

setAppName(n) {
	global __Webapp_Name
	__Webapp_Name := __Webapp_DefaultVar(n,"My App")
	Gui, __Webapp_:Show, , %__Webapp_Name%
}

setFullscreen(bool) {
	global __Webapp_GuiHwnd
	global __Webapp_Width
	global __Webapp_height
	global __Webapp_FullScreen

	if (bool) {
		;Save old GUI values
		WinGetPos,nFS_x,nFS_y,__Webapp_Width,__Webapp_height,ahk_id %__Webapp_GuiHwnd%

		;Set New GUI Values
		SysGet, caption, 31
		SysGet, borderH, 32
		SysGet, borderV, 33
		FS_x := 0 - (borderH)
		FS_y := 0 - (caption) - (borderV)
		FS_w := A_ScreenWidth + (borderH*2)
		FS_h := A_ScreenHeight + (caption) + (borderV*2)

		;hide taskbar
		;WinSet,AlwaysOnTop,On,ahk_id %__Webapp_GuiHwnd%
		WinHide, ahk_class Shell_TrayWnd
		WinHide, Start ahk_class Button

		WinMove,ahk_id %__Webapp_GuiHwnd%,,%FS_x%,%FS_y%,%FS_w%,%FS_h%
		WinActivate,ahk_id %__Webapp_GuiHwnd% ;avoid bug
		__Webapp_FullScreen:=true ;FULLSCREEN = TRUE
	} else {
		nFS_x := (A_ScreenWidth//2) - (__Webapp_Width//2)
		nFS_y := (A_ScreenHeight//2) - (__Webapp_height//2)
		nFS_w := __Webapp_Width
		nFS_h := __Webapp_height
		WinMove,ahk_id %__Webapp_GuiHwnd%,,%nFS_x%,%nFS_y%,%nFS_w%,%nFS_h%

		;show taskbar
		;WinSet,AlwaysOnTop,Off,ahk_id %__Webapp_GuiHwnd%
		WinShow, ahk_class Shell_TrayWnd
		WinShow, Start ahk_class Button

		WinActivate,ahk_id %__Webapp_GuiHwnd% ;avoid bug
		__Webapp_FullScreen:=false ;FULLSCREEN = FALSE
	}
}

setZoomLevel(z) {
	global __Webapp_DPI_Aware

	; https://stackoverflow.com/a/738254/883015
	OLECMDID_OPTICAL_ZOOM := 63
	OLECMDID_OPTICAL_GETZOOMRANGE := 64
	OLECMDEXECOPT_DONTPROMPTUSER :=  2 ;?  https://social.msdn.microsoft.com/Forums/ie/en-US/21d2bc41-d182-4af6-81e9-6e06793058b9
	wb := getDOM()

	if (__Webapp_DPI_Aware) {
		DPI_Scale := A_ScreenDPI/96
		z := z * DPI_Scale
	}

	; ensure INT
	z := z & 0xFFFFFFFF

	wb.ExecWB( OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, z, 0)
}

ErrorExit(errMsg) {
	MsgBox 16, Webapp.ahk, %errMsg%
	ExitApp 1
}

;{ other stuff

GetErrorMessage(error_code="") {
	VarSetCapacity(buf, 1024) ; Probably won't exceed 1024 chars.
	if DllCall("FormatMessage", "uint", 0x1200, "ptr", 0, "int", error_code!=""
		? error_code : A_LastError, "uint", 1024, "str", buf, "uint", 1024, "ptr", 0)
	return buf
}

getFileFullPath(f) {
	Loop, Files, %f%
	{
		if (A_LoopFileLongPath)
			return A_LoopFileLongPath
	}
}

/*  Complex workaround to override "Active scripting" setting
 *  and ensure scripts can run within the WebBrowser control.
 */

global WBClientSite

SetWBClientSite()
{
	interfaces := {
	(Join,
		IOleClientSite: [0,3,1,0,1,0]
		IServiceProvider: [3]
		IInternetSecurityManager: [1,1,3,4,8,7,3,3]
	)}
	unkQI      := RegisterCallback("WBClientSite_QI", "Fast")
	unkAddRef  := RegisterCallback("WBClientSite_AddRef", "Fast")
	unkRelease := RegisterCallback("WBClientSite_Release", "Fast")
	WBClientSite := {_buffers: bufs := {}}, bufn := 0,
	for name, prms in interfaces
	{
		bufn += 1
		bufs.SetCapacity(bufn, (4 + prms.MaxIndex()) * A_PtrSize)
		buf := bufs.GetAddress(bufn)
		NumPut(unkQI,       buf + 1*A_PtrSize)
		NumPut(unkAddRef,   buf + 2*A_PtrSize)
		NumPut(unkRelease,  buf + 3*A_PtrSize)
		for i, prmc in prms
			NumPut(RegisterCallback("WBClientSite_" name, "Fast", prmc+1, i), buf + (3+i)*A_PtrSize)
		NumPut(buf + A_PtrSize, buf + 0)
		WBClientSite[name] := buf
	}
	wb := getDOM()
	if pOleObject := ComObjQuery(wb, "{00000112-0000-0000-C000-000000000046}")
	{   ; IOleObject::SetClientSite
		DllCall(NumGet(NumGet(pOleObject+0)+3*A_PtrSize), "ptr"
			, pOleObject, "ptr", WBClientSite.IOleClientSite, "uint")
		ObjRelease(pOleObject)
	}
}

WBClientSite_QI(p, piid, ppvObject)
{
	static IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"
	static IID_IOleClientSite := "{00000118-0000-0000-C000-000000000046}"
	static IID_IServiceProvider := "{6d5140c1-7436-11ce-8034-00aa006009fa}"
	iid := _String4GUID(piid)
	if (iid = IID_IOleClientSite || iid = IID_IUnknown)
	{
		NumPut(WBClientSite.IOleClientSite, ppvObject+0)
		return 0 ; S_OK
	}
	if (iid = IID_IServiceProvider)
	{
		NumPut(WBClientSite.IServiceProvider, ppvObject+0)
		return 0 ; S_OK
	}
	NumPut(0, ppvObject+0)
	return 0x80004002 ; E_NOINTERFACE
}

WBClientSite_AddRef(p)
{
	return 1
}

WBClientSite_Release(p)
{
	return 1
}

WBClientSite_IOleClientSite(p, p1="", p2="", p3="")
{
	if (A_EventInfo = 3) ; GetContainer
	{
		NumPut(0, p1+0) ; *ppContainer := NULL
		return 0x80004002 ; E_NOINTERFACE
	}
	return 0x80004001 ; E_NOTIMPL
}

WBClientSite_IServiceProvider(p, pguidService, piid, ppvObject)
{
	static IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"
	static IID_IInternetSecurityManager := "{79eac9ee-baf9-11ce-8c82-00aa004ba90b}"
	if (_String4GUID(pguidService) = IID_IInternetSecurityManager)
	{
		iid := _String4GUID(piid)
		if (iid = IID_IInternetSecurityManager || iid = IID_IUnknown)
		{
			NumPut(WBClientSite.IInternetSecurityManager, ppvObject+0)
			return 0 ; S_OK
		}
		NumPut(0, ppvObject+0)
		return 0x80004002 ; E_NOINTERFACE
	}
	NumPut(0, ppvObject+0)
	return 0x80004001 ; E_NOTIMPL
}

WBClientSite_IInternetSecurityManager(p, p1="", p2="", p3="", p4="", p5="", p6="", p7="", p8="")
{
	if (A_EventInfo = 5) ; ProcessUrlAction
	{
		if (p2 = 0x1400) ; dwAction = URLACTION_SCRIPT_RUN
		{
			NumPut(0, p3+0)  ; *pPolicy := URLPOLICY_ALLOW
			return 0 ; S_OK
		}
	}
	return 0x800C0011 ; INET_E_DEFAULT_ACTION
}

_String4GUID(pGUID)
{
	VarSetCapacity(String,38*2)
	DllCall("ole32\StringFromGUID2", "ptr", pGUID, "str", String, "int", 39)
	Return	String
}

/*  Fix keyboard shortcuts in WebBrowser control.
 *  References:
 *    http://www.autohotkey.com/community/viewtopic.php?p=186254#p186254
 *    http://msdn.microsoft.com/en-us/library/ms693360
 */

gui_KeyDown(wParam, lParam, nMsg, hWnd) {
	global __Webapp_AllowZoomLevelChange

	wb := getDOM()

	if (Chr(wParam) ~= "[A-Z]" || wParam = 0x74) ; Disable Ctrl+O/L/F/N and F5.
		return

	; joedf: optionally disable ctrl zooming
	if (!__Webapp_AllowZoomLevelChange) {
		if(GetKeyState("CTRL") && (wParam=187 || wParam=189)) ;CTRL+ CTRL-
			return
	}

	pipa := ComObjQuery(wb, "{00000117-0000-0000-C000-000000000046}")
	VarSetCapacity(kMsg, 48), NumPut(A_GuiY, NumPut(A_GuiX
	, NumPut(A_EventInfo, NumPut(lParam, NumPut(wParam
	, NumPut(nMsg, NumPut(hWnd, kMsg)))), "uint"), "int"), "int")
	Loop 2
	r := DllCall(NumGet(NumGet(1*pipa)+5*A_PtrSize), "ptr", pipa, "ptr", &kMsg)
	; Loop to work around an odd tabbing issue (it's as if there
	; is a non-existent element at the end of the tab order).
	until wParam != 9 || wb.Document.activeElement != ""
	ObjRelease(pipa)
	if r = 0 ; S_OK: the message was translated to an accelerator.
		return 0
}

gui_WheelScroll(wParam, lParam) {
	if(GET_KEYSTATE_WPARAM(wParam)==8)
		return 1
}

GET_KEYSTATE_WPARAM(wparam) {
	return (wparam & 0xFFFF)
}

;}

;-----end-----


Update ahk

Update ahk

#InstallKeybdHook
#UseHook

is_not_terminal()
{
  ifWinActive,ahk_exe WindowsTerminal.exe
    return 1
  return 0
}

is_vscode()
{
  ifWinActive,ahk_exe Code.exe
    return 0
  return 1
}

SetKeyDelay 0

; Cursor

^a::
  if is_not_terminal()
    send %A_ThisHotkey%
  else
    send {HOME}
  return

^e::
  if is_not_terminal()
    send %A_ThisHotkey%
  else
    send {END}
  return

^p::
  if is_not_terminal()
    send %A_ThisHotkey%
  else
    send {Up}
  return

^n::
  if is_not_terminal()
    send %A_ThisHotkey%
  else
    send {Down}
  return

^f::
  if is_not_terminal()
    send %A_ThisHotKey%
  else
    send {Right}
  return

^+f::
  if is_not_terminal()
    send %A_ThisHotKey%
  else
    send ^f
  return

^b::
  if is_not_terminal()
    send %A_ThisHotKey%
  else
    send {Left}
  return

; Mac-style commands

<#a::
  if is_not_terminal()
    send %A_ThisHotkey%
  else
    send ^a
  return

<#b::
  if is_vscode()
    send %A_ThisHotKey%
  else
    send ^b
  return

<#j::
  if is_vscode()
    send %A_ThisHotKey%
  else
    send ^j
  return

#InstallKeybdHook
#UseHook

is_target()
{
  ; In terminal app, I disable AHK
  ifWinActive,ahk_exe WindowsTerminal.exe
    return 1
  return 0
}

SetKeyDelay 0

; Cursor

^a::
  if is_target()
    send %A_ThisHotkey%
  else
    send {HOME}
  return

^e::
  if is_target()
    send %A_ThisHotkey%
  else
    send {END}
  return

^p::
  if is_target()
    send %A_ThisHotkey%
  else
    send {Up}
  return

^n::
  if is_target()
    send %A_ThisHotkey%
  else
    send {Down}
  return

^f::
  if is_target()
    send %A_ThisHotKey%
  else
    send {Right}
  return

^+f::
  if is_target()
    send %A_ThisHotKey%
  else
    send ^f
  return

^b::
  if is_target()
    send %A_ThisHotKey%
  else
    send {Left}
  return

; Mac-style commands

<#a::
  if is_target()
    send %A_ThisHotkey%
  else
    send ^a
  return