patch to only allow visible title

patch to only allow visible title

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

#SingleInstance Force
#Persistent

GLOBAL_DEBUG_MODE := 1
Return

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

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

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

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

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

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

  n_process_windows := process_windows.Length()
  ; MsgBox, %process_name% -> %n_process_windows%

  index := 1 ; AHK arrays are 1 indexed

  While(GetKeyState("Alt", "P")) {
    If (GetKeyState("``", "P")) {
      If (index < n_process_windows) {
        index := index + 1
        ; MsgBox %index% of %n_process_windows%
      } Else {
        index := 1
      }

      active_id := process_windows[index]
      WinActivate, ahk_id %active_id%
    }
  }

  KeyWait, Alt
  WinActivate, ahk_id %active_id%
  index := ""
Return

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

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

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

; Start the timer on the selected item in the daily view
#IfWinActive ahk_class WindowsForms10.Window.8.app.0.262fb3d
  >+s::
    WinGetActiveTitle, active_title
    match_result := RegExMatch(active_title, "^Entries for")
    ; each item in the dropdown is approximately 25 pixels
    ; so item 4 (Start Timer) is 100 pixels down from the context menu
    drop_down := 100
    If(match_result > 0) {
      WinMove, 100, 100
      MouseMove, 100, 280
      Send {RButton}
      Sleep, 10 ; need to sleep to allow submenu time to come up
      MouseMove, 170, 300 + drop_down
      Send {LButton}
    }
Return

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

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

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

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

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

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

#SingleInstance Force
#Persistent

GLOBAL_DEBUG_MODE := 1
Return

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

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

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

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

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

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

  n_process_windows := process_windows.Length()
  index := 1 ; AHK arrays are 1 indexed

  While(GetKeyState("Alt", "P")) {
    If (index < n_process_windows ) {
      index := index + 1
    } Else {
      index := 1
    }
    active_id := process_windows[index]
    WinActivate, ahk_id %active_id%
    KeyWait, Tab
  }

  KeyWait, Alt
  index := ""
Return

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

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

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

; Start the timer on the selected item in the daily view
#IfWinActive ahk_class WindowsForms10.Window.8.app.0.262fb3d
  >+s::
    WinGetActiveTitle, active_title
    match_result := RegExMatch(active_title, "^Entries for")
    ; each item in the dropdown is approximately 25 pixels
    ; so item 4 (Start Timer) is 100 pixels down from the context menu
    drop_down := 100
    If(match_result > 0) {
      WinMove, 100, 100
      MouseMove, 100, 280
      Send {RButton}
      Sleep, 10 ; need to sleep to allow submenu time to come up
      MouseMove, 170, 300 + drop_down
      Send {LButton}
    }
Return

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

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

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

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

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


DC 插件：从模板新建文件后自动定位功能调整

DC 插件：从模板新建文件后自动定位功能调整

DoubleCommander:
    global DC_Name := "DoubleCommander"
    global DC_Class := "TTOTAL_CMD"
    global DC := "ahk_class " . DC_Class
    global DC_Dir := "c:\mine\app\doublecmd"
    global DC_Path := DC_Dir . "\doublecmd.exe --no-splash"
    ; 用于记录文件打开对话框所属窗体
    global DC_CallerId := 0

    Vim.SetWin(DC_Name, DC_Class, "doublecmd.exe")
    Vim.Mode("normal", DC_Name)
    Vim.BeforeActionDo("DC_ForceInsertMode", DC_Name)
return

DC_ForceInsertMode() {
    ControlGetFocus, Ctrl
    ; Edit 用于底部命令行
    ; Windows1 或 Windows3 用于磁盘列表
    ; Button 用于各种确认窗口，影响正常使用
    if (InStr(Ctrl, "Edit") || Ctrl == "Window1" || Ctrl == "Window3")  {
        return true
    }

    WinGet, MenuID, ID, AHK_CLASS #32768
    if (MenuID != "") {
        return true
    }

    return false
}

DC_Run(Cmd) {
    ControlSetText, Edit1, % Cmd, % DC
    ControlSend, Edit1, {Enter}, % DC
}

DC_RunGet(Cmd, SaveClipboard := True) {
    if (SaveClipboard) {
        ClipSaved := ClipboardAll
    }

    Clipboard := ""

    DC_Run(Cmd)

    ClipWait, 1

    if (SaveClipboard) {
        Result := Clipboard

        Clipboard := ClipSaved
        ClipSaved := ""

        return Result
    }

    return Clipboard
}

; 返回值 [1]: left/right [2]: 左侧面板所占比例 0-100
DC_GetPanelInfo() {
    return StrSplit(DC_RunGet("cm_CopyPanelInfoToClip"), " ")
}

DC_ExecuteToolbarItem(ID) {
    DC_Run("cm_ExecuteToolbarItem ToolItemID=" . ID)
}

DC_OpenPath(Path, InNewTab := true, LeftOrRight := "") {
    LeftOfRight := DC_GetPanelInfo()[1]
    if (LeftOfRight == "right") {
        LeftOrRight := "-R"
    } else {
        LeftOrRight := "-L"
    }

    if (InNewTab) {
        Run, %DC_Path% -C -T "%LeftOrRight%" "%Path%"
    } else {
        Run, %DC_Path% -C "%LeftOrRight%" "%Path%"
    }
}

; funcend

<DC_Test>:
    ; DC_ExecuteToolbarItem("{700FF494-B939-48A3-B248-8823EB366AEA}")
    DC_Run("cm_About")
return

<DC_Restart>:
    WinClose, % DC
    WinWaitClose, % DC, , 2

    Run, % DC_Path

    WinWaitActive, % DC

    if (!WinExist(DC)) {
        MsgBox, 重启失败 %ErrorMessage%
    }
return

<DC_Toggle_50_100>:
    PanelInfo := DC_GetPanelInfo()

    if (Abs(50 - PanelInfo[2]) < 10) {
        if (PanelInfo[1] == "left") {
            DC_Run("cm_PanelsSplitterPerPos splitpct=100")
        } else {
            DC_Run("cm_PanelsSplitterPerPos splitpct=0")
        }
    } else {
        DC_Run("cm_PanelsSplitterPerPos splitpct=50")
    }
return

<DC_PrevParallelDir>:
    DC_Run("cm_ExecuteToolbarItem ToolItemID={D682D989-E31B-4774-A95F-FCAAC0723803}")

    Sleep, 50
return

<DC_NextParallelDir>:
    DC_Run("cm_ExecuteToolbarItem ToolItemID={5CFC019B-CF36-4029-B3F6-3F1AAE3FE462}")

    Sleep, 50
return

<DC_CreateNewFile>:
    ControlGetFocus, TLB, % DC
    ControlGetPos, Xn, Yn, , , % TLB, % DC

    Menu, NewFileMenu, Add
    Menu, NewFileMenu, DeleteAll
    Menu, NewFileMenu, Add , S >> 快捷方式, <DC_CreateFileShortcut>
    Menu, NewFileMenu, Icon, S >> 快捷方式, %A_WinDir%\system32\Shell32.dll, 264
    Menu, NewFileMenu, Add

    Loop, % DC_Dir . "\shellnew\*.*" {
        Ft := SubStr(A_LoopFileName, 1, 1) . " >> " . A_LoopFileName
        Menu, NewFileMenu, Add, % Ft, DC_NewFileMenuAction
        Menu, NewFileMenu, Icon, % Ft, %A_WinDir%\system32\Shell32.dll
    }

    Menu, NewFileMenu, Show, % Xn, % Yn + 2
return

DC_NewFileMenuAction:
    Filename := RegExReplace(A_ThisMenuItem, ".\s>>\s")
    FilePath := DC_Dir . "\ShellNew\" . Filename

    Gui, Destroy
    Gui, Add, Text, x12 y20 w50 h20 +Center, 模板源
    Gui, Add, Edit, x72 y20 w300 h20 Disabled, % FilePath
    Gui, Add, Text, x12 y50 w50 h20 +Center, 新建文件
    Gui, Add, Edit, x72 y50 w300 h20, % Filename
    Gui, Add, Button, x162 y80 w90 h30 gDC_NewFileOk default, 确认(&S)
    Gui, Add, Button, x282 y80 w90 h30 gDC_NewFileClose , 取消(&C)
    Gui, Show, w400 h120, 新建文件

    if (InStr(Filename, ".")) {
        ; 只选定扩展名之外的文件名
        PostMessage, 0x0B1, 0, % InStr(Filename, ".") - 1, Edit2, A
    }
return

DC_NewFileClose:
    Gui, Destroy
return

DC_NewFileOK:
    GuiControlGet, SrcFilePath, , Edit1
    GuiControlGet, NewFilename, , Edit2

    DstPath := DC_RunGet("cm_CopyCurrentPathToClip")

    if (InStr(DstPath, "`r")) {
        DstPath := SubStr(DstPath, 1, InStr(DstPath, "`r") - 1)
    } else if (DstPath == "") {
        return
    }

    NewFilePath := DstPath . NewFilename
    if (FileExist(NewFilePath)) {
        MsgBox, 4, 新建文件, 新建文件已存在，是否覆盖？
        IfMsgBox No
            return
    }

    FileCopy, % SrcFilePath, % NewFilePath, 1

    Gui, Destroy

    ; 验证有没有用
    Sleep, 10
    ; 虽然不是完全匹配，基本也能用了
    DC_Run("cm_QuickSearch text=" . NewFilename)
return

<DC_Toggle>:
    if (WinExist(DC)) {
        WinGet, Ac, MinMax, % DC
        if (Ac == -1) {
            WinActivate, % DC
        } else {
            if (!WinActive(DC)) {
                WinActivate, % DC
            } else {
                WinMinimize, % DC
            }
        }
    } else {
        Run, % DC_Path
        WinWait, % DC

        if (!WinActive(DC)) {
            WinActivate, % DC
        }
    }
return

<DC_MarkFile>:
    SelectedFiles := DC_RunGet("cm_CopyNamesToClip")
    Result := """" . StrReplace(SelectedFiles, "`r`n", """ 🖥`r`n""") . """ 🖥`r`n"

    Sleep, 10
    DC_Run("cm_MarkUnmarkAll")

    FileAppend, % Result, % DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion", UTF-8-RAW

    DC_Run("cm_Refresh")

    SelectedFiles := ""
    Result := ""
return

<DC_UnMarkFile>:
    SelectedFiles := DC_RunGet("cm_CopyNamesToClip")
    DescriptPath := DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion"

    ; 有时取消选定会失效，改 20 也一样，不清楚怎么修复
    Sleep, 10
    DC_Run("cm_MarkUnmarkAll")

    FileRead, Content, % DescriptPath

    Loop, Parse, SelectedFiles, `n, `r
    {
        Content := StrReplace(Content, """" . A_LoopField . """ 🖥`r`n")
    }

    FileDelete, % DescriptPath

    if (Content != "") {
        FileAppend, % Content, % DescriptPath, UTF-8-RAW
    }

    DC_Run("cm_Refresh")

    SelectedFiles := ""
    Content := ""
return

<DC_AddComment>:
    InputBox, Content, , 请输入注释, , 375, 125
    if ErrorLevel
        return

    SelectedFiles := DC_RunGet("cm_CopyNamesToClip")

    Result := """" . StrReplace(SelectedFiles, "`r`n", """ " . Content . "`r`n""") . """ " . Content . "`r`n"

    Sleep, 10
    DC_Run("cm_MarkUnmarkAll")

    FileAppend, % Result, % DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion", UTF-8-RAW

    DC_Run("cm_Refresh")

    SelectedFiles := ""
    Result := ""
return

<DC_RemoveComment>:
    SelectedFiles := DC_RunGet("cm_CopyNamesToClip")
    DescriptPath := DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion"

    ; 有时取消选定会失效，改 20 也一样，不清楚怎么修复
    Sleep, 10
    DC_Run("cm_MarkUnmarkAll")

    FileRead, Content, % DescriptPath

    Loop, Parse, SelectedFiles, `n, `r
    {
        Content := RegexReplace(Content, "m)^""?" . A_LoopField . """? .*")
    }

    ; \K：前边的不算，重新开始匹配
    Content := RegexReplace(Content, "(^|\R)\K\R+")

    FileDelete, % DescriptPath

    if (Content != "") {
        FileAppend, % Content, % DescriptPath, UTF-8-RAW
    }

    DC_Run("cm_Refresh")

    SelectedFiles := ""
    Content := ""
return

<DC_EditComment>:
    Run, % editor . " """ . DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion"""
return

<DC_ToggleShowInfo>:
    Vim.GetWin(DC_Name).SetInfo(!Vim.GetWin(DC_Name).info)
return

<DC_CopyFileContent>:
    FileRead, Clipboard, % DC_RunGet("cm_CopyFullNamesToClip", false)
return

<DC_PasteFileContent>:
    Filename := DC_RunGet("cm_CopyFullNamesToClip")
    FileAppend, % Clipboard, % Filename, UTF-8-RAW
return

<DC_CopyFilenamesOnly>:
    Result := DC_RunGet("cm_CopyFullNamesToClip")

    SplitPath, Result, OutFileName, , , OutFilenameNoExt

    if (InStr(FileExist(Result), "D")) {
        Clipboard := OutFileName
    } else if (InStr(Result, ".")) {
        Clipboard := OutFilenameNoExt
    }
return

<DC_CreateFileShortcut>:
    FilePath := DC_RunGet("cm_CopyFullNamesToClip")

    OutVar := FileExist(FilePath)
    if (InStr(OutVar, "D")) {
        FileCreateShortcut, % FilePath, % FilePath . ".lnk", % RegExReplace(FilePath, "\\[^\\]*$")
    } else if (OutVar != "") {
        FileCreateShortcut, % FilePath, % RegExReplace(FilePath, "\.[^.]*$", ".lnk"), % RegExReplace(FilePath, "\\[^\\]*$")
    }
return

<DC_Focus>:
    IfWinExist, % DC
        Winactivate, % DC
    else {
        Run, % DC_Path
        WinWait, % DC
        IfWinNotActive, % DC
            WinActivate, % DC
    }
return

<DC_MapKeys>:
	Vim.Mode("normal", DC_Name)
    Vim.Map("<S-Enter>", "<DC_SelectedCurrentDir>", DC_Name)
    Vim.Map("<Esc>", "<DC_ReturnToCaller>", DC_Name)
return

<DC_UnMapKeys>:
	Vim.Mode("normal", DC_Name)
    Vim.Map("<S-Enter>", "<Default>", DC_Name)
    Vim.Map("<Esc>", "<Default>", DC_Name)
return

; 返回调用者
<DC_ReturnToCaller>:
    gosub <DC_UnMapKeys>

    WinActivate, ahk_id %DC_CallerId%

    DC_CallerId := 0
return

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

    ; 在 DC 按下快捷键时，激活调用窗体并执行粘贴操作
    if (Name == DC_Class) {
        if (DC_CallerId != 0) {
            gosub <DC_Selected>
            return
		}
    } else {
        DC_CallerId := WinExist("A")
        if (DC_CallerId == 0) {
            return
		}

        gosub <DC_Focus>
        gosub <DC_MapKeys>
    }
return

<DC_Selected>:
    gosub <DC_UnMapKeys>

    if (DC_CallerId == 0) {
        return
    }

    ; 避免发送回车时受同时按下的 Win 等键影响
    ; MsgBox, , , 处理中, 0.3
    ; 通过修改 DC 代码解决

    Pwd := DC_RunGet("cm_CopyCurrentPathToClip", false)

    Filename := DC_RunGet("cm_CopyNamesToClip", false)

    WinActivate, ahk_id %DC_CallerId%
    WinWait, ahk_id %DC_CallerId%
    DC_CallerId := 0

    if (!InStr(Filename, "`n")) {
        Clipboard := Pwd . Filename
        Send, {Home}
        Send, ^v
        Send, {Enter}

        return
    }

    ; 多选

    Files := ""
    Loop, Parse, FIlename, `n, `r
        Files .= """" . A_LoopField  . """ "

    ; 第一步：跳转到当前路径
    Clipboard := Pwd
    Send, ^a
    Send, ^v
    Send, {Enter}
    sleep, 100

    ; 第二步：提交文件名
    Clipboard := Files
    Send, ^v
    Send, {Enter}
return

<DC_SelectedCurrentDir>:
    gosub <DC_UnMapKeys>

    if (DC_CallerId == 0) {
        return
    }

    DC_Run("cm_CopyCurrentPathToClip")

    WinActivate, ahk_id %DC_CallerId%
    WinWait, ahk_id %DC_CallerId%
    DC_CallerId := 0

    Send, {Home}
    Send, ^v
    Send, {Enter}
return

DoubleCommander:
    global DC_Name := "DoubleCommander"
    global DC_Class := "TTOTAL_CMD"
    global DC := "ahk_class " . DC_Class
    global DC_Dir := "c:\mine\app\doublecmd"
    global DC_Path := DC_Dir . "\doublecmd.exe --no-splash"
    ; 用于记录文件打开对话框所属窗体
    global DC_CallerId := 0

    Vim.SetWin(DC_Name, DC_Class, "doublecmd.exe")
    Vim.Mode("normal", DC_Name)
    Vim.BeforeActionDo("DC_ForceInsertMode", DC_Name)
return

DC_ForceInsertMode() {
    ControlGetFocus, Ctrl
    ; Edit 用于底部命令行
    ; Windows1 或 Windows3 用于磁盘列表
    ; Button 用于各种确认窗口，影响正常使用
    if (InStr(Ctrl, "Edit") || Ctrl == "Window1" || Ctrl == "Window3")  {
        return true
    }

    WinGet, MenuID, ID, AHK_CLASS #32768
    if (MenuID != "") {
        return true
    }

    return false
}

DC_Run(Cmd) {
    ControlSetText, Edit1, % Cmd, % DC
    ControlSend, Edit1, {Enter}, % DC
}

DC_RunGet(Cmd, SaveClipboard := True) {
    if (SaveClipboard) {
        ClipSaved := ClipboardAll
    }

    Clipboard := ""

    DC_Run(Cmd)

    ClipWait, 1

    if (SaveClipboard) {
        Result := Clipboard

        Clipboard := ClipSaved
        ClipSaved := ""

        return Result
    }

    return Clipboard
}

; 返回值 [1]: left/right [2]: 左侧面板所占比例 0-100
DC_GetPanelInfo() {
    return StrSplit(DC_RunGet("cm_CopyPanelInfoToClip"), " ")
}

DC_ExecuteToolbarItem(ID) {
    DC_Run("cm_ExecuteToolbarItem ToolItemID=" . ID)
}

DC_OpenPath(Path, InNewTab := true, LeftOrRight := "") {
    LeftOfRight := DC_GetPanelInfo()[1]
    if (LeftOfRight == "right") {
        LeftOrRight := "-R"
    } else {
        LeftOrRight := "-L"
    }

    if (InNewTab) {
        Run, %DC_Path% -C -T "%LeftOrRight%" "%Path%"
    } else {
        Run, %DC_Path% -C "%LeftOrRight%" "%Path%"
    }
}

; funcend

<DC_Test>:
    ; DC_ExecuteToolbarItem("{700FF494-B939-48A3-B248-8823EB366AEA}")
    DC_Run("cm_About")
return

<DC_Restart>:
    WinClose, % DC
    WinWaitClose, % DC, , 2

    Run, % DC_Path

    WinWaitActive, % DC

    if (!WinExist(DC)) {
        MsgBox, 重启失败 %ErrorMessage%
    }
return

<DC_Toggle_50_100>:
    PanelInfo := DC_GetPanelInfo()

    if (Abs(50 - PanelInfo[2]) < 10) {
        if (PanelInfo[1] == "left") {
            DC_Run("cm_PanelsSplitterPerPos splitpct=100")
        } else {
            DC_Run("cm_PanelsSplitterPerPos splitpct=0")
        }
    } else {
        DC_Run("cm_PanelsSplitterPerPos splitpct=50")
    }
return

<DC_PrevParallelDir>:
    DC_Run("cm_ExecuteToolbarItem ToolItemID={D682D989-E31B-4774-A95F-FCAAC0723803}")

    Sleep, 50
return

<DC_NextParallelDir>:
    DC_Run("cm_ExecuteToolbarItem ToolItemID={5CFC019B-CF36-4029-B3F6-3F1AAE3FE462}")

    Sleep, 50
return

<DC_CreateNewFile>:
    ControlGetFocus, TLB, % DC
    ControlGetPos, Xn, Yn, , , % TLB, % DC

    Menu, NewFileMenu, Add
    Menu, NewFileMenu, DeleteAll
    Menu, NewFileMenu, Add , S >> 快捷方式, <DC_CreateFileShortcut>
    Menu, NewFileMenu, Icon, S >> 快捷方式, %A_WinDir%\system32\Shell32.dll, 264
    Menu, NewFileMenu, Add

    Loop, % DC_Dir . "\shellnew\*.*" {
        Ft := SubStr(A_LoopFileName, 1, 1) . " >> " . A_LoopFileName
        Menu, NewFileMenu, Add, % Ft, DC_NewFileMenuAction
        Menu, NewFileMenu, Icon, % Ft, %A_WinDir%\system32\Shell32.dll
    }

    Menu, NewFileMenu, Show, % Xn, % Yn + 2
return

DC_NewFileMenuAction:
    Filename := RegExReplace(A_ThisMenuItem, ".\s>>\s")
    FilePath := DC_Dir . "\ShellNew\" . Filename

    Gui, Destroy
    Gui, Add, Text, x12 y20 w50 h20 +Center, 模板源
    Gui, Add, Edit, x72 y20 w300 h20 Disabled, % FilePath
    Gui, Add, Text, x12 y50 w50 h20 +Center, 新建文件
    Gui, Add, Edit, x72 y50 w300 h20, % Filename
    Gui, Add, Button, x162 y80 w90 h30 gDC_NewFileOk default, 确认(&S)
    Gui, Add, Button, x282 y80 w90 h30 gDC_NewFileClose , 取消(&C)
    Gui, Show, w400 h120, 新建文件

    if (InStr(Filename, ".")) {
        ; 只选定扩展名之外的文件名
        PostMessage, 0x0B1, 0, % InStr(Filename, ".") - 1, Edit2, A
    }
return

DC_NewFileClose:
    Gui, Destroy
return

DC_NewFileOK:
    GuiControlGet, SrcFilePath, , Edit1
    GuiControlGet, NewFilename, , Edit2

    DstPath := DC_RunGet("cm_CopyCurrentPathToClip")

    if (InStr(DstPath, "`r")) {
        DstPath := SubStr(DstPath, 1, InStr(DstPath, "`r") - 1)
    } else if (DstPath == "") {
        return
    }

    NewFilePath := DstPath . NewFilename
    if (FileExist(NewFilePath)) {
        MsgBox, 4, 新建文件, 新建文件已存在，是否覆盖？
        IfMsgBox No
            return
    }

    FileCopy, % SrcFilePath, % NewFilePath, 1

    ; 虽然不是完全匹配，基本也能用了
    DC_Run("cm_QuickSearch text=" . NewFilename)

    Gui, Destroy
return

<DC_Toggle>:
    if (WinExist(DC)) {
        WinGet, Ac, MinMax, % DC
        if (Ac == -1) {
            WinActivate, % DC
        } else {
            if (!WinActive(DC)) {
                WinActivate, % DC
            } else {
                WinMinimize, % DC
            }
        }
    } else {
        Run, % DC_Path
        WinWait, % DC

        if (!WinActive(DC)) {
            WinActivate, % DC
        }
    }
return

<DC_MarkFile>:
    SelectedFiles := DC_RunGet("cm_CopyNamesToClip")
    Result := """" . StrReplace(SelectedFiles, "`r`n", """ 🖥`r`n""") . """ 🖥`r`n"

    Sleep, 10
    DC_Run("cm_MarkUnmarkAll")

    FileAppend, % Result, % DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion", UTF-8-RAW

    DC_Run("cm_Refresh")

    SelectedFiles := ""
    Result := ""
return

<DC_UnMarkFile>:
    SelectedFiles := DC_RunGet("cm_CopyNamesToClip")
    DescriptPath := DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion"

    ; 有时取消选定会失效，改 20 也一样，不清楚怎么修复
    Sleep, 10
    DC_Run("cm_MarkUnmarkAll")

    FileRead, Content, % DescriptPath

    Loop, Parse, SelectedFiles, `n, `r
    {
        Content := StrReplace(Content, """" . A_LoopField . """ 🖥`r`n")
    }

    FileDelete, % DescriptPath

    if (Content != "") {
        FileAppend, % Content, % DescriptPath, UTF-8-RAW
    }

    DC_Run("cm_Refresh")

    SelectedFiles := ""
    Content := ""
return

<DC_AddComment>:
    InputBox, Content, , 请输入注释, , 375, 125
    if ErrorLevel
        return

    SelectedFiles := DC_RunGet("cm_CopyNamesToClip")

    Result := """" . StrReplace(SelectedFiles, "`r`n", """ " . Content . "`r`n""") . """ " . Content . "`r`n"

    Sleep, 10
    DC_Run("cm_MarkUnmarkAll")

    FileAppend, % Result, % DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion", UTF-8-RAW

    DC_Run("cm_Refresh")

    SelectedFiles := ""
    Result := ""
return

<DC_RemoveComment>:
    SelectedFiles := DC_RunGet("cm_CopyNamesToClip")
    DescriptPath := DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion"

    ; 有时取消选定会失效，改 20 也一样，不清楚怎么修复
    Sleep, 10
    DC_Run("cm_MarkUnmarkAll")

    FileRead, Content, % DescriptPath

    Loop, Parse, SelectedFiles, `n, `r
    {
        Content := RegexReplace(Content, "m)^""?" . A_LoopField . """? .*")
    }

    ; \K：前边的不算，重新开始匹配
    Content := RegexReplace(Content, "(^|\R)\K\R+")

    FileDelete, % DescriptPath

    if (Content != "") {
        FileAppend, % Content, % DescriptPath, UTF-8-RAW
    }

    DC_Run("cm_Refresh")

    SelectedFiles := ""
    Content := ""
return

<DC_EditComment>:
    Run, % editor . " """ . DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion"""
return

<DC_ToggleShowInfo>:
    Vim.GetWin(DC_Name).SetInfo(!Vim.GetWin(DC_Name).info)
return

<DC_CopyFileContent>:
    FileRead, Clipboard, % DC_RunGet("cm_CopyFullNamesToClip", false)
return

<DC_PasteFileContent>:
    Filename := DC_RunGet("cm_CopyFullNamesToClip")
    FileAppend, % Clipboard, % Filename, UTF-8-RAW
return

<DC_CopyFilenamesOnly>:
    Result := DC_RunGet("cm_CopyFullNamesToClip")

    SplitPath, Result, OutFileName, , , OutFilenameNoExt

    if (InStr(FileExist(Result), "D")) {
        Clipboard := OutFileName
    } else if (InStr(Result, ".")) {
        Clipboard := OutFilenameNoExt
    }
return

<DC_CreateFileShortcut>:
    FilePath := DC_RunGet("cm_CopyFullNamesToClip")

    OutVar := FileExist(FilePath)
    if (InStr(OutVar, "D")) {
        FileCreateShortcut, % FilePath, % FilePath . ".lnk", % RegExReplace(FilePath, "\\[^\\]*$")
    } else if (OutVar != "") {
        FileCreateShortcut, % FilePath, % RegExReplace(FilePath, "\.[^.]*$", ".lnk"), % RegExReplace(FilePath, "\\[^\\]*$")
    }
return

<DC_Focus>:
    IfWinExist, % DC
        Winactivate, % DC
    else {
        Run, % DC_Path
        WinWait, % DC
        IfWinNotActive, % DC
            WinActivate, % DC
    }
return

<DC_MapKeys>:
	Vim.Mode("normal", DC_Name)
    Vim.Map("<S-Enter>", "<DC_SelectedCurrentDir>", DC_Name)
    Vim.Map("<Esc>", "<DC_ReturnToCaller>", DC_Name)
return

<DC_UnMapKeys>:
	Vim.Mode("normal", DC_Name)
    Vim.Map("<S-Enter>", "<Default>", DC_Name)
    Vim.Map("<Esc>", "<Default>", DC_Name)
return

; 返回调用者
<DC_ReturnToCaller>:
    gosub <DC_UnMapKeys>

    WinActivate, ahk_id %DC_CallerId%

    DC_CallerId := 0
return

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

    ; 在 DC 按下快捷键时，激活调用窗体并执行粘贴操作
    if (Name == DC_Class) {
        if (DC_CallerId != 0) {
            gosub <DC_Selected>
            return
		}
    } else {
        DC_CallerId := WinExist("A")
        if (DC_CallerId == 0) {
            return
		}

        gosub <DC_Focus>
        gosub <DC_MapKeys>
    }
return

<DC_Selected>:
    gosub <DC_UnMapKeys>

    if (DC_CallerId == 0) {
        return
    }

    ; 避免发送回车时受同时按下的 Win 等键影响
    ; MsgBox, , , 处理中, 0.3
    ; 通过修改 DC 代码解决

    Pwd := DC_RunGet("cm_CopyCurrentPathToClip", false)

    Filename := DC_RunGet("cm_CopyNamesToClip", false)

    WinActivate, ahk_id %DC_CallerId%
    WinWait, ahk_id %DC_CallerId%
    DC_CallerId := 0

    if (!InStr(Filename, "`n")) {
        Clipboard := Pwd . Filename
        Send, {Home}
        Send, ^v
        Send, {Enter}

        return
    }

    ; 多选

    Files := ""
    Loop, Parse, FIlename, `n, `r
        Files .= """" . A_LoopField  . """ "

    ; 第一步：跳转到当前路径
    Clipboard := Pwd
    Send, ^a
    Send, ^v
    Send, {Enter}
    sleep, 100

    ; 第二步：提交文件名
    Clipboard := Files
    Send, ^v
    Send, {Enter}
return

<DC_SelectedCurrentDir>:
    gosub <DC_UnMapKeys>

    if (DC_CallerId == 0) {
        return
    }

    DC_Run("cm_CopyCurrentPathToClip")

    WinActivate, ahk_id %DC_CallerId%
    WinWait, ahk_id %DC_CallerId%
    DC_CallerId := 0

    Send, {Home}
    Send, ^v
    Send, {Enter}
return


Update PluginTemplete.ahk

Update PluginTemplete.ahk

; 插件名和目录名一致，插件要放到 plugins/PluginName/PluginName.ahk 位置。
; 放入插件后，重新运行 vimd 会自动启用插件。
; 标签名请添加 PluginName_ 前缀，避免和其他插件冲突。

; 该标签名需要和插件名一致
PluginName:
    ; 定义注释（可选）
    vim.SetAction("<PluginName_NormalMode>", "进入normal模式")
    vim.SetAction("<PluginName_InsertMode>", "进入insert模式")
    vim.SetAction("<PluginName_Function1>", "功能1")
    vim.SetAction("<PluginName_Function2>", "功能2")

    ; 请务必调用 vim.SetWin 并保证 PluginName 和文件名一致，以避免名称混乱影响使用
    vim.SetWin("PluginName", "ahk_class名")
    ; 或：
    vim.SetWin("PluginName", "ahk_class名", "PluginName.exe")
    ; 如果 class 和 exe 同时填写，以 exe 为准

    ; insert模式（如果无需 insert 模式，可去掉）
    vim.SetMode("insert", "PluginName")

    vim.Map("<esc>", "<PluginName_NormalMode>", "PluginName")

    ; normal模式（必需）
    vim.SetMode("normal", "PluginName")

    vim.Map("i", "<PluginName_InsertMode>", "PluginName")

    vim.Map("a", "<PluginName_Function1>", "PluginName")
    vim.Map("b", "<PluginName_Function2>", "PluginName")

    ; 可选
    vim.BeforeActionDo("PluginName_BeforeActionDo", "PluginName")
return

; 对符合条件的控件使用insert模式，而不是normal模式
; 此段代码可以直接复制，但请修改AHK_CLASS的值和RegExMatch的第二个参数
PluginName_BeforeActionDo()
{
    ControlGetFocus, ctrl, AHK_CLASS PluginName
    ; MsgBox % ctrl
    if RegExMatch(ctrl, "Edit2")
        return true
    return false
}

<PluginName_NormalMode>:
    vim.SetMode("normal", "PluginName")
return

<PluginName_InsertMode>:
    vim.SetMode("insert", "PluginName")
return

<PluginName_Function1>:
    Send, ^n
return

<PluginName_Function2>:
    Send, ^p
return

; 插件名和目录名一致，插件要放到 plugins/PluginName/PluginName.ahk 位置。
; 放入插件后，重新运行 vimd 会自动启用插件。
; 标签名请添加 PluginName_ 前缀，避免和其他插件冲突。

PluginName:
    ; 定义注释（可选）
    vim.SetAction("<PluginName_NormalMode>", "进入normal模式")
    vim.SetAction("<PluginName_InsertMode>", "进入insert模式")
    vim.SetAction("<PluginName_Function1>", "功能1")
    vim.SetAction("<PluginName_Function2>", "功能2")

    vim.SetWin("PluginName", "ahk_class名")
    ; 或：
    vim.SetWin("PluginName", , "PluginName.exe")
    ; 如果 class 和 exe 同时填写，以 exe 为准

    ; insert模式（如果无需 insert 模式，可去掉）
    vim.SetMode("insert", "PluginName")

    vim.Map("<esc>", "<PluginName_NormalMode>", "PluginName")

    ; normal模式（必需）
    vim.SetMode("normal", "PluginName")

    vim.Map("i", "<PluginName_InsertMode>", "PluginName")

    vim.Map("a", "<PluginName_Function1>", "PluginName")
    vim.Map("b", "<PluginName_Function2>", "PluginName")

    ; 可选
    vim.BeforeActionDo("PluginName_BeforeActionDo", "PluginName")
return

; 对符合条件的控件使用insert模式，而不是normal模式
; 此段代码可以直接复制，但请修改AHK_CLASS的值和RegExMatch的第二个参数
PluginName_BeforeActionDo()
{
    ControlGetFocus, ctrl, AHK_CLASS PluginName
    ; MsgBox % ctrl
    if RegExMatch(ctrl, "Edit2")
        return true
    return false
}

<PluginName_NormalMode>:
    vim.SetMode("normal", "PluginName")
return

<PluginName_InsertMode>:
    vim.SetMode("insert", "PluginName")
return

<PluginName_Function1>:
    Send, ^n
return

<PluginName_Function2>:
    Send, ^p
return


DC 插件：通过修改 DC 代码实现可以把 DC_Run 绑到 Win/Ctrl/Alt + ... 上

/*
    此插件仅供自用，依赖对 DC 代码的修改以及专门的配置
    我修改版的 DC 代码：https://github.com/goreliu/doublecmd

    ---

    DC 的优势

    开源，免费，跨平台，可以自由改代码定制功能，很好编译
    可以改代码让所有目录中的父目录（..）消失（已完成）
    可以把按键绑定到工具栏的子菜单上，然后再通过按键触发功能
    内建 lua 解释器，方便写一些高级功能（感觉功能有限，用处不大）
    主界面和配置界面更漂亮、好用
*/

DoubleCommander:
    global DC_Class := "TTOTAL_CMD"
    global DC := "ahk_class " . DC_Class
    global DC_Dir := "c:\mine\app\doublecmd"
    global DC_Path := "c:\mine\app\doublecmd\doublecmd.exe --no-splash"
    ; 用于记录文件打开对话框所属窗体
    global DC_CallerId := 0

    DC_Name := "DoubleCommander"

    Vim.SetWin(DC_Name, DC_Class, "doublecmd.exe")
    Vim.Mode("normal", DC_Name)

    Vim.BeforeActionDo("DC_ForceInsertMode", DC_Name)
return

DC_ForceInsertMode() {
    ControlGetFocus, Ctrl
    if (InStr(Ctrl, "Edit") || Ctrl == "Window1") {
        return true
    }

    WinGet, MenuID, ID, AHK_CLASS #32768
    if (MenuID != "") {
        return true
    }

    return false
}

DC_Run(Cmd) {
    ControlSetText, Edit1, % Cmd, % DC
    ControlSend, Edit1, {Enter}, % DC
}

DC_RunGet(Cmd, SaveClipboard := True) {
    if (SaveClipboard) {
        ClipSaved := ClipboardAll
    }

    Clipboard := ""

    DC_Run(Cmd)

    ClipWait, 1

    if (SaveClipboard) {
        Result := Clipboard

        Clipboard := ClipSaved
        ClipSaved := ""

        return Result
    }

    return Clipboard
}

; 返回值 [1]: left/right [2]: 左侧面板所占比例 0-100
DC_GetPanelInfo() {
    return StrSplit(DC_RunGet("cm_CopyPanelInfoToClip"), " ")
}

DC_ExecuteToolbarItem(ID) {
    DC_Run("cm_ExecuteToolbarItem ToolItemID=" . ID)
}

DC_OpenPath(Path, InNewTab := true, LeftOrRight := "") {
    LeftOfRight := DC_GetPanelInfo()[1]
    if (LeftOfRight == "right") {
        LeftOrRight := "-R"
    } else {
        LeftOrRight := "-L"
    }

    if (InNewTab) {
        Run, %DC_Path% -C -T "%LeftOrRight%" "%Path%"
    } else {
        Run, %DC_Path% -C "%LeftOrRight%" "%Path%"
    }
}

; funcend

<DC_Test>:
    ; DC_ExecuteToolbarItem("{700FF494-B939-48A3-B248-8823EB366AEA}")
    DC_Run("cm_About")
return

<DC_Restart>:
    WinClose, % DC
    WinWaitClose, % DC, , 2

    Run, % DC_Path

    WinWaitActive, % DC

    if (!WinExist(DC)) {
        MsgBox, 重启失败 %ErrorMessage%
    }
return

<DC_Toggle_50_100>:
    PanelInfo := DC_GetPanelInfo()

    if (Abs(50 - PanelInfo[2]) < 10) {
        if (PanelInfo[1] == "left") {
            DC_Run("cm_PanelsSplitterPerPos splitpct=100")
        } else {
            DC_Run("cm_PanelsSplitterPerPos splitpct=0")
        }
    } else {
        DC_Run("cm_PanelsSplitterPerPos splitpct=50")
    }
return

<DC_PrevParallelDir>:
    SleepTime := 50

    OldPwd := DC_RunGet("cm_CopyCurrentPathToClip")

    if (StrLen(OldPwd) == 3) {
        ; 在根分区

        return
    }

    DC_Run("cm_ChangeDirToParent")
    Sleep, % SleepTime

    ; 可能没跳转过去 TODO
    DC_Run("cm_GoToPrevEntry")
    Sleep, % SleepTime

    DC_Run("cm_EnterActiveDir")
    Sleep, % SleepTime
return

<DC_NextParallelDir>:
    SleepTime := 50

    OldPwd := DC_RunGet("cm_CopyCurrentPathToClip")

    if (StrLen(OldPwd) == 3) {
        ; 在根分区

        return
    }

    DC_Run("cm_ChangeDirToParent")
    Sleep, % SleepTime

    ; 可能没跳转过去 TODO
    DC_Run("cm_GoToNextEntry")
    Sleep, % SleepTime

    DC_Run("cm_EnterActiveDir")
    Sleep, % SleepTime

    Pwd := DC_RunGet("cm_CopyCurrentPathToClip", false)
    Sleep, % SleepTime

    if (OldPwd != Pwd && InStr(OldPwd, Pwd) == 1) {
        ; 下一个是文件
        DC_Run("cm_ViewHistoryPrev")
    }
return

<DC_CreateNewFile>:
    ControlGetFocus, TLB, % DC
    ControlGetPos, Xn, Yn, , , % TLB, % DC

    Menu, NewFileMenu, Add
    Menu, NewFileMenu, DeleteAll
    Menu, NewFileMenu, Add , S >> 快捷方式, <DC_CreateFileShortcut>
    Menu, NewFileMenu, Icon, S >> 快捷方式, %A_WinDir%\system32\Shell32.dll, 264
    Menu, NewFileMenu, Add

    Loop, % DC_Dir . "\shellnew\*.*" {
        Ft := SubStr(A_LoopFileName, 1, 1) . " >> " . A_LoopFileName
        Menu, NewFileMenu, Add, % Ft, DC_NewFileMenuAction
        Menu, NewFileMenu, Icon, % Ft, %A_WinDir%\system32\Shell32.dll
    }

    Menu, NewFileMenu, Show, % Xn, % Yn + 2
return

DC_NewFileMenuAction:
    Filename := RegExReplace(A_ThisMenuItem, ".\s>>\s")
    FilePath := DC_Dir . "\ShellNew\" . Filename

    Gui, Destroy
    Gui, Add, Text, x12 y20 w50 h20 +Center, 模板源
    Gui, Add, Edit, x72 y20 w300 h20 Disabled, % FilePath
    Gui, Add, Text, x12 y50 w50 h20 +Center, 新建文件
    Gui, Add, Edit, x72 y50 w300 h20, % Filename
    Gui, Add, Button, x162 y80 w90 h30 gDC_NewFileOk default, 确认(&S)
    Gui, Add, Button, x282 y80 w90 h30 gDC_NewFileClose , 取消(&C)
    Gui, Show, w400 h120, 新建文件

    if (InStr(Filename, ".")) {
        ; 只选定扩展名之外的文件名
        PostMessage, 0x0B1, 0, % InStr(Filename, ".") - 1, Edit2, A
    }
return

DC_NewFileClose:
    Gui, Destroy
return

DC_NewFileOK:
    GuiControlGet, SrcFilePath, , Edit1
    GuiControlGet, NewFilename, , Edit2

    DstPath := DC_RunGet("cm_CopyCurrentPathToClip")

    if (InStr(DstPath, "`r")) {
        DstPath := SubStr(DstPath, 1, InStr(DstPath, "`r") - 1)
    } else if (DstPath == "") {
        return
    }

    NewFilePath := DstPath . NewFilename
    if (FileExist(NewFilePath)) {
        MsgBox, 4, 新建文件, 新建文件已存在，是否覆盖？
        IfMsgBox No
            return
    }

    FileCopy, % SrcFilePath, % NewFilePath, 1

    ; 虽然不是完全匹配，基本也能用了
    DC_Run("cm_QuickSearch matchbeginning=on | text=" . NewFilename)

    Gui, Destroy
return

<DC_Toggle>:
    if (WinExist(DC)) {
        WinGet, Ac, MinMax, % DC
        if (Ac == -1) {
            WinActivate, % DC
        } else {
            if (!WinActive(DC)) {
                WinActivate, % DC
            } else {
                WinMinimize, % DC
            }
        }
    } else {
        Run, % DC_Path
        WinWait, % DC

        if (!WinActive(DC)) {
            WinActivate, % DC
        }
    }
return

<DC_MarkFile>:
    DC_Run("cm_EditComment")
    ; 不要在已有备注的文件使用
    Send, ^+{End}🖥{F2}
return

<DC_UnMarkFile>:
    DC_Run("cm_EditComment")
    ; 删除 DC_MarkFile 的文件标记，也可用于清空文件备注
    Send, ^+{End}{Del}{F2}
return

<DC_ToggleShowInfo>:
    Vim.GetWin(DC_Name).SetInfo(!Vim.GetWin(DC_Name).info)
return

<DC_CopyFileContent>:
    Fileread, Contents, % DC_RunGet("cm_CopyFullNamesToClip", false)
    Clipboard := Contents
return

<DC_CopyFilenamesOnly>:
    Result := DC_RunGet("cm_CopyFullNamesToClip")

    SplitPath, Result, OutFileName, , , OutFilenameNoExt

    if (InStr(FileExist(Result), "D")) {
        Clipboard := OutFileName
    } else if (InStr(Result, ".")) {
        Clipboard := OutFilenameNoExt
    }
return

<DC_CreateFileShortcut>:
    FilePath := DC_RunGet("cm_CopyFullNamesToClip")

    OutVar := FileExist(FilePath)
    if (InStr(OutVar, "D")) {
        FileCreateShortcut, % FilePath, % FilePath . ".lnk"
    } else if (OutVar != "") {
        FileCreateShortcut, % FilePath, % RegExReplace(FilePath, "\.[^.]*$", ".lnk")
    }
return

<DC_Focus>:
    IfWinExist, % DC
        Winactivate, % DC
    else {
        Run, % DC_Path
        WinWait, % DC
        IfWinNotActive, % DC
            WinActivate, % DC
    }
return

<DC_MapKeys>:
	Vim.Mode("normal", DC_Name)
    Vim.Map("<S-Enter>", "<DC_SelectedCurrentDir>", DC_Name)
    Vim.Map("<Esc>", "<DC_ReturnToCaller>", DC_Name)
return

<DC_UnMapKeys>:
	Vim.Mode("normal", DC_Name)
    Vim.Map("<S-Enter>", "<Default>", DC_Name)
    Vim.Map("<Esc>", "<Default>", DC_Name)
return

; 返回调用者
<DC_ReturnToCaller>:
    gosub <DC_UnMapKeys>

    WinActivate, ahk_id %DC_CallerId%

    DC_CallerId := 0
return

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

    ; 在 DC 按下快捷键时，激活调用窗体并执行粘贴操作
    if (Name == DC_Class) {
        if (DC_CallerId != 0) {
            gosub <DC_Selected>
            return
		}
    } else {
        DC_CallerId := WinExist("A")
        if (DC_CallerId == 0) {
            return
		}

        gosub <DC_Focus>
        gosub <DC_MapKeys>
    }
return

<DC_Selected>:
    gosub <DC_UnMapKeys>

    if (DC_CallerId == 0) {
        return
    }

    ; 避免发送回车时受同时按下的 Win 等键影响
    ; MsgBox, , , 处理中, 0.3
    ; 通过修改 DC 代码解决

    Pwd := DC_RunGet("cm_CopyCurrentPathToClip", false)

    Filename := DC_RunGet("cm_CopyNamesToClip", false)

    WinActivate, ahk_id %DC_CallerId%
    WinWait, ahk_id %DC_CallerId%
    DC_CallerId := 0

    if (!InStr(Filename, "`n")) {
        Clipboard := Pwd . Filename
        Send, {Home}
        Send, ^v
        Send, {Enter}

        return
    }

    ; 多选

    Files := ""
    Loop, parse, FIlename, `n, `r
        Files .= """" . A_LoopField  . """ "

    ; 第一步：跳转到当前路径
    Clipboard := Pwd
    Send, ^a
    Send, ^v
    Send, {Enter}
    sleep, 100

    ; 第二步：提交文件名
    Clipboard := Files
    Send, ^v
    Send, {Enter}
return

<DC_SelectedCurrentDir>:
    gosub <DC_UnMapKeys>

    if (DC_CallerId == 0) {
        return
    }

    DC_Run("cm_CopyCurrentPathToClip")

    WinActivate, ahk_id %DC_CallerId%
    WinWait, ahk_id %DC_CallerId%
    DC_CallerId := 0

    Send, {Home}
    Send, ^v
    Send, {Enter}
return

/*
    此插件仅供自用，依赖对 DC 代码的修改以及专门的配置

    ---

    DC 的优势

    开源，免费，跨平台，可以自由改代码定制功能，很好编译
    可以改代码让所有目录中的父目录（..）消失（已完成）
    可以把按键绑定到工具栏的子菜单上，然后再通过按键触发功能
    内建 lua 解释器，方便写一些高级功能（感觉功能有限，用处不大）
    主界面和配置界面更漂亮、好用
*/

DoubleCommander:
    global DC_Class := "TTOTAL_CMD"
    global DC := "ahk_class " . DC_Class
    global DC_Dir := "c:\mine\app\doublecmd"
    global DC_Path := "c:\mine\app\doublecmd\doublecmd.exe --no-splash"
    ; 用于记录文件打开对话框所属窗体
    global DC_CallerId := 0

    DC_Name := "DoubleCommander"

    Vim.SetWin(DC_Name, DC_Class, "doublecmd.exe")
    Vim.Mode("normal", DC_Name)

    Vim.BeforeActionDo("DC_ForceInsertMode", DC_Name)
return

DC_ForceInsertMode() {
    ControlGetFocus, Ctrl
    if (InStr(Ctrl, "Edit") || Ctrl == "Window1") {
        return true
    }

    WinGet, MenuID, ID, AHK_CLASS #32768
    if (MenuID != "") {
        return true
    }

    return false
}

DC_Run(Cmd) {
    ControlSetText, Edit1, % Cmd, % DC
    ControlSend, Edit1, {Enter}, % DC
}

DC_RunGet(Cmd, SaveClipboard := True) {
    if (SaveClipboard) {
        ClipSaved := ClipboardAll
    }

    Clipboard := ""

    DC_Run(Cmd)

    ClipWait, 1

    if (SaveClipboard) {
        Result := Clipboard

        Clipboard := ClipSaved
        ClipSaved := ""

        return Result
    }

    return Clipboard
}

; 返回值 [1]: left/right [2]: 左侧面板所占比例 0-100
DC_GetPanelInfo() {
    return StrSplit(DC_RunGet("cm_CopyPanelInfoToClip"), " ")
}

DC_ExecuteToolbarItem(ID) {
    DC_Run("cm_ExecuteToolbarItem ToolItemID=" . ID)
}

DC_OpenPath(Path, InNewTab := true, LeftOrRight := "") {
    LeftOfRight := DC_GetPanelInfo()[1]
    if (LeftOfRight == "right") {
        LeftOrRight := "-R"
    } else {
        LeftOrRight := "-L"
    }

    if (InNewTab) {
        Run, %DC_Path% -C -T "%LeftOrRight%" "%Path%"
    } else {
        Run, %DC_Path% -C "%LeftOrRight%" "%Path%"
    }
}

; funcend

<DC_Test>:
    ; DC_ExecuteToolbarItem("{700FF494-B939-48A3-B248-8823EB366AEA}")
    DC_Run("cm_About")
return

<DC_Restart>:
    WinClose, % DC
    WinWaitClose, % DC, , 2

    Run, % DC_Path

    WinWaitActive, % DC

    if (!WinExist(DC)) {
        MsgBox, 重启失败 %ErrorMessage%
    }
return

<DC_Toggle_50_100>:
    PanelInfo := DC_GetPanelInfo()

    if (Abs(50 - PanelInfo[2]) < 10) {
        if (PanelInfo[1] == "left") {
            DC_Run("cm_PanelsSplitterPerPos splitpct=100")
        } else {
            DC_Run("cm_PanelsSplitterPerPos splitpct=0")
        }
    } else {
        DC_Run("cm_PanelsSplitterPerPos splitpct=50")
    }
return

<DC_PrevParallelDir>:
    SleepTime := 50

    OldPwd := DC_RunGet("cm_CopyCurrentPathToClip")

    if (StrLen(OldPwd) == 3) {
        ; 在根分区

        return
    }

    DC_Run("cm_ChangeDirToParent")
    Sleep, % SleepTime

    ; 可能没跳转过去 TODO
    DC_Run("cm_GoToPrevEntry")
    Sleep, % SleepTime

    DC_Run("cm_EnterActiveDir")
    Sleep, % SleepTime
return

<DC_NextParallelDir>:
    SleepTime := 50

    OldPwd := DC_RunGet("cm_CopyCurrentPathToClip")

    if (StrLen(OldPwd) == 3) {
        ; 在根分区

        return
    }

    DC_Run("cm_ChangeDirToParent")
    Sleep, % SleepTime

    ; 可能没跳转过去 TODO
    DC_Run("cm_GoToNextEntry")
    Sleep, % SleepTime

    DC_Run("cm_EnterActiveDir")
    Sleep, % SleepTime

    Pwd := DC_RunGet("cm_CopyCurrentPathToClip", false)
    Sleep, % SleepTime

    if (OldPwd != Pwd && InStr(OldPwd, Pwd) == 1) {
        ; 下一个是文件
        DC_Run("cm_ViewHistoryPrev")
    }
return

<DC_CreateNewFile>:
    ControlGetFocus, TLB, % DC
    ControlGetPos, Xn, Yn, , , % TLB, % DC

    Menu, NewFileMenu, Add
    Menu, NewFileMenu, DeleteAll
    Menu, NewFileMenu, Add , S >> 快捷方式, <DC_CreateFileShortcut>
    Menu, NewFileMenu, Icon, S >> 快捷方式, %A_WinDir%\system32\Shell32.dll, 264
    Menu, NewFileMenu, Add

    Loop, % DC_Dir . "\shellnew\*.*" {
        Ft := SubStr(A_LoopFileName, 1, 1) . " >> " . A_LoopFileName
        Menu, NewFileMenu, Add, % Ft, DC_NewFileMenuAction
        Menu, NewFileMenu, Icon, % Ft, %A_WinDir%\system32\Shell32.dll
    }

    Menu, NewFileMenu, Show, % Xn, % Yn + 2
return

DC_NewFileMenuAction:
    Filename := RegExReplace(A_ThisMenuItem, ".\s>>\s")
    FilePath := DC_Dir . "\ShellNew\" . Filename

    Gui, Destroy
    Gui, Add, Text, x12 y20 w50 h20 +Center, 模板源
    Gui, Add, Edit, x72 y20 w300 h20 Disabled, % FilePath
    Gui, Add, Text, x12 y50 w50 h20 +Center, 新建文件
    Gui, Add, Edit, x72 y50 w300 h20, % Filename
    Gui, Add, Button, x162 y80 w90 h30 gDC_NewFileOk default, 确认(&S)
    Gui, Add, Button, x282 y80 w90 h30 gDC_NewFileClose , 取消(&C)
    Gui, Show, w400 h120, 新建文件

    if (InStr(Filename, ".")) {
        ; 只选定扩展名之外的文件名
        PostMessage, 0x0B1, 0, % InStr(Filename, ".") - 1, Edit2, A
    }
return

DC_NewFileClose:
    Gui, Destroy
return

DC_NewFileOK:
    GuiControlGet, SrcFilePath, , Edit1
    GuiControlGet, NewFilename, , Edit2

    DstPath := DC_RunGet("cm_CopyCurrentPathToClip")

    if (InStr(DstPath, "`r")) {
        DstPath := SubStr(DstPath, 1, InStr(DstPath, "`r") - 1)
    } else if (DstPath == "") {
        return
    }

    NewFilePath := DstPath . NewFilename
    if (FileExist(NewFilePath)) {
        MsgBox, 4, 新建文件, 新建文件已存在，是否覆盖？
        IfMsgBox No
            return
    }

    FileCopy, % SrcFilePath, % NewFilePath, 1

    ; 虽然不是完全匹配，基本也能用了
    DC_Run("cm_QuickSearch matchbeginning=on | text=" . NewFilename)

    Gui, Destroy
return

<DC_Toggle>:
    if (WinExist(DC)) {
        WinGet, Ac, MinMax, % DC
        if (Ac == -1) {
            WinActivate, % DC
        } else {
            if (!WinActive(DC)) {
                WinActivate, % DC
            } else {
                WinMinimize, % DC
            }
        }
    } else {
        Run, % DC_Path
        WinWait, % DC

        if (!WinActive(DC)) {
            WinActivate, % DC
        }
    }
return

<DC_MarkFile>:
    DC_Run("cm_EditComment")
    ; 不要在已有备注的文件使用
    Send, ^+{End}🖥{F2}
return

<DC_UnMarkFile>:
    DC_Run("cm_EditComment")
    ; 删除 DC_MarkFile 的文件标记，也可用于清空文件备注
    Send, ^+{End}{Del}{F2}
return

<DC_ToggleShowInfo>:
    Vim.GetWin(DC_Name).SetInfo(!Vim.GetWin(DC_Name).info)
return

<DC_CopyFileContent>:
    Fileread, Contents, % DC_RunGet("cm_CopyFullNamesToClip", false)
    Clipboard := Contents
return

<DC_CopyFilenamesOnly>:
    Result := DC_RunGet("cm_CopyFullNamesToClip")

    SplitPath, Result, OutFileName, , , OutFilenameNoExt

    if (InStr(FileExist(Result), "D")) {
        Clipboard := OutFileName
    } else if (InStr(Result, ".")) {
        Clipboard := OutFilenameNoExt
    }
return

<DC_CreateFileShortcut>:
    FilePath := DC_RunGet("cm_CopyFullNamesToClip")

    OutVar := FileExist(FilePath)
    if (InStr(OutVar, "D")) {
        FileCreateShortcut, % FilePath, % FilePath . ".lnk"
    } else if (OutVar != "") {
        FileCreateShortcut, % FilePath, % RegExReplace(FilePath, "\.[^.]*$", ".lnk")
    }
return

<DC_Focus>:
    IfWinExist, % DC
        Winactivate, % DC
    else {
        Run, % DC_Path
        WinWait, % DC
        IfWinNotActive, % DC
            WinActivate, % DC
    }
return

<DC_MapKeys>:
	Vim.Mode("normal", DC_Name)
    Vim.Map("<S-Enter>", "<DC_SelectedCurrentDir>", DC_Name)
    Vim.Map("<Esc>", "<DC_ReturnToCaller>", DC_Name)
return

<DC_UnMapKeys>:
	Vim.Mode("normal", DC_Name)
    Vim.Map("<S-Enter>", "<Default>", DC_Name)
    Vim.Map("<Esc>", "<Default>", DC_Name)
return

; 返回调用者
<DC_ReturnToCaller>:
    gosub <DC_UnMapKeys>

    WinActivate, ahk_id %DC_CallerId%

    DC_CallerId := 0
return

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

    ; 在 DC 按下快捷键时，激活调用窗体并执行粘贴操作
    if (Name == DC_Class) {
        if (DC_CallerId != 0) {
            gosub <DC_Selected>
            return
		}
    } else {
        DC_CallerId := WinExist("A")
        if (DC_CallerId == 0) {
            return
		}

        gosub <DC_Focus>
        gosub <DC_MapKeys>
    }
return

<DC_Selected>:
    gosub <DC_UnMapKeys>

    if (DC_CallerId == 0) {
        return
    }

    ; 避免发送回车时受其他按键影响
    MsgBox, , , 处理中, 0.3

    Pwd := DC_RunGet("cm_CopyCurrentPathToClip", false)

    Filename := DC_RunGet("cm_CopyNamesToClip", false)

    WinActivate, ahk_id %DC_CallerId%
    WinWait, ahk_id %DC_CallerId%
    DC_CallerId := 0

    if (!InStr(Filename, "`n")) {
        Clipboard := Pwd . Filename
        Send, {Home}
        Send, ^v
        Send, {Enter}

        return
    }

    ; 多选

    Files := ""
    Loop, parse, FIlename, `n, `r
        Files .= """" . A_LoopField  . """ "

    ; 第一步：跳转到当前路径
    Clipboard := Pwd
    Send, ^a
    Send, ^v
    Send, {Enter}
    sleep, 100

    ; 第二步：提交文件名
    Clipboard := Files
    Send, ^v
    Send, {Enter}
return

<DC_SelectedCurrentDir>:
    gosub <DC_UnMapKeys>

    if (DC_CallerId == 0) {
        return
    }

    DC_Run("cm_CopyCurrentPathToClip")

    WinActivate, ahk_id %DC_CallerId%
    WinWait, ahk_id %DC_CallerId%
    DC_CallerId := 0

    Send, {Home}
    Send, ^v
    Send, {Enter}
return


完成 TC 到 DC 的迁移，从此我不再维护 TC 插件

完成 TC 到 DC 的迁移，从此我不再维护 TC 插件

/*
    此插件仅供自用，依赖对 DC 代码的修改以及专门的配置

    ---

    DC 的优势

    开源，免费，跨平台，可以自由改代码定制功能，很好编译
    可以改代码让所有目录中的父目录（..）消失（已完成）
    可以把按键绑定到工具栏的子菜单上，然后再通过按键触发功能
    内建 lua 解释器，方便写一些高级功能（感觉功能有限，用处不大）
    主界面和配置界面更漂亮、好用

    ---

    TODO

    看怎么给命令传递多个参数
*/

DoubleCommander:
    global DC_Class := "TTOTAL_CMD"
    global DC := "ahk_class " . DC_Class
    global DC_Dir := "c:\mine\app\doublecmd"
    global DC_Path := "c:\mine\app\doublecmd\doublecmd.exe --no-splash"
    ; 用于记录文件打开对话框所属窗体
    global DC_CallerId := 0

    DC_Name := "DoubleCommander"

    Vim.SetWin(DC_Name, DC_Class, "doublecmd.exe")
    Vim.Mode("normal", DC_Name)

    Vim.BeforeActionDo("DC_ForceInsertMode", DC_Name)
return

DC_ForceInsertMode() {
    ControlGetFocus, Ctrl
    if (InStr(Ctrl, "Edit") == 1) {
        return true
    }

    WinGet, MenuID, ID, AHK_CLASS #32768
    if (MenuID != "") {
        return true
    }

    return false
}

DC_Run(Cmd) {
    ControlSetText, Edit1, % Cmd, % DC
    ControlSend, Edit1, {Enter}, % DC
}

; 返回值 [1]: left/right [2]: 左侧面板所占比例 0-100
DC_GetPanelInfo() {
    ClipSaved := ClipboardAll
    Clipboard := ""
    DC_Run("cm_CopyPanelInfoToClip")
    ClipWait, 1

    PanelInfo := StrSplit(Clipboard, " ")
    Clipboard := ClipSaved

    return PanelInfo
}

DC_ExecuteToolbarItem(ID) {
    DC_Run("cm_ExecuteToolbarItem ToolItemID=" . ID)
}

DC_ColumnsView(ColumnSet) {
    if (ColumnSet == "") {
        DC_Run("cm_ColumnsView")
    } else {
        DC_Run("cm_ColumnsView columnset=" ColumnSet)
    }
}

DC_OpenPath(Path, InNewTab := true, LeftOrRight := "") {
    LeftOfRight := DC_GetPanelInfo()[1]
    if (LeftOfRight == "right") {
        LeftOrRight := "-R"
    } else {
        LeftOrRight := "-L"
    }

    if (InNewTab) {
        Run, %DC_Path% -C -T "%LeftOrRight%" "%Path%"
    } else {
        Run, %DC_Path% -C "%LeftOrRight%" "%Path%"
    }
}

; funcend

<DC_Test>:
    ; DC_ExecuteToolbarItem("{700FF494-B939-48A3-B248-8823EB366AEA}")
    DC_Run("cm_About")
return

<DC_Restart>:
    WinClose, % DC
    WinWaitClose, % DC, , 2

    Run, % DC_Path

    WinWaitActive, % DC

    if (!WinExist(DC)) {
        MsgBox, 重启失败 %ErrorMessage%
    }
return

<DC_Show_50_50>:
    DC_Run("cm_PanelsSplitterPerPos splitpct=50")
return

<DC_Show_100_0>:
    DC_Run("cm_PanelsSplitterPerPos splitpct=100")
return

<DC_Show_0_100>:
    DC_Run("cm_PanelsSplitterPerPos splitpct=0")
return

<DC_HorizontalFilePanels>:
    DC_Run("cm_HorizontalFilePanels mode=legacy")
return

<DC_Toggle_50_100>:
    PanelInfo := DC_GetPanelInfo()

    if (abs(50 - PanelInfo[2]) < 10) {
        if (PanelInfo[1] == "left") {
            DC_Run("cm_PanelsSplitterPerPos splitpct=100")
        } else {
            DC_Run("cm_PanelsSplitterPerPos splitpct=0")
        }
    } else {
        DC_Run("cm_PanelsSplitterPerPos splitpct=50")
    }
return

<DC_MakeDir>:
    DC_Run("cm_MakeDir")
return

<DC_PreviousParallelDir>:
    SleepTime := 10

    ClipSaved := ClipboardAll
    Clipboard := ""
    DC_Run("cm_CopyCurrentPathToClip")
    ClipWait, 1

    OldPwd := Clipboard

    if (InStr(OldPwd, "\") == 1) {
        ; 网络文件系统比较慢
        SleepTime := 50
    }

    if (StrLen(OldPwd) == 3) {
        ; 在根分区

        Clipboard := ClipSaved
        ClipSaved := ""

        return
    }

    DC_Run("cm_ChangeDirToParent")
    Sleep, % SleepTime

    DC_Run("cm_GoToPrevEntry")
    Sleep, % SleepTime

    Send, {Right}

    Clipboard := ClipSaved
    ClipSaved := ""
return

<DC_NextParallelDir>:
    SleepTime := 10

    ClipSaved := ClipboardAll
    Clipboard := ""
    DC_Run("cm_CopyCurrentPathToClip")
    ClipWait, 1

    OldPwd := Clipboard

    if (InStr(OldPwd, "\") == 1) {
        ; 网络文件系统比较慢
        SleepTime := 50
    }

    if (StrLen(OldPwd) == 3) {
        ; 在根分区
        ; Gosub, <cm_GotoPreviousDrive>

        Clipboard := ClipSaved
        ClipSaved := ""

        return
    }

    DC_Run("cm_ChangeDirToParent")
    Sleep, % SleepTime

    DC_Run("cm_GoToNextEntry")
    Sleep, % SleepTime

    Send, {Right}
    Sleep, % SleepTime

    Clipboard := ""
    DC_Run("cm_CopyCurrentPathToClip")
    ClipWait, 1

    if (OldPwd != Clipboard && InStr(OldPwd, Clipboard) == 1) {
        ; 下一个是文件
        DC_Run("cm_ViewHistoryPrev")
    }

    Clipboard := ClipSaved
    ClipSaved := ""
return

<DC_CreateNewFile>:
    ControlGetFocus, TLB, % DC
    ControlGetPos, Xn, Yn, , , % TLB, % DC

    Menu, NewFileMenu, Add
    Menu, NewFileMenu, DeleteAll
    Menu, NewFileMenu, Add , S >> 快捷方式, <DC_CreateFileShortcut>
    Menu, NewFileMenu, Icon, S >> 快捷方式, %A_WinDir%\system32\Shell32.dll, 264
    Menu, NewFileMenu, Add

    Loop, % DC_Dir . "\shellnew\*.*" {
        Ft := SubStr(A_LoopFileName, 1, 1) . " >> " . A_LoopFileName
        Menu, NewFileMenu, Add, % Ft, DC_NewFileMenuAction
        Menu, NewFileMenu, Icon, % Ft, %A_WinDir%\system32\Shell32.dll
    }

    Menu, NewFileMenu, Show, % Xn, % Yn + 2
return

DC_NewFileMenuAction:
    Filename := RegExReplace(A_ThisMenuItem, ".\s>>\s")
    FilePath := DC_Dir . "\ShellNew\" . Filename

    Gui, Destroy
    Gui, Add, Text, x12 y20 w50 h20 +Center, 模板源
    Gui, Add, Edit, x72 y20 w300 h20 Disabled, % FilePath
    Gui, Add, Text, x12 y50 w50 h20 +Center, 新建文件
    Gui, Add, Edit, x72 y50 w300 h20, % Filename
    Gui, Add, Button, x162 y80 w90 h30 gDC_NewFileOk default, 确认(&S)
    Gui, Add, Button, x282 y80 w90 h30 gDC_NewFileClose , 取消(&C)
    Gui, Show, w400 h120, 新建文件
return

DC_NewFileClose:
    Gui, Destroy
return

DC_NewFileOK:
    GuiControlGet, SrcFilePath, , Edit1
    GuiControlGet, NewFilename, , Edit2

    ClipSaved := ClipboardAll
    Clipboard :=
    DC_Run("cm_CopyCurrentPathToClip")
    ClipWait, 1
    DstPath := Clipboard
    Clipboard := ClipSaved
    ClipSaved := ""

    if (InStr(DstPath, "`r")) {
        DstPath := SubStr(DstPath, 1, InStr(DstPath, "`r") - 1)
    } else if (DstPath == "") {
        return
    }

    NewFilePath := DstPath . NewFilename
    if (FileExist(NewFilePath)) {
        MsgBox, 4, 新建文件, 新建文件已存在，是否覆盖？
        IfMsgBox No
            return
    }

    FileCopy, % SrcFilePath, % NewFilePath, 1

    ; TODO
    ; 好像无法实现定位到新创建的文件

    Gui, Destroy
return

<DC_Toggle>:
    if (WinExist(DC)) {
        WinGet, Ac, MinMax, % DC
        if (Ac == -1) {
            WinActivate, % DC
        } else {
            if (!WinActive(DC)) {
                WinActivate, % DC
            } else {
                WinMinimize, % DC
            }
        }
    } else {
        Run, % DC_Path
        WinWait, % DC

        if (!WinActive(DC)) {
            WinActivate, % DC
        }
    }
return

<DC_SortByName>:
    DC_Run("cm_SortByName")
return

<DC_SortByExt>:
    DC_Run("cm_SortByExt")
return

<DC_SortBySize>:
    DC_Run("cm_SortBySize")
return

<DC_SortByDate>:
    DC_Run("cm_SortByDate")
return

<DC_SortByAttr>:
    DC_Run("cm_SortByAttr")
return

<DC_ReverseOrder>:
    DC_Run("cm_ReverseOrder")
return

<DC_FocusSwap>:
    DC_Run("cm_FocusSwap")
    ; side=left/right
return

<DC_CopyCurrentPathToClip>:
    DC_Run("cm_CopyCurrentPathToClip")
return

<DC_OpenExplorer>:
    DC_Run(".")
return

<DC_MarkFile>:
    DC_Run("cm_EditComment")
    ; 不要在已有备注的文件使用
    Send, ^+{End}🖥{F2}
return

<DC_UnMarkFile>:
    DC_Run("cm_EditComment")
    ; 删除 DC_MarkFile 的文件标记，也可用于清空文件备注
    Send, ^+{End}{Del}{F2}
return

<DC_ShowMainMenu>:
    DC_Run("cm_ShowMainMenu")
return

<DC_ShowButtonMenu>:
    DC_Run("cm_ShowButtonMenu")
return

<DC_OperationsViewer>:
    DC_Run("cm_OperationsViewer")
return

<DC_TreeView>:
    DC_Run("cm_TreeView")
return

<DC_FocusTreeView>:
    DC_Run("cm_FocusTreeView")
return

<DC_BriefView>:
    DC_Run("cm_BriefView")
return

<DC_ColumnsView1>:
    DC_ColumnsView("mine")
return

<DC_ColumnsView2>:
    DC_ColumnsView("test")
return

<DC_ThumbnailsView>:
    DC_Run("cm_ThumbnailsView")
    Gosub, <DC_ThumbnailsSwitchKey>
return

<DC_ThumbnailsSwitchKey>:
    InThumbsView := !InThumbsView

    if (InThumbsView) {
        Vim.Map("l", "<right>", DC_Name)
    } else {
        Vim.Map("l", "<enter>", DC_Name)
    }
return

<DC_ToggleShowInfo>:
    Vim.GetWin(DC_Name).SetInfo(!Vim.GetWin(DC_Name).info)
return

<DC_CopyFileContent>:
    Clipboard := ""
    DC_Run("cm_CopyFullNamesToClip")
    ClipWait, 1

    Fileread, Contents, % Clipboard
    Clipboard := Contents
return

<DC_CopyFilenamesOnly>:
    Clipboard := ""
    DC_Run("cm_CopyFullNamesToClip")
    ClipWait, 1

    SplitPath, Clipboard, OutFileName, , , OutFilenameNoExt

    if (InStr(FileExist(Clipboard), "D")) {
        Clipboard := OutFileName
    } else if (InStr(Clipboard, ".")) {
        Clipboard := OutFilenameNoExt
    }
return

<DC_CreateFileShortcut>:
    ClipSaved := ClipboardAll
    Clipboard := ""
    DC_Run("cm_CopyFullNamesToClip")
    ClipWait

    FilePath := Clipboard
    Clipboard := ClipSaved
    ClipSaved := ""

    OutVar := FileExist(FilePath)
    if (InStr(OutVar, "D")) {
        FileCreateShortcut, % FilePath, % FilePath . ".lnk"
    } else if (OutVar != "") {
        FileCreateShortcut, % FilePath, % RegExReplace(FilePath, "\.[^.]*$", ".lnk")
    }
return

<DC_Focus>:
    IfWinExist, % DC
        Winactivate, % DC
    else {
        Run, % DC_Path
        WinWait, % DC
        IfWinNotActive, % DC
            WinActivate, % DC
    }
return

<DC_MapKeys>:
	Vim.Mode("normal", DC_Name)
    Vim.Map("<S-Enter>", "<DC_SelectedCurrentDir>", DC_Name)
    Vim.Map("<Esc>", "<DC_ReturnToCaller>", DC_Name)
return

<DC_UnMapKeys>:
	Vim.Mode("normal", DC_Name)
    Vim.Map("<S-Enter>", "<Default>", DC_Name)
    Vim.Map("<Esc>", "<Default>", DC_Name)
return

; 返回调用者
<DC_ReturnToCaller>:
    gosub <DC_UnMapKeys>

    WinActivate, ahk_id %DC_CallerId%

    DC_CallerId := 0
return

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

    ; 在 DC 按下快捷键时，激活调用窗体并执行粘贴操作
    if (name == DC_Class) {
        if (DC_CallerId != 0) {
            gosub <DC_Selected>
            DC_CallerId := 0
		}
    } else {
        DC_CallerId := WinExist("A")
        if (DC_CallerId == 0) {
            return
		}

        gosub <DC_Focus>
        gosub <DC_MapKeys>
    }
return

<DC_Selected>:
    gosub <DC_UnMapKeys>

    Clipboard := ""
    ; 不知道什么原因，必须加一个 MsgBox 功能才正常
    MsgBox, , , 处理中, 0.3

    DC_Run("cm_CopyCurrentPathToClip")

    ClipWait, 1
    Pwd := Clipboard

    Clipboard := ""
    DC_Run("cm_CopyNamesToClip")
    ClipWait, 1

    WinActivate, ahk_id %DC_CallerId%
    WinWait, ahk_id %DC_CallerId%
    DC_CallerId := 0

    if (!InStr(Clipboard, "`n")) {
        Clipboard := Pwd . Clipboard
        Send, {Home}
        Send, ^v
        Send, {Enter}

        return
    }

    ; 多选

    Files := ""
    Loop, parse, Clipboard, `n, `r
        Files .= """" . A_LoopField  . """ "

    ; 第一步：跳转到当前路径
    Clipboard := Pwd
    Send, ^a
    Send, ^v
    Send, {Enter}
    sleep, 100

    ; 第二步：提交文件名
    Clipboard := Files
    Send, ^v
    Send, {Enter}
return

<DC_SelectedCurrentDir>:
    gosub <DC_UnMapKeys>

    if (DC_CallerId == 0) {
        return
    }

    Clipboard := ""
    DC_Run("cm_CopyCurrentPathToClip")
    ClipWait

    ; 添加默认路径不带反斜杠，添加之

    Clipboard .= "\"

    WinActivate, ahk_id %DC_CallerId%
    WinWait, ahk_id %DC_CallerId%
    DC_CallerId := 0

    Send, {Home}
    Send, ^v
    Send, {Enter}
return

<DC_FlatViewSel>:
    DC_Run("cm_FlatViewSel")
return

/*
    此插件仅供自用，依赖对 DC 代码的修改以及专门的配置

    ---

    DC 的优势

    开源，免费，跨平台，可以自由改代码定制功能，很好编译
    可以改代码让所有目录中的父目录（..）消失（已完成）
    可以把按键绑定到工具栏的子菜单上，然后再通过按键触发功能
    内建 lua 解释器，方便写一些高级功能（感觉功能有限，用处不大）
    主界面和配置界面更漂亮、好用

    ---

    TODO

    看怎么给命令传递多个参数

    专用 DC 的配置类型
*/

DoubleCommander:
    global DC_Class := "TTOTAL_CMD"
    global DC := "ahk_class " . DC_Class
    global DC_Dir := "c:\mine\app\doublecmd"
    global DC_Path := "c:\mine\app\doublecmd\doublecmd.exe --no-splash"
    ; 用于记录文件打开对话框所属窗体
    global DC_CallerId := 0

    DC_Name := "DoubleCommander"

    vim.SetWin(DC_Name, DC_Class, "doublecmd.exe")
    vim.Mode("normal", DC_Name)

    vim.BeforeActionDo("DC_ForceInsertMode", DC_Name)
return

DC_ForceInsertMode() {
    ControlGetFocus, Ctrl
    if (InStr(Ctrl, "Edit") == 1) {
        return true
    }

    WinGet, MenuID, ID, AHK_CLASS #32768
    if (MenuID != "") {
        return true
    }

    return false
}

DC_Run(Cmd) {
    ControlSetText, Edit1, % Cmd, % DC
    ControlSend, Edit1, {Enter}, % DC
}

; 返回值 [1]: left/right [2]: 左侧面板所占比例 0-100
DC_GetPanelInfo() {
    ClipSaved := ClipboardAll
    Clipboard := ""
    DC_Run("cm_CopyPanelInfoToClip")
    ClipWait, 1

    PanelInfo := StrSplit(Clipboard, " ")
    Clipboard := ClipSaved

    return PanelInfo
}

DC_ExecuteToolbarItem(ID) {
    DC_Run("cm_ExecuteToolbarItem ToolItemID=" . ID)
}

DC_ColumnsView(ColumnSet) {
    if (ColumnSet == "") {
        DC_Run("cm_ColumnsView")
    } else {
        DC_Run("cm_ColumnsView columnset=" ColumnSet)
    }
}

DC_OpenPath(Path, InNewTab := true, LeftOrRight := "") {
    LeftOfRight := DC_GetPanelInfo()[1]
    if (LeftOfRight == "right") {
        LeftOrRight := "-R"
    } else {
        LeftOrRight := "-L"
    }

    if (InNewTab) {
        Run, %DC_Path% -C -T "%LeftOrRight%" "%Path%"
    } else {
        Run, %DC_Path% -C "%LeftOrRight%" "%Path%"
    }
}

; funcend

<DC_Test>:
    ; DC_ExecuteToolbarItem("{700FF494-B939-48A3-B248-8823EB366AEA}")
    DC_Run("cm_About")
return

<DC_Restart>:
    WinClose, % DC
    WinWaitClose, % DC, , 2

    Run, % DC_Path

    WinWaitActive, % DC

    if (!WinExist(DC)) {
        MsgBox, 重启失败 %ErrorMessage%
    }
return

<DC_Show_50_50>:
    DC_Run("cm_PanelsSplitterPerPos splitpct=50")
return

<DC_Show_100_0>:
    DC_Run("cm_PanelsSplitterPerPos splitpct=100")
return

<DC_Show_0_100>:
    DC_Run("cm_PanelsSplitterPerPos splitpct=0")
return

<DC_HorizontalFilePanels>:
    DC_Run("cm_HorizontalFilePanels mode=legacy")
return

<DC_Toggle_50_100>:
    PanelInfo := DC_GetPanelInfo()

    if (abs(50 - PanelInfo[2]) < 10) {
        if (PanelInfo[1] == "left") {
            DC_Run("cm_PanelsSplitterPerPos splitpct=100")
        } else {
            DC_Run("cm_PanelsSplitterPerPos splitpct=0")
        }
    } else {
        DC_Run("cm_PanelsSplitterPerPos splitpct=50")
    }
return

<DC_MakeDir>:
    DC_Run("cm_MakeDir")
return

<DC_PreviousParallelDir>:
    SleepTime := 10

    ClipSaved := ClipboardAll
    Clipboard := ""
    DC_Run("cm_CopyCurrentPathToClip")
    ClipWait, 1

    OldPwd := Clipboard

    if (InStr(OldPwd, "\") == 1) {
        ; 网络文件系统比较慢
        SleepTime := 50
    }

    if (StrLen(OldPwd) == 3) {
        ; 在根分区

        Clipboard := ClipSaved
        ClipSaved := ""

        return
    }

    DC_Run("cm_ChangeDirToParent")
    Sleep, % SleepTime

    DC_Run("cm_GoToPrevEntry")
    Sleep, % SleepTime

    Send, {Right}

    Clipboard := ClipSaved
    ClipSaved := ""
return

<DC_NextParallelDir>:
    SleepTime := 10

    ClipSaved := ClipboardAll
    Clipboard := ""
    DC_Run("cm_CopyCurrentPathToClip")
    ClipWait, 1

    OldPwd := Clipboard

    if (InStr(OldPwd, "\") == 1) {
        ; 网络文件系统比较慢
        SleepTime := 50
    }

    if (StrLen(OldPwd) == 3) {
        ; 在根分区
        ; Gosub, <cm_GotoPreviousDrive>

        Clipboard := ClipSaved
        ClipSaved := ""

        return
    }

    DC_Run("cm_ChangeDirToParent")
    Sleep, % SleepTime

    DC_Run("cm_GoToNextEntry")
    Sleep, % SleepTime

    Send, {Right}
    Sleep, % SleepTime

    Clipboard := ""
    DC_Run("cm_CopyCurrentPathToClip")
    ClipWait, 1

    if (OldPwd != Clipboard && InStr(OldPwd, Clipboard) == 1) {
        ; 下一个是文件
        DC_Run("cm_ViewHistoryPrev")
    }

    Clipboard := ClipSaved
    ClipSaved := ""
return

<DC_CreateNewFile>:
    ControlGetFocus, TLB, % DC
    ControlGetPos, Xn, Yn, , , % TLB, % DC

    Menu, NewFileMenu, Add
    Menu, NewFileMenu, DeleteAll
    Menu, NewFileMenu, Add , S >> 快捷方式, <DC_CreateFileShortcut>
    Menu, NewFileMenu, Icon, S >> 快捷方式, %A_WinDir%\system32\Shell32.dll, 264
    Menu, NewFileMenu, Add

    Loop, % DC_Dir . "\shellnew\*.*" {
        Ft := SubStr(A_LoopFileName, 1, 1) . " >> " . A_LoopFileName
        Menu, NewFileMenu, Add, % Ft, DC_NewFileMenuAction
        Menu, NewFileMenu, Icon, % Ft, %A_WinDir%\system32\Shell32.dll
    }

    Menu, NewFileMenu, Show, % Xn, % Yn + 2
return

DC_NewFileMenuAction:
    Filename := RegExReplace(A_ThisMenuItem, ".\s>>\s")
    FilePath := DC_Dir . "\ShellNew\" . Filename

    Gui, Destroy
    Gui, Add, Text, x12 y20 w50 h20 +Center, 模板源
    Gui, Add, Edit, x72 y20 w300 h20 Disabled, % FilePath
    Gui, Add, Text, x12 y50 w50 h20 +Center, 新建文件
    Gui, Add, Edit, x72 y50 w300 h20, % Filename
    Gui, Add, Button, x162 y80 w90 h30 gDC_NewFileOk default, 确认(&S)
    Gui, Add, Button, x282 y80 w90 h30 gDC_NewFileClose , 取消(&C)
    Gui, Show, w400 h120, 新建文件
return

DC_NewFileClose:
    Gui, Destroy
return

DC_NewFileOK:
    GuiControlGet, SrcFilePath, , Edit1
    GuiControlGet, NewFilename, , Edit2

    ClipSaved := ClipboardAll
    Clipboard :=
    DC_Run("cm_CopyCurrentPathToClip")
    ClipWait, 1
    DstPath := Clipboard
    Clipboard := ClipSaved
    ClipSaved := ""

    if (InStr(DstPath, "`r")) {
        DstPath := SubStr(DstPath, 1, InStr(DstPath, "`r") - 1)
    } else if (DstPath == "") {
        return
    }

    NewFilePath := DstPath . NewFilename
    if (FileExist(NewFilePath)) {
        MsgBox, 4, 新建文件, 新建文件已存在，是否覆盖？
        IfMsgBox No
            return
    }

    FileCopy, % SrcFilePath, % NewFilePath, 1

    ; TODO
    ; 好像无法实现定位到新创建的文件

    Gui, Destroy
return

<DC_Toggle>:
    if (WinExist(DC)) {
        WinGet, Ac, MinMax, % DC
        if (Ac == -1) {
            WinActivate, % DC
        } else {
            if (!WinActive(DC)) {
                WinActivate, % DC
            } else {
                WinMinimize, % DC
            }
        }
    } else {
        Run, % DC_Path
        WinWait, % DC

        if (!WinActive(DC)) {
            WinActivate, % DC
        }
    }
return

<DC_SortByName>:
    DC_Run("cm_SortByName")
return

<DC_SortByExt>:
    DC_Run("cm_SortByExt")
return

<DC_SortBySize>:
    DC_Run("cm_SortBySize")
return

<DC_SortByDate>:
    DC_Run("cm_SortByDate")
return

<DC_SortByAttr>:
    DC_Run("cm_SortByAttr")
return

<DC_ReverseOrder>:
    DC_Run("cm_ReverseOrder")
return

<DC_FocusSwap>:
    DC_Run("cm_FocusSwap")
    ; side=left/right
return

<DC_CopyCurrentPathToClip>:
    DC_Run("cm_CopyCurrentPathToClip")
return

<DC_OpenExplorer>:
    DC_Run(".")
return

<DC_MarkFile>:
    DC_Run("cm_EditComment")
    ; 不要在已有备注的文件使用
    Send, ^+{End}🖥{F2}
return

<DC_UnMarkFile>:
    DC_Run("cm_EditComment")
    ; 删除 DC_MarkFile 的文件标记，也可用于清空文件备注
    Send, ^+{End}{Del}{F2}
return

<DC_ShowMainMenu>:
    DC_Run("cm_ShowMainMenu")
return

<DC_ShowButtonMenu>:
    DC_Run("cm_ShowButtonMenu")
return

<DC_OperationsViewer>:
    DC_Run("cm_OperationsViewer")
return

<DC_TreeView>:
    DC_Run("cm_TreeView")
return

<DC_FocusTreeView>:
    DC_Run("cm_FocusTreeView")
return

<DC_BriefView>:
    DC_Run("cm_BriefView")
return

<DC_ColumnsView1>:
    DC_ColumnsView("mine")
return

<DC_ColumnsView2>:
    DC_ColumnsView("test")
return

<DC_ThumbnailsView>:
    DC_Run("cm_ThumbnailsView")
    Gosub, <DC_ThumbnailsSwitchKey>
return

<DC_ThumbnailsSwitchKey>:
    InThumbsView := !InThumbsView

    if (InThumbsView) {
        vim.Map("l", "<right>", DC_Name)
    } else {
        vim.Map("l", "<enter>", DC_Name)
    }
return

<DC_ToggleShowInfo>:
    vim.GetWin(DC_Name).SetInfo(!vim.GetWin(DC_Name).info)
return

<DC_CopyFileContent>:
    Clipboard := ""
    DC_Run("cm_CopyFullNamesToClip")
    ClipWait, 1

    Fileread, Contents, % Clipboard
    Clipboard := Contents
return

<DC_CopyFilenamesOnly>:
    Clipboard := ""
    DC_Run("cm_CopyFullNamesToClip")
    ClipWait, 1

    SplitPath, Clipboard, OutFileName, , , OutFilenameNoExt

    if (InStr(FileExist(Clipboard), "D")) {
        Clipboard := OutFileName
    } else if (InStr(Clipboard, ".")) {
        Clipboard := OutFilenameNoExt
    }
return

<DC_CreateFileShortcut>:
    ClipSaved := ClipboardAll
    Clipboard := ""
    DC_Run("cm_CopyFullNamesToClip")
    ClipWait

    FilePath := Clipboard
    Clipboard := ClipSaved
    ClipSaved := ""

    OutVar := FileExist(FilePath)
    if (InStr(OutVar, "D")) {
        FileCreateShortcut, % FilePath, % FilePath . ".lnk"
    } else if (OutVar != "") {
        FileCreateShortcut, % FilePath, % RegExReplace(FilePath, "\.[^.]*$", ".lnk")
    }
return

<DC_Focus>:
    IfWinExist, % DC
        Winactivate, % DC
    else {
        Run, % DC_Path
        WinWait, % DC
        IfWinNotActive, % DC
            WinActivate, % DC
    }
return

<DC_MapKeys>:
	vim.Mode("normal", DC_Name)
    vim.Map("<S-Enter>", "<DC_SelectedCurrentDir>", DC_Name)
    vim.Map("<Esc>", "<DC_ReturnToCaller>", DC_Name)
return

<DC_UnMapKeys>:
	vim.Mode("normal", DC_Name)
    vim.Map("<S-Enter>", "<Default>", DC_Name)
    vim.Map("<Esc>", "<Default>", DC_Name)
return

; 返回调用者
<DC_ReturnToCaller>:
    gosub <DC_UnMapKeys>

    WinActivate, ahk_id %DC_CallerId%

    DC_CallerId := 0
return

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

    ; 在 DC 按下快捷键时，激活调用窗体并执行粘贴操作
    if (name == DC_Class) {
        if (DC_CallerId != 0) {
            gosub <DC_Selected>
            DC_CallerId := 0
		}
    } else {
        DC_CallerId := WinExist("A")
        if (DC_CallerId == 0) {
            return
		}

        gosub <DC_Focus>
        gosub <DC_MapKeys>
    }
return

<DC_Selected>:
    gosub <DC_UnMapKeys>

    Clipboard := ""
    ; 不知道什么原因，必须加一个 MsgBox 功能才正常
    MsgBox, , , 处理中, 0.3

    DC_Run("cm_CopyCurrentPathToClip")

    ClipWait, 1
    Pwd := Clipboard

    Clipboard := ""
    DC_Run("cm_CopyNamesToClip")
    ClipWait, 1

    WinActivate, ahk_id %DC_CallerId%
    WinWait, ahk_id %DC_CallerId%
    DC_CallerId := 0

    if (!InStr(Clipboard, "`n")) {
        Clipboard := Pwd . Clipboard
        Send, {Home}
        Send, ^v
        Send, {Enter}

        return
    }

    ; 多选

    Files := ""
    Loop, parse, Clipboard, `n, `r
        Files .= """" . A_LoopField  . """ "

    ; 第一步：跳转到当前路径
    Clipboard := Pwd
    Send, ^a
    Send, ^v
    Send, {Enter}
    sleep, 100

    ; 第二步：提交文件名
    Clipboard := Files
    Send, ^v
    Send, {Enter}
return

<DC_SelectedCurrentDir>:
    gosub <DC_UnMapKeys>

    if (DC_CallerId == 0) {
        return
    }

    Clipboard := ""
    DC_Run("cm_CopyCurrentPathToClip")
    ClipWait

    ; 添加默认路径不带反斜杠，添加之

    Clipboard .= "\"

    WinActivate, ahk_id %DC_CallerId%
    WinWait, ahk_id %DC_CallerId%
    DC_CallerId := 0

    Send, {Home}
    Send, ^v
    Send, {Enter}
return

<DC_FlatViewSel>:
    DC_Run("cm_FlatViewSel")
return


Update LedKeyboardShortcuts.ahk

Update LedKeyboardShortcuts.ahk

#NoEnv
#SingleInstance force ; only lets one run
SetBatchLines, -1

socket := new Example("ws://192.168.1.33:81") ; !!! Update this !!!
connected := 0 ;  state variable for server connection

incrementAmount := 10 ; how finely you adjust the color, speed, and brightness per keypress
maxColor := 255
maxMode := 56 ; the maximum mode id number

red := 127
green := 127
blue := 127

brightness := 127
speed := 127
mode := 1

^#Numpad4:: ; switch modes down
	mode := mode - 1
	if(mode < 0)
		mode := maxMode
	cmd = /%mode% ; / is the set effect mode command
	TrayTip, , Mode: %mode%
	sendCmd(cmd)
	; MsgBox %cmd%
	return

^#Numpad6:: ; switch modes up
	mode := mode + 1
	if(mode > maxMode)
		mode := 0
	TrayTip, , Mode: %mode%
	cmd = /%mode%
	sendCmd(cmd)
	; MsgBox %cmd%
	return

^#Numpad5:: ; turn off
	TrayTip, , Leds are off
	sendCmd("=off") ; = is the set control command
	return

^#Numpad0:: ; turn on to static color
	TrayTip, , Leds are on
	cmd := "*"+toHexColor(red,green,blue) ; * is the set all command
	sendCmd(cmd) ; = is the set control command
	return

^#NumpadSub:: ; decreases brightness
	brightness := brightness - incrementAmount
	if(brightness < 0)
		brightness := 0
	cmd = `%%brightness% ;  % is the set brightness mode command. ` is the escape character
	TrayTip, , Brightness: %brightness%
	sendCmd(cmd)
	; MsgBox %cmd%
	return

^#NumpadAdd:: ; increases brightness
	brightness := brightness + incrementAmount
	if(brightness > maxColor)
		brightness := maxColor
	cmd = `%%brightness% ; % is the set brightness mode command
	TrayTip, , Brightness: %brightness%
	sendCmd(cmd)
	; MsgBox %cmd%
	return

^#NumpadDiv:: ; decreases speed
	speed := speed - incrementAmount
	if(speed < 0)
		speed := 0
	cmd = ?%speed% ;  ? is the set brightness mode command
	TrayTip, , Speed: %speed%
	sendCmd(cmd)
	; MsgBox %cmd%
	return

^#NumpadMult:: ; increases speed
	speed := speed + incrementAmount
	if(speed > maxColor)
		speed := maxColor
	cmd = ?%speed% ;  ? is the set brightness mode command
	TrayTip, , Speed: %speed%
	sendCmd(cmd)
	; MsgBox %cmd%
	return

^#Numpad7:: ; increase red amount
	red := red + incrementAmount
	if(red > maxColor)
		red := maxColor

	cmd := "#"+toHexColor(red,green,blue) ; # is the set main color command
	; MsgBox %cmd%
	TrayTip, , Red: %red%
	sendCmd(cmd)

	return

^#Numpad1:: ; decrease red amount
	red := red - incrementAmount
	if(red < 0)
		red := 0

	cmd := "#"+toHexColor(red,green,blue) ; # is the set main color command
	; MsgBox %cmd%
	TrayTip, , Red: %red%
	sendCmd(cmd)

	return

^#Numpad8:: ; increase green amount
	green := green + incrementAmount
	if(green > maxColor)
		green := maxColor

	cmd := "#"+toHexColor(red,green,blue) ; # is the set main color command
	; MsgBox %cmd%
	TrayTip, , Green: %green%
	sendCmd(cmd)

	return

^#Numpad2:: ; decrease green amount
	green := green - incrementAmount
	if(green < 0)
		green := 0

	cmd := "#"+toHexColor(red,green,blue) ; # is the set main color command
	; MsgBox %cmd%
	TrayTip, , Green: %green%
	sendCmd(cmd)

	return

^#Numpad9:: ; increase blue amount
	blue := blue + incrementAmount
	if(blue > maxColor)
		blue := maxColor

	cmd := "#"+toHexColor(red,green,blue) ; # is the set main color command
	; MsgBox %cmd%
	TrayTip, , Blue: %blue%
	sendCmd(cmd)

	return

^#Numpad3:: ; decrease blue amount
	blue := blue - incrementAmount
	if(blue < 0)
		blue := 0

	cmd := "#"+toHexColor(red,green,blue) ; # is the set main color command
	; MsgBox %cmd%
	TrayTip, , Blue: %blue%
	sendCmd(cmd)

	return

sendCmd(cmd)
{
	global connected
	global socket
	; MsgBox %connected%
	if( connected )
	{
		socket.Send(cmd)
		; MsgBox %cmd%
	}
	else
		TrayTip, , Not connected to server!
}

toHexColor(r, g, b)
{
	SetFormat, IntegerFast, hex ; To print values as hexadecimal
	colorNum := r*65536 + g*256 + b
	color = 000000%colorNum% ; convert to string and add preceeding zeros
	color := StrReplace(color, "0x") ; replace the 0x from the middle
	color := SubStr( color, -5 ) ; get last 6 characters

	SetFormat, IntegerFast, dec ; sets the print mode back to decimal
	return ""+color ;
}

class Example extends WebSocket
{
	OnOpen(Event)
	{
		TrayTip, ,Connection established to led controller!
		; InputBox, Data, WebSocket, Enter some text to send through the websocket.
		; this.Send(Data)
		global connected := 1
	}

	OnMessage(Event)
	{
		; MsgBox, % "Received Data: " Event.data
		; this.Close()
	}

	OnClose(Event)
	{
		TrayTip, , Websocket Closed
		global connected := 0
		this.Disconnect()
		ExitApp
	}

	OnError(Event)
	{
		TrayTip, , Websocket Error
		global connected := 0
		this.Close()
	}

	__Delete()
	{
		TrayTip, , Exiting
		ExitApp
	}
}

class WebSocket
{
	__New(WS_URL)
	{
		static wb

		; Create an IE instance
		Gui, +hWndhOld
		Gui, New, +hWndhWnd
		this.hWnd := hWnd
		Gui, Add, ActiveX, vWB, Shell.Explorer
		Gui, %hOld%: Default

		; Write an appropriate document
		WB.Navigate("about:<!DOCTYPE html><meta http-equiv='X-UA-Compatible'"
		. "content='IE=edge'><body></body>")
		while (WB.ReadyState < 4)
			sleep, 50
		this.document := WB.document

		; Add our handlers to the JavaScript namespace
		this.document.parentWindow.ahk_savews := this._SaveWS.Bind(this)
		this.document.parentWindow.ahk_event := this._Event.Bind(this)
		this.document.parentWindow.ahk_ws_url := WS_URL

		; Add some JavaScript to the page to open a socket
		Script := this.document.createElement("script")
		Script.text := "ws = new WebSocket(ahk_ws_url);`n"
		. "ws.onopen = function(event){ ahk_event('Open', event); };`n"
		. "ws.onclose = function(event){ ahk_event('Close', event); };`n"
		. "ws.onerror = function(event){ ahk_event('Error', event); };`n"
		. "ws.onmessage = function(event){ ahk_event('Message', event); };"
		this.document.body.appendChild(Script)
	}

	; Called by the JS in response to WS events
	_Event(EventName, Event)
	{
		this["On" EventName](Event)
	}

	; Sends data through the WebSocket
	Send(Data)
	{
		; MsgBox %Data%
		this.document.parentWindow.ws.send(Data)
	}

	; Closes the WebSocket connection
	Close(Code:=1000, Reason:="")
	{
		this.document.parentWindow.ws.close(Code, Reason)
	}

	; Closes and deletes the WebSocket, removing
	; references so the class can be garbage collected
	Disconnect()
	{
		if this.hWnd
		{
			this.Close()
			Gui, % this.hWnd ": Destroy"
			this.hWnd := False
		}
	}
}

#NoEnv
#SingleInstance force ; only lets one run
SetBatchLines, -1

socket := new Example("ws://192.168.1.33:81") ; replace with the ip address of the mclighting controller
connected := 0 ;  state variable for server connection

incrementAmount := 10 ; how finely you adjust the color, speed, and brightness per keypress
maxColor := 255
maxMode := 56 ; the maximum mode id number

red := 127
green := 127
blue := 127

brightness := 127
speed := 127
mode := 1

^#Numpad4:: ; switch modes down
	mode := mode - 1
	if(mode < 0)
		mode := maxMode
	cmd = /%mode% ; / is the set effect mode command
	TrayTip, , Mode: %mode%
	sendCmd(cmd)
	; MsgBox %cmd%
	return

^#Numpad6:: ; switch modes up
	mode := mode + 1
	if(mode > maxMode)
		mode := 0
	TrayTip, , Mode: %mode%
	cmd = /%mode%
	sendCmd(cmd)
	; MsgBox %cmd%
	return

^#Numpad5:: ; turn off
	TrayTip, , Leds are off
	sendCmd("=off") ; = is the set control command
	return

^#Numpad0:: ; turn on to static color
	TrayTip, , Leds are on
	cmd := "*"+toHexColor(red,green,blue) ; * is the set all command
	sendCmd(cmd) ; = is the set control command
	return

^#NumpadSub:: ; decreases brightness
	brightness := brightness - incrementAmount
	if(brightness < 0)
		brightness := 0
	cmd = `%%brightness% ;  % is the set brightness mode command. ` is the escape character
	TrayTip, , Brightness: %brightness%
	sendCmd(cmd)
	; MsgBox %cmd%
	return

^#NumpadAdd:: ; increases brightness
	brightness := brightness + incrementAmount
	if(brightness > maxColor)
		brightness := maxColor
	cmd = `%%brightness% ; % is the set brightness mode command
	TrayTip, , Brightness: %brightness%
	sendCmd(cmd)
	; MsgBox %cmd%
	return

^#NumpadDiv:: ; decreases speed
	speed := speed - incrementAmount
	if(speed < 0)
		speed := 0
	cmd = ?%speed% ;  ? is the set brightness mode command
	TrayTip, , Speed: %speed%
	sendCmd(cmd)
	; MsgBox %cmd%
	return

^#NumpadMult:: ; increases speed
	speed := speed + incrementAmount
	if(speed > maxColor)
		speed := maxColor
	cmd = ?%speed% ;  ? is the set brightness mode command
	TrayTip, , Speed: %speed%
	sendCmd(cmd)
	; MsgBox %cmd%
	return

^#Numpad7:: ; increase red amount
	red := red + incrementAmount
	if(red > maxColor)
		red := maxColor

	cmd := "#"+toHexColor(red,green,blue) ; # is the set main color command
	; MsgBox %cmd%
	TrayTip, , Red: %red%
	sendCmd(cmd)

	return

^#Numpad1:: ; decrease red amount
	red := red - incrementAmount
	if(red < 0)
		red := 0

	cmd := "#"+toHexColor(red,green,blue) ; # is the set main color command
	; MsgBox %cmd%
	TrayTip, , Red: %red%
	sendCmd(cmd)

	return

^#Numpad8:: ; increase green amount
	green := green + incrementAmount
	if(green > maxColor)
		green := maxColor

	cmd := "#"+toHexColor(red,green,blue) ; # is the set main color command
	; MsgBox %cmd%
	TrayTip, , Green: %green%
	sendCmd(cmd)

	return

^#Numpad2:: ; decrease green amount
	green := green - incrementAmount
	if(green < 0)
		green := 0

	cmd := "#"+toHexColor(red,green,blue) ; # is the set main color command
	; MsgBox %cmd%
	TrayTip, , Green: %green%
	sendCmd(cmd)

	return

^#Numpad9:: ; increase blue amount
	blue := blue + incrementAmount
	if(blue > maxColor)
		blue := maxColor

	cmd := "#"+toHexColor(red,green,blue) ; # is the set main color command
	; MsgBox %cmd%
	TrayTip, , Blue: %blue%
	sendCmd(cmd)

	return

^#Numpad3:: ; decrease blue amount
	blue := blue - incrementAmount
	if(blue < 0)
		blue := 0

	cmd := "#"+toHexColor(red,green,blue) ; # is the set main color command
	; MsgBox %cmd%
	TrayTip, , Blue: %blue%
	sendCmd(cmd)

	return

sendCmd(cmd)
{
	global connected
	global socket
	; MsgBox %connected%
	if( connected )
	{
		socket.Send(cmd)
		; MsgBox %cmd%
	}
	else
		TrayTip, , Not connected to server!
}

toHexColor(r, g, b)
{
	SetFormat, IntegerFast, hex ; To print values as hexadecimal
	colorNum := r*65536 + g*256 + b
	color = 000000%colorNum% ; convert to string and add preceeding zeros
	color := StrReplace(color, "0x") ; replace the 0x from the middle
	color := SubStr( color, -5 ) ; get last 6 characters

	SetFormat, IntegerFast, dec ; sets the print mode back to decimal
	return ""+color ;
}

class Example extends WebSocket
{
	OnOpen(Event)
	{
		TrayTip, ,Connection established to led controller!
		; InputBox, Data, WebSocket, Enter some text to send through the websocket.
		; this.Send(Data)
		global connected := 1
	}

	OnMessage(Event)
	{
		; MsgBox, % "Received Data: " Event.data
		; this.Close()
	}

	OnClose(Event)
	{
		TrayTip, , Websocket Closed
		global connected := 0
		this.Disconnect()
		ExitApp
	}

	OnError(Event)
	{
		TrayTip, , Websocket Error
		global connected := 0
		this.Close()
	}

	__Delete()
	{
		TrayTip, , Exiting
		ExitApp
	}
}

class WebSocket
{
	__New(WS_URL)
	{
		static wb

		; Create an IE instance
		Gui, +hWndhOld
		Gui, New, +hWndhWnd
		this.hWnd := hWnd
		Gui, Add, ActiveX, vWB, Shell.Explorer
		Gui, %hOld%: Default

		; Write an appropriate document
		WB.Navigate("about:<!DOCTYPE html><meta http-equiv='X-UA-Compatible'"
		. "content='IE=edge'><body></body>")
		while (WB.ReadyState < 4)
			sleep, 50
		this.document := WB.document

		; Add our handlers to the JavaScript namespace
		this.document.parentWindow.ahk_savews := this._SaveWS.Bind(this)
		this.document.parentWindow.ahk_event := this._Event.Bind(this)
		this.document.parentWindow.ahk_ws_url := WS_URL

		; Add some JavaScript to the page to open a socket
		Script := this.document.createElement("script")
		Script.text := "ws = new WebSocket(ahk_ws_url);`n"
		. "ws.onopen = function(event){ ahk_event('Open', event); };`n"
		. "ws.onclose = function(event){ ahk_event('Close', event); };`n"
		. "ws.onerror = function(event){ ahk_event('Error', event); };`n"
		. "ws.onmessage = function(event){ ahk_event('Message', event); };"
		this.document.body.appendChild(Script)
	}

	; Called by the JS in response to WS events
	_Event(EventName, Event)
	{
		this["On" EventName](Event)
	}

	; Sends data through the WebSocket
	Send(Data)
	{
		; MsgBox %Data%
		this.document.parentWindow.ws.send(Data)
	}

	; Closes the WebSocket connection
	Close(Code:=1000, Reason:="")
	{
		this.document.parentWindow.ws.close(Code, Reason)
	}

	; Closes and deletes the WebSocket, removing
	; references so the class can be garbage collected
	Disconnect()
	{
		if this.hWnd
		{
			this.Close()
			Gui, % this.hWnd ": Destroy"
			this.hWnd := False
		}
	}
}


totalcommander: fix uninstallation on non-English OSes

The standard system message box button texts are localized, e.g. on Polish
Windows 10 "Yes" is "Tak". This causes the ahk script to fail and leaves
the message box warning about removing the 32-bit Total Commander open.

The third argument to ControlClick is interpreted in the same way as in
WinWait - any text fragment from the window containing the control, not
neccessarily the text of the control to click. So, let's use the same text
as for WinWait.

; default environment
DetectHiddenWindows, off
SetControlDelay, 20

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

; variables
winTitle1 = Uninstall /Repair Total Commander ahk_class #32770
winTitle2 = Uninstall Total Commander ahk_class #32770
winTitle3 = Uninstall ahk_class #32770

WinWait, %winTitle1%, Removes the program, 20
ControlClick, Button1, %winTitle1%, &Uninstall

WinWait, %winTitle2%, Uninstall Program, 20
ControlClick, Button4, %winTitle2%, Remove configuration files
ControlClick, Button5, %winTitle2%, Uninstall

WinWait, %winTitle3%, Warning: This will, 20
ControlClick, Button1, %winTitle3%, Warning: This will ; Yes

WinWait, %winTitle3%, The following, 20
ControlClick, Button1, %winTitle3%, OK

WinWait, %winTitle3%, , 20
ControlClick, Button1, %winTitle3%, OK

ExitApp

; default environment
DetectHiddenWindows, off
SetControlDelay, 20

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

; variables
winTitle1 = Uninstall /Repair Total Commander ahk_class #32770
winTitle2 = Uninstall Total Commander ahk_class #32770
winTitle3 = Uninstall ahk_class #32770

WinWait, %winTitle1%, Removes the program, 20
ControlClick, Button1, %winTitle1%, &Uninstall

WinWait, %winTitle2%, Uninstall Program, 20
ControlClick, Button4, %winTitle2%, Remove configuration files
ControlClick, Button5, %winTitle2%, Uninstall

WinWait, %winTitle3%, Warning: This will, 20
ControlClick, Button1, %winTitle3%, &Yes

WinWait, %winTitle3%, The following, 20
ControlClick, Button1, %winTitle3%, OK

WinWait, %winTitle3%, , 20
ControlClick, Button1, %winTitle3%, OK

ExitApp


bugfix

bugfix

^Tab::
Send #{Tab}
return

^!o::
IfWinActive, ahk_exe Obsidian.exe
    sleep 10
else
    WinActivate ahk_exe Obsidian.exe
return

^!g::
IfWinActive, ahk_exe msedge.exe
    sleep 10
else
;    WinShow ahk_exe msedge.exe
;    WinActivate ahk_exe msedge.exe
;    sleep 10
;    WinSet Top
;    MouseClick
    Send #0
return

^!m::
IfWinActive, ahk_exe chrome.exe
    sleep 10
else
    WinShow ahk_exe chrome.exe
    WinActivate ahk_exe chrome.exe
    sleep 10
    WinSet Top
return

^!Space::
Process,close,explorer.exe
sleep 50 ;This sleep 5000 is to let you see what actually happens. Decrease it later
run, explorer.exe
WinWait, ahk_class CabinetWClass
WinClose ;close the new explorer window
return

^Tab::
Send #{Tab}
return

^!o::
IfWinActive, ahk_exe Obsidian.exe
    sleep 10
else
    WinActivate ahk_exe Obsidian.exe
return

^!g::
IfWinActive, ahk_exe msedge.exe
    sleep 10
else
    WinShow ahk_exe msedge.exe
    WinActivate ahk_exe msedge.exe
    sleep 10
    WinSet Top
    ;MouseClick
return

^!m::
IfWinActive, ahk_exe chrome.exe
    sleep 10
else
;    WinShow ahk_exe msedge.exe
;    WinActivate ahk_exe msedge.exe
;    sleep 10
;    WinSet Top
;    MouseClick
return

^!Space::
Process,close,explorer.exe
sleep 50 ;This sleep 5000 is to let you see what actually happens. Decrease it later
run, explorer.exe
WinWait, ahk_class CabinetWClass
WinClose ;close the new explorer window
return


bpmicro ahk date file names

bpmicro ahk date file names

Signed-off-by: John McMaster <527ca5438b47432dedda4309be2f991b71bfb11c@gmail.com>

; loops reads in BPWin GUI
; displays results and logs dumps to file
; alt a to activate
; shift to stop
!a::

show_data := 0
save_data := 1

loopi := 0

FormatTime, StartDateTime,, yyyy-MM-dd_HH.mm.ss
basedir = D:\buffer\rom\ahk\out
dirout = %basedir%\%StartDateTime%
; MsgBox %dirout%
FileCreateDir, %dirout%

Loop {
	;initiate read
	send {SPACE}
	Sleep, 2000

	; clear abnormal condition (if any)
	; ex: overcurrent during read
	Send {Esc}
	Sleep, 200

	if (show_data) {
		; activate data view
		send ^e
		; select hex view
		send {Tab}
		send B
		send {Up}
		; let user oogle the data
		Sleep, 2000
		; Close hex view
		Send {Esc}

		Sleep, 200
	}

	if (save_data) {
		; file => save pattern as
		; activate file menu
		; send !f
		Send {Alt}
		Send {Down}
		Send {Down}
		Send {Down}
		Send {Down}
		send {Enter}
		; save dialogue
		Sleep, 200
		loops := Format("{:04}", loopi)
		FormatTime, curdt,, yyyy-MM-dd_HH.mm.ss
		fn = %dirout%\%loops%_%curdt%.bin
		Send %fn%
		send {Enter}
		; file format options: accept deafult
		send {Enter}

		Sleep, 200
	}

	loopi := loopi + 1
	;MsgBox, %loopi%
}

; this makes it so if you press escape, it stops the script, good for infinite loops
; supposedly you keep this at the bottom of the file per stackoverflow
; interfering with closing message boxes
; Esc::ExitApp
; harmless key
Shift::ExitApp

; loops reads in BPWin GUI
; displays results and logs dumps to file
; alt a to activate
; shift to stop
!a::

loopi := 0

FormatTime, CurrentDateTime,, yyyy-MM-dd_HH.mm.ss
basedir = D:\buffer\rom\ahk\out
dirout = %basedir%\%CurrentDateTime%
; MsgBox %dirout%
FileCreateDir, %dirout%

Loop {
	;initiate read
	send {SPACE}
	Sleep, 2000

	; clear abnormal condition (if any)
	; ex: overcurrent during read
	Send {Esc}
	Sleep, 200

	; activate data view
	send ^e
	; select hex view
	Loop, 7 {
		send {Tab}
	}
	send {Up}
	; let user oogle the data
	Sleep, 2000
	; Close hex view
	Send {Esc}

	Sleep, 200

	; file => save pattern as
	; activate file menu
	; send !f
	Send {Alt}
	Send {Down}
	Send {Down}
	Send {Down}
	Send {Down}
	send {Enter}
	; save dialogue
	Sleep, 200
	loops := Format("{:04}", loopi)
	fn = %dirout%\%loops%.bin
	Send %fn%
	send {Enter}
	; file format options: accept deafult
	send {Enter}

	Sleep, 200

	loopi := loopi + 1
	;MsgBox, %loopi%
}

; this makes it so if you press escape, it stops the script, good for infinite loops
; supposedly you keep this at the bottom of the file per stackoverflow
; interfering with closing message boxes
; Esc::ExitApp
; harmless key
Shift::ExitApp