├── .gitignore ├── Conf └── VimD.ini.help.txt ├── Core ├── Main.ahk ├── Vim.ahk └── VimDConfig.ahk ├── Doc ├── Example.ahk ├── Images │ ├── vimdesktop_128.jpg │ ├── vimdesktop_32.jpg │ └── vimdesktop_64.jpg └── PluginTemplete.ahk ├── LICENSE ├── Lib ├── Acc.ahk ├── EasyIni.ahk ├── GDIP.ahk └── Logger.ahk ├── Plugins ├── BeyondCompare4 │ └── BeyondCompare4.ahk ├── DoubleCommander │ ├── DoubleCommander.ahk │ └── Readme.md ├── Explorer │ └── Explorer.ahk ├── Foobar2000 │ └── Foobar2000.ahk ├── General │ └── General.ahk ├── MicrosoftExcel │ ├── InputColor.ahk │ ├── MicrosoftExcel.ahk │ └── readme.ini ├── Plugins.ahk ├── Readme.txt ├── TCCompare │ └── TCCompare.ahk ├── TCDialog │ ├── Readme.md │ └── TCDialog.ahk ├── TotalCommander │ ├── GenerateCommands.zsh │ ├── TCCommand.ahk │ ├── TotalCommander.ahk │ └── a-zhistory.icl └── WinMerge │ └── WinMerge.ahk ├── README.md ├── VERSION ├── VimD.ahk └── VimD.ico /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | /Conf/VimD.ini 3 | /Custom.ahk 4 | -------------------------------------------------------------------------------- /Conf/VimD.ini.help.txt: -------------------------------------------------------------------------------- 1 | ; [使用说明] 2 | ; 1. 如果当前目录无vimd.ini文件,VimDesktop会将此文件复制为vimd.ini 3 | ; 2. 根据分号 ; 之后的提示内容进行相应修改 4 | ; 5 | ; [自定义配置用法] 6 | ; 在当前目录添加 custom.ahk文件,内容如下: 7 | ; 8 | ; : 9 | ; 对应功能 10 | ; return 11 | ; 12 | ; : 13 | ; 对应功能 14 | ; return 15 | ; ;;; 16 | ; 17 | ; 然后可以在作为功能标签使用,如: 18 | ; a=[=normal] 19 | 20 | [config] 21 | ; 是否默认开启快捷键提示,可以被插件的 enable_show_info 覆盖 22 | default_enable_show_info=1 23 | ; 配置编辑器,请填写完整路径,如果填写的是 notepad ,将使用 notepad2 的参数 24 | editor= 25 | ; RunZ 所在目录,请填写完整路径,默认在 ..\RunZ 26 | runz_dir= 27 | ; 打印调试日志 28 | enable_log=0 29 | ; 打开调试窗口 30 | enable_debug=0 31 | ; 自定义的配置文件路径,需要 .ini 扩展名,主要方便备份和升级 32 | ;custom_config_path=vimd_custom.ini 33 | 34 | [exclude] 35 | vim 36 | 37 | [global] 38 | ; 激活通用快捷键 39 | = 40 | ; 切换TC 41 | = 42 | ; 重新加载VimDesktop 43 | = 44 | = 45 | = 46 | 47 | ; 激活TC作为文件选择框,再次按下该快捷键可执行文件打开操作 48 | = 49 | =run|explorer 50 | 51 | ; 启用(1)/禁用(0) 插件,默认禁用 52 | [plugins] 53 | General=1 54 | TotalCommander=1 55 | WinMerge=1 56 | TCDialog=1 57 | TCCompare=1 58 | BeyondCompare4=1 59 | Foobar2000=1 60 | VimDConfig=1 61 | MicrosoftExcel=1 62 | Explorer=1 63 | 64 | ; 设置窗口名 65 | ;[记事本] 66 | ;set_class=Notepad 67 | ;set_file=Notepad.exe 68 | ;设置超时时间 69 | ;set_time_out=800 70 | ;设置最大重复执行次数 71 | ;set_max_count=1000 72 | ;设置显示提示 73 | ;enable_show_info=1 74 | ;设置热键 75 | ;j=[=normal] 76 | ;k=[=normal] 77 | ;h=[=normal] 78 | ;l=[=normal] 79 | ;=run|notepad.exe 80 | ;=key|^o 81 | 82 | ;[Explorer] 83 | ;f= 84 | ;= 85 | 86 | [TotalCommander_Config] 87 | ;TCPath: TotalCommander可执行文件路径--TC运行时,可被自动识别 88 | TCPath=C:\mine\app\totalcmd\TOTALCMD.EXE 89 | 90 | ;TCINI: TotalCommander配置文件路径--TC运行时,可被自动识别 91 | TCINI=C:\mine\app\totalcmd\wincmd.ini 92 | 93 | ;是否在配置文件中记录Mark 94 | SaveMark=1 95 | 96 | ;弹出菜单中的图标尺寸 97 | ;目前仅用于TC中的AZHistory导航:可用尺寸16,20,24,32 98 | MenuIconSize=20 99 | 100 | ; Total Commander快捷键配置 101 | [TTOTAL_CMD] 102 | ; 热键定义语法 103 | ; f=[=normal] 104 | ; f: 热键,按下f 105 | ; 对应的动作 106 | ; [=normal] 在normal模式下生效,可省略,默认为normal 107 | ; 108 | ; = 109 | ; :shift + f,大写F 110 | ; :ctrl + f 111 | ; :alt + f 112 | ; :lalt + f 113 | ; :space + f 114 | ; 使用时避免空格不可用,加下一行 115 | ; = 116 | ; 117 | ; =run|notepad.exe 118 | ; 运行命令,[=normal]可选,默认为normal模式 119 | ; =key|^o 120 | ; 映射按键,[=normal]可选,默认为normal模式 121 | ; =dir|c:\test 122 | ; 用TC打开目录,[=normal]可选,默认为normal模式 123 | ; =tccmd|em_test 124 | ; 在TC的命令行运行命令,[=normal]可选,默认为normal模式 125 | ; =wshkey|xx 126 | ; 映射按键,使用WScript.Shell的SendKeys()调用,[=normal]可选,默认为normal模式 127 | ; =function|TestFunction|arg 128 | ; 映射函数,|arg 可以省略,只支持一个参数 129 | 130 | a= 131 | b= 132 | c= 133 | d= 134 | e= 135 | h= 136 | i= 137 | l= 138 | m= 139 | o= 140 | p= 141 | u= 142 | fa= 143 | ff= 144 | zh= 145 | zz= 146 | = 147 | = 148 | = 149 | = 150 | = 151 | = 152 | = 153 | = 154 | = 155 | = 156 | = 157 | = 158 | = 159 | = 160 | = 161 | = 162 | = 163 | = 164 | = 165 | = 166 | = 167 | = 168 | = 169 | = 170 | = 171 | = 172 | = 173 | = 174 | = 175 | = 176 | = 177 | ,= 178 | .=function|TC_Run|explorer . 179 | = 180 | = 181 | = 182 | = 183 | ;"= 184 | ;_= 185 | -------------------------------------------------------------------------------- /Core/Main.ahk: -------------------------------------------------------------------------------- 1 | global ConfigPath 2 | global vim 3 | global ini 4 | global default_enable_show_info 5 | global editor 6 | global VIMD_CMD_LIST 7 | 8 | VimdRun() 9 | { 10 | CustomInit := "CustomInit" 11 | if (IsLabel(CustomInit)) 12 | { 13 | GoSub, %CustomInit% 14 | } 15 | 16 | ConfigPath := A_ScriptDir "\conf\vimd.ini" 17 | IniRead, CustomConfigPath, %ConfigPath%, config, custom_config_path 18 | if (FileExist(A_ScriptDir "\conf\" CustomConfigPath)) 19 | { 20 | ConfigPath := A_ScriptDir "\conf\" CustomConfigPath 21 | } 22 | 23 | vim := class_vim() 24 | VIMD_CMD_LIST := [] 25 | 26 | if (!FileExist(ConfigPath)) 27 | { 28 | FileCopy, %A_ScriptDir%\conf\vimd.ini.help.txt, %ConfigPath% 29 | } 30 | 31 | ini := class_EasyINI(ConfigPath) 32 | default_enable_show_info := ini.config.default_enable_show_info 33 | editor := ini.config.editor 34 | 35 | if (ini.config.enable_log == 1) 36 | { 37 | global log := new Logger(A_ScriptDir "\debug.log") 38 | } 39 | 40 | if (ini.config.enable_debug == 1) 41 | { 42 | vim.Debug(true) 43 | } 44 | 45 | ; 第二个参数为存放描述信息的全局变量名 46 | act := vim.SetAction("VIMD_CMD", "VIMD_CMD_LIST") 47 | act.SetFunction("VIMD_CMD") 48 | 49 | CheckPlugin() 50 | CheckHotKey() 51 | 52 | ; 定时检查配置文件更新 53 | SetTimer, WatchConfigFile, 2000 54 | } 55 | 56 | CheckPlugin() 57 | { 58 | ExtensionsAHK := A_ScriptDir "\Plugins\Plugins.ahk" 59 | 60 | ; 检测是否有新增插件 61 | Loop, %A_ScriptDir%\plugins\*, 2, 0 62 | { 63 | IniRead, PluginTime, %ExtensionsAHK%, ExtensionsTime, %A_LoopFileName% 64 | if (PluginTime = "ERROR") 65 | { 66 | MsgBox, 发现新插件 %A_LoopFileName%,将自动加载该插件 67 | 68 | Filedelete, %ExtensionsAHK% 69 | 70 | Loop, %A_ScriptDir%\plugins\*.*, 2 71 | plugins .= "#include *i `%A_ScriptDir`%\plugins\" A_LoopFileName "\" A_LoopFileName ".ahk`n" 72 | FileAppend, %plugins%, %ExtensionsAHK% 73 | 74 | SaveTime := "/*`r`n[ExtensionsTime]`r`n" 75 | Loop, %A_ScriptDir%\plugins\*.*, 2 76 | { 77 | plugin := A_ScriptDir "\plugins\" A_LoopFileName "\" A_LoopFileName ".ahk" 78 | FileGetTime, ExtensionsTime, %plugin%, M 79 | SaveTime .= A_LoopFileName "=" ExtensionsTime "`r`n" 80 | } 81 | SaveTime .= "*/`r`n" 82 | FileAppend, %SaveTime%, %ExtensionsAHK% 83 | 84 | IniWrite, 1, %ConfigPath%, plugins, %A_LoopFileName% 85 | Reload 86 | } 87 | } 88 | 89 | for plugin, flag in ini.plugins 90 | if flag 91 | vim.LoadPlugin(plugin) 92 | } 93 | 94 | CheckHotKey() 95 | { 96 | for this_key, this_action in ini.global 97 | { 98 | this_mode := "normal" 99 | if RegExMatch(this_action, "\[=[^\[\]]*\]", mode) 100 | { 101 | this_mode := Substr(mode, 3, strlen(mode) - 3) 102 | this_action := RegExReplace(this_action, "\[=[^\[\]]*\]") 103 | } 104 | 105 | vim.mode(this_mode) 106 | if RegExMatch(this_action, "^(run|key|dir|tccmd|dccmd|wshkey|function)\|") 107 | { 108 | vim.map(this_key, "VIMD_CMD") 109 | VIMD_CMD_LIST[this_key] := this_action 110 | } 111 | else 112 | { 113 | vim.map(this_key, this_action) 114 | } 115 | } 116 | 117 | for win, flag in ini.exclude 118 | { 119 | vim.SetWin(win, win) 120 | vim.ExcludeWin(win, true) 121 | } 122 | 123 | for PluginName, Key in ini 124 | { 125 | if RegExMatch(PluginName, "i)(config)|(exclude)|(global)|(plugins)") 126 | continue 127 | 128 | win := vim.SetWin(PluginName, Key.set_class, Key.set_file) 129 | vim.SetTimeOut(Key.set_time_out, PluginName) 130 | vim.SetMaxCount(Key.set_max_count, PluginName) 131 | if (Key.enable_show_info = 1) 132 | { 133 | win.SetInfo(true) 134 | } 135 | 136 | class_name := Key.set_class 137 | if (class_name == "") 138 | { 139 | class_name := PluginName 140 | } 141 | 142 | for m, n in Key 143 | { 144 | if RegExMatch(m, "i)(set_class)|(set_file)|(set_time_out)|(set_max_count)|(enable_show_info)") 145 | continue 146 | 147 | this_mode := "normal" 148 | this_action := n 149 | 150 | if RegExMatch(this_action, "\[=[^\[\]]*\]", mode) 151 | { 152 | this_mode := Substr(mode, 3, strlen(mode) - 3) 153 | this_action := RegExReplace(n, "\[=[^\[\]]*\]") 154 | } 155 | 156 | vim.mode(this_mode, PluginName) 157 | 158 | if RegExMatch(n, "i)^(run|key|dir|tccmd|dccmd|wshkey|function)\|") 159 | { 160 | /* 161 | 示例: 162 | =run|notepad.exe 163 | */ 164 | 165 | vim.map(m, "VIMD_CMD", PluginName) 166 | VIMD_CMD_LIST[PluginName "#" m] := n 167 | } 168 | else 169 | { 170 | vim.map(m, this_action, PluginName) 171 | } 172 | } 173 | } 174 | } 175 | 176 | VIMD_CMD() 177 | { 178 | obj := GetLastAction() 179 | key := obj.KeyTemp 180 | 181 | if (obj.WinName != "") 182 | { 183 | key := obj.WinName "#" obj.KeyTemp 184 | } 185 | 186 | if RegExMatch(VIMD_CMD_LIST[key], "i)^(run)\|", m) 187 | { 188 | Run, % substr(VIMD_CMD_LIST[key], strlen(m1) + 2) 189 | } 190 | else if RegExMatch(VIMD_CMD_LIST[key], "i)^(key)\|", m) 191 | { 192 | Send, % substr(VIMD_CMD_LIST[key], strlen(m1) + 2) 193 | } 194 | else if RegExMatch(VIMD_CMD_LIST[key], "i)^(dir)\|", m) 195 | { 196 | TC_OpenPath(substr(VIMD_CMD_LIST[key], strlen(m1) + 2), false) 197 | } 198 | else if RegExMatch(VIMD_CMD_LIST[key], "i)^(function)\|", m) 199 | { 200 | splitedCommand:= StrSplit(substr(VIMD_CMD_LIST[key], strlen(m1) + 2), "|") 201 | functionName := splitedCommand[1] 202 | if (IsFunc(functionName)) 203 | { 204 | ; 简单起见只支持一个参数,需要更多函数的话请自行切割字符串 205 | %functionName%(splitedCommand[2]) 206 | } 207 | else 208 | { 209 | MsgBox, %functionName% 函数不存在! 210 | } 211 | } 212 | else if RegExMatch(VIMD_CMD_LIST[key], "i)^(tccmd)\|", m) 213 | { 214 | TC_Run(substr(VIMD_CMD_LIST[key], strlen(m1) + 2)) 215 | } 216 | else if RegExMatch(VIMD_CMD_LIST[key], "i)^(dccmd)\|", m) 217 | { 218 | DC_Run(substr(VIMD_CMD_LIST[key], strlen(m1) + 2)) 219 | } 220 | else if RegExMatch(VIMD_CMD_LIST[key], "i)^(wshkey)\|", m) 221 | { 222 | SendLevel, 1 223 | Send, % substr(VIMD_CMD_LIST[key], strlen(m1) + 2) 224 | } 225 | } 226 | 227 | VIMD_Reload: 228 | Reload 229 | return 230 | 231 | WatchConfigFile: 232 | FileGetTime, newConfigFileModifyTime, %ConfigPath% 233 | 234 | if (lastConfigFileModifyTime != "" && lastConfigFileModifyTime != newConfigFileModifyTime) 235 | { 236 | GoSub, VIMD_Reload 237 | } 238 | lastConfigFileModifyTime := newConfigFileModifyTime 239 | return 240 | -------------------------------------------------------------------------------- /Core/Vim.ahk: -------------------------------------------------------------------------------- 1 | global __vimLastAction 2 | 3 | ; 初始化class_Vim 4 | vim_Init: 5 | #UseHook 6 | SetKeyDelay, -1 7 | return 8 | 9 | ; 用于热键映射 10 | vim_Key: 11 | vim.Key() 12 | return 13 | 14 | ; 用于热键超时 15 | vim_TimeOut: 16 | vim.IsTimeOut() 17 | return 18 | 19 | ; 用于Count计数 20 | Internal: 21 | __v.SetPlugin("Internal", "Array", "0.1", "内置插件") 22 | __v.SetAction("<1>", "数字 1") 23 | __v.SetAction("<2>", "数字 2") 24 | __v.SetAction("<3>", "数字 3") 25 | __v.SetAction("<4>", "数字 4") 26 | __v.SetAction("<5>", "数字 5") 27 | __v.SetAction("<6>", "数字 6") 28 | __v.SetAction("<7>", "数字 7") 29 | __v.SetAction("<8>", "数字 8") 30 | __v.SetAction("<9>", "数字 9") 31 | __v.SetAction("<0>", "数字 0") 32 | __v.SetAction("<>", "空操作") 33 | __v.SetAction("", "空操作") 34 | __v.SetAction("", "恢复默认") 35 | __v := "" 36 | return 37 | 38 | <1>: 39 | <2>: 40 | <3>: 41 | <4>: 42 | <5>: 43 | <6>: 44 | <7>: 45 | <8>: 46 | <9>: 47 | <0>: 48 | <>: 49 | : 50 | : 51 | return 52 | 53 | Class_vim() 54 | { 55 | global __v 56 | GoSub, vim_Init 57 | __v := v := new __vim 58 | __v.LoadPlugin("Internal") 59 | return v 60 | } 61 | 62 | GetLastAction() 63 | { 64 | return __vimLastAction 65 | } 66 | 67 | ShowInfo() 68 | { 69 | Global vim 70 | obj := vim.GetMore(true) 71 | winObj := vim.GetWin(vim.LastFoundWin) 72 | if winObj.Count 73 | np .= winObj.Count 74 | Loop, % obj.MaxIndex() 75 | { 76 | act := vim.GetAction(obj[A_Index]["Action"]) 77 | key := RegExReplace(obj[A_Index]["key"], "", "$1") 78 | 79 | ; Type = 1 : Function 80 | if (act.Type = 1) 81 | { 82 | ActionDescList := act.Comment 83 | np .= key "`t" %ActionDescList%[vim.LastFoundWin "#" Key] "`n" 84 | } 85 | else 86 | { 87 | np .= key "`t" act.Comment "`n" 88 | } 89 | 90 | if (A_Index = 1) 91 | np .= "=====================`n" 92 | } 93 | MouseGetPos, posx, posy, A 94 | posx += 40 95 | posy += 40 96 | Tooltip, %np%, %posx%, %posy% 97 | } 98 | 99 | HideInfo() 100 | { 101 | ; 当屏幕有非快捷键补全帮助信息时,不清理 102 | Global showToolTipStatus 103 | if (!showToolTipStatus) 104 | { 105 | Tooltip 106 | } 107 | } 108 | 109 | ; 定义数据结构 110 | ; Class __vim {{{1 111 | Class __vim 112 | { 113 | __new() 114 | { 115 | this.PluginList := [] 116 | this.WinList := [] 117 | this.WinInfo := [] 118 | this.ActionList := [] 119 | this.ActionFromPlugin := [] 120 | this.ExcludeWinList := [] 121 | this.winGlobal := new __win 122 | this.ErrorCode := 0 123 | tihs.ActionFromPluginName := "" 124 | this.LastFoundWin := "" 125 | } 126 | 127 | ; LoadPlugin(PluginName) {{{2 128 | ; 用于注册插件 129 | LoadPlugin(PluginName) 130 | { 131 | if this.PluginList[PluginName] 132 | return this.PluginList[PluginName] 133 | p := new __Plugin(PluginName) 134 | this.PluginList[PluginName] := p 135 | back := this.ActionFromPluginName 136 | this.ActionFromPluginName := PluginName 137 | p.CheckSub() 138 | if p.Error 139 | { 140 | MsgBox load plugin "%PluginName%" error 141 | this.ActionFromPluginName := back 142 | } 143 | } 144 | 145 | ; SetPlugin(PluginName, Author = "", Ver = "", Comment = "") {{{2 146 | ; 设置Plugin信息 147 | SetPlugin(PluginName, Author = "", Ver = "", Comment = "") 148 | { 149 | p := this.PluginList[PluginName] 150 | p.Author := Author 151 | p.Ver := Ver 152 | p.Comment := Comment 153 | } 154 | 155 | ; GetPlugin(PluginName) {{{2 156 | ; 获取Plugin信息 157 | GetPlugin(PluginName) 158 | { 159 | return this.PluginList[PluginName] 160 | } 161 | 162 | ; Comment(Action, Desc, Complex = 1) {{{2 163 | ; 兼容老版本的vimcore.ahk 164 | Comment(Action, Desc = "", Complex = 1) 165 | { 166 | act := this.SetAction(Action, Desc) 167 | if not complex ; 不允许多次运行 168 | act.SetMaxTimes(1) 169 | return act 170 | } 171 | 172 | ; SetAction(Name, Comment) {{{2 173 | ; 用于为Action(动作)进行注释 174 | SetAction(Name, Comment = "") 175 | { 176 | if this.ActionList[Name] 177 | ra := This.ActionList[Name] 178 | else 179 | ra := This.ActionList[Name] := new __Action(Name, Comment) 180 | This.ActionFromPlugin[Name] := this.ActionFromPluginName 181 | return ra 182 | } 183 | 184 | ; GetAction(Name) {{{2 185 | ; 获取Action的信息 186 | GetAction(Name) 187 | { 188 | return this.ActionList[Name] 189 | } 190 | 191 | ; SetWin(winName, class, filepath, title) {{{2 192 | ; 添加win成员 193 | SetWin(winName, class, filepath = "", title = "") 194 | { 195 | if this.WinList[winName] 196 | rw := this.WinList[winName] 197 | else 198 | rw := this.WinList[winName] := new __win(class, filepath, title) 199 | 200 | if (class != "") 201 | { 202 | this.WinInfo["class`t"class] := winName 203 | } 204 | 205 | if (filepath != "") 206 | { 207 | this.WinInfo["filepath`t"filepath] := winName 208 | } 209 | 210 | if (title != "") 211 | { 212 | this.WinInfo["title`t"title] := winName 213 | } 214 | 215 | return rw 216 | } 217 | 218 | ; GetWin(winName) {{{2 219 | GetWin(winName = "") 220 | { 221 | if strlen(winName) 222 | return this.WinList[winName] 223 | else 224 | return this.winGlobal 225 | } 226 | 227 | ; CheckWin() {{{2 228 | CheckWin() 229 | { 230 | /* 231 | WinGetTitle, t, A 232 | if Strlen(winName := this.WinInfo["title`t"t]) 233 | return winName 234 | */ 235 | 236 | WinGet, f, ProcessName, A 237 | if Strlen(winName := this.WinInfo["filepath`t"f]) 238 | return winName 239 | WinGetClass, c, A 240 | if Strlen(winName := this.WinInfo["class`t"c]) 241 | return winName 242 | } 243 | 244 | ; mode(mode, win = "") {{{2 245 | ; 兼容老版本的vimcore.ahk 246 | mode(mode, win = "") 247 | { 248 | if not IsObject(this.GetWin(win)) 249 | this.SetWin(win, win) 250 | return this.SetMode(mode, win) 251 | } 252 | 253 | ; SetMode(modeName, winName) {{{2 254 | SetMode(modeName, winName = "") 255 | { 256 | winObj := This.GetWin(winName) 257 | return winObj.ChangeMode(modeName) 258 | } 259 | 260 | ; SetModeFunction(func, modeName, winName = "") {{{2 261 | SetModeFunction(func, modeName, winName = "") 262 | { 263 | winObj := This.GetWin(winName) 264 | modeObj := winObj.modeList[modeName] 265 | modeObj.modeFunction := func 266 | } 267 | 268 | ; GetMode(winName) {{{2 269 | ; 获取指定win中当前的模式 270 | GetMode(winName = "") 271 | { 272 | winObj := This.GetWin(winName) 273 | return winObj.modeList[winObj.ExistMode()] 274 | } 275 | 276 | ; GetInputState {{{2 277 | ; 0:英文 1:中文 278 | GetInputState(WinTitle = "A") 279 | { 280 | ControlGet, hwnd, HWND, , , %WinTitle% 281 | if (A_Cursor = "IBeam") 282 | return 1 283 | if (WinActive(WinTitle)) 284 | { 285 | ptrSize := !A_PtrSize ? 4 : A_PtrSize 286 | VarSetCapacity(stGTI, cbSize := 4 + 4 + (PtrSize * 6) + 16, 0) 287 | NumPut(cbSize, stGTI, 0, "UInt") ; DWORD cbSize; 288 | hwnd := DllCall("GetGUIThreadInfo", Uint, 0, Uint, &stGTI) 289 | ? NumGet(stGTI, 8 + PtrSize, "UInt") : hwnd 290 | } 291 | return DllCall("SendMessage" 292 | , UInt, DllCall("imm32\ImmGetDefaultIMEWnd", Uint, hwnd) 293 | , UInt, 0x0283 ;Message : WM_IME_CONTROL 294 | , Int, 0x0005 ;wParam : IMC_GETOPENSTATUS 295 | , Int, 0) ;lParam : 0 296 | } 297 | 298 | ; BeforeActionDo(Function, winName = "") {{{2 299 | BeforeActionDo(Function, winName = "") 300 | { 301 | winObj := this.GetWin(winName) 302 | winObj.BeforeActionDoFunc := Function 303 | } 304 | 305 | ; AfterActionDo(Function, winName = "") {{{2 306 | AfterActionDo(Function, winName = "") 307 | { 308 | winObj := this.GetWin(winName) 309 | winObj.AfterActionDoFunc := Function 310 | } 311 | 312 | ; SetMaxCount(Int, winName) {{{2 313 | SetMaxCount(Int, winName = "") 314 | { 315 | winObj := This.GetWin(winName) 316 | winObj.MaxCount := int 317 | } 318 | 319 | ; GetMaxCount(winName) {{{2 320 | GetMaxCount(winName = "") 321 | { 322 | winObj := This.GetWin(winName) 323 | return winObj.MaxCount 324 | } 325 | 326 | ; SetCount(int, winName) {{{2 327 | SetCount(int, winName = "") 328 | { 329 | winObj := This.GetWin(winName) 330 | winObj.Count := int 331 | } 332 | 333 | ; GetCount(winName) {{{2 334 | GetCount(winName = "") 335 | { 336 | winObj := This.GetWin(winName) 337 | return winObj.Count 338 | } 339 | 340 | ; SetTimeOut(Int, winName) {{{2 341 | SetTimeOut(Int, winName = "") 342 | { 343 | winObj := This.GetWin(winName) 344 | winObj.TimeOut := int 345 | } 346 | 347 | ; GetTimeOut(winName) {{{2 348 | GetTimeOut(winName = "") 349 | { 350 | winObj := This.GetWin(winName) 351 | return winObj.TimeOut 352 | } 353 | 354 | ; Map(keyName, Action, winName) {{{2 355 | ; 例 Map("jjj", , "TC") 356 | ; Map("jk", , "TC") 357 | Map(keyName, Action, winName = "") 358 | { 359 | if not this.GetAction(Action) 360 | { 361 | if Islabel(action) 362 | this.SetAction(Action, Action) 363 | else 364 | { 365 | MsgBox % "map " keyname " to " action " error" 366 | this.ErrorCode := "MAP_ACTION_ERROR" 367 | return 368 | } 369 | } 370 | 371 | winObj := This.GetWin(winName) 372 | modeObj := this.GetMode(winName) 373 | Class := winObj.class 374 | filepath := winObj.filepath 375 | if winName 376 | { 377 | if strlen(filepath) 378 | Hotkey, IfWinActive, ahk_exe %filepath% 379 | else 380 | Hotkey, IfWinActive, ahk_class %class% 381 | } 382 | else 383 | Hotkey, IfWinActive 384 | keyName := RegExReplace(keyName, "i)", "", nowait) 385 | keyName := RegExReplace(keyName, "i)", "", super) 386 | newkeyName := keyName 387 | keyIndex := 0 388 | Loop 389 | { 390 | if not strlen(newkeyName) 391 | break 392 | else 393 | { 394 | saveMoreKey .= thisKey 395 | modeobj.SetMoreKey(saveMoreKey) 396 | } 397 | 398 | if RegExMatch(newkeyName, "P)^<.+?>", m) 399 | { 400 | thisKey := SubStr(newkeyName, 1, m) 401 | newkeyName := SubStr(newkeyName, m+1) 402 | } 403 | else 404 | { 405 | thisKey := SubStr(newkeyName, 1, 1) 406 | newKeyName := SubStr(newkeyName, 2) 407 | } 408 | 409 | if RegExMatch(thisKey, "^([A-Z])$", m) 410 | thisKey := "" 411 | SaveKeyName .= thisKey 412 | key := this.Convert2AHK(thisKey) 413 | this.Debug.Add("Map: " thiskey " to: " Action) 414 | 415 | if (Action <> "") 416 | { 417 | Hotkey, %Key%, vim_Key, On, UseErrorLevel 418 | } 419 | else 420 | { 421 | Hotkey, %Key%, Off, UseErrorLevel 422 | } 423 | 424 | if ErrorLevel 425 | { 426 | Msgbox % KeyName "`n" key "`n映射错误" 427 | this.ErrorCode := "MAP_KEY_ERROR" 428 | return 429 | } 430 | else 431 | { 432 | winObj.SuperKeyList[key] := super 433 | winObj.KeyList[key] := true 434 | keyIndex++ 435 | } 436 | } 437 | 438 | modeObj.SetKeyMap(SavekeyName, Action) 439 | modeObj.SetNoWait(SavekeyName, nowait) 440 | return false 441 | } 442 | 443 | ; ExcludeWin(winName = "", Bold = true) {{{2 444 | ExcludeWin(winName = "", Bold = true) 445 | { 446 | this.ExcludeWinList[winName] := Bold 447 | } 448 | 449 | ; Toggle(winName) {{{2 450 | Toggle(winName) 451 | { 452 | winObj := this.GetWin(winName) 453 | winObj.Status := !winObj.Status 454 | this.Control(winObj.Status, winName) 455 | return winObj.Status 456 | } 457 | 458 | ; Control(bold, winName) {{{2 459 | Control(bold, winName = "", all=false) 460 | { 461 | local class 462 | 463 | winObj := this.GetWin(winName) 464 | class := winObj.Class 465 | filepath := winObj.filepath 466 | if Strlen(filepath) 467 | Hotkey, IfWinActive, ahk_exe %filepath% 468 | else if Strlen(class) 469 | Hotkey, IfWinActive, ahk_class %class% 470 | else 471 | Hotkey, IfWinActive 472 | 473 | this.Debug.Add("===== Control End =====") 474 | for i , k in winObj.KeyList 475 | { 476 | if winObj.SuperKeyList[i] And (not all) 477 | Continue 478 | this.Debug.Add("class: " class "`tkey: " i "`tcontrol: " bold) 479 | if bold 480 | Hotkey, %i%, vim_Key, On 481 | else 482 | Hotkey, %i%, vim_Key, off 483 | winObj.KeyList[i] := bold 484 | } 485 | this.Debug.Add("===== Control Start =====") 486 | } 487 | 488 | ; Copy(winName1, winName2) {{{2 489 | ; 复制winName1到winName2, winName2按class/filepath/title定义 490 | Copy(winName1, winName2, class, filepath = "", title = "") 491 | { 492 | this.debug.Add("Copy>> "winName1 "`t" winName2 "`t" class) 493 | win1 := This.GetWin(winName1) 494 | win2 := this.SetWin(winName2, class, filepath, title) 495 | win2.class := class 496 | win2.filepath := filepath 497 | win2.title := title 498 | win2.KeyList := win1.KeyList 499 | win2.SuperKeyList := win1.SuperKeyList 500 | win2.modeList := win1.modeList 501 | win2.mode := win1.mode 502 | win2.LastKey := win1.LastKey 503 | win2.KeyTemp := win1.KeyTemp 504 | win2.MaxCount := win1.MaxCount 505 | win2.Count := win1.Count 506 | win2.TimeOut := win1.TimeOut 507 | win2.Info := win1.Info 508 | win2.BeforeActionDoFunc := win1.BeforeActionDoFunc 509 | win2.AfterActionDoFunc := win1.AfterActionDoFunc 510 | win2.ShowInfoFunc := win1.ShowInfoFunc 511 | win2.HideInfoFunc := win1.HideInfoFunc 512 | this.Control(Bold := true, winName2, all := true) 513 | return win2 514 | } 515 | 516 | ; CopyMode(win, mode, to) {{{2 517 | ; 在当前的Win中复制一个模式 518 | CopyMode(winName, fromMode, toMode) 519 | { 520 | winObj := This.GetWin(winName) 521 | winObj.mode := modeName 522 | winObj.KeyTemp := "" 523 | winObj.Count := 0 524 | from := winObj.modeList[fromMode] 525 | from.name := toMode 526 | winObj.modeList[toMode] := from 527 | return from 528 | } 529 | 530 | ; Delete(winName) {{{2 531 | Delete(winName = "") 532 | { 533 | this.Control(false, winName, all := true) 534 | this.WinList[winName] := "" 535 | } 536 | 537 | ; GetMore() {{{2 538 | GetMore(obj = false) 539 | { 540 | rt_obj := [] 541 | winObj := this.GetWin(this.LastFoundWin) 542 | modeObj := this.GetMode(this.LastFoundWin) 543 | if Strlen(winObj.KeyTemp) 544 | { 545 | r := winObj.KeyTemp "`n" 546 | rt_obj[1] := {"key":winObj.KeyTemp, "Action":modeObj.GetKeyMap(winObj.KeyTemp)} 547 | m := "i)^" this.ToMatch(winObj.KeyTemp) ".+" 548 | for i , k in modeObj.keymapList 549 | { 550 | if RegExMatch(i, m) 551 | { 552 | r .= i "`t" modeObj.GetKeyMap(i) "`n" 553 | rt_obj[rt_obj.MaxIndex()+1] := {"key":i, "Action":modeObj.GetKeyMap(i)} 554 | } 555 | } 556 | 557 | if obj 558 | return rt_obj 559 | else 560 | return r 561 | } 562 | else 563 | if winObj.count 564 | return winObj.count 565 | } 566 | 567 | ; Clear() {{{2 568 | Clear(winName = "") 569 | { 570 | winObj := This.GetWin(winName) 571 | winObj.KeyTemp := "" 572 | winObj.Count := 0 573 | } 574 | 575 | ; Key() {{{2 576 | Key() 577 | { 578 | ; 获取winName 579 | winName := this.CheckWin() 580 | ; 获取当前的热键 581 | k := this.CheckCapsLock(this.Convert2VIM(A_ThisHotkey)) 582 | ; 如果winName在排除窗口中,直接发送热键 583 | if this.ExcludeWinList[winName] 584 | { 585 | Send, % this.Convert2AHK(k, ToSend := true) 586 | return 587 | } 588 | ; 如果当前热键在当前winName无效,判断全局热键中是否有效? 589 | winObj := this.GetWin(winName) 590 | if Not winObj.KeyList[A_thisHotkey] 591 | { 592 | winObj := this.GetWin() 593 | if Not winObj.KeyList[A_thisHotkey] 594 | { 595 | ; 无效热键,按普通键输出 596 | Send, % this.Convert2AHK(k, ToSend := true) 597 | return 598 | } 599 | else 600 | winName := "" 601 | } 602 | 603 | this.LastFoundWin := winName 604 | ; 执行在判断热键前的函数, 如果函数返回true,按普通键输出 605 | if IsFunc(f := winObj.BeforeActionDoFunc) 606 | { 607 | if %f%() 608 | { 609 | Send, % this.Convert2AHK(k, ToSend := true) 610 | return 611 | } 612 | } 613 | 614 | ; 获取当前模式对应的对象 615 | modeObj := this.GetMode(winName) 616 | ; 把当前热键添加到热键缓存中, 并设置最后热键为k 617 | winObj.KeyTemp .= winObj.LastKey := k 618 | this.Debug.Add(" win: " winname "`tHotkey: " k) 619 | 620 | /* 621 | if winObj.Count 622 | this.Debug.Add(" [" winName "`t热键:" winObj.Count winObj.KeyTemp) 623 | else 624 | this.Debug.Add(" [" winName "]`t热键:" winObj.KeyTemp) 625 | */ 626 | 627 | ; 热键缓存是否有对应的Action? 628 | ; 判断是否有更多热键, 如果当前具有设置,则无视更多热键 629 | if modeObj.GetMoreKey(winObj.KeyTemp) And (Not modeObj.GetNoWait(winObj.KeyTemp)) 630 | { 631 | ; 启用TimeOut 632 | if strlen(modeObj.GetKeymap(winObj.KeyTemp)) 633 | if tick := winObj.TimeOut 634 | Settimer, Vim_TimeOut, %tick% 635 | 636 | winObj.ShowMore() 637 | ; 执行在判断热键后的函数, 如果函数返回true,按普通键输出 638 | if IsFunc(f := winObj.AfterActionDoFunc) 639 | { 640 | if %f%() 641 | Send, % this.Convert2AHK(k, ToSend := true) 642 | } 643 | 644 | return 645 | } 646 | 647 | ; 如果没有更多,热键缓存是否有对应的Action? 648 | if strlen(actionName := modeObj.GetKeymap(winObj.KeyTemp)) 649 | { 650 | actObj := this.GetAction(actionName) 651 | if (actObj.Type = 0) And RegExMatch(actionName , "^<(\d)>$", m) 652 | { 653 | ; 数字则进行累加 654 | winObj.Count := winObj.Count * 10 + m1 655 | if winObj.MaxCount And winObj.Count > winObj.MaxCount 656 | winObj.Count := winObj.MaxCount 657 | 658 | winObj.KeyTemp := "" 659 | winObj.ShowMore() 660 | if IsFunc(f := winObj.AfterActionDoFunc) 661 | %f%() 662 | return 663 | } 664 | else 665 | { 666 | ; 非数字则直接运行 667 | ;this.Debug.Add("act: " actionName "`tLK: " winObj.KeyTemp) 668 | __vimLastAction := {"LastKey":k, "winName":winName, "ActionName":ActionName, "KeyTemp":winObj.KeyTemp, "Count":winObj.Count} 669 | Settimer, Vim_TimeOut, Off 670 | actObj.Do(winObj.Count) 671 | winObj.Count := 0 672 | } 673 | } 674 | else 675 | { 676 | Settimer, Vim_TimeOut, Off 677 | ; 如果没有,按普通键输出 678 | if strlen(actionName := modeObj.GetKeymap(winObj.LastKey)) 679 | { 680 | actObj := this.GetAction(actionName) 681 | __vimLastAction := {"LastKey":k, "WinName":winName, "ActionName":ActionName, "KeyTemp":winObj.KeyTemp, "Count":winObj.Count} 682 | actObj.Do(winObj.Count) 683 | winObj.Count := 0 684 | } 685 | else 686 | { 687 | Send, % this.Convert2AHK(k, ToSend := true) 688 | winObj.Count := 0 689 | } 690 | } 691 | 692 | winObj.KeyTemp := "" 693 | winObj.HideMore() 694 | ; 执行在判断热键后的函数, 如果函数返回true,按普通键输出 695 | if IsFunc(f := winObj.AfterActionDoFunc) 696 | { 697 | if %f%() 698 | Send, % this.Convert2AHK(k, ToSend := true) 699 | ; %f%() ;直接运行 700 | } 701 | return 702 | } 703 | 704 | ; IsTimeOut() {{{2 705 | IsTimeOut() 706 | { 707 | winObj := this.GetWin(this.LastFoundWin) 708 | modeObj := this.GetMode(this.LastFoundWin) 709 | act := this.GetAction(modeObj.GetKeyMap(winObj.KeyTemp)) 710 | if act 711 | { 712 | winObj.HideMore() 713 | __vimLastAction := {"LastKey":k, "WinName":winName, "ActionName":ActionName, "KeyTemp":winObj.KeyTemp, "Count":winObj.Count} 714 | act.Do(winObj.Count) 715 | winObj.Count := 0 716 | winObj.KeyTemp := "" 717 | ; 执行在判断热键后的函数, 如果函数返回true,按普通键输出 718 | if IsFunc(f := winObj.AfterActionDoFunc) 719 | { 720 | if %f%() 721 | Send, % this.Convert2AHK(k, ToSend := true) 722 | } 723 | Settimer, Vim_TimeOut, Off 724 | } 725 | } 726 | 727 | ; Debug(Bold) {{{2 728 | Debug(Bold, history = false) 729 | { 730 | if Bold 731 | { 732 | this.Debug := new __vimDebug(history) 733 | this.Debug.var(this) 734 | } 735 | else 736 | { 737 | GUI, vimDebug:Destroy 738 | this.Debug := "" 739 | } 740 | } 741 | 742 | ; Convert2VIM(key) {{{2 743 | ; 将AHK热键名转换为类VIM的热键名 744 | ; 例 Convert2VIM("f1") 745 | Convert2VIM(key) 746 | { 747 | if RegExMatch(key, "^[A-Z]$") 748 | return "" 749 | if RegExMatch(key, "i)^(F[0-9]{1,2}|Numpad.*)$") 750 | return "<" key ">" 751 | if RegExMatch(key, "i)^(AppsKey|Tab|Enter|Space|Home|End|CapsLock|ScrollLock|Up|Down|Left|Right|PgUp|PgDn|Pause)$") 752 | return "<" key ">" 753 | if RegExMatch(key, "i)^(BS|BackSpace)$") 754 | return "" 755 | if RegExMatch(key, "i)^(Esc|Escape)$") 756 | return "" 757 | if RegExMatch(key, "i)^(Ins|Insert)$") 758 | return "" 759 | if RegExMatch(key, "i)^(Del|Delete)$") 760 | return "" 761 | if RegExMatch(key, "i)^PrintScreen$") 762 | return "" 763 | if RegExMatch(key, "i)^shift\s&\s(.*)", m) or RegExMatch(key, "^\+(.*)", m) 764 | return "" 765 | if RegExMatch(key, "i)^lshift\s&\s(.*)", m) or RegExMatch(key, "^<\+(.*)", m) 766 | return "" 767 | if RegExMatch(key, "i)^rshift\s&\s(.*)", m) or RegExMatch(key, "^>\+(.*)", m) 768 | return "" 769 | if RegExMatch(key, "i)^Ctrl\s&\s(.*)", m) or RegExMatch(key, "^\^(.*)", m) 770 | return "" 771 | if RegExMatch(key, "i)^lctrl\s&\s(.*)", m) or RegExMatch(key, "^<\^(.*)", m) 772 | return "" 773 | if RegExMatch(key, "i)^rctrl\s&\s(.*)", m) or RegExMatch(key, "^>\^(.*)", m) 774 | return "" 775 | if RegExMatch(key, "i)^alt\s&\s(.*)", m) or RegExMatch(key, "^\!(.*)", m) 776 | return "" 777 | if RegExMatch(key, "i)^lalt\s&\s(.*)", m) or RegExMatch(key, "^<\!(.*)", m) 778 | return "" 779 | if RegExMatch(key, "i)^ralt\s&\s(.*)", m) or RegExMatch(key, "^>\!(.*)", m) 780 | return "" 781 | if RegExMatch(key, "i)^lwin\s&\s(.*)", m) or RegExMatch(key, "^#(.*)", m) 782 | return "" 783 | if RegExMatch(key, "i)^space\s&\s(.*)", m) 784 | return "" 785 | if RegExMatch(key, "i)^alt$") 786 | return "" 787 | if RegExMatch(key, "i)^ctrl$") 788 | return "" 789 | if RegExMatch(key, "i)^shift$") 790 | return "" 791 | if RegExMatch(key, "i)^lwin$") 792 | return "" 793 | return key 794 | } 795 | 796 | Upper(k) 797 | { 798 | StringUpper, k, k 799 | return k 800 | } 801 | 802 | ; Convert2AHK(key, ToSend=false) {{{2 803 | ; 将类VIM的热键名转换为AHK热键名 804 | ; 例 Convert2AHK("") 805 | Convert2AHK(key, ToSend=false) 806 | { 807 | this.CheckCapsLock(key) 808 | if RegExMatch(key, "^<.*>$") 809 | { 810 | key := SubStr(key, 2, strlen(key)-2) 811 | if RegExMatch(key, "i)^(F[0-9]{1,2}|Numpad.*)$") 812 | return ToSend ? "{" key "}" : key 813 | if RegExMatch(key, "i)^(AppsKey|Tab|Enter|Space|Home|End|CapsLock|ScrollLock|Up|Down|Left|Right|PgUp|PgDn|BS|ESC|Insert|Delete|Pause)$") 814 | return ToSend ? "{" key "}" : key 815 | if RegExMatch(key, "i)^PrtSc$") 816 | return ToSend ? "{PrintScreen}" : "PrintScreen" 817 | if RegExMatch(key, "i)^alt$") 818 | return ToSend ? "{!}" : "alt" 819 | if RegExMatch(key, "i)^ctrl$") 820 | return ToSend ? "{^}" : "ctrl" 821 | if RegExMatch(key, "i)^shift$") 822 | return ToSend ? "{+}" : "shift" 823 | if RegExMatch(key, "i)^win$") 824 | return ToSend ? "{#}" : "lwin" 825 | if RegExMatch(key, "") 826 | return "<" 827 | if RegExMatch(key, "") 828 | return ">" 829 | if RegExMatch(key, "i)^S\-(.*)", m) 830 | return ToSend ? "+" this.CheckToSend(m1) : "+" m1 831 | if RegExMatch(key, "i)^LS\-(.*)", m) 832 | return ToSend ? "+" this.CheckToSend(m1) : "<+" m1 833 | if RegExMatch(key, "i)^RS-(.*)", m) 834 | return ToSend ? "+" this.CheckToSend(m1) : ">+" m1 835 | if RegExMatch(key, "i)^C\-(.*)", m) 836 | return ToSend ? "^" this.CheckToSend(m1) : "^" m1 837 | if RegExMatch(key, "i)^LC\-(.*)", m) 838 | return ToSend ? "^" this.CheckToSend(m1) : "<^" m1 839 | if RegExMatch(key, "i)^RC\-(.*)", m) 840 | return ToSend ? "^" this.CheckToSend(m1) : ">^" m1 841 | if RegExMatch(key, "i)^A\-(.*)", m) 842 | return ToSend ? "!" this.CheckToSend(m1) : "!" m1 843 | if RegExMatch(key, "i)^LA\-(.*)", m) 844 | ; 暂时先不区分左右键 845 | return ToSend ? "!" this.CheckToSend(m1): "!" m1 849 | if RegExMatch(key, "i)^w\-(.*)", m) 850 | return ToSend ? "#" this.CheckToSend(m1) : "#" m1 851 | if RegExMatch(key, "i)^SP\-(.*)", m) 852 | return ToSend ? "{space}" this.CheckToSend(m1) : "space & " m1 853 | } 854 | else 855 | return key 856 | } 857 | 858 | CheckToSend(key) 859 | { 860 | if RegExMatch(key, "i)^(F[0-9]{1,2}|Numpad.*)$") 861 | return "{" key "}" 862 | if RegExMatch(key, "i)^(AppsKey|Tab|Enter|Space|Home|End|CapsLock|ScrollLock|Up|Down|Left|Right|PgUp|PgDn|BS|ESC|Insert|Delete|Pause)$") 863 | return "{" key "}" 864 | if RegExMatch(key, "i)^PrtSc$") 865 | return "{PrintScreen}" 866 | if RegExMatch(key, "i)^alt$") 867 | return "{!}" 868 | if RegExMatch(key, "i)^ctrl$") 869 | return "{^}" 870 | if RegExMatch(key, "i)^shift$") 871 | return "{+}" 872 | if RegExMatch(key, "i)^win$") 873 | return "{#}" 874 | if RegExMatch(key, "") 875 | return "<" 876 | if RegExMatch(key, "") 877 | return ">" 878 | return Key 879 | } 880 | 881 | ; CheckCapsLock(key) {{{2 882 | ; 检测CapsLock是否按下,返回对应的值 883 | ; key 的值为类VIM键,如 CheckCapsLock("") 884 | CheckCapsLock(key) 885 | { 886 | if GetKeyState("CapsLock", "T") 887 | { 888 | if RegExMatch(key, "^[a-z]$") 889 | return "" 890 | if RegExMatch(key, "i)^", m) 891 | { 892 | StringLower, key, m1 893 | return key 894 | } 895 | } 896 | return key 897 | } 898 | 899 | ToMatch(v) 900 | { 901 | v := RegExReplace(v , "\+|\?|\.|\*|\{|\}|\(|\)|\||\^|\$|\[|\]|\\", "\$0") 902 | return RegExReplace(v , "\s", "\s") 903 | } 904 | } 905 | 906 | ; Class __win {{{1 907 | Class __win 908 | { 909 | __new(class = "", filepath = "", title = "") 910 | { 911 | this.class := class 912 | this.filepath := filepath 913 | this.title := title 914 | this.KeyList := [] 915 | this.SuperKeyList := [] 916 | this.modeList := [] 917 | this.Status := true 918 | this.mode := "" 919 | this.LastKey := "" 920 | this.KeyTemp := "" 921 | this.MaxCount := 99 922 | this.Count := 0 923 | this.TimeOut := 0 924 | this.Info := default_enable_show_info 925 | this.BeforeActionDoFunc := "" 926 | this.AfterActionDoFunc := "" 927 | this.ShowInfoFunc := "ShowInfo" 928 | this.HideInfoFunc := "HideInfo" 929 | } 930 | 931 | ; ChangeMode(modeName) {{{2 932 | ; 检查模式是否存在,如存在则返回模式对象,如果不存在则新建并返回模式对象 933 | ChangeMode(modeName) 934 | { 935 | this.mode := modeName 936 | this.KeyTemp := "" 937 | this.Count := 0 938 | if not this.modeList[modeName] 939 | this.modeList[modeName] := new __Mode(modeName) 940 | 941 | modeObj := this.modeList[modeName] 942 | if IsFunc(func := modeObj.modeFunction) 943 | %func%() 944 | return modeObj 945 | } 946 | 947 | ; ExistMode() {{{2 948 | ; 获取当前模式名 949 | ExistMode() 950 | { 951 | return this.mode 952 | } 953 | 954 | ; SetInfo() {{{2 955 | SetInfo(bold) 956 | { 957 | this.info := bold 958 | } 959 | 960 | ; SetShowInfo() {{{2 961 | SetShowInfo(func) 962 | { 963 | this.ShowInfoFunc := func 964 | } 965 | 966 | ; SetHideInfo() {{{2 967 | SetHideInfo(func) 968 | { 969 | this.HideInfoFunc := func 970 | } 971 | 972 | ; ShowMore() {{{2 973 | ShowMore() 974 | { 975 | if IsFunc(f := this.ShowInfoFunc) And this.Info 976 | %f%() 977 | } 978 | 979 | ; HideMore() {{{2 980 | HideMore() 981 | { 982 | if IsFunc(f:=this.HideInfoFunc) And this.Info 983 | %f%() 984 | } 985 | } 986 | 987 | ; Class __Mode {{{1 988 | Class __Mode 989 | { 990 | __new(modeName) 991 | { 992 | this.name := modeName 993 | this.keymapList := [] 994 | this.keymoreList := [] 995 | this.nowaitList := [] 996 | this.modeFunction := "" 997 | } 998 | 999 | ; SetKeyMap(key, action) {{{2 1000 | SetKeyMap(key, action) 1001 | { 1002 | this.keymapList[key] := action 1003 | } 1004 | 1005 | ; GetKeyMap(key) {{{2 1006 | GetKeyMap(key) 1007 | { 1008 | return this.keymapList[key] 1009 | } 1010 | 1011 | ; DelKeyMap(key) {{{2 1012 | DelKeyMap(key) 1013 | { 1014 | this.keymapList[key] := "" 1015 | } 1016 | 1017 | ; SetNoWait(key, bold) {{{2 1018 | ; 无视TimeOut执行热键 1019 | SetNoWait(key, bold) 1020 | { 1021 | this.nowaitList[key] := bold 1022 | } 1023 | 1024 | ; GetNoWait(key) {{{2 1025 | GetNoWait(key) 1026 | { 1027 | return this.nowaitList[key] 1028 | } 1029 | 1030 | ; SetMoreKey(key) {{{2 1031 | SetMoreKey(key) 1032 | { 1033 | this.keymoreList[key] := true 1034 | } 1035 | 1036 | ; GetMoreKey(key) {{{2 1037 | GetMoreKey(key) 1038 | { 1039 | return this.keymoreList[key] 1040 | } 1041 | } 1042 | 1043 | ; Class __Action {{{1 1044 | Class __Action 1045 | { 1046 | ; Action 有几种类型 1047 | ; 0 代表执行Action对应的Label (默认) 1048 | ; 1 代表执行Function的值对应的函数 1049 | ; 2 代表运行CmdLine对应的值 1050 | ; 3 代表发送HotString对应的文本 1051 | 1052 | __new(Name, Comment) 1053 | { 1054 | this.Name := Name 1055 | this.Comment := Comment 1056 | this.MaxTimes := 0 1057 | this.Type := 0 1058 | this.Function := "" 1059 | this.CmdLine := "" 1060 | this.HotString := "" 1061 | } 1062 | 1063 | ; SetFunction(Function) {{{2 1064 | ; 设置Action执行的函数名 1065 | SetFunction(Function) 1066 | { 1067 | this.Function := Function 1068 | this.Type := 1 1069 | } 1070 | 1071 | ; SetCmdLine(CmdLine) {{{2 1072 | ; 设置Action运行的字符串 1073 | SetCmdLine(CmdLine) 1074 | { 1075 | this.CmdLine := CmdLine 1076 | this.Type := 2 1077 | } 1078 | 1079 | ; SetHotString(HotString) {{{2 1080 | ; 设置Action发送的文本 1081 | SetHotString(HotString) 1082 | { 1083 | this.HotString := HotString 1084 | this.Type := 3 1085 | } 1086 | 1087 | ; SetMaxTimes(Times) {{{2 1088 | ; 设置最大运行次数 1089 | SetMaxTimes(Times) 1090 | { 1091 | this.MaxTimes := Times 1092 | } 1093 | 1094 | ; Do(Times=1) {{{2 1095 | ; 执行Action 1096 | Do(Times=0) 1097 | { 1098 | Times := !Times ? 1 : Times 1099 | if this.MaxTimes And (Times > this.MaxTimes) 1100 | Times := this.MaxTimes 1101 | Loop, %Times% 1102 | { 1103 | if this.Type = 0 1104 | { 1105 | if IsLabel(label := this.Name) 1106 | GoSub, %label% 1107 | } 1108 | else if this.Type = 1 1109 | { 1110 | if IsFunc(f := this.Function) 1111 | %f%() 1112 | } 1113 | else if this.Type = 2 1114 | { 1115 | c := this.CmdLine 1116 | Run, %cmd% 1117 | } 1118 | else if This.Type = 3 1119 | { 1120 | t := this.HotString 1121 | Send, %t% 1122 | } 1123 | } 1124 | } 1125 | } 1126 | 1127 | ; Class __Plugin {{{1 1128 | Class __Plugin 1129 | { 1130 | __new(PluginName) 1131 | { 1132 | this.PluginName := PluginName 1133 | this.Author := "" 1134 | this.Ver := "" 1135 | this.Comment := "" 1136 | } 1137 | 1138 | ; CheckSub() {{{2 1139 | CheckSub() 1140 | { 1141 | if IsLabel(p := this.PluginName) 1142 | { 1143 | GoSub, %p% 1144 | this.Error := false 1145 | } 1146 | else 1147 | this.Error := true 1148 | } 1149 | } 1150 | 1151 | ; Class __vimDebug {{{1 1152 | Class __vimDebug 1153 | { 1154 | __new(key) 1155 | { 1156 | this.mode := key 1157 | if key 1158 | { 1159 | GUI, vimDebug:Destroy 1160 | GUI, vimDebug:+hwnd_vimdebug -Caption +ToolWindow +Border 1161 | GUI, vimDebug:color, 454545, 454545 1162 | GUI, vimDebug:font, s16 cFFFFFF 1163 | GUI, vimDebug:Add, Edit, x-2 y-2 w400 h60 readonly 1164 | GUI, vimDebug:Show, w378 h56 y600 1165 | WinSet, AlwaysOnTop, On, ahk_id %_vimdebug% 1166 | } 1167 | else 1168 | { 1169 | GUI, vimDebug:font, s12 1170 | GUI, vimDebug:Destroy 1171 | GUI, vimDebug:Add, Edit, x10 y10 w400 h300 readonly 1172 | GUI, vimDebug:Add, Edit, x10 y320 w400 h26 readonly 1173 | GUI, vimDebug:Show, w420 h356 1174 | } 1175 | } 1176 | 1177 | var(obj) 1178 | { 1179 | this.vim := obj 1180 | } 1181 | 1182 | Set(v) 1183 | { 1184 | winName := this.vim.CheckWin() 1185 | winObj := this.vim.GetWin(winName) 1186 | if winObj.Count 1187 | k := " 热键缓存:" winObj.Count winObj.KeyTemp 1188 | else 1189 | k := " 热键缓存:" winObj.KeyTemp 1190 | GUI, vimDebug:Default 1191 | GUIControl, , Edit1, %v% 1192 | GUIControl, , Edit2, %k% 1193 | } 1194 | 1195 | Get() 1196 | { 1197 | GUI, vimDebug:Default 1198 | GUIControlGet, v, , Edit1 1199 | return v 1200 | } 1201 | 1202 | ; Add(v) {{{2 1203 | Add(v) 1204 | { 1205 | b := this.Get() 1206 | if this.mode 1207 | this.Set(b) 1208 | else 1209 | this.Set(v "`n" b) 1210 | } 1211 | 1212 | ; Clear() {{{2 1213 | Clear() 1214 | { 1215 | this.Set("") 1216 | } 1217 | } 1218 | -------------------------------------------------------------------------------- /Core/VimDConfig.ahk: -------------------------------------------------------------------------------- 1 | VimDConfig: 2 | vim.SetPlugin("VimDConfig", "Array", "0.1", "VimDesktop的配置界面") 3 | vim.SetAction("", "显示 VimDesktop 插件信息") 4 | vim.SetAction("", "显示 VimDesktop 热键信息") 5 | vim.SetAction("", "打开 VimDesktop 配置文件") 6 | return 7 | 8 | : 9 | GUI, VimDConfig_plugin:Destroy 10 | GUI, VimDConfig_plugin:Default 11 | GUI, VimDConfig_plugin:Font, s10, Microsoft YaHei 12 | 13 | GUI, VimDConfig_plugin:Add, GroupBox, x10 y460 w170 h70, 过滤 &F 14 | GUI, VimDConfig_plugin:Add, Edit, x20 y490 gsearch_plugin v_search 15 | 16 | GUI, VimDConfig_plugin:Add, GroupBox, x190 y10 w650 h520, 动作 &A 17 | GUI, VimDConfig_plugin:Add, ListView, glistview x200 y35 w630 h482 grid altsubmit, 序号|动作|描述(双击进入文件) 18 | 19 | LV_ModifyCol(1, "center") 20 | LV_ModifyCol(2, "left 250") 21 | LV_ModifyCol(3, "left 320") 22 | 23 | ; 先创建右边的 ListView,再创建左边的 ListView,否则 LV_Modify 时会出问题。 24 | GUI, VimDConfig_plugin:Add, GroupBox, x10 y10 w170 h440, 插件 &P 25 | GUI, VimDConfig_plugin:Add, ListView, x20 y35 w150 h400 grid altsubmit gVimDConfig_LoadActions, 名称 26 | 27 | for plugin, obj in vim.PluginList 28 | LV_Add("", plugin) 29 | 30 | LV_Modify(1, "Select") 31 | 32 | GUI, VimDConfig_plugin:Show 33 | return 34 | 35 | : 36 | menu, VimDConfig_keymap_menu, add 37 | menu, VimDConfig_keymap_menu, add, &Exit, VimDConfig_keymap_exit 38 | 39 | GUI, VimDConfig_keymap:Destroy 40 | GUI, VimDConfig_keymap:Default 41 | GUI, VimDConfig_keymap:Font, s10, Microsoft YaHei 42 | 43 | GUI, VimDConfig_keymap:Add, GroupBox, x10 y10 w200 h269, 插件 &P 44 | GUI, VimDConfig_keymap:Add, ListBox, x20 y35 w180 R12 center gVimDConfig_keymap_loadmodelist 45 | 46 | GUI, VimDConfig_keymap:Add, GroupBox, x10 y290 w200 h135, 模式 &M 47 | GUI, VimDConfig_keymap:Add, ListBox, x20 y315 w180 R5 center gVimDConfig_keymap_loadhotkey 48 | 49 | GUI, VimDConfig_keymap:Add, GroupBox, x10 y435 w200 h61, 过滤 &F 50 | GUI, VimDConfig_keymap:Add, Edit, gsearch_keymap v_search x20 y460 w180 h25 51 | 52 | GUI, VimDConfig_keymap:Add, GroupBox, x225 y10 w650 h486, 映射 &K 53 | GUI, VimDConfig_keymap:Add, Listview, glistview x235 y36 w630 h450 grid, 热键|动作(双击定位,右键双击编辑)|描述 54 | 55 | LV_ModifyCol(1, "left 100") 56 | LV_ModifyCol(2, "left 250") 57 | LV_ModifyCol(3, "left 259") 58 | 59 | VimDConfig_keymap_loadwinlist() 60 | VimDConfig_keymap_loadhotkey(VimDConfig_keymap_loadmodelist(thiswin)) 61 | 62 | GUI, VimDConfig_keymap:Show 63 | ControlFocus, Edit1, A 64 | return 65 | 66 | : 67 | EditFile(ConfigPath) 68 | return 69 | 70 | VimDConfig_LoadActions: 71 | If A_GuiEvent = I 72 | { 73 | if not InStr(ErrorLevel, "S", true) 74 | { 75 | return 76 | } 77 | 78 | GUI, VimDConfig_plugin:ListView, sysListview322 79 | LV_GetText(plugin, A_EventInfo) 80 | GUI, VimDConfig_plugin:Default 81 | GUI, VimDConfig_plugin:ListView, sysListview321 82 | idx := 1 83 | LV_Delete() 84 | 85 | global current_plugin := "" 86 | for action, type in vim.ActionFromPlugin 87 | { 88 | If type = %plugin% 89 | { 90 | Desc := vim.GetAction(action) 91 | LV_Add("", idx, action, Desc.Comment) 92 | current_plugin .= idx "`t" action "`t" Desc.Comment "`n" 93 | idx++ 94 | } 95 | } 96 | } 97 | 98 | ControlFocus, Edit1, A 99 | return 100 | 101 | VimDConfig_keymap_exit: 102 | { 103 | GUI, VimDConfig_keymap:Destroy 104 | return 105 | } 106 | 107 | VimDConfig_keymap_loadwinlist() 108 | { 109 | global vim 110 | list := "|全局" 111 | GUI, VimDConfig_keymap:Default 112 | for win, obj in vim.WinList 113 | { 114 | if vim.ExcludeWinList[win] 115 | { 116 | continue 117 | } 118 | 119 | ; Convert class name TTOTAL_CMD to plugin name TotalCommander 120 | if (win = "TTOTAL_CMD") 121 | { 122 | win := "TotalCommander" 123 | } 124 | list .= "|" win 125 | } 126 | GuiControl, , ListBox1, %list% 127 | } 128 | 129 | VimDConfig_keymap_loadmodelist: 130 | VimDConfig_keymap_loadmodelist() 131 | GUI, VimDConfig_keymap:Default 132 | LV_delete() 133 | GuiControl, Choose, ListBox2, |normal 134 | ControlFocus, Edit1, A 135 | return 136 | 137 | VimDConfig_keymap_loadmodelist(win = "") 138 | { 139 | global vim 140 | GUI, VimDConfig_keymap:Default 141 | If not strlen(win) 142 | ControlGet, win, Choice, , ListBox1 143 | If win = 全局 144 | winObj := vim.GetWin() 145 | Else 146 | winObj := vim.GetWin(win) 147 | for mode, obj in winObj.modeList 148 | mlist .= "|" mode 149 | GuiControl, , ListBox2, %mlist% 150 | return win 151 | } 152 | 153 | VimDConfig_keymap_loadhotkey: 154 | GUI, VimDConfig_keymap:Default 155 | ControlGet, win, Choice, , ListBox1 156 | win := RegExMatch(win, "^全局$") ? "" : win 157 | 158 | ; Convert plugin name TotalCommander to class name TTOTAL_CMD 159 | if (win = "TotalCommander") 160 | { 161 | win := "TTOTAL_CMD" 162 | } 163 | 164 | ControlGet, mode, Choice, , ListBox2 165 | VimDConfig_keymap_loadhotkey(win, mode) 166 | return 167 | 168 | VimDConfig_keymap_loadhotkey(win, mode = "") 169 | { 170 | global vim 171 | global current_keymap := "" 172 | If strlen(mode) 173 | { 174 | winObj := vim.GetWin(win) 175 | modeobj := winObj.modeList[mode] 176 | } 177 | Else 178 | modeobj := vim.GetMode(win) 179 | GUI, VimDConfig_keymap:Default 180 | LV_delete() 181 | for key, i in modeobj.keymapList 182 | { 183 | action_key := key 184 | if (win != "") 185 | { 186 | action_key := win "#" key 187 | } 188 | 189 | ; Type = 1 : Function 190 | if (vim.GetAction(i).Type = 1) 191 | { 192 | ActionDescList := vim.GetAction(i).Comment 193 | actionDesc := StrSplit(%ActionDescList%[action_key], "|") 194 | LV_ADD("", key, actionDesc[1], actionDesc[2]) 195 | current_keymap .= key "`t" actionDesc[1] "`t" actionDesc[2] "`n" 196 | } 197 | else 198 | { 199 | LV_Add("", RegExReplace(key, "", "$1"), i, vim.GetAction(i).Comment) 200 | current_keymap .= key "`t" i "`t" vim.GetAction(i).Comment "`n" 201 | } 202 | } 203 | } 204 | 205 | listview: 206 | if A_GuiEvent = DoubleClick 207 | { 208 | ;~ ToolTip You double-clicked row number %A_EventInfo%. 209 | LV_GetText(SelectedAction, A_EventInfo, 2) 210 | LV_GetText(SelectedDesc, A_EventInfo, 3) 211 | SearchFileForEdit(SelectedAction, SelectedDesc, false) 212 | } 213 | else if A_GuiEvent = R 214 | { 215 | LV_GetText(SelectedAction, A_EventInfo, 2) 216 | LV_GetText(SelectedDesc, A_EventInfo, 3) 217 | SearchFileForEdit(SelectedAction, SelectedDesc, true) 218 | } 219 | return 220 | 221 | SearchFileForEdit(Action, Desc, EditKeyMapping) 222 | { 223 | IsUserCmd := RegExMatch(Action, "^(run|key|dir|tccmd|dccmd|wshkey)$") 224 | if (IsUserCmd || EditKeyMapping) 225 | { 226 | SearchLine := "=" Action 227 | if (IsUserCmd || Action == "function") 228 | { 229 | SearchLine := Action "|" Desc 230 | } 231 | 232 | Loop, Read, %ConfigPath% 233 | { 234 | if (InStr(A_LoopReadLine, SearchLine)) 235 | { 236 | EditFile(ConfigPath, A_Index) 237 | return 238 | } 239 | } 240 | 241 | EditFile(ConfigPath) 242 | return 243 | } 244 | 245 | label := Action ":" 246 | if (Action == "function") 247 | { 248 | label := Desc 249 | } 250 | 251 | Loop, %A_ScriptDir%\plugins\*.ahk, , 1 252 | { 253 | Loop, Read, %A_LoopFileFullPath% 254 | { 255 | if (InStr(A_LoopReadLine, label) == 1) 256 | { 257 | EditFile(A_LoopFileFullPath, A_Index) 258 | return 259 | } 260 | } 261 | } 262 | 263 | Loop, %A_ScriptDir%\core\*.ahk, , 1 264 | { 265 | Loop, Read, %A_LoopFileFullPath% 266 | { 267 | if (InStr(A_LoopReadLine, label) = 1) 268 | { 269 | EditFile(A_LoopFileFullPath, A_Index) 270 | return 271 | } 272 | } 273 | } 274 | } 275 | 276 | EditFile(editPath, line := 1) 277 | { 278 | editorArgs := {} 279 | editorArgs["notepad"] := "/g $line $file" 280 | editorArgs["notepad2"] := "/g $line $file" 281 | editorArgs["sublime_text"] := "$file:$line" 282 | editorArgs["vim"] := "+$line $file" 283 | editorArgs["gvim"] := "--remote-silent-tab +$line $file" 284 | editorArgs["everedit"] := "-n$line $file" 285 | editorArgs["notepad++"] := "-n$line $file" 286 | editorArgs["EmEditor"] := "-l $line $file" 287 | editorArgs["uedit32"] := "$file/$line" 288 | editorArgs["Editplus"] := "$file -cursor $line" 289 | editorArgs["textpad"] := "$file($line)" 290 | editorArgs["pspad"] := "$file /$line" 291 | editorArgs["ConTEXT"] := "$file /g1:$line" 292 | editorArgs["scite"] := "$file -goto:$line" 293 | 294 | Global editor 295 | 296 | If not FileExist(editor) 297 | { 298 | MsgBox, 请配置 %ConfigPath% 中 [config] 中的 editor ,并重启 vimd ! 299 | return 300 | } 301 | 302 | ; 根据编辑器 exe 名称获取打开参数 303 | SplitPath, editor, , , OutExtension, OutNameNoExt 304 | args := editorArgs[OutNameNoExt] 305 | StringReplace, args, args, $line, %line% 306 | StringReplace, args, args, $file, "%editPath%" 307 | target := editor " " args 308 | 309 | run, %target% 310 | } 311 | 312 | search_keymap: 313 | global current_keymap 314 | search_to_display(current_keymap) 315 | return 316 | 317 | search_plugin: 318 | global current_plugin 319 | search_to_display(current_plugin) 320 | return 321 | 322 | search_to_display(lines) 323 | { 324 | Gui Submit, nohide 325 | GuiControlGet, OutputVar, , _search 326 | 327 | text := StrSplit(lines, "`n") 328 | 329 | LV_Delete() ; 清理不掉,第二次加载后,都成了重复的了,不知道怎么处理 330 | GuiControl, -Redraw, listview ; 重新启用重绘 (上面把它禁用了) 331 | for k, v in text 332 | { 333 | if v = 334 | continue 335 | if Instr(v, OutputVar) 336 | { 337 | list := StrSplit(v, "`t") 338 | LV_Add("", list[1], list[2], list[3]) 339 | } 340 | } 341 | GuiControl, +Redraw, listview ; 重新启用重绘 (上面把它禁用了) 342 | } 343 | -------------------------------------------------------------------------------- /Doc/Example.ahk: -------------------------------------------------------------------------------- 1 | ; 文件名: example.ahk 2 | ; 功能: 提供class_vim.ahk的应用说明,可以直接运行,独立于VimDesktop,以记事本为例子。 3 | ; 作者: Array(linxinhong) 4 | ; 时间: 2015年2月5日 5 | 6 | 7 | ; 初始化class_vim 8 | vim := class_vim() 9 | 10 | ; 运行Notepad作为示例 11 | run, notepad.exe "%A_ScriptFullPath%" 12 | WinWait, ahk_class Notepad 13 | 14 | msgbox 按h或者gg查看帮助 15 | 16 | ; 加载Action 17 | ; 加载名为的Action,备注为向下移动,默认为GoSub对与Action名一致的Label,即 18 | vim.SetAction("", "向下移动") 19 | vim.SetAction("", "向上移动") 20 | vim.SetAction("", "向左移动") 21 | vim.SetAction("", "向右移动") 22 | vim.SetAction("", "插入模式") 23 | vim.SetAction("", "普通模式") 24 | ; 可以设置Action热键执行的是函数、命令行或者发送文本、执行的最大次数 25 | act := vim.SetAction("帮助", "这是帮助内容") 26 | ; 设置Action为执行函数"msgbox_help" 27 | act.SetFunction("msgbox_help") 28 | /* 29 | ; 设置运行的次数为3次 30 | act.SetMaxTimes(3) 31 | 32 | ; 设置Action为运行命令行 cmd.exe 33 | act.setCmdLine("cmd.exe") 34 | 35 | ; 设置Action为发送文本" this is vimd" 36 | act.setHotString("this is vimd") 37 | 38 | Action执行的功能只能是Label/function/cmdline/hotstring.其中的一种,建议使用Lable或者function。方便修改 39 | */ 40 | 41 | class := "Notepad" 42 | filepath := "Notepad.exe" 43 | 44 | ; 在VimD中,filepath会作为 ahk_exe 的判断条件,class作为 ahk_class 的判断条件 45 | ; 但是filepath的优先级更高 46 | 47 | ; 设置Win 48 | vim.SetWin("记事本", class, filepath) 49 | 50 | ; 切换到Inert模式,后续map的所有热键都是在Insert模式下 51 | vim.SetMode("Insert", "记事本") 52 | 53 | ; 映射热键 54 | vim.map("", "", "记事本") 55 | 56 | ; 切换到Normal模式,后续map的所有热键都是在Noraml模式下 57 | vim.SetMode("Normal", "记事本") 58 | 59 | ; 映射热键 60 | ; <0>~<9>是内置的Label,可以看一下class_vim.ahk 61 | vim.map("0", "<0>", "记事本") 62 | vim.map("1", "<1>", "记事本") 63 | vim.map("2", "<2>", "记事本") 64 | vim.map("3", "<3>", "记事本") 65 | vim.map("4", "<4>", "记事本") 66 | vim.map("5", "<5>", "记事本") 67 | vim.map("6", "<6>", "记事本") 68 | vim.map("7", "<7>", "记事本") 69 | vim.map("8", "<8>", "记事本") 70 | vim.map("9", "<9>", "记事本") 71 | vim.map("j", "", "记事本") 72 | vim.map("k", "", "记事本") 73 | vim.map("h", "", "记事本") 74 | vim.map("l", "", "记事本") 75 | ; 组合键,按g,再按g 76 | vim.map("gg", "帮助", "记事本") 77 | vim.map("h", "帮助", "记事本") 78 | vim.map("i", "", "记事本") 79 | 80 | ; 注意,最后一次SetMode 为 "normal" 则当前为Noraml模式, 如果最后一次SetMode 为 "insert" ,则当前为 Insert 模式,以此类推 81 | 82 | vim.BeforeActionDo("Notepad_BeforeAction", "记事本") ; 设置在对应热键执行功能之前运行 Notepad_CheckMode 函数 83 | 84 | return 85 | 86 | ; 函数如果返回 True,则当前热键按正常状态输出,不运行对应的动作 87 | Notepad_BeforeAction() 88 | { 89 | global vim 90 | ; 获取当前输入模式,并返回相应的值,为输入状态,返回True;否则返回False。 91 | ; 判断原理:"I" 型光标,一般为输入状态,而为"->" 型箭头光标,一般为操作状态 92 | ; return vim.GetInputState() 93 | return false 94 | } 95 | 96 | 97 | ; 以下为热键对应的功能区 98 | ; 切换为Insert 模式 99 | : 100 | vim.SetMode("Insert","记事本") 101 | return 102 | ; 切换为Normal 模式 103 | : 104 | vim.SetMode("Normal","记事本") 105 | return 106 | 107 | : 108 | send,{down} 109 | return 110 | : 111 | send,{up} 112 | return 113 | : 114 | send,{left} 115 | return 116 | : 117 | send,{right} 118 | return 119 | 120 | msgbox_help() 121 | { 122 | v = 123 | ( 124 | 按0~9是设置执行次数 125 | 按j为向下 126 | 按k为向上 127 | 按h为向左 128 | 按l为向右 129 | 按i切换到Insert模式 130 | 按Esc切换到Normal模式 131 | 按h或者gg查看帮助 132 | ) 133 | msgbox % v 134 | } 135 | 136 | 137 | ; class_vim必须放在最后 138 | #include %A_ScriptDir%\..\core\class_vim.ahk 139 | -------------------------------------------------------------------------------- /Doc/Images/vimdesktop_128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goreliu/vimdesktop/eff9f52f41be39185c8d894b058785617a655c34/Doc/Images/vimdesktop_128.jpg -------------------------------------------------------------------------------- /Doc/Images/vimdesktop_32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goreliu/vimdesktop/eff9f52f41be39185c8d894b058785617a655c34/Doc/Images/vimdesktop_32.jpg -------------------------------------------------------------------------------- /Doc/Images/vimdesktop_64.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goreliu/vimdesktop/eff9f52f41be39185c8d894b058785617a655c34/Doc/Images/vimdesktop_64.jpg -------------------------------------------------------------------------------- /Doc/PluginTemplete.ahk: -------------------------------------------------------------------------------- 1 | ; 插件名和目录名一致,插件要放到 plugins/PluginName/PluginName.ahk 位置。 2 | ; 放入插件后,重新运行 vimd 会自动启用插件。 3 | ; 标签名请添加 PluginName_ 前缀,避免和其他插件冲突。 4 | 5 | ; 该标签名需要和插件名一致 6 | PluginName: 7 | ; 定义注释(可选) 8 | vim.SetAction("", "进入normal模式") 9 | vim.SetAction("", "进入insert模式") 10 | vim.SetAction("", "功能1") 11 | vim.SetAction("", "功能2") 12 | 13 | ; 请务必调用 vim.SetWin 并保证 PluginName 和文件名一致,以避免名称混乱影响使用 14 | vim.SetWin("PluginName", "ahk_class名") 15 | ; 或: 16 | vim.SetWin("PluginName", "ahk_class名", "PluginName.exe") 17 | ; 如果 class 和 exe 同时填写,以 exe 为准 18 | 19 | ; insert模式(如果无需 insert 模式,可去掉) 20 | vim.SetMode("insert", "PluginName") 21 | 22 | vim.Map("", "", "PluginName") 23 | 24 | ; normal模式(必需) 25 | vim.SetMode("normal", "PluginName") 26 | 27 | vim.Map("i", "", "PluginName") 28 | 29 | vim.Map("a", "", "PluginName") 30 | vim.Map("b", "", "PluginName") 31 | 32 | ; 可选 33 | vim.BeforeActionDo("PluginName_BeforeActionDo", "PluginName") 34 | return 35 | 36 | ; 对符合条件的控件使用insert模式,而不是normal模式 37 | ; 此段代码可以直接复制,但请修改AHK_CLASS的值和RegExMatch的第二个参数 38 | PluginName_BeforeActionDo() 39 | { 40 | ControlGetFocus, ctrl, AHK_CLASS PluginName 41 | ; MsgBox % ctrl 42 | if RegExMatch(ctrl, "Edit2") 43 | return true 44 | return false 45 | } 46 | 47 | : 48 | vim.SetMode("normal", "PluginName") 49 | return 50 | 51 | : 52 | vim.SetMode("insert", "PluginName") 53 | return 54 | 55 | : 56 | Send, ^n 57 | return 58 | 59 | : 60 | Send, ^p 61 | return 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 victorwoo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Lib/Acc.ahk: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; Acc.ahk Standard Library 3 | ; by Sean 4 | ; Updated by jethrow: 5 | ; Modified ComObjEnwrap params from (9,pacc) --> (9,pacc,1) 6 | ; Changed ComObjUnwrap to ComObjValue in order to avoid AddRef (thanks fincs) 7 | ; Added Acc_GetRoleText & Acc_GetStateText 8 | ; Added additional functions - commented below 9 | ; Removed original Acc_Children function 10 | ; Added Acc_Error, Acc_ChildrenByRole, & Acc_Get functions 11 | ; last updated 10/25/2012 12 | ;------------------------------------------------------------------------------ 13 | 14 | Acc_Init() 15 | { 16 | Static h 17 | If Not h 18 | h:=DllCall("LoadLibrary","Str","oleacc","Ptr") 19 | } 20 | Acc_ObjectFromEvent(ByRef _idChild_, hWnd, idObject, idChild) 21 | { 22 | Acc_Init() 23 | If DllCall("oleacc\AccessibleObjectFromEvent", "Ptr", hWnd, "UInt", idObject, "UInt", idChild, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0 24 | Return ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt") 25 | } 26 | 27 | Acc_ObjectFromPoint(ByRef _idChild_ = "", x = "", y = "") 28 | { 29 | Acc_Init() 30 | If DllCall("oleacc\AccessibleObjectFromPoint", "Int64", x==""||y==""?0*DllCall("GetCursorPos","Int64*",pt)+pt:x&0xFFFFFFFF|y<<32, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0 31 | Return ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt") 32 | } 33 | 34 | Acc_ObjectFromWindow(hWnd, idObject = 0) 35 | { 36 | Acc_Init() 37 | If DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0 38 | Return ComObjEnwrap(9,pacc,1) 39 | } 40 | 41 | Acc_WindowFromObject(pacc) 42 | { 43 | If DllCall("oleacc\WindowFromAccessibleObject", "Ptr", IsObject(pacc)?ComObjValue(pacc):pacc, "Ptr*", hWnd)=0 44 | Return hWnd 45 | } 46 | 47 | Acc_GetRoleText(nRole) 48 | { 49 | nSize := DllCall("oleacc\GetRoleText", "Uint", nRole, "Ptr", 0, "Uint", 0) 50 | VarSetCapacity(sRole, (A_IsUnicode?2:1)*nSize) 51 | DllCall("oleacc\GetRoleText", "Uint", nRole, "str", sRole, "Uint", nSize+1) 52 | Return sRole 53 | } 54 | 55 | Acc_GetStateText(nState) 56 | { 57 | nSize := DllCall("oleacc\GetStateText", "Uint", nState, "Ptr", 0, "Uint", 0) 58 | VarSetCapacity(sState, (A_IsUnicode?2:1)*nSize) 59 | DllCall("oleacc\GetStateText", "Uint", nState, "str", sState, "Uint", nSize+1) 60 | Return sState 61 | } 62 | 63 | Acc_SetWinEventHook(eventMin, eventMax, pCallback) 64 | { 65 | Return DllCall("SetWinEventHook", "Uint", eventMin, "Uint", eventMax, "Uint", 0, "Ptr", pCallback, "Uint", 0, "Uint", 0, "Uint", 0) 66 | } 67 | 68 | Acc_UnhookWinEvent(hHook) 69 | { 70 | Return DllCall("UnhookWinEvent", "Ptr", hHook) 71 | } 72 | /* Win Events: 73 | 74 | pCallback := RegisterCallback("WinEventProc") 75 | WinEventProc(hHook, event, hWnd, idObject, idChild, eventThread, eventTime) 76 | { 77 | Critical 78 | Acc := Acc_ObjectFromEvent(_idChild_, hWnd, idObject, idChild) 79 | ; Code Here: 80 | 81 | } 82 | */ 83 | 84 | ; Written by jethrow 85 | Acc_Role(Acc, ChildId=0) { 86 | try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetRoleText(Acc.accRole(ChildId)):"invalid object" 87 | } 88 | Acc_State(Acc, ChildId=0) { 89 | try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetStateText(Acc.accState(ChildId)):"invalid object" 90 | } 91 | Acc_Location(Acc, ChildId=0, byref Position="") { ; adapted from Sean's code 92 | try Acc.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId) 93 | catch 94 | return 95 | Position := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int") 96 | return {x:NumGet(x,0,"int"), y:NumGet(y,0,"int"), w:NumGet(w,0,"int"), h:NumGet(h,0,"int")} 97 | } 98 | Acc_Parent(Acc) { 99 | try parent:=Acc.accParent 100 | return parent?Acc_Query(parent): 101 | } 102 | Acc_Child(Acc, ChildId=0) { 103 | try child:=Acc.accChild(ChildId) 104 | return child?Acc_Query(child): 105 | } 106 | Acc_Query(Acc) { ; thanks Lexikos - www.autohotkey.com/forum/viewtopic.php?t=81731&p=509530#509530 107 | try return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1) 108 | } 109 | Acc_Error(p="") { 110 | static setting:=0 111 | return p=""?setting:setting:=p 112 | } 113 | Acc_Children(Acc) { 114 | if ComObjType(Acc,"Name") != "IAccessible" 115 | ErrorLevel := "Invalid IAccessible Object" 116 | else { 117 | Acc_Init(), cChildren:=Acc.accChildCount, Children:=[] 118 | if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 { 119 | Loop %cChildren% 120 | i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i), Children.Insert(NumGet(varChildren,i-8)=9?Acc_Query(child):child), NumGet(varChildren,i-8)=9?ObjRelease(child): 121 | return Children.MaxIndex()?Children: 122 | } else 123 | ErrorLevel := "AccessibleChildren DllCall Failed" 124 | } 125 | if Acc_Error() 126 | throw Exception(ErrorLevel,-1) 127 | } 128 | Acc_ChildrenByRole(Acc, Role) { 129 | if ComObjType(Acc,"Name")!="IAccessible" 130 | ErrorLevel := "Invalid IAccessible Object" 131 | else { 132 | Acc_Init(), cChildren:=Acc.accChildCount, Children:=[] 133 | if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 { 134 | Loop %cChildren% { 135 | i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i) 136 | if NumGet(varChildren,i-8)=9 137 | AccChild:=Acc_Query(child), ObjRelease(child), Acc_Role(AccChild)=Role?Children.Insert(AccChild): 138 | else 139 | Acc_Role(Acc, child)=Role?Children.Insert(child): 140 | } 141 | return Children.MaxIndex()?Children:, ErrorLevel:=0 142 | } else 143 | ErrorLevel := "AccessibleChildren DllCall Failed" 144 | } 145 | if Acc_Error() 146 | throw Exception(ErrorLevel,-1) 147 | } 148 | Acc_Get(Cmd, ChildPath="", ChildID=0, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="") { 149 | static properties := {Action:"DefaultAction", DoAction:"DoDefaultAction", Keyboard:"KeyboardShortcut"} 150 | AccObj := IsObject(WinTitle)? WinTitle 151 | : Acc_ObjectFromWindow( WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText), 0 ) 152 | if ComObjType(AccObj, "Name") != "IAccessible" 153 | ErrorLevel := "Could not access an IAccessible Object" 154 | else { 155 | StringReplace, ChildPath, ChildPath, _, %A_Space%, All 156 | AccError:=Acc_Error(), Acc_Error(true) 157 | Loop Parse, ChildPath, ., %A_Space% 158 | try { 159 | if A_LoopField is digit 160 | Children:=Acc_Children(AccObj), m2:=A_LoopField ; mimic "m2" output in else-statement 161 | else 162 | RegExMatch(A_LoopField, "(\D*)(\d*)", m), Children:=Acc_ChildrenByRole(AccObj, m1), m2:=(m2?m2:1) 163 | if Not Children.HasKey(m2) 164 | throw 165 | AccObj := Children[m2] 166 | } catch { 167 | ErrorLevel:="Cannot access ChildPath Item #" A_Index " -> " A_LoopField, Acc_Error(AccError) 168 | if Acc_Error() 169 | throw Exception("Cannot access ChildPath Item", -1, "Item #" A_Index " -> " A_LoopField) 170 | return 171 | } 172 | Acc_Error(AccError) 173 | StringReplace, Cmd, Cmd, %A_Space%, , All 174 | properties.HasKey(Cmd)? Cmd:=properties[Cmd]: 175 | try { 176 | if (Cmd = "Location") 177 | AccObj.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId) 178 | , ret_val := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int") 179 | else if (Cmd = "Object") 180 | ret_val := AccObj 181 | else if Cmd in Role,State 182 | ret_val := Acc_%Cmd%(AccObj, ChildID+0) 183 | else if Cmd in ChildCount,Selection,Focus 184 | ret_val := AccObj["acc" Cmd] 185 | else 186 | ret_val := AccObj["acc" Cmd](ChildID+0) 187 | } catch { 188 | ErrorLevel := """" Cmd """ Cmd Not Implemented" 189 | if Acc_Error() 190 | throw Exception("Cmd Not Implemented", -1, Cmd) 191 | return 192 | } 193 | return ret_val, ErrorLevel:=0 194 | } 195 | if Acc_Error() 196 | throw Exception(ErrorLevel,-1) 197 | } -------------------------------------------------------------------------------- /Lib/EasyIni.ahk: -------------------------------------------------------------------------------- 1 | ; http://ahkscript.org/boards/viewtopic.php?f=6&t=5522&hilit=lib+ini 2 | ; Author : Verdlin 3 | class_EasyIni(sFile="", sLoadFromStr="") 4 | { 5 | return new EasyIni(sFile, sLoadFromStr) 6 | } 7 | 8 | class EasyIni 9 | { 10 | __New(sFile="", sLoadFromStr="") ; Loads ths file into memory. 11 | { 12 | this := this.CreateIniObj("EasyIni_ReservedFor_m_sFile", sFile 13 | , "EasyIni_ReservedFor_TopComments", Object()) ; Top comments can be stored in linear array because order will simply be numeric 14 | 15 | if (sFile == A_Blank && sLoadFromStr == A_Blank) 16 | return this 17 | 18 | ; Append ".ini" if it is not already there. 19 | if (SubStr(sFile, StrLen(sFile)-3, 4) != ".ini") 20 | this.EasyIni_ReservedFor_m_sFile := sFile := (sFile . ".ini") 21 | 22 | sIni := sLoadFromStr 23 | if (sIni == A_Blank) 24 | FileRead, sIni, %sFile% 25 | 26 | /* 27 | Current design (not fully implemented): 28 | --------------------------------------------------------------------------------------------------------------------------------------------------- 29 | Comments at the top of the section apply to the file as a whole. They are keyed off an internal section called "EasyIni_ReservedFor_TopComments." 30 | Comments above section headers apply to the the last key of the previous section. 31 | If a comment appears between two keys, then it will apply to the key above it -- this is consistent with the solution for comments above section headers. 32 | Newlines will be stored in similar fashion to comments. 33 | --------------------------------------------------------------------------------------------------------------------------------------------------- 34 | 35 | --------------------------------------------------------------------------------------------------------------------------------------------------- 36 | If full-support for comments needs to be added, then the design below should supersede the design above. 37 | By saying, "Full-support" I mean a way to directly access these comments based upon sections and keys. 38 | --------------------------------------------------------------------------------------------------------------------------------------------------- 39 | 40 | --------------------------------------------------------------------------------------------------------------------------------------------------- 41 | Comments at the top of the section apply to the file as a whole. They are keyed off an internal section called "EasyIni_ReservedFor_TopComments." 42 | Comments above section headers apply to the section header. If people dislike this, I may instead chose to make the comments apply to the last key of the previous section if there a newline in-between the comment in question and the next section. I may come up with some decent solution as I experiment 43 | If a comment appears between two keys, then it will apply to the key below it -- this is consistent with the solution for comments above section headers. 44 | Newlines will be stored in similar fashion to comments. 45 | --------------------------------------------------------------------------------------------------------------------------------------------------- 46 | */ 47 | 48 | Loop, Parse, sIni, `n, `r 49 | { 50 | sTrimmedLine := Trim(A_LoopField) 51 | 52 | ; Comments or newlines within the ini 53 | if (SubStr(sTrimmedLine, 1, 1) == ";" || sTrimmedLine == A_Blank) ; A_Blank would be a newline 54 | { 55 | ; Chr(14) is just the magical char to indicate that this line should only be a newline "`n" 56 | LoopField := A_LoopField == A_Blank ? Chr(14) : A_LoopField 57 | 58 | if (sCurSec == A_Blank) 59 | this.EasyIni_ReservedFor_TopComments.Insert(A_Index, LoopField) ; not using sTrimmedLine so as to keep comment formatting 60 | else 61 | { 62 | if (sPrevKeyForThisSec == A_Blank) ; This happens when there is a comment in the section before the first key, if any 63 | sPrevKeyForThisSec := "SectionComment" 64 | 65 | if (IsObject(this[sCurSec].EasyIni_ReservedFor_Comments)) 66 | { 67 | if (this[sCurSec].EasyIni_ReservedFor_Comments.HasKey(sPrevKeyForThisSec)) 68 | this[sCurSec].EasyIni_ReservedFor_Comments[sPrevKeyForThisSec] .= "`n" LoopField 69 | else this[sCurSec].EasyIni_ReservedFor_Comments.Insert(sPrevKeyForThisSec, LoopField) 70 | } 71 | else 72 | { 73 | if (IsObject(this[sCurSec])) 74 | this[sCurSec].EasyIni_ReservedFor_Comments := {(sPrevKeyForThisSec):LoopField} 75 | else this[sCurSec, "EasyIni_ReservedFor_Comments"] := {(sPrevKeyForThisSec):LoopField} 76 | } 77 | } 78 | continue 79 | } 80 | 81 | ; [Section] 82 | if (SubStr(sTrimmedLine, 1, 1) = "[" && InStr(sTrimmedLine, "]")) ; need to be sure that this isn't just a key starting with "[" 83 | { 84 | if (sCurSec != A_Blank && !this.HasKey(sCurSec)) 85 | this[sCurSec] := EasyIni_CreateBaseObj() 86 | sCurSec := SubStr(sTrimmedLine, 2, InStr(sTrimmedLine, "]", false, 0) - 2) ; 0 search right to left. We want to trim the *last* occurence of "]" 87 | sPrevKeyForThisSec := "" 88 | continue 89 | } 90 | 91 | ; key=val 92 | iPosOfEquals := InStr(sTrimmedLine, "=") 93 | if (iPosOfEquals) 94 | { 95 | sPrevKeyForThisSec := SubStr(sTrimmedLine, 1, iPosOfEquals - 1) ; so it's not the previous key yet...but it will be on next iteration :P 96 | val := SubStr(sTrimmedLine, iPosOfEquals + 1) 97 | StringReplace, val, val , `%A_ScriptDir`%, %A_ScriptDir%, All 98 | StringReplace, val, val , `%A_WorkingDir`%, %A_ScriptDir%, All 99 | this[sCurSec, sPrevKeyForThisSec] := val 100 | } 101 | else ; at this point, we know it isn't a comment, or newline, it isn't a section, and it isn't a conventional key-val pair. Treat this line as a key with no val 102 | { 103 | sPrevKeyForThisSec := sTrimmedLine 104 | this[sCurSec, sPrevKeyForThisSec] := "" 105 | } 106 | } 107 | ; if there is a section with no keys and it is at the bottom of the file, then we missed it 108 | if (sCurSec != A_Blank && !this.HasKey(sCurSec)) 109 | this[sCurSec] := EasyIni_CreateBaseObj() 110 | 111 | return this 112 | } 113 | 114 | CreateIniObj(parms*) 115 | { 116 | ; Define prototype object for ini arrays: 117 | static base := {__Set: "EasyIni_Set", _NewEnum: "EasyIni_NewEnum", Remove: "EasyIni_Remove", Insert: "EasyIni_Insert", InsertBefore: "EasyIni_InsertBefore", AddSection: "EasyIni.AddSection", RenameSection: "EasyIni.RenameSection", DeleteSection: "EasyIni.DeleteSection", GetSections: "EasyIni.GetSections", FindSecs: "EasyIni.FindSecs", AddKey: "EasyIni.AddKey", RenameKey: "EasyIni.RenameKey", DeleteKey: "EasyIni.DeleteKey", GetKeys: "EasyIni.GetKeys", FindKeys: "EasyIni.FindKeys", GetVals: "EasyIni.GetVals", FindVals: "EasyIni.FindVals", HasVal: "EasyIni.HasVal", Copy: "EasyIni.Copy", Merge: "EasyIni.Merge", GetFileName: "EasyIni.GetFileName", GetOnlyIniFileName:"EasyIni.GetOnlyIniFileName", IsEmpty:"EasyIni.IsEmpty", Reload: "EasyIni.Reload", GetIsSaved: "EasyIni.GetIsSaved", Save: "EasyIni.Save", ToVar: "EasyIni.ToVar", GetValue: "EasyIni.GetValue"} 118 | ; Create and return new object: 119 | return Object("_keys", Object(), "base", base, parms*) 120 | } 121 | 122 | AddSection(sec, key="", val="", ByRef rsError="") 123 | { 124 | if (this.HasKey(sec)) 125 | { 126 | rsError := "Error! Cannot add new section [" sec "], because it already exists." 127 | return false 128 | } 129 | 130 | if (key == A_Blank) 131 | this[sec] := EasyIni_CreateBaseObj() 132 | else this[sec, key] := val 133 | 134 | return true 135 | } 136 | 137 | RenameSection(sOldSec, sNewSec, ByRef rsError="") 138 | { 139 | if (!this.HasKey(sOldSec)) 140 | { 141 | rsError := "Error! Could not rename section [" sOldSec "], because it does not exist." 142 | return false 143 | } 144 | 145 | aKeyValsCopy := this[sOldSec] 146 | this.DeleteSection(sOldSec) 147 | this[sNewSec] := aKeyValsCopy 148 | return true 149 | } 150 | 151 | DeleteSection(sec) 152 | { 153 | this.Remove(sec) 154 | return 155 | } 156 | 157 | GetSections(sDelim="`n", sSort="") 158 | { 159 | for sec in this 160 | secs .= (A_Index == 1 ? sec : sDelim sec) 161 | 162 | if (sSort) 163 | Sort, secs, D%sDelim% %sSort% 164 | 165 | return secs 166 | } 167 | 168 | FindSecs(sExp, iMaxSecs="") 169 | { 170 | aSecs := [] 171 | for sec in this 172 | { 173 | if (RegExMatch(sec, sExp)) 174 | { 175 | aSecs.Insert(sec) 176 | if (iMaxSecs&& aSecs.MaxIndex() == iMaxSecs) 177 | return aSecs 178 | } 179 | } 180 | return aSecs 181 | } 182 | 183 | AddKey(sec, key, val="", ByRef rsError="") 184 | { 185 | if (this.HasKey(sec)) 186 | { 187 | if (this[sec].HasKey(key)) 188 | { 189 | rsError := "Error! Could not add key, " key " because there is a key in the same section:`nSection: " sec "`nKey: " key 190 | return false 191 | } 192 | } 193 | else 194 | { 195 | rsError := "Error! Could not add key, " key " because Section, " sec " does not exist." 196 | return false 197 | } 198 | this[sec, key] := val 199 | return true 200 | } 201 | 202 | RenameKey(sec, OldKey, NewKey, ByRef rsError="") 203 | { 204 | if (!this[sec].HasKey(OldKey)) 205 | { 206 | rsError := "Error! The specified key " OldKey " could not be modified because it does not exist." 207 | return false 208 | } 209 | 210 | ValCopy := this[sec][OldKey] 211 | this.DeleteKey(sec, OldKey) 212 | this.AddKey(sec, NewKey) 213 | this[sec][NewKey] := ValCopy 214 | return true 215 | } 216 | 217 | DeleteKey(sec, key) 218 | { 219 | this[sec].Remove(key) 220 | return 221 | } 222 | 223 | GetKeys(sec, sDelim="`n", sSort="") 224 | { 225 | for key in this[sec] 226 | keys .= A_Index == 1 ? key : sDelim key 227 | 228 | if (sSort) 229 | Sort, keys, D%sDelim% %sSort% 230 | 231 | return keys 232 | } 233 | 234 | FindKeys(sec, sExp, iMaxKeys="") 235 | { 236 | aKeys := [] 237 | for key in this[sec] 238 | { 239 | if (RegExMatch(key, sExp)) 240 | { 241 | aKeys.Insert(key) 242 | if (iMaxKeys && aKeys.MaxIndex() == iMaxKeys) 243 | return aKeys 244 | } 245 | } 246 | return aKeys 247 | } 248 | 249 | ; Non-regex, exact match on key 250 | ; returns key(s) and their assocationed section(s) 251 | FindExactKeys(key, iMaxKeys="") 252 | { 253 | aKeys := {} 254 | for sec, aData in this 255 | { 256 | if (aData.HasKey(key)) 257 | { 258 | aKeys.Insert(sec, key) 259 | if (iMaxKeys && aKeys.MaxIndex() == iMaxKeys) 260 | return aKeys 261 | } 262 | } 263 | return aKeys 264 | } 265 | 266 | GetVals(sec, sDelim="`n", sSort="") 267 | { 268 | for key, val in this[sec] 269 | vals .= A_Index == 1 ? val : sDelim val 270 | 271 | if (sSort) 272 | Sort, vals, D%sDelim% %sSort% 273 | 274 | return vals 275 | } 276 | 277 | GetValue(sec, key) 278 | { 279 | return this[sec, key] 280 | } 281 | 282 | FindVals(sec, sExp, iMaxVals="") 283 | { 284 | aVals := [] 285 | for key, val in this[sec] 286 | { 287 | if (RegExMatch(val, sExp)) 288 | { 289 | aVals.Insert(val) 290 | if (iMaxVals && aVals.MaxIndex() == iMaxVals) 291 | break 292 | } 293 | } 294 | return aVals 295 | } 296 | 297 | HasVal(sec, FindVal) 298 | { 299 | for k, val in this[sec] 300 | if (FindVal = val) 301 | return true 302 | return false 303 | } 304 | 305 | ; SourceIni: May be EasyIni object or simply a path to an ini file. 306 | ; bCopyFileName = true: Allow copying of data without copying the file name. 307 | Copy(SourceIni, bCopyFileName = true) 308 | { 309 | ; Get ini as string. 310 | if (IsObject(SourceIni)) 311 | sIniString := SourceIni.ToVar() 312 | else FileRead, sIniString, %SourceIni% 313 | 314 | ; Effectively make this function static by allowing calls via EasyIni.Copy. 315 | if (IsObject(this)) 316 | { 317 | if (bCopyFileName) 318 | sOldFileName := this.GetFileName() 319 | this := A_Blank ; avoid any copy constructor issues. 320 | 321 | ; ObjClone doesn't work consistently. It's likely a problem with the meta-function overrides, 322 | ; but this is a nice, quick hack. 323 | this := class_EasyIni(SourceIni.GetFileName(), sIniString) 324 | 325 | ; Restore file name. 326 | this.EasyIni_ReservedFor_m_sFile := sOldFileName 327 | } 328 | else 329 | return class_EasyIni(bCopyFileName ? SourceIni.GetFileName() : "", sIniString) 330 | 331 | return this 332 | } 333 | 334 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 335 | /* 336 | Author: Verdlin 337 | STILL UNDER CONSTRUCTION. Need to handle comments, and then this will be complete. 338 | Function: Merge 339 | Purpose: Merge two EasyIni objects. 340 | Parameters 341 | vOtherIni: Other EasyIni object to merge with this. 342 | bRemoveNonMatching: If true, removes sections and keys that do not exist in both inis. 343 | bOverwriteMatching: If true, any key that exists in both objects will use the val from vOtherIni. 344 | vExceptionsIni: class_Easy ini object full of exceptions keys for secs. Any matching key will remain unchanged. 345 | */ 346 | Merge(vOtherIni, bRemoveNonMatching = false, bOverwriteMatching = false, vExceptionsIni = "") 347 | { 348 | ; TODO: Perhaps just save one ini, read it back in, and then perform merging? I think this would help with formatting. 349 | ; [Sections] 350 | for sec, aKeysAndVals in vOtherIni 351 | { 352 | if (!this.HasKey(sec)) 353 | if (bRemoveNonMatching) 354 | this.DeleteSection(sec) 355 | else this.AddSection(sec) 356 | 357 | ; key=val 358 | for key, val in aKeysAndVals 359 | { 360 | bMakeException := vExceptionsIni[sec].HasKey(key) 361 | 362 | if (this[sec].HasKey(key)) 363 | { 364 | if (bOverwriteMatching && !bMakeException) 365 | this[sec, key] := val 366 | } 367 | else 368 | { 369 | if (bRemoveNonMatching && !bMakeException) 370 | this.DeleteKey(sec, key) 371 | else if (!bRemoveNonMatching) 372 | this.AddKey(sec, key, val) 373 | } 374 | } 375 | } 376 | return 377 | } 378 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 379 | 380 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 381 | /* 382 | Author: Verdlin 383 | Function: GetFileName 384 | Purpose: Wrapper to return the extremely long named member var, EasyIni_ReservedFor_m_sFile 385 | Parameters 386 | None 387 | */ 388 | GetFileName() 389 | { 390 | return this.EasyIni_ReservedFor_m_sFile 391 | } 392 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 393 | 394 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 395 | /* 396 | Author: Verdlin 397 | Function: GetFileName 398 | Purpose: Wrapper to return just the .ini name without the path. 399 | Parameters 400 | None 401 | */ 402 | GetOnlyIniFileName() 403 | { 404 | return SubStr(this.EasyIni_ReservedFor_m_sFile, InStr(this.EasyIni_ReservedFor_m_sFile,"\", false, -1)+1) 405 | } 406 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 407 | 408 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 409 | /* 410 | Author: Verdlin 411 | Function: IsEmpty 412 | Purpose: To indicate whether or not this ini has data 413 | Parameters 414 | None 415 | */ 416 | IsEmpty() 417 | { 418 | return (this.GetSections() == A_Blank ; No sections. 419 | && !this.EasyIni_ReservedFor_TopComments.HasKey(1)) ; and no comments. 420 | } 421 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 422 | 423 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 424 | /* 425 | Author: Verdlin 426 | Function: Reload 427 | Purpose: Reloads object from ini file. This is necessary when other routines may be modifying the same ini file. 428 | Parameters 429 | None 430 | */ 431 | Reload() 432 | { 433 | if (FileExist(this.GetFileName())) 434 | this := class_EasyIni(this.GetFileName()) ; else nothing to reload. 435 | return this 436 | } 437 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 438 | 439 | ; TODO: Add option to store load and save times in comment at bottom of ini? 440 | Save(sSaveAs="", bWarnIfExist=false) 441 | { 442 | if (sSaveAs == A_Blank) 443 | sFile := this.GetFileName() 444 | else 445 | { 446 | sFile := sSaveAs 447 | 448 | ; Append ".ini" if it is not already there. 449 | if (SubStr(sFile, StrLen(sFile)-3, 4) != ".ini") 450 | sFile .= ".ini" 451 | 452 | if (bWarnIfExist && FileExist(sFile)) 453 | { 454 | MsgBox, 4,, The file "%sFile%" already exists.`n`nAre you sure that you want to overwrite it? 455 | IfMsgBox, No 456 | return false 457 | } 458 | } 459 | 460 | ; Formatting is preserved in ini object. 461 | FileDelete, %sFile% 462 | 463 | bIsFirstLine := true 464 | for k, v in this.EasyIni_ReservedFor_TopComments 465 | { 466 | FileAppend, % (A_Index == 1 ? "" : "`n") (v == Chr(14) ? "" : v), %sFile% 467 | bIsFirstLine := false 468 | } 469 | 470 | for section, aKeysAndVals in this 471 | { 472 | FileAppend, % (bIsFirstLine ? "[" : "`n[") section "]", %sFile% 473 | bIsFirstLine := false 474 | 475 | bEmptySection := true 476 | for key, val in aKeysAndVals 477 | { 478 | bEmptySection := false 479 | FileAppend, `n%key%=%val%, %sFile% 480 | 481 | ; Add the comment(s) for this key 482 | sComments := this[section].EasyIni_ReservedFor_Comments[key] 483 | Loop, Parse, sComments, `n 484 | FileAppend, % "`n" (A_LoopField == Chr(14) ? "" : A_LoopField), %sFile% 485 | } 486 | if (bEmptySection) 487 | { 488 | ; An empy section may contain comments... 489 | sComments := this[section].EasyIni_ReservedFor_Comments["SectionComment"] 490 | Loop, Parse, sComments, `n 491 | FileAppend, % "`n" (A_LoopField == Chr(14) ? "" : A_LoopField), %sFile% 492 | } 493 | } 494 | return true 495 | } 496 | 497 | ToVar() 498 | { 499 | sTmpFile := "$$$EasyIni_Temp.ini" 500 | this.Save(sTmpFile, !A_IsCompiled) 501 | FileRead, sIniAsVar, %sTmpFile% 502 | FileDelete, %sTmpFile% 503 | return sIniAsVar 504 | } 505 | } 506 | 507 | ; For all of the EasyIni_* functions below, much credit is due to Lexikos and Rbrtryn for their work with ordered arrays 508 | ; See http://www.autohotkey.com/board/topic/61792-ahk-l-for-loop-in-order-of-key-value-pair-creation/?p=389662 for Lexikos's initial work with ordered arrays 509 | ; See http://www.autohotkey.com/board/topic/94043-ordered-array/#entry592333 for Rbrtryn's OrderedArray lib 510 | EasyIni_CreateBaseObj(parms*) 511 | { 512 | ; Define prototype object for ordered arrays: 513 | static base := {__Set: "EasyIni_Set", _NewEnum: "EasyIni_NewEnum", Remove: "EasyIni_Remove", Insert: "EasyIni_Insert", InsertBefore: "EasyIni_InsertBefore"} 514 | ; Create and return new base object: 515 | return Object("_keys", Object(), "base", base, parms*) 516 | } 517 | 518 | EasyIni_Set(obj, parms*) 519 | { 520 | ; If this function is called, the key must not already exist. 521 | ; Sub-class array if necessary then add this new key to the key list, if it doesn't begin with "EasyIni_ReservedFor_" 522 | if parms.maxindex() > 2 523 | ObjInsert(obj, parms[1], EasyIni_CreateBaseObj()) 524 | 525 | ; Skip over member variables 526 | if (SubStr(parms[1], 1, 20) <> "EasyIni_ReservedFor_") 527 | ObjInsert(obj._keys, parms[1]) 528 | ; Since we don't return a value, the default behaviour takes effect. 529 | ; That is, a new key-value pair is created and stored in the object. 530 | } 531 | 532 | EasyIni_NewEnum(obj) 533 | { 534 | ; Define prototype object for custom enumerator: 535 | static base := Object("Next", "EasyIni_EnumNext") 536 | ; Return an enumerator wrapping our _keys array's enumerator: 537 | return Object("obj", obj, "enum", obj._keys._NewEnum(), "base", base) 538 | } 539 | 540 | EasyIni_EnumNext(e, ByRef k, ByRef v="") 541 | { 542 | ; If Enum.Next() returns a "true" value, it has stored a key and 543 | ; value in the provided variables. In this case, "i" receives the 544 | ; current index in the _keys array and "k" receives the value at 545 | ; that index, which is a key in the original object: 546 | if r := e.enum.Next(i,k) 547 | ; We want it to appear as though the user is simply enumerating 548 | ; the key-value pairs of the original object, so store the value 549 | ; associated with this key in the second output variable: 550 | v := e.obj[k] 551 | return r 552 | } 553 | 554 | EasyIni_Remove(obj, parms*) 555 | { 556 | r := ObjRemove(obj, parms*) ; Remove keys from main object 557 | Removed := [] 558 | for k, v in obj._keys ; Get each index key pair 559 | if not ObjHasKey(obj, v) ; if key is not in main object 560 | Removed.Insert(k) ; Store that keys index to be removed later 561 | for k, v in Removed ; For each key to be removed 562 | ObjRemove(obj._keys, v, "") ; remove that key from key list 563 | 564 | return r 565 | } 566 | 567 | EasyIni_Insert(obj, parms*) 568 | { 569 | r := ObjInsert(obj, parms*) ; Insert keys into main object 570 | enum := ObjNewEnum(obj) ; Can't use for-loop because it would invoke EasyIni_NewEnum 571 | while enum[k] { ; For each key in main object 572 | for i, kv in obj._keys ; Search for key in obj._keys 573 | if (k = "_keys" || k = kv || SubStr(k, 1, 20) = "EasyIni_ReservedFor_" || SubStr(kv, 1, 20) = "EasyIni_ReservedFor_") ; If found... 574 | continue 2 ; Get next key in main object 575 | ObjInsert(obj._keys, k) ; Else insert key into obj._keys 576 | } 577 | 578 | return r 579 | } 580 | 581 | EasyIni_InsertBefore(obj, key, parms*) 582 | { 583 | OldKeys := obj._keys ; Save key list 584 | obj._keys := [] ; Clear key list 585 | for idx, k in OldKeys { ; Put the keys before key 586 | if (k = key) ; back into key list 587 | break 588 | obj._keys.Insert(k) 589 | } 590 | 591 | r := ObjInsert(obj, parms*) ; Insert keys into main object 592 | enum := ObjNewEnum(obj) ; Can't use for-loop because it would invoke EasyIni_NewEnum 593 | while enum[k] { ; For each key in main object 594 | for i, kv in OldKeys ; Search for key in OldKeys 595 | if (k = "_keys" || k = kv) ; If found... 596 | continue 2 ; Get next key in main object 597 | ObjInsert(obj._keys, k) ; Else insert key into obj._keys 598 | } 599 | 600 | for i, k in OldKeys { ; Put the keys after key 601 | if (i < idx) ; back into key list 602 | continue 603 | obj._keys.Insert(k) 604 | } 605 | 606 | return r 607 | } 608 | -------------------------------------------------------------------------------- /Lib/Logger.ahk: -------------------------------------------------------------------------------- 1 | ; log := new Logger("test.log") 2 | ; log.Debug("test") 3 | 4 | class Logger 5 | { 6 | __New(filename) 7 | { 8 | this.filename := filename 9 | } 10 | 11 | Debug(msg) 12 | { 13 | FileAppend, % A_Now . " " . msg . "`n", % this.filename 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Plugins/BeyondCompare4/BeyondCompare4.ahk: -------------------------------------------------------------------------------- 1 | BeyondCompare4: 2 | vim.comment("", "进入normal模式") 3 | vim.comment("", "进入insert模式") 4 | vim.comment("", "下一处不同") 5 | vim.comment("", "上一处不同") 6 | vim.comment("", "下一行不同") 7 | vim.comment("", "上一行不同") 8 | vim.comment("", "跳转到文件开头") 9 | vim.comment("", "跳转到文件结尾") 10 | vim.comment("", "搜索内容") 11 | vim.comment("", "复制到左侧") 12 | vim.comment("", "复制到右侧") 13 | 14 | vim.SetWin("BeyondCompare4", "TViewForm") 15 | 16 | ; insert模式 17 | vim.mode("insert", "BeyondCompare4") 18 | 19 | vim.map("", "", "BeyondCompare4") 20 | 21 | ; normal模式 22 | vim.mode("normal", "BeyondCompare4") 23 | 24 | vim.map("i", "", "BeyondCompare4") 25 | 26 | vim.map("", "", "BeyondCompare4") 27 | 28 | vim.map("j", "", "BeyondCompare4") 29 | vim.map("k", "", "BeyondCompare4") 30 | vim.map("J", "", "BeyondCompare4") 31 | vim.map("K", "", "BeyondCompare4") 32 | vim.map("gg", "", "BeyondCompare4") 33 | vim.map("G", "", "BeyondCompare4") 34 | vim.map("/", "", "BeyondCompare4") 35 | vim.map("h", "", "BeyondCompare4") 36 | vim.map("l", "", "BeyondCompare4") 37 | return 38 | 39 | ; 对符合条件的控件使用insert模式,而不是normal模式 40 | ; 此段代码可以直接复制,但请修改AHK_CLASS的值和RegExMatch的第二个参数 41 | BeyondCompare4_CheckMode() 42 | { 43 | ControlGetFocus, ctrl, AHK_CLASS BeyondCompare4 44 | ; msgbox, ctrl 45 | if RegExMatch(ctrl, "Edit2") 46 | return true 47 | return false 48 | } 49 | 50 | : 51 | vim.mode("normal", "BeyondCompare4") 52 | return 53 | 54 | : 55 | vim.mode("insert", "BeyondCompare4") 56 | return 57 | 58 | : 59 | Send, ^n 60 | return 61 | 62 | : 63 | Send, ^p 64 | return 65 | 66 | : 67 | Send, ^+n 68 | return 69 | 70 | : 71 | Send, ^+p 72 | return 73 | 74 | : 75 | Send, ^{home} 76 | return 77 | 78 | : 79 | Send, ^{end} 80 | return 81 | 82 | : 83 | Send, ^f 84 | return 85 | 86 | : 87 | Send, ^+r 88 | return 89 | 90 | : 91 | Send, ^r 92 | return 93 | -------------------------------------------------------------------------------- /Plugins/DoubleCommander/DoubleCommander.ahk: -------------------------------------------------------------------------------- 1 | DoubleCommander: 2 | global DC_Name := "DoubleCommander" 3 | global DC_Class := "TTOTAL_CMD" 4 | global DC := "ahk_class " . DC_Class 5 | global DC_Dir := "c:\mine\app\doublecmd" 6 | global DC_Path := DC_Dir . "\doublecmd.exe --no-splash" 7 | ; 用于记录文件打开对话框所属窗体 8 | global DC_CallerId := 0 9 | 10 | Vim.SetWin(DC_Name, DC_Class, "doublecmd.exe") 11 | Vim.Mode("normal", DC_Name) 12 | Vim.BeforeActionDo("DC_ForceInsertMode", DC_Name) 13 | return 14 | 15 | DC_ForceInsertMode() { 16 | ControlGetFocus, Ctrl 17 | ; Edit 用于底部命令行 18 | ; Window1 或 Window3 用于磁盘列表 19 | ; Button 用于各种确认窗口,影响正常使用 20 | if (InStr(Ctrl, "Edit") || Ctrl == "Window1" || Ctrl == "Window3") { 21 | return true 22 | } 23 | 24 | WinGet, MenuID, ID, AHK_CLASS #32768 25 | if (MenuID != "") { 26 | return true 27 | } 28 | 29 | return false 30 | } 31 | 32 | DC_Run(Cmd) { 33 | ControlSetText, Edit1, % Cmd, % DC 34 | ControlSend, Edit1, {Enter}, % DC 35 | } 36 | 37 | DC_RunGet(Cmd, SaveClipboard := True) { 38 | if (SaveClipboard) { 39 | ClipSaved := ClipboardAll 40 | } 41 | 42 | Clipboard := "" 43 | 44 | DC_Run(Cmd) 45 | 46 | ClipWait, 1 47 | 48 | if (SaveClipboard) { 49 | Result := Clipboard 50 | 51 | Clipboard := ClipSaved 52 | ClipSaved := "" 53 | 54 | return Result 55 | } 56 | 57 | return Clipboard 58 | } 59 | 60 | ; 返回值 [1]: left/right [2]: 左侧面板所占比例 0-100 61 | DC_GetPanelInfo() { 62 | return StrSplit(DC_RunGet("cm_CopyPanelInfoToClip"), " ") 63 | } 64 | 65 | DC_ExecuteToolbarItem(ID) { 66 | DC_Run("cm_ExecuteToolbarItem ToolItemID=" . ID) 67 | } 68 | 69 | DC_OpenPath(Path, InNewTab := true, LeftOrRight := "") { 70 | LeftOfRight := DC_GetPanelInfo()[1] 71 | if (LeftOfRight == "right") { 72 | LeftOrRight := "-R" 73 | } else { 74 | LeftOrRight := "-L" 75 | } 76 | 77 | if (InNewTab) { 78 | Run, %DC_Path% -C -T "%LeftOrRight%" "%Path%" 79 | } else { 80 | Run, %DC_Path% -C "%LeftOrRight%" "%Path%" 81 | } 82 | } 83 | 84 | ; funcend 85 | 86 | : 87 | ; DC_ExecuteToolbarItem("{700FF494-B939-48A3-B248-8823EB366AEA}") 88 | DC_Run("cm_About") 89 | return 90 | 91 | : 92 | WinClose, % DC 93 | WinWaitClose, % DC, , 2 94 | 95 | Run, % DC_Path 96 | 97 | WinWaitActive, % DC 98 | 99 | if (!WinExist(DC)) { 100 | MsgBox, 重启失败 %ErrorMessage% 101 | } 102 | return 103 | 104 | : 105 | PanelInfo := DC_GetPanelInfo() 106 | 107 | if (Abs(50 - PanelInfo[2]) < 10) { 108 | if (PanelInfo[1] == "left") { 109 | DC_Run("cm_PanelsSplitterPerPos splitpct=100") 110 | } else { 111 | DC_Run("cm_PanelsSplitterPerPos splitpct=0") 112 | } 113 | } else { 114 | DC_Run("cm_PanelsSplitterPerPos splitpct=50") 115 | } 116 | return 117 | 118 | : 119 | ControlGetFocus, TLB, % DC 120 | ControlGetPos, Xn, Yn, , , % TLB, % DC 121 | 122 | Menu, NewFileMenu, Add 123 | Menu, NewFileMenu, DeleteAll 124 | Menu, NewFileMenu, Add , S >> 快捷方式, 125 | Menu, NewFileMenu, Icon, S >> 快捷方式, %A_WinDir%\system32\Shell32.dll, 264 126 | Menu, NewFileMenu, Add 127 | 128 | Loop, % DC_Dir . "\shellnew\*.*" { 129 | Ft := SubStr(A_LoopFileName, 1, 1) . " >> " . A_LoopFileName 130 | Menu, NewFileMenu, Add, % Ft, DC_NewFileMenuAction 131 | Menu, NewFileMenu, Icon, % Ft, %A_WinDir%\system32\Shell32.dll 132 | } 133 | 134 | Menu, NewFileMenu, Show, % Xn, % Yn + 2 135 | return 136 | 137 | DC_NewFileMenuAction: 138 | Filename := RegExReplace(A_ThisMenuItem, ".\s>>\s") 139 | FilePath := DC_Dir . "\ShellNew\" . Filename 140 | 141 | Gui, Destroy 142 | Gui, Add, Text, x12 y20 w50 h20 +Center, 模板源 143 | Gui, Add, Edit, x72 y20 w300 h20 Disabled, % FilePath 144 | Gui, Add, Text, x12 y50 w50 h20 +Center, 新建文件 145 | Gui, Add, Edit, x72 y50 w300 h20, % Filename 146 | Gui, Add, Button, x162 y80 w90 h30 gDC_NewFileOk default, 确认(&S) 147 | Gui, Add, Button, x282 y80 w90 h30 gDC_NewFileClose , 取消(&C) 148 | Gui, Show, w400 h120, 新建文件 149 | 150 | if (InStr(Filename, ".")) { 151 | ; 只选定扩展名之外的文件名 152 | PostMessage, 0x0B1, 0, % InStr(Filename, ".") - 1, Edit2, A 153 | } 154 | return 155 | 156 | DC_NewFileClose: 157 | Gui, Destroy 158 | return 159 | 160 | DC_NewFileOK: 161 | GuiControlGet, SrcFilePath, , Edit1 162 | GuiControlGet, NewFilename, , Edit2 163 | 164 | DstPath := DC_RunGet("cm_CopyCurrentPathToClip") 165 | 166 | if (InStr(DstPath, "`r")) { 167 | DstPath := SubStr(DstPath, 1, InStr(DstPath, "`r") - 1) 168 | } else if (DstPath == "") { 169 | return 170 | } 171 | 172 | NewFilePath := DstPath . NewFilename 173 | if (FileExist(NewFilePath)) { 174 | MsgBox, 4, 新建文件, 新建文件已存在,是否覆盖? 175 | IfMsgBox No 176 | return 177 | } 178 | 179 | FileCopy, % SrcFilePath, % NewFilePath, 1 180 | 181 | Gui, Destroy 182 | 183 | ; 验证有没有用 184 | Sleep, 10 185 | ; 虽然不是完全匹配,基本也能用了 186 | DC_Run("cm_QuickSearch text=" . NewFilename) 187 | return 188 | 189 | : 190 | if (WinExist(DC)) { 191 | WinGet, Ac, MinMax, % DC 192 | if (Ac == -1) { 193 | WinActivate, % DC 194 | } else { 195 | if (!WinActive(DC)) { 196 | WinActivate, % DC 197 | } else { 198 | WinMinimize, % DC 199 | } 200 | } 201 | } else { 202 | Run, % DC_Path 203 | WinWait, % DC 204 | 205 | if (!WinActive(DC)) { 206 | WinActivate, % DC 207 | } 208 | } 209 | return 210 | 211 | : 212 | SelectedFiles := DC_RunGet("cm_CopyNamesToClip") 213 | Result := """" . StrReplace(SelectedFiles, "`r`n", """ 🖥`r`n""") . """ 🖥`r`n" 214 | 215 | Sleep, 10 216 | DC_Run("cm_MarkUnmarkAll") 217 | 218 | FileAppend, % Result, % DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion", UTF-8-RAW 219 | 220 | DC_Run("cm_Refresh") 221 | 222 | SelectedFiles := "" 223 | Result := "" 224 | return 225 | 226 | : 227 | SelectedFiles := DC_RunGet("cm_CopyNamesToClip") 228 | DescriptPath := DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion" 229 | 230 | ; 有时取消选定会失效,改 20 也一样,不清楚怎么修复 231 | Sleep, 10 232 | DC_Run("cm_MarkUnmarkAll") 233 | 234 | FileRead, Content, % DescriptPath 235 | 236 | Loop, Parse, SelectedFiles, `n, `r 237 | { 238 | Content := RegExReplace(Content, """?" . A_LoopField . """? .*`r`n") 239 | ; Content := StrReplace(Content, """" . A_LoopField . """ 🖥`r`n") 240 | } 241 | 242 | FileDelete, % DescriptPath 243 | 244 | if (Content != "") { 245 | FileAppend, % Content, % DescriptPath, UTF-8-RAW 246 | } 247 | 248 | DC_Run("cm_Refresh") 249 | 250 | SelectedFiles := "" 251 | Content := "" 252 | return 253 | 254 | : 255 | InputBox, Content, , 请输入注释, , 375, 125 256 | if ErrorLevel 257 | return 258 | 259 | SelectedFiles := DC_RunGet("cm_CopyNamesToClip") 260 | 261 | Result := """" . StrReplace(SelectedFiles, "`r`n", """ " . Content . "`r`n""") . """ " . Content . "`r`n" 262 | 263 | Sleep, 10 264 | DC_Run("cm_MarkUnmarkAll") 265 | 266 | FileAppend, % Result, % DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion", UTF-8-RAW 267 | 268 | DC_Run("cm_Refresh") 269 | 270 | SelectedFiles := "" 271 | Result := "" 272 | return 273 | 274 | : 275 | SelectedFiles := DC_RunGet("cm_CopyNamesToClip") 276 | DescriptPath := DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion" 277 | 278 | ; 有时取消选定会失效,改 20 也一样,不清楚怎么修复 279 | Sleep, 10 280 | DC_Run("cm_MarkUnmarkAll") 281 | 282 | FileRead, Content, % DescriptPath 283 | 284 | Loop, Parse, SelectedFiles, `n, `r 285 | { 286 | Content := RegexReplace(Content, "m)^""?" . A_LoopField . """? .*") 287 | } 288 | 289 | ; \K:前边的不算,重新开始匹配 290 | Content := RegexReplace(Content, "(^|\R)\K\R+") 291 | 292 | FileDelete, % DescriptPath 293 | 294 | if (Content != "") { 295 | FileAppend, % Content, % DescriptPath, UTF-8-RAW 296 | } 297 | 298 | DC_Run("cm_Refresh") 299 | 300 | SelectedFiles := "" 301 | Content := "" 302 | return 303 | 304 | : 305 | Run, % editor . " """ . DC_RunGet("cm_CopyCurrentPathToClip") . "descript.ion""" 306 | return 307 | 308 | : 309 | Vim.GetWin(DC_Name).SetInfo(!Vim.GetWin(DC_Name).info) 310 | return 311 | 312 | : 313 | FileRead, Clipboard, % DC_RunGet("cm_CopyFullNamesToClip", false) 314 | return 315 | 316 | : 317 | Filename := DC_RunGet("cm_CopyFullNamesToClip") 318 | FileAppend, % Clipboard, % Filename, UTF-8-RAW 319 | return 320 | 321 | : 322 | Result := DC_RunGet("cm_CopyFullNamesToClip") 323 | 324 | SplitPath, Result, OutFileName, , , OutFilenameNoExt 325 | 326 | if (InStr(FileExist(Result), "D")) { 327 | Clipboard := OutFileName 328 | } else if (InStr(Result, ".")) { 329 | Clipboard := OutFilenameNoExt 330 | } 331 | return 332 | 333 | : 334 | Result := DC_RunGet("cm_CopyCurrentPathToClip") 335 | Clipboard := SubStr(Result, InStr(Result, "\", , -1) + 1, -1) 336 | return 337 | 338 | : 339 | Result := DC_RunGet("cm_CopyFullNamesToClip") 340 | SplitPath, Result, OutFileName, OutDir, OutExt 341 | 342 | Dirname := SubStr(OutDir, InStr(OutDir, "\", , -1) + 1) 343 | FileMove, % OutDir . "\" . OutFileName, % OutDir . "\" . Dirname . "." . OutExt 344 | return 345 | 346 | : 347 | FilePath := DC_RunGet("cm_CopyFullNamesToClip") 348 | 349 | OutVar := FileExist(FilePath) 350 | if (InStr(OutVar, "D")) { 351 | FileCreateShortcut, % FilePath, % FilePath . ".lnk", % RegExReplace(FilePath, "\\[^\\]*$") 352 | } else if (OutVar != "") { 353 | FileCreateShortcut, % FilePath, % RegExReplace(FilePath, "\.[^.]*$", ".lnk"), % RegExReplace(FilePath, "\\[^\\]*$") 354 | } 355 | return 356 | 357 | : 358 | IfWinExist, % DC 359 | Winactivate, % DC 360 | else { 361 | Run, % DC_Path 362 | WinWait, % DC 363 | IfWinNotActive, % DC 364 | WinActivate, % DC 365 | } 366 | return 367 | 368 | : 369 | Vim.Mode("normal", DC_Name) 370 | Vim.Map("", "", DC_Name) 371 | Vim.Map("", "", DC_Name) 372 | return 373 | 374 | : 375 | Vim.Mode("normal", DC_Name) 376 | Vim.Map("", "", DC_Name) 377 | Vim.Map("", "", DC_Name) 378 | return 379 | 380 | ; 返回调用者 381 | : 382 | gosub 383 | 384 | WinActivate, ahk_id %DC_CallerId% 385 | 386 | DC_CallerId := 0 387 | return 388 | 389 | ; 非 TC 窗口按下后激活 TC 窗口 390 | ; TC 窗口按下后复制当前选中文件返回原窗口后粘贴 391 | : 392 | WinGetClass, Name, A 393 | 394 | ; 在 DC 按下快捷键时,激活调用窗体并执行粘贴操作 395 | if (Name == DC_Class) { 396 | if (DC_CallerId != 0) { 397 | gosub 398 | return 399 | } 400 | } else { 401 | DC_CallerId := WinExist("A") 402 | if (DC_CallerId == 0) { 403 | return 404 | } 405 | 406 | gosub 407 | gosub 408 | } 409 | return 410 | 411 | : 412 | gosub 413 | 414 | if (DC_CallerId == 0) { 415 | return 416 | } 417 | 418 | ; 避免发送回车时受同时按下的 Win 等键影响 419 | ; MsgBox, , , 处理中, 0.3 420 | ; 通过修改 DC 代码解决 421 | 422 | Pwd := DC_RunGet("cm_CopyCurrentPathToClip", false) 423 | 424 | Filename := DC_RunGet("cm_CopyNamesToClip", false) 425 | 426 | WinActivate, ahk_id %DC_CallerId% 427 | WinWait, ahk_id %DC_CallerId% 428 | DC_CallerId := 0 429 | 430 | if (!InStr(Filename, "`n")) { 431 | Clipboard := Pwd . Filename 432 | Send, {Home} 433 | Send, ^v 434 | Send, {Enter} 435 | 436 | return 437 | } 438 | 439 | ; 多选 440 | 441 | Files := "" 442 | Loop, Parse, Filename, `n, `r 443 | Files .= """" . A_LoopField . """ " 444 | 445 | ; 第一步:跳转到当前路径 446 | Clipboard := Pwd 447 | Send, ^a 448 | Send, ^v 449 | Send, {Enter} 450 | sleep, 100 451 | 452 | ; 第二步:提交文件名 453 | Clipboard := Files 454 | Send, ^v 455 | Send, {Enter} 456 | return 457 | 458 | : 459 | gosub 460 | 461 | if (DC_CallerId == 0) { 462 | return 463 | } 464 | 465 | DC_Run("cm_CopyCurrentPathToClip") 466 | 467 | WinActivate, ahk_id %DC_CallerId% 468 | WinWait, ahk_id %DC_CallerId% 469 | DC_CallerId := 0 470 | 471 | Send, {Home} 472 | Send, ^v 473 | Send, {Enter} 474 | return 475 | 476 | : 477 | DC_Run("cd \\\回收站\") 478 | return 479 | -------------------------------------------------------------------------------- /Plugins/DoubleCommander/Readme.md: -------------------------------------------------------------------------------- 1 | ## 说明 2 | 3 | 此插件仅供自用,依赖对 DC 代码的修改以及专门的配置。 4 | 我修改版的 DC 代码:https://github.com/goreliu/doublecmd 5 | 6 | ## DC 和 TC 相比的优势 7 | 8 | * 开源,免费,跨平台,可以自由改代码定制功能,很好编译 9 | * 可以把按键绑定到工具栏的子菜单上,然后再通过按键触发子菜单功能 10 | * 主界面和配置界面更漂亮、好用 11 | * 配置文件都使用 UTF-8 编码,方便备份和程序处理 12 | * 内建 lua 解释器,方便写一些高级功能(感觉功能有限,用处不大) 13 | 14 | ## DC 和 TC 相比的劣势 15 | 16 | * 缺乏一些功能,内置命令少了一些 17 | * 内存占用稍多 18 | 19 | ## 待办事项 20 | 21 | ### 插件 22 | 23 | * 有时插件调用所有命令都会失效,原因不明,可能是 DC 的问题。 24 | 25 | ### DC 26 | 27 | * q 绑定到快速查看功能会触发 bug。 28 | 用 q 快速查看一个文本文件(1),然后用鼠标在右侧点一下(2),按 q(3),会卡住直到崩溃。 29 | 好像只有 q 会有问题。可以在 VimD 绑定绕过。 30 | 从 0.8.0 到 trunk 版本都存在这个问题。Linux 的 gtk2 版本也存在相同问题。 31 | -------------------------------------------------------------------------------- /Plugins/Explorer/Explorer.ahk: -------------------------------------------------------------------------------- 1 | ; 因为Explorer对快捷键支持很不友好,此插件功能不全而且部分功能有问题。 2 | ; 仅用于必须临时使用Explorer的场景。 3 | 4 | Explorer: 5 | vim.comment("", "进入normal模式") 6 | vim.comment("", "进入insert模式") 7 | vim.comment("", "进入上一层目录") 8 | vim.comment("", "进入目录") 9 | vim.comment("", "图标视图 超大") 10 | vim.comment("", "图标视图 大") 11 | vim.comment("", "图标视图 中等") 12 | vim.comment("", "图标视图 小") 13 | vim.comment("", "图标视图 平铺") 14 | vim.comment("", "列表视图 列表") 15 | vim.comment("", "列表视图 详情") 16 | vim.comment("", "列表视图 内容") 17 | vim.comment("", "定位到左侧目录栏") 18 | vim.comment("", "定位到右侧文件栏") 19 | vim.comment("", "重命名") 20 | vim.comment("", "使用TC打开当前目录") 21 | vim.comment("", "使用TC打开当前目录,并关闭Explorer") 22 | vim.comment("", "使用TC在新标签页打开当前目录") 23 | vim.comment("", "使用TC在新标签页打开当前目录,并关闭Explorer") 24 | vim.comment("", "使用DC打开当前目录") 25 | vim.comment("", "使用DC打开当前目录,并关闭Explorer") 26 | vim.comment("", "使用DC在新标签页打开当前目录") 27 | vim.comment("", "使用DC在新标签页打开当前目录,并关闭Explorer") 28 | 29 | vim.SetWin("Explorer", "CabinetWClass") 30 | 31 | ; insert模式 32 | vim.mode("insert", "Explorer") 33 | 34 | vim.map("", "", "Explorer") 35 | 36 | ; normal模式 37 | vim.mode("normal", "Explorer") 38 | 39 | vim.map("i", "", "Explorer") 40 | 41 | vim.map("j", "", "Explorer") 42 | vim.map("k", "", "Explorer") 43 | vim.map("h", "", "Explorer") 44 | vim.map("l", "", "Explorer") 45 | 46 | vim.map("t", "", "Explorer") 47 | vim.map("m", "", "Explorer") 48 | vim.map("n", "", "Explorer") 49 | vim.map("N", "", "Explorer") 50 | vim.map("r", "", "Explorer") 51 | 52 | vim.map("H", "", "Explorer") 53 | vim.map("", "", "Explorer") 54 | vim.map("", "", "Explorer") 55 | vim.map("", "", "Explorer") 56 | vim.map("", "", "Explorer") 57 | vim.map("gg", "", "Explorer") 58 | vim.map("G", "", "Explorer") 59 | vim.map("f", "", "Explorer") 60 | vim.map("F", "", "Explorer") 61 | 62 | vim.BeforeActionDo("Explorer_ForceInsertMode", "Explorer") 63 | 64 | return 65 | 66 | ; 对指定控件使用insert模式 67 | Explorer_ForceInsertMode() 68 | { 69 | ControlGetFocus, ctrl, AHK_CLASS CabinetWClass 70 | ;MsgBox ctrl 71 | if (RegExMatch(ctrl, "Edit|DirectUIHWND1") or WinExist("ahk_class #32768")) 72 | return true 73 | return false 74 | } 75 | 76 | : 77 | vim.mode("normal", "Explorer") 78 | return 79 | 80 | : 81 | vim.mode("insert", "Explorer") 82 | return 83 | 84 | : 85 | Send, !{up} 86 | return 87 | 88 | : 89 | ; 这系列命令必须保证鼠标不在焦点文件上才有效 90 | Send, {Click, right}vx 91 | return 92 | 93 | : 94 | Send, {Click, right}vr 95 | return 96 | 97 | : 98 | Send, {Click, right}vm 99 | return 100 | 101 | : 102 | Send, {Click, right}vn 103 | return 104 | 105 | : 106 | Send, {Click, right}vs 107 | return 108 | 109 | : 110 | Send, {Click, right}vl 111 | return 112 | 113 | : 114 | Send, {Click, right}vd 115 | return 116 | 117 | : 118 | Send, {Click, right}vs 119 | return 120 | 121 | : 122 | Send, {Click, right}vt 123 | return 124 | 125 | : 126 | Send, {enter} 127 | sleep, 100 128 | ; 如果载入目录时间过长,不会自动定位到第一个文件 129 | Send, {down}{up}{right}{left} 130 | return 131 | 132 | : 133 | ControlFocus, SysTreeView321 134 | return 135 | 136 | : 137 | ControlFocus, DirectUIHWND3 138 | return 139 | 140 | : 141 | Send, {f2} 142 | return 143 | 144 | : 145 | Explorer_GotoTC(false) 146 | return 147 | 148 | : 149 | Explorer_GotoTC(false, true) 150 | return 151 | 152 | : 153 | Explorer_GotoTC(true) 154 | return 155 | 156 | : 157 | Explorer_GotoTC(true, true) 158 | return 159 | 160 | Explorer_GotoTC(newTab, closeExplorer = false) 161 | { 162 | OldClipboard := ClipboardAll 163 | Clipboard = 164 | 165 | Send, ^c 166 | ClipWait, 0.3 167 | 168 | if (!ErrorLevel) 169 | { 170 | FileToOpen := Clipboard 171 | if (closeExplorer) 172 | { 173 | WinClose, A 174 | } 175 | TC_OpenPath(FileToOpen, newTab, "/L") 176 | Clipboard := OldClipboard 177 | OldClipboard = 178 | } 179 | else 180 | { 181 | FileToOpen := Explorer_GetPath() 182 | if (closeExplorer) 183 | { 184 | WinClose, A 185 | } 186 | TC_OpenPath(FileToOpen, newTab, "/L") 187 | } 188 | 189 | Clipboard := OldClipboard 190 | OldClipboard = 191 | } 192 | 193 | : 194 | Explorer_GotoDC(false) 195 | return 196 | 197 | : 198 | Explorer_GotoDC(false, true) 199 | return 200 | 201 | : 202 | Explorer_GotoDC(true) 203 | return 204 | 205 | : 206 | Explorer_GotoDC(true, true) 207 | return 208 | 209 | Explorer_GotoDC(newTab, closeExplorer = false) 210 | { 211 | OldClipboard := ClipboardAll 212 | Clipboard = 213 | 214 | Send, ^c 215 | ClipWait, 0.3 216 | 217 | if (!ErrorLevel) 218 | { 219 | FileToOpen := Clipboard 220 | if (closeExplorer) 221 | { 222 | WinClose, A 223 | } 224 | DC_OpenPath(FileToOpen, newTab, "-L") 225 | Clipboard := OldClipboard 226 | OldClipboard = 227 | } 228 | else 229 | { 230 | FileToOpen := Explorer_GetPath() 231 | if (closeExplorer) 232 | { 233 | WinClose, A 234 | } 235 | DC_OpenPath(FileToOpen, newTab, "-L") 236 | } 237 | 238 | Clipboard := OldClipboard 239 | OldClipboard = 240 | } 241 | 242 | Explorer_GetPath(hwnd = "") 243 | { 244 | if !(window := Explorer_GetWindow(hwnd)) 245 | return ErrorLevel := "Error" 246 | if (window = "desktop") 247 | return A_Desktop 248 | path := window.LocationURL 249 | path := RegExReplace(path, "ftp://.*@", "ftp://") 250 | StringReplace, path, path, file:/// 251 | StringReplace, path, path, /, \, All 252 | 253 | ; thanks to polyethene 254 | Loop 255 | if RegExMatch(path, "i)(?<=%)[\da-f]{1,2}", hex) 256 | StringReplace, path, path, `%%hex%, % Chr("0x" . hex), All 257 | else Break 258 | return path 259 | } 260 | 261 | Explorer_GetAll(hwnd = "") 262 | { 263 | return Explorer_Get(hwnd) 264 | } 265 | 266 | Explorer_GetSelected(hwnd = "") 267 | { 268 | return Explorer_Get(hwnd, true) 269 | } 270 | 271 | Explorer_GetWindow(hwnd = "") 272 | { 273 | ; thanks to jethrow for some pointers here 274 | WinGet, Process, ProcessName, % "ahk_id" hwnd := hwnd ? hwnd:WinExist("A") 275 | WinGetClass class, ahk_id %hwnd% 276 | 277 | if (Process!="explorer.exe") 278 | return 279 | 280 | if (class ~= "(Cabinet|Explore)WClass") 281 | { 282 | for window in ComObjCreate("Shell.Application").Windows 283 | if (window.hwnd == hwnd) 284 | return window 285 | } 286 | else if (class ~= "Progman|WorkerW") 287 | return "desktop" ; desktop found 288 | } 289 | 290 | Explorer_Get(hwnd = "", selection = false) 291 | { 292 | if !(window := Explorer_GetWindow(hwnd)) 293 | return ErrorLevel := "Error" 294 | if (window="desktop") 295 | { 296 | ControlGet, hwWindow, HWND,, SysListView321, ahk_class Progman 297 | if !hwWindow ; #D mode 298 | ControlGet, hwWindow, HWND,, SysListView321, A 299 | ControlGet, files, List, % ( selection ? "Selected":"") "Col1",,ahk_id %hwWindow% 300 | base := SubStr(A_Desktop,0,1)=="\" ? SubStr(A_Desktop,1,-1) : A_Desktop 301 | Loop, Parse, files, `n, `r 302 | { 303 | path := base "\" A_LoopField 304 | IfExist %path% ; Ignore special icons like Computer (at least for now) 305 | ret .= path "`n" 306 | } 307 | } 308 | else 309 | { 310 | if selection 311 | collection := window.document.SelectedItems 312 | else 313 | collection := window.document.Folder.Items 314 | for item in collection 315 | ret .= item.path "`n" 316 | } 317 | return Trim(ret,"`n") 318 | } 319 | return 320 | -------------------------------------------------------------------------------- /Plugins/Foobar2000/Foobar2000.ahk: -------------------------------------------------------------------------------- 1 | Foobar2000: 2 | global Foobar2000_name := "Foobar2000" 3 | global Foobar2000_class := "{97E27FAA-C0B3-4b8e-A693-ED7881E99FC1}" 4 | global Foobar2000_exe := "Foobar2000.exe" 5 | global Foobar2000_list_classnn := "{4B94B650-C2D8-40de-A0AD-E8FADF62D56C}1" 6 | 7 | vim.comment("", "打开搜索窗口") 8 | vim.comment("", "定位到目录窗口") 9 | vim.comment("", "定位到播放列表") 10 | vim.comment("", "显示/隐藏 按键提示") 11 | 12 | ; normal模式 13 | vim.SetWin(Foobar2000_name, Foobar2000_class, Foobar2000_exe) 14 | vim.mode("normal", Foobar2000_name) 15 | 16 | ;vim.map("i", "", Foobar2000_name) 17 | vim.map("", "", Foobar2000_name) 18 | 19 | vim.map("0", "<0>", Foobar2000_name) 20 | vim.map("1", "<1>", Foobar2000_name) 21 | vim.map("2", "<2>", Foobar2000_name) 22 | vim.map("3", "<3>", Foobar2000_name) 23 | vim.map("4", "<4>", Foobar2000_name) 24 | vim.map("5", "<5>", Foobar2000_name) 25 | vim.map("6", "<6>", Foobar2000_name) 26 | vim.map("7", "<7>", Foobar2000_name) 27 | vim.map("8", "<8>", Foobar2000_name) 28 | vim.map("9", "<9>", Foobar2000_name) 29 | 30 | vim.map("j", "", Foobar2000_name) 31 | vim.map("k", "", Foobar2000_name) 32 | vim.map("l", "", Foobar2000_name) 33 | vim.map("gg", "", Foobar2000_name) 34 | vim.map("G", "", Foobar2000_name) 35 | vim.map("", "", Foobar2000_name) 36 | vim.map("", "", Foobar2000_name) 37 | vim.map("", "", Foobar2000_name) 38 | vim.map("/", "", Foobar2000_name) 39 | vim.map("t", "", Foobar2000_name) 40 | vim.map("m", "", Foobar2000_name) 41 | vim.map("n", "", Foobar2000_name) 42 | vim.map("p", "", Foobar2000_name) 43 | vim.map("s", "", Foobar2000_name) 44 | vim.map("z", "", Foobar2000_name) 45 | 46 | vim.map("N", "", Foobar2000_name) 47 | vim.map("P", "", Foobar2000_name) 48 | 49 | vim.map("``", "", Foobar2000_name) 50 | 51 | vim.BeforeActionDo("Foobar2000_ForceInsertMode", Foobar2000_name) 52 | return 53 | 54 | Foobar2000_ForceInsertMode() 55 | { 56 | ControlGetFocus, ctrl 57 | ;MsgBox % ctrl 58 | if RegExMatch(ctrl, "Edit|Eslyric_Scintilla1") 59 | return true 60 | return false 61 | } 62 | 63 | : 64 | send ^f 65 | return 66 | 67 | : 68 | ControlFocus, SysTreeView321 69 | return 70 | 71 | : 72 | ControlFocus, %Foobar2000_list_classnn% 73 | return 74 | 75 | : 76 | vim.GetWin(Foobar2000_name).SetInfo(!vim.GetWin(Foobar2000_name).info) 77 | return 78 | -------------------------------------------------------------------------------- /Plugins/General/General.ahk: -------------------------------------------------------------------------------- 1 | General: 2 | Gen_Save_Win := [] 3 | vim.SetAction("", "向下移动") 4 | vim.SetAction("", "向上移动") 5 | vim.SetAction("", "向左移动") 6 | vim.SetAction("", "向右移动") 7 | vim.SetAction("", "home键") 8 | vim.SetAction("", "end键") 9 | vim.SetAction("", "插入模式") 10 | vim.SetAction("", "浏览模式") 11 | vim.SetAction("", "启用/禁用 Vim 热键(General 插件)") 12 | vim.SetAction("", "重新加载") 13 | vim.SetAction("", "禁用") 14 | vim.SetAction("", "窗口移动到下方") 15 | vim.SetAction("", "窗口移动到上方") 16 | vim.SetAction("", "窗口移动到左侧") 17 | vim.SetAction("", "窗口移动到右侧") 18 | vim.SetAction("", "窗口移动到中间") 19 | vim.SetAction("", "最大化窗口") 20 | vim.SetAction("", "最大化窗口,并且隐藏标题栏") 21 | vim.SetAction("", "最小化窗口") 22 | vim.SetAction("", "还原当前窗口") 23 | vim.SetAction("", "全屏当前程序") 24 | vim.SetAction("", "下一个标签") 25 | vim.SetAction("", "前一个标签") 26 | vim.SetAction("", "关闭当前标签") 27 | vim.SetAction("", "新建标签") 28 | vim.SetAction("", "激活第一个标签") 29 | vim.SetAction("", "激活第二个标签") 30 | vim.SetAction("", "激活第三个标签") 31 | vim.SetAction("", "激活第四个标签") 32 | vim.SetAction("", "激活第五个标签") 33 | vim.SetAction("", "激活第六个标签") 34 | vim.SetAction("", "激活第七个标签") 35 | vim.SetAction("", "激活第八个标签") 36 | vim.SetAction("", "激活第九个标签") 37 | vim.SetAction("", "激活最后一个标签") 38 | vim.SetAction("", "上一页") 39 | vim.SetAction("", "下一页") 40 | vim.SetAction("", "回车键") 41 | vim.SetAction("", "空格键") 42 | vim.SetAction("", "退格键") 43 | vim.SetAction("", "屏蔽按键") 44 | vim.SetAction("", "播放下一首") 45 | vim.SetAction("", "播放上一首") 46 | vim.SetAction("", "播放/停止") 47 | vim.SetAction("", "停止播放") 48 | vim.SetAction("", "清除屏幕的 ToolTip") 49 | vim.SetAction("", "显示所有按键帮助信息") 50 | vim.SetAction("", "切换大小写") 51 | vim.SetAction("", "向上移动鼠标") 52 | vim.SetAction("", "向下移动鼠标") 53 | vim.SetAction("", "向左移动鼠标") 54 | vim.SetAction("", "向右移动鼠标") 55 | vim.SetAction("", "在网络搜索剪切板内容") 56 | vim.SetAction("", "截图并保存") 57 | vim.SetAction("", "运行 RunZ") 58 | vim.SetAction("", "测试") 59 | vim.SetAction("", "显示/隐藏标题栏") 60 | vim.SetAction("", "关闭显示器") 61 | vim.SetAction("", "打开回收站") 62 | vim.SetAction("", "输出当前时间") 63 | vim.SetAction("", "置顶显示") 64 | vim.SetAction("", "取消置顶显示") 65 | vim.SetAction("", "睡眠") 66 | vim.SetAction("", "运行剪切板中的 AHK 代码") 67 | vim.SetAction("", "打开百度网盘链接") 68 | vim.SetAction("", "往剪切板中追加内容") 69 | vim.SetAction("", "切换到英文输入法并按 Esc 键") 70 | vim.SetAction("", "切换到英文输入法") 71 | 72 | 73 | vim.SetWin("General", "General") 74 | vim.SetMode("insert", "General") 75 | vim.map("", "", "General") 76 | vim.SetMode("normal", "General") 77 | vim.map("i", "", "General") 78 | vim.map("0", "<0>", "General") 79 | vim.map("1", "<1>", "General") 80 | vim.map("2", "<2>", "General") 81 | vim.map("3", "<3>", "General") 82 | vim.map("4", "<4>", "General") 83 | vim.map("5", "<5>", "General") 84 | vim.map("6", "<6>", "General") 85 | vim.map("7", "<7>", "General") 86 | vim.map("8", "<8>", "General") 87 | vim.map("9", "<9>", "General") 88 | vim.map("k", "", "General") 89 | vim.map("j", "", "General") 90 | vim.map("k", "", "General") 91 | vim.map("h", "", "General") 92 | vim.map("l", "", "General") 93 | vim.map("zj", "", "General") 94 | vim.map("zk", "", "General") 95 | vim.map("zh", "", "General") 96 | vim.map("zl", "", "General") 97 | vim.map("zc", "", "General") 98 | vim.map("zf", "", "General") 99 | vim.map("zm", "", "General") 100 | vim.map("zn", "", "General") 101 | vim.map("zr", "", "General") 102 | vim.map("t", "", "General") 103 | vim.map("x", "", "General") 104 | vim.map("gn", "", "General") 105 | vim.map("gp", "", "General") 106 | vim.map("g1", "", "General") 107 | vim.map("g2", "", "General") 108 | vim.map("g3", "", "General") 109 | vim.map("g4", "", "General") 110 | vim.map("g5", "", "General") 111 | vim.map("g6", "", "General") 112 | vim.map("g7", "", "General") 113 | vim.map("g8", "", "General") 114 | vim.map("g9", "", "General") 115 | vim.map("g0", "", "General") 116 | vim.BeforeActionDo("Gen_Before", "General") 117 | return 118 | 119 | Gen_Before() 120 | { 121 | Global vim 122 | WinGet, MenuID, ID, AHK_CLASS #32768 123 | If MenuID 124 | return True 125 | } 126 | 127 | : 128 | vim.SetMode("Insert", vim.CheckWin()) 129 | Tooltip, Insert模式, , , 19 130 | Settimer, cancelTooltip, 1200 131 | return 132 | 133 | : 134 | vim.SetMode("Normal", vim.CheckWin()) 135 | Tooltip, Normal模式, , , 19 136 | Settimer, cancelTooltip, 1200 137 | return 138 | 139 | : 140 | Global vim, Gen_Save_Win 141 | WinGetClass, c, A 142 | WinGet, f, ProcessPath, ahk_class %c% 143 | WinName:=vim.CheckWin() 144 | If not Gen_Save_Win[c] 145 | { 146 | If Strlen(winName) And IsObject(vim.GetWin(winName)) 147 | { 148 | MsgBox, , VimDesktop, 当前窗口 [ %winName% ] 已经拥有Vim模式`n不允许替换为通用(General)模式! 149 | return 150 | } 151 | } 152 | winObj := vim.GetWin(c) 153 | If not Isobject(winObj) 154 | { 155 | vim.copy("General", c, c, f) 156 | Gen_Save_Win[c] := True 157 | Tooltip, 复制VIMD热键到当前窗口成功, , , 19 158 | } 159 | Else 160 | { 161 | if vim.Toggle(c) 162 | Tooltip, 激活当前窗口的VIMD热键, , , 19 163 | else 164 | Tooltip, 取消当前窗口的VIMD热键, , , 19 165 | } 166 | Settimer, cancelTooltip, 1200 167 | return 168 | 169 | cancelTooltip: 170 | Tooltip, , , , 19 171 | return 172 | 173 | : 174 | Reload 175 | return 176 | 177 | : 178 | ExitApp 179 | return 180 | 181 | : 182 | Suspend 183 | return 184 | 185 | : 186 | send, {down} 187 | return 188 | 189 | : 190 | send, {up} 191 | return 192 | 193 | : 194 | send, {left} 195 | return 196 | 197 | : 198 | send, {right} 199 | return 200 | 201 | : 202 | send, {home} 203 | return 204 | 205 | : 206 | send, {end} 207 | return 208 | 209 | : 210 | send, {pgup} 211 | return 212 | 213 | : 214 | send, {pgdn} 215 | return 216 | 217 | : 218 | send, {enter} 219 | return 220 | 221 | : 222 | send, {space} 223 | return 224 | 225 | : 226 | send, {backspace} 227 | return 228 | 229 | : 230 | send, {Media_Next} 231 | return 232 | 233 | : 234 | send, {Media_Prev} 235 | return 236 | 237 | : 238 | send, {Media_Stop} 239 | return 240 | 241 | : 242 | send, {Media_Play_Pause} 243 | return 244 | 245 | : 246 | WindowPadMove("0, +1, 1.0, 0.5") 247 | Return 248 | 249 | : 250 | WindowPadMove("0, -1, 1.0, 0.5") 251 | Return 252 | 253 | : 254 | WindowPadMove("-1, 0, 0.5, 1.0") 255 | Return 256 | 257 | : 258 | WindowPadMove("+1, 0, 0.5, 1.0") 259 | Return 260 | 261 | : 262 | WindowPadMove("0, 0, 0.5, 0.7") 263 | return 264 | 265 | : 266 | WinMaximize, A 267 | return 268 | 269 | : 270 | WinMaximize, A 271 | WinSet, Style, -0xc00000, A 272 | return 273 | 274 | : 275 | WinMinimize, A 276 | return 277 | 278 | : 279 | WinRestore, A 280 | return 281 | 282 | ; 全屏当前程序 283 | : 284 | WinGet, windowID, ID, A 285 | WindowState := FullScreenID[windowID] 286 | If Strlen(windowState) = 0 287 | WindowState := 0 288 | If WindowState 289 | { 290 | WinSet, Style, ^0xC40000, ahk_id %WindowID% 291 | Loop, Parse, windowState, `, 292 | { 293 | If A_Index = 2 294 | WinPosX := A_LoopField 295 | If A_Index = 3 296 | WinPosY := A_LoopField 297 | If A_Index = 4 298 | WindowWidth := A_LoopField 299 | If A_Index = 5 300 | WindowHeight := A_LoopField 301 | } 302 | WinMove, ahk_id %WindowID%, , WinPosX, WinPosY, WindowWidth, WindowHeight 303 | WindowState := 0 304 | } 305 | Else 306 | { 307 | WinGetPos, WinPosX, WinPosY, WindowWidth, WindowHeight, ahk_id %WindowID% 308 | WinSet, Style, ^0xC40000, ahk_id %WindowID% 309 | WinMove, ahk_id %WindowID%, , 0, 0, A_ScreenWidth, A_ScreenHeight 310 | WindowState := 1 ", " WinPosX ", " WinPosY ", " WindowWidth ", " WindowHeight 311 | ;MsgBox 再按一下刚刚的热键退出全屏 312 | } 313 | FullScreenID[windowID] := WindowState 314 | return 315 | 316 | 317 | ;==================================================================================== 318 | ; 319 | ; WindowPad.ahk 320 | ; Version: 0.4 321 | ; Last Updated: 11/5/2009 322 | ; 323 | ; This file contains functions which are useful for manipulating and moving windows. 324 | ; This is a stripped down version of WindowPad v.1.56 by Lexikos. 325 | ; Downloaded from http://www.autohotkey.com/forum/topic21703.html 326 | ; 327 | 328 | WindowPadMove(P) 329 | { 330 | StringSplit, P, P, `, , %A_Space%%A_Tab% 331 | ; Params: 1:dirX, 2:dirY, 3:widthFactor, 4:heightFactor, 5:window 332 | 333 | if P1 = 334 | P1 = R 335 | if P2 = 336 | P2 = R 337 | 338 | WindowPad_WinExist(P5) 339 | 340 | if !WinExist() 341 | return 342 | 343 | ; Determine width/height factors. 344 | if (P1 or P2) { 345 | ; to a side 346 | widthFactor := P3+0 ? P3 : (P1 ? 0.5 : 1.0) 347 | heightFactor := P4+0 ? P4 : (P2 ? 0.5 : 1.0) 348 | } else { 349 | ; to center 350 | widthFactor := P3+0 ? P3 : 1.0 351 | heightFactor := P4+0 ? P4 : 1.0 352 | } 353 | 354 | ; Move the window! 355 | MoveWindowInDirection(P1, P2, widthFactor, heightFactor) 356 | } 357 | 358 | MaximizeToggle(P) 359 | { 360 | WindowPad_WinExist(P) 361 | 362 | WinGet, state, MinMax 363 | if state 364 | WinRestore 365 | else 366 | WinMaximize 367 | } 368 | 369 | ; Does the grunt work of the script. 370 | MoveWindowInDirection(sideX, sideY, widthFactor, heightFactor) 371 | { 372 | WinGetPos, x, y, w, h 373 | 374 | hwnd:=WinExist() 375 | if (can_restore := GetWindowProperty(hwnd, "wpHasRestorePos")) 376 | { ; Window has restore info. Check if it is where we last put it. 377 | last_x := GetWindowProperty(hwnd, "wpLastX") 378 | last_y := GetWindowProperty(hwnd, "wpLastY") 379 | last_w := GetWindowProperty(hwnd, "wpLastW") 380 | last_h := GetWindowProperty(hwnd, "wpLastH") 381 | } 382 | if (can_restore && last_x = x && last_y = y && last_w = w && last_h = h) 383 | { ; Window is where we last put it. Check if user wants to restore. 384 | if SubStr(sideX, 1, 1) = "R" 385 | { ; Restore on X-axis. 386 | restore_x := GetWindowProperty(hwnd, "wpRestoreX") 387 | restore_w := GetWindowProperty(hwnd, "wpRestoreW") 388 | StringTrimLeft, sideX, sideX, 1 389 | } 390 | if SubStr(sideY, 1, 1) = "R" 391 | { ; Restore on Y-axis. 392 | restore_y := GetWindowProperty(hwnd, "wpRestoreY") 393 | restore_h := GetWindowProperty(hwnd, "wpRestoreH") 394 | StringTrimLeft, sideY, sideY, 1 395 | } 396 | if (restore_x != "" || restore_y != "") 397 | { ; If already at the "restored" size and position, do the normal thing instead. 398 | if ((restore_x = x || restore_x = "") && (restore_y = y || restore_y = "") 399 | && (restore_w = w || restore_w = "") && (restore_h = h || restore_h = "")) 400 | { 401 | restore_x = 402 | restore_y = 403 | restore_w = 404 | restore_h = 405 | } 406 | } 407 | } 408 | else 409 | { ; Next time user requests the window be "restored" use this position and size. 410 | SetWindowProperty(hwnd, "wpHasRestorePos", true) 411 | SetWindowProperty(hwnd, "wpRestoreX", x) 412 | SetWindowProperty(hwnd, "wpRestoreY", y) 413 | SetWindowProperty(hwnd, "wpRestoreW", w) 414 | SetWindowProperty(hwnd, "wpRestoreH", h) 415 | 416 | if SubStr(sideX, 1, 1) = "R" 417 | StringTrimLeft, sideX, sideX, 1 418 | if SubStr(sideY, 1, 1) = "R" 419 | StringTrimLeft, sideY, sideY, 1 420 | } 421 | 422 | ; If no direction specified, restore or only switch monitors. 423 | if (sideX+0 = "" && restore_x = "") 424 | restore_x := x, restore_w := w 425 | if (sideY+0 = "" && restore_y = "") 426 | restore_y := y, restore_h := h 427 | 428 | ; Determine which monitor contains the center of the window. 429 | m := GetMonitorAt(x+w/2, y+h/2) 430 | 431 | ; Get work area of active monitor. 432 | gosub CalcMonitorStats 433 | ; Calculate possible new position for window. 434 | gosub CalcNewSizeAndPosition 435 | 436 | ; If the window is already there, 437 | if (newx ", " newy ", " neww ", " newh) = (x ", " y ", " w ", " h) 438 | { ; ..move to the next monitor along instead. 439 | 440 | if (sideX or sideY) 441 | { ; Move in the direction of sideX or sideY. 442 | SysGet, monB, Monitor, %m% ; get bounds of entire monitor (vs. work area) 443 | x := (sideX=0) ? (x+w/2) : (sideX>0 ? monBRight : monBLeft) + sideX 444 | y := (sideY=0) ? (y+h/2) : (sideY>0 ? monBBottom : monBTop) + sideY 445 | newm := GetMonitorAt(x, y, m) 446 | } 447 | else 448 | { ; Move to center (Numpad5) 449 | newm := m+1 450 | SysGet, mon, MonitorCount 451 | if (newm > mon) 452 | newm := 1 453 | } 454 | 455 | if (newm != m) 456 | { 457 | m := newm 458 | ; Move to opposite side of monitor (left of a monitor is another monitor's right edge) 459 | sideX *= -1 460 | sideY *= -1 461 | ; Get new monitor's work area. 462 | gosub CalcMonitorStats 463 | } 464 | else 465 | { 466 | ; No monitor to move to, alternate size of window instead. 467 | if sideX 468 | widthFactor /= 2 469 | else if sideY 470 | heightFactor /= 2 471 | else 472 | widthFactor *= 1.5 473 | gosub CalcNewSizeAndPosition 474 | } 475 | 476 | ; Calculate new position for window. 477 | gosub CalcNewSizeAndPosition 478 | } 479 | 480 | ; Restore before resizing... 481 | WinGet, state, MinMax 482 | if state 483 | WinRestore 484 | 485 | WinDelay := A_WinDelay 486 | SetWinDelay, 0 487 | 488 | ; Move the window! 489 | WinMove, , , newx, newy, neww, newh 490 | 491 | ; For console windows and other windows which have size restrictions, check 492 | ; that the window was actually resized. If not, reposition based on actual size. 493 | WinGetPos, newx, newy, realw, realh 494 | if (neww != realw || newh != realh) 495 | { 496 | neww := realw 497 | newh := realh 498 | gosub CalcNewPosition 499 | if ((newm = "" || newm = m) && (newx ", " newy ", " realw ", " realh)=(x ", " y ", " w ", " h)) 500 | { 501 | if sideX 502 | neww //= 2 503 | else if sideY 504 | newh //= 2 505 | else 506 | neww := Round(neww*1.5) 507 | ; Size first, since the window size will probably be restricted in some way. 508 | WinMove, , , , , neww, newh 509 | WinGetPos, , , neww, newh 510 | gosub CalcNewPosition 511 | } 512 | WinMove, , , newx, newy 513 | } 514 | 515 | ; Explorer uses WM_EXITSIZEMOVE to detect when a user finishes moving a window 516 | ; in order to save the position for next time. May also be used by other apps. 517 | PostMessage, 0x232 518 | 519 | SetWinDelay, WinDelay 520 | 521 | ; Remember where we put it, to detect if the user moves it. 522 | SetWindowProperty(hwnd, "wpLastX", newx) 523 | SetWindowProperty(hwnd, "wpLastY", newy) 524 | SetWindowProperty(hwnd, "wpLastW", neww) 525 | SetWindowProperty(hwnd, "wpLastH", newh) 526 | return 527 | 528 | CalcNewSizeAndPosition: 529 | ; Calculate new size. 530 | if (IsResizable()) { 531 | neww := restore_w != "" ? restore_w : Round(monWidth * widthFactor) 532 | newh := restore_h != "" ? restore_h : Round(monHeight * heightFactor) 533 | } else { 534 | neww := w 535 | newh := h 536 | } 537 | CalcNewPosition: 538 | ; Calculate new position. 539 | newx := restore_x != "" ? restore_x : Round(monLeft + (sideX+1) * (monWidth - neww)/2) 540 | newy := restore_y != "" ? restore_y : Round(monTop + (sideY+1) * (monHeight - newh)/2) 541 | return 542 | 543 | CalcMonitorStats: 544 | ; Get work area (excludes taskbar-reserved space.) 545 | SysGet, mon, MonitorWorkArea, %m% 546 | monWidth := monRight - monLeft 547 | monHeight := monBottom - monTop 548 | return 549 | } 550 | 551 | ; Get/set window property. type should be int, uint or float. 552 | GetWindowProperty(hwnd, property_name, type="int") { 553 | return DllCall("GetProp", "uint", hwnd, "str", property_name, type) 554 | } 555 | 556 | SetWindowProperty(hwnd, property_name, data, type="int") { 557 | return DllCall("SetProp", "uint", hwnd, "str", property_name, type, data) 558 | } 559 | 560 | ; Get the index of the monitor containing the specified x and y co-ordinates. 561 | GetMonitorAt(x, y, default=1) 562 | { 563 | SysGet, m, MonitorCount 564 | ; Iterate through all monitors. 565 | Loop, %m% 566 | { 567 | ; Check if the window is on this monitor. 568 | SysGet, Mon, Monitor, %A_Index% 569 | if (x >= MonLeft && x <= MonRight && y >= MonTop && y <= MonBottom) 570 | return A_Index 571 | } 572 | 573 | return default 574 | } 575 | 576 | IsResizable() 577 | { 578 | WinGetClass, Class 579 | if Class = Chrome_XPFrame 580 | return true 581 | if Class = ConsoleWindowClass 582 | return false 583 | WinGet, Style, Style 584 | return (Style & 0x40000) ; WS_SIZEBOX 585 | } 586 | 587 | WindowPad_WinExist(WinTitle) 588 | { 589 | if WinTitle = P 590 | return WinPreviouslyActive() 591 | if WinTitle = M 592 | { 593 | MouseGetPos, , , win 594 | return WinExist("ahk_id " win) 595 | } 596 | return WinExist(WinTitle!="" ? WinTitle : "A") 597 | } 598 | 599 | ; Note: This may not work properly with always-on-top windows. (Needs testing) 600 | WinPreviouslyActive() 601 | { 602 | active := WinActive("A") 603 | WinGet, win, List 604 | 605 | ; Find the active window. 606 | ; (Might not be win1 if there are always-on-top windows?) 607 | Loop, %win% 608 | if (win%A_Index% = active) 609 | { 610 | if (A_Index < win) 611 | N := A_Index+1 612 | 613 | ; hack for PSPad: +1 seems to get the document (child!) window, so do +2 614 | ifWinActive, ahk_class TfPSPad 615 | N += 1 616 | 617 | break 618 | } 619 | 620 | ; Use WinExist to set Last Found Window (for consistency with WinActive()) 621 | return WinExist("ahk_id " . win%N%) 622 | } 623 | 624 | ; 625 | ; Switch without moving/resizing (relative to screen) 626 | ; 627 | WindowScreenMove(P) 628 | { 629 | SetWinDelay, 0 630 | 631 | StringSplit, P, P, `, , %A_Space%%A_Tab% 632 | ; 1:Next|Prev|Num, 2:Window 633 | 634 | WindowPad_WinExist(P2) 635 | 636 | WinGet, state, MinMax 637 | if state = 1 638 | WinRestore 639 | 640 | WinGetPos, x, y, w, h 641 | 642 | ; Determine which monitor contains the center of the window. 643 | ms := GetMonitorAt(x+w/2, y+h/2) 644 | 645 | SysGet, mc, MonitorCount 646 | 647 | ; Determine which monitor to move to. 648 | if P1 in , N, Next 649 | { 650 | md := ms+1 651 | if (md > mc) 652 | md := 1 653 | } 654 | else if P1 in P, Prev, Previous 655 | { 656 | md := ms-1 657 | if (md < 1) 658 | md := mc 659 | } 660 | else if P1 is integer 661 | md := P1 662 | 663 | if (md=ms or (md+0)="" or md<1 or md>mc) 664 | return 665 | 666 | ; Get source and destination work areas (excludes taskbar-reserved space.) 667 | SysGet, ms, MonitorWorkArea, %ms% 668 | SysGet, md, MonitorWorkArea, %md% 669 | msw := msRight - msLeft, msh := msBottom - msTop 670 | mdw := mdRight - mdLeft, mdh := mdBottom - mdTop 671 | 672 | ; Calculate new size. 673 | if (IsResizable()) { 674 | w := Round(w*(mdw/msw)) 675 | h := Round(h*(mdh/msh)) 676 | } 677 | 678 | ; Move window, using resolution difference to scale co-ordinates. 679 | WinMove, , , mdLeft + (x-msLeft)*(mdw/msw), mdTop + (y-msTop)*(mdh/msh), w, h 680 | 681 | if state = 1 682 | WinMaximize 683 | } 684 | 685 | ; 686 | ; "Gather" windows on a specific screen. 687 | ; 688 | GatherWindows(md=1) 689 | { 690 | global ProcessGatherExcludeList 691 | 692 | SetWinDelay, 0 693 | 694 | ; List all visible windows. 695 | WinGet, win, List 696 | 697 | ; Copy bounds of all monitors to an array. 698 | SysGet, mc, MonitorCount 699 | Loop, %mc% 700 | SysGet, mon%A_Index%, MonitorWorkArea, %A_Index% 701 | 702 | if md = M 703 | { 704 | ; Special exception for 'M', since the desktop window 705 | ; spreads across all screens. 706 | CoordMode, Mouse, Screen 707 | MouseGetPos, x, y 708 | md := GetMonitorAt(x, y, 0) 709 | } 710 | else if md is not integer 711 | { 712 | ; Support A, P and WinTitle. 713 | ; (Gather at screen containing specified window.) 714 | WindowPad_WinExist(md) 715 | WinGetPos, x, y, w, h 716 | md := GetMonitorAt(x+w/2, y+h/2, 0) 717 | } 718 | if (md<1 or md>mc) 719 | return 720 | 721 | ; Destination monitor 722 | mdx := mon%md%Left 723 | mdy := mon%md%Top 724 | mdw := mon%md%Right - mdx 725 | mdh := mon%md%Bottom - mdy 726 | 727 | Loop, %win% 728 | { 729 | ; If this window matches the GatherExclude group, don't touch it. 730 | if (WinExist("ahk_group GatherExclude ahk_id " . win%A_Index%)) 731 | continue 732 | 733 | ; Set Last Found Window. 734 | if (!WinExist("ahk_id " . win%A_Index%)) 735 | continue 736 | 737 | WinGet, procname, ProcessName 738 | ; Check process (program) exclusion list. 739 | if procname in %ProcessGatherExcludeList% 740 | continue 741 | 742 | WinGetPos, x, y, w, h 743 | 744 | ; Determine which monitor this window is on. 745 | xc := x+w/2, yc := y+h/2 746 | ms := 0 747 | Loop, %mc% 748 | if (xc >= mon%A_Index%Left && xc <= mon%A_Index%Right 749 | && yc >= mon%A_Index%Top && yc <= mon%A_Index%Bottom) 750 | { 751 | ms := A_Index 752 | break 753 | } 754 | ; If already on destination monitor, skip this window. 755 | if (ms = md) 756 | continue 757 | 758 | WinGet, state, MinMax 759 | if (state = 1) { 760 | WinRestore 761 | WinGetPos, x, y, w, h 762 | } 763 | 764 | if ms 765 | { 766 | ; Source monitor 767 | msx := mon%ms%Left 768 | msy := mon%ms%Top 769 | msw := mon%ms%Right - msx 770 | msh := mon%ms%Bottom - msy 771 | 772 | ; If the window is resizable, scale it by the monitors' resolution difference. 773 | if (IsResizable()) { 774 | w *= (mdw/msw) 775 | h *= (mdh/msh) 776 | } 777 | 778 | ; Move window, using resolution difference to scale co-ordinates. 779 | WinMove, , , mdx + (x-msx)*(mdw/msw), mdy + (y-msy)*(mdh/msh), w, h 780 | } 781 | else 782 | { 783 | ; Window not on any monitor, move it to center. 784 | WinMove, , , mdx + (mdw-w)/2, mdy + (mdh-h)/2 785 | } 786 | 787 | if state = 1 788 | WinMaximize 789 | } 790 | } 791 | 792 | GetLastMinimizedWindow() 793 | { 794 | WinGet, w, List 795 | 796 | Loop %w% 797 | { 798 | wi := w%A_Index% 799 | WinGet, m, MinMax, ahk_id %wi% 800 | if m = -1 ; minimized 801 | { 802 | lastFound := wi 803 | break 804 | } 805 | } 806 | 807 | return "ahk_id " . (lastFound ? lastFound : 0) 808 | } 809 | 810 | 811 | ;================================== 功能代码 :由北风一叶提供 812 | ;下一个标签 813 | : 814 | send ^{tab} 815 | return 816 | 817 | ;上一个标签 818 | : 819 | send ^+{tab} 820 | return 821 | 822 | ;关闭当前标签 823 | : 824 | send ^{w} 825 | return 826 | 827 | ;新建标签 828 | : 829 | send ^{t} 830 | return 831 | 832 | ;激活第一个标签 833 | : 834 | send ^{1} 835 | return 836 | 837 | ;激活第二个标签 838 | : 839 | send ^{2} 840 | return 841 | 842 | ;激活第三个标签 843 | : 844 | send ^{3} 845 | return 846 | 847 | ;激活第四个标签 848 | : 849 | send ^{4} 850 | return 851 | 852 | ;激活第五个标签 853 | : 854 | send ^{5} 855 | return 856 | 857 | ;激活第六个标签 858 | : 859 | send ^{6} 860 | return 861 | 862 | ;激活第七个标签 863 | : 864 | send ^{7} 865 | return 866 | 867 | ;激活第八个标签 868 | : 869 | send ^{8} 870 | return 871 | 872 | ;激活第九个标签 873 | : 874 | send ^{8}^{tab} 875 | return 876 | 877 | ;激活最后一个标签 878 | : 879 | send ^{9} 880 | return 881 | 882 | ;清除 ToolTip 计时器 883 | : 884 | Global showToolTipStatus 885 | 886 | SetTimer, , Off 887 | ToolTip 888 | showToolTipStatus := false 889 | return 890 | 891 | ;进入、退出模式时显示提示 892 | DisplayMode(ahk_class_name, mode_name) 893 | { 894 | Global vim 895 | Global showToolTipStatus 896 | 897 | ToolTip, 进入 %mode_name% 模式 898 | showToolTipStatus := true 899 | 900 | SetTimer, , 500 901 | } 902 | 903 | ShowHelp() 904 | { 905 | Global vim 906 | 907 | modeObj := vim.GetMode(vim.LastFoundWin) 908 | 909 | np := "help`n" 910 | np .= "=====================`n" 911 | 912 | for i, k in modeObj.keymapList 913 | { 914 | if (i >= 0 && i <= 9) 915 | { 916 | Continue 917 | } 918 | 919 | act := vim.GetAction(modeObj.GetKeyMap(i)) 920 | if (act.Type = 1) 921 | { 922 | ActionDescList := act.Comment 923 | np .= i "`t" %ActionDescList%[i] "`n" 924 | } 925 | else 926 | { 927 | np .= i "`t" act.Comment "`n" 928 | } 929 | } 930 | 931 | MouseGetPos, posx, posy, A 932 | posx += 40 933 | posy += 40 934 | Tooltip, %np%, %posx%, %posy% 935 | } 936 | 937 | : 938 | Global showToolTipStatus 939 | 940 | if (!showToolTipStatus) 941 | { 942 | ShowHelp() 943 | } 944 | else 945 | { 946 | ToolTip 947 | } 948 | 949 | showToolTipStatus := !showToolTipStatus 950 | return 951 | 952 | : 953 | GetKeyState, CapsLockState, CapsLock, T 954 | if CapsLockState = D 955 | SetCapsLockState, AlwaysOff 956 | else 957 | SetCapsLockState, AlwaysOn 958 | return 959 | 960 | : 961 | MouseMove, 0, -10, 0, R 962 | return 963 | 964 | : 965 | MouseMove, 0, 10, 0, R 966 | return 967 | 968 | : 969 | MouseMove, -10, 0, 0, R 970 | return 971 | 972 | : 973 | MouseMove, 10, 0, 0, R 974 | return 975 | 976 | : 977 | Run, explorer "https://www.baidu.com/s?wd=%Clipboard%", , 978 | return 979 | 980 | : 981 | MsgBox, 测试 982 | return 983 | 984 | TestFunction(arg) 985 | { 986 | MsgBox, 参数:%arg% 987 | } 988 | 989 | : 990 | if (RegExMatch(A_ThisHotkey, "i)!PrintScreen")) 991 | { 992 | Send, !{PrintScreen} 993 | } 994 | else 995 | { 996 | Send, {PrintScreen} 997 | } 998 | 999 | sleep, 50 1000 | 1001 | FileSelectFile, selectedFile, s16, 截图_%A_Now%.png, 另存为, 图片(*.png; *.jpg; *.gif; *.bmp) 1002 | 1003 | if (selectedFile == "") 1004 | { 1005 | return 1006 | } 1007 | else if (!InStr(selectedFile, ".")) 1008 | { 1009 | selectedFile .= ".png" 1010 | } 1011 | 1012 | SaveImageFromClipboard(selectedFile) 1013 | return 1014 | 1015 | SaveImageFromClipboard(filename) 1016 | { 1017 | pToken := Gdip_Startup() 1018 | pBitmap := Gdip_CreateBitmapFromClipboard() 1019 | Gdip_SaveBitmapToFile(pBitmap, filename, 100) 1020 | Gdip_DisposeImage(pBitmap) 1021 | Gdip_Shutdown(pToken) 1022 | } 1023 | 1024 | ; ScreenSnapshot("FullScreen.png") 1025 | ; ScreenSnapshot("Area_xywh.png", "10|20|200|200") 1026 | ScreenSnapshot(filename, area := 0) 1027 | { 1028 | pToken := Gdip_Startup() 1029 | pBitmap := Gdip_BitmapFromScreen(area) 1030 | Gdip_SaveBitmapToFile(pBitmap, filename) 1031 | Gdip_DisposeImage(pBitmap) 1032 | Gdip_Shutdown(pToken) 1033 | } 1034 | 1035 | IME_GET(WinTitle := "") 1036 | ;----------------------------------------------------------- 1037 | ; IMEの状態の取得 1038 | ; 対象: AHK v1.0.34以降 1039 | ; WinTitle : 対象Window (省略時:アクティブウィンドウ) 1040 | ; 戻り値 1:ON 0:OFF 1041 | ;----------------------------------------------------------- 1042 | { 1043 | ; ifEqual WinTitle, ,SetEnv, WinTitle, A 1044 | ; WinGet, hWnd, ID, %WinTitle% 1045 | WinGet, hWnd, ID, A 1046 | DefaultIMEWnd := DllCall("imm32\ImmGetDefaultIMEWnd", Uint, hWnd, Uint) 1047 | 1048 | ; Message : WM_IME_CONTROL wParam:IMC_GETOPENSTATUS 1049 | DetectSave := A_DetectHiddenWindows 1050 | DetectHiddenWindows, ON 1051 | SendMessage 0x283, 0x005, 0, , ahk_id %DefaultIMEWnd% 1052 | DetectHiddenWindows, %DetectSave% 1053 | return ErrorLevel 1054 | } 1055 | 1056 | SwitchIME(dwLayout) 1057 | { 1058 | HKL := DllCall("LoadKeyboardLayout", Str, dwLayout, UInt, 1) 1059 | ControlGetFocus, ctl, A 1060 | SendMessage, 0x50, 0, HKL, %ctl%, A 1061 | } 1062 | 1063 | ; 来自天甜 1064 | ; 用法:SwitchIMEname("中文(简体) - 百度输入法") 1065 | SwitchIMEByName(name) 1066 | { 1067 | Loop, HKLM, SYSTEM\CurrentControlSet\Control\Keyboard Layouts, 1, 1 1068 | { 1069 | IfEqual, A_LoopRegName, Layout Text 1070 | { 1071 | RegRead, Value 1072 | IfInString,value,%name% 1073 | { 1074 | RegExMatch(A_LoopRegSubKey, "[^\\]+$", dwLayout) 1075 | HKL := DllCall("LoadKeyboardLayout", Str, dwLayout, UInt, 1) 1076 | ControlGetFocus, ctl, A 1077 | SendMessage, 0x50, 0, HKL, %ctl%, A 1078 | break 1079 | } 1080 | } 1081 | } 1082 | } 1083 | 1084 | : 1085 | ; 下方代码可只保留一个 1086 | SwitchIME(0x04090409) ; 英语(美国) 美式键盘 1087 | SwitchIME(0x08040804) ; 中文(中国) 简体中文-美式键盘 1088 | return 1089 | 1090 | : 1091 | Send, {esc} 1092 | ; 下方代码可只保留一个 1093 | SwitchIME(0x04090409) ; 英语(美国) 美式键盘 1094 | SwitchIME(0x08040804) ; 中文(中国) 简体中文-美式键盘 1095 | return 1096 | 1097 | : 1098 | RunZPath := A_ScriptDir "\..\RunZ\RunZ.exe" 1099 | if (ini.config.runz_dir != "") 1100 | { 1101 | RunZPath := ini.config.runz_dir "\RunZ.exe" 1102 | } 1103 | 1104 | if (!FileExist(RunZPath)) 1105 | { 1106 | return 1107 | } 1108 | 1109 | Run, "%RunZPath%" 1110 | return 1111 | 1112 | : 1113 | OldClipboard := Clipboard 1114 | Clipboard = 1115 | Send, ^c 1116 | ClipWait, 2 1117 | Clipboard := OldClipboard . Clipboard 1118 | return 1119 | 1120 | : 1121 | Clipboard := Clipboard 1122 | Send, ^v 1123 | return 1124 | 1125 | : 1126 | Clipboard = 1127 | Send, ^c 1128 | ClipWait, 1 1129 | 1130 | Result := StrSplit(RegExReplace(Clipboard, "(链接:|密码:|提取)"), " ") 1131 | Run, % Result[1] 1132 | Sleep, 2000 1133 | Send, % Result[2] 1134 | Send, {Enter} 1135 | return 1136 | 1137 | ClickContextMenu(key) 1138 | { 1139 | Send, {AppsKey} 1140 | WinWait, ahk_class #32768 1141 | Send, %key% 1142 | } 1143 | 1144 | : 1145 | tmp_file := A_Temp "\tmpcode.ahk" 1146 | FileDelete, %tmp_file% 1147 | FileAppend, %Clipboard%, %tmp_file% 1148 | Run, %A_ScriptDir%\vimd.exe %tmp_file% 1149 | return 1150 | 1151 | : 1152 | DllCall("PowrProf\SetSuspendState", "int", 0, "int", 0, "int", 0) 1153 | return 1154 | 1155 | : 1156 | WinSet, AlwaysOnTop, on, A 1157 | return 1158 | 1159 | : 1160 | WinSet, AlwaysOnTop, off, A 1161 | return 1162 | 1163 | : 1164 | WinSet, Style, ^0xC40000, A 1165 | return 1166 | 1167 | : 1168 | Sleep, 300 1169 | SendMessage, 0x112, 0xF170, 2, , Program Manager 1170 | return 1171 | 1172 | : 1173 | Run, explorer.exe ::{645ff040-5081-101b-9f08-00aa002f954e} 1174 | return 1175 | 1176 | : 1177 | Send, % A_Now 1178 | return 1179 | 1180 | : 1181 | MsgBox, 4, , 将要清空回收站,是否执行? 1182 | IfMsgBox Yes 1183 | FileRecycleEmpty 1184 | return 1185 | 1186 | ; https://www.autohotkey.com/boards/viewtopic.php?f=5&t=46654 1187 | ; https://msdn.microsoft.com/en-us/library/windows/desktop/dd370805(v=vs.85).aspx 1188 | 1189 | GetAppVolume(pid) 1190 | { 1191 | Local MasterVolume := "" 1192 | 1193 | IMMDeviceEnumerator := ComObjCreate("{BCDE0395-E52F-467C-8E3D-C4579291692E}", "{A95664D2-9614-4F35-A746-DE8DB63617E6}") 1194 | DllCall(NumGet(NumGet(IMMDeviceEnumerator+0)+4*A_PtrSize), "UPtr", IMMDeviceEnumerator, "UInt", 0, "UInt", 1, "UPtrP", IMMDevice, "UInt") 1195 | ObjRelease(IMMDeviceEnumerator) 1196 | 1197 | VarSetCapacity(GUID, 16) 1198 | DllCall("Ole32.dll\CLSIDFromString", "Str", "{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}", "UPtr", &GUID) 1199 | DllCall(NumGet(NumGet(IMMDevice+0)+3*A_PtrSize), "UPtr", IMMDevice, "UPtr", &GUID, "UInt", 23, "UPtr", 0, "UPtrP", IAudioSessionManager2, "UInt") 1200 | ObjRelease(IMMDevice) 1201 | 1202 | DllCall(NumGet(NumGet(IAudioSessionManager2+0)+5*A_PtrSize), "UPtr", IAudioSessionManager2, "UPtrP", IAudioSessionEnumerator, "UInt") 1203 | ObjRelease(IAudioSessionManager2) 1204 | 1205 | DllCall(NumGet(NumGet(IAudioSessionEnumerator+0)+3*A_PtrSize), "UPtr", IAudioSessionEnumerator, "UIntP", SessionCount, "UInt") 1206 | Loop % SessionCount 1207 | { 1208 | DllCall(NumGet(NumGet(IAudioSessionEnumerator+0)+4*A_PtrSize), "UPtr", IAudioSessionEnumerator, "Int", A_Index-1, "UPtrP", IAudioSessionControl, "UInt") 1209 | IAudioSessionControl2 := ComObjQuery(IAudioSessionControl, "{BFB7FF88-7239-4FC9-8FA2-07C950BE9C6D}") 1210 | ObjRelease(IAudioSessionControl) 1211 | 1212 | DllCall(NumGet(NumGet(IAudioSessionControl2+0)+14*A_PtrSize), "UPtr", IAudioSessionControl2, "UIntP", ProcessId, "UInt") 1213 | If (pid == ProcessId) 1214 | { 1215 | ISimpleAudioVolume := ComObjQuery(IAudioSessionControl2, "{87CE5498-68D6-44E5-9215-6DA47EF883D8}") 1216 | DllCall(NumGet(NumGet(ISimpleAudioVolume+0)+4*A_PtrSize), "UPtr", ISimpleAudioVolume, "FloatP", MasterVolume, "UInt") 1217 | ObjRelease(ISimpleAudioVolume) 1218 | } 1219 | ObjRelease(IAudioSessionControl2) 1220 | } 1221 | ObjRelease(IAudioSessionEnumerator) 1222 | 1223 | Return Round(MasterVolume * 100) 1224 | } 1225 | 1226 | SetAppVolume(pid, MasterVolume) ; WIN_V+ 1227 | { 1228 | IMMDeviceEnumerator := ComObjCreate("{BCDE0395-E52F-467C-8E3D-C4579291692E}", "{A95664D2-9614-4F35-A746-DE8DB63617E6}") 1229 | DllCall(NumGet(NumGet(IMMDeviceEnumerator+0)+4*A_PtrSize), "UPtr", IMMDeviceEnumerator, "UInt", 0, "UInt", 1, "UPtrP", IMMDevice, "UInt") 1230 | ObjRelease(IMMDeviceEnumerator) 1231 | 1232 | VarSetCapacity(GUID, 16) 1233 | DllCall("Ole32.dll\CLSIDFromString", "Str", "{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}", "UPtr", &GUID) 1234 | DllCall(NumGet(NumGet(IMMDevice+0)+3*A_PtrSize), "UPtr", IMMDevice, "UPtr", &GUID, "UInt", 23, "UPtr", 0, "UPtrP", IAudioSessionManager2, "UInt") 1235 | ObjRelease(IMMDevice) 1236 | 1237 | DllCall(NumGet(NumGet(IAudioSessionManager2+0)+5*A_PtrSize), "UPtr", IAudioSessionManager2, "UPtrP", IAudioSessionEnumerator, "UInt") 1238 | ObjRelease(IAudioSessionManager2) 1239 | 1240 | DllCall(NumGet(NumGet(IAudioSessionEnumerator+0)+3*A_PtrSize), "UPtr", IAudioSessionEnumerator, "UIntP", SessionCount, "UInt") 1241 | Loop % SessionCount 1242 | { 1243 | DllCall(NumGet(NumGet(IAudioSessionEnumerator+0)+4*A_PtrSize), "UPtr", IAudioSessionEnumerator, "Int", A_Index-1, "UPtrP", IAudioSessionControl, "UInt") 1244 | IAudioSessionControl2 := ComObjQuery(IAudioSessionControl, "{BFB7FF88-7239-4FC9-8FA2-07C950BE9C6D}") 1245 | ObjRelease(IAudioSessionControl) 1246 | 1247 | DllCall(NumGet(NumGet(IAudioSessionControl2+0)+14*A_PtrSize), "UPtr", IAudioSessionControl2, "UIntP", ProcessId, "UInt") 1248 | If (pid == ProcessId) 1249 | { 1250 | ISimpleAudioVolume := ComObjQuery(IAudioSessionControl2, "{87CE5498-68D6-44E5-9215-6DA47EF883D8}") 1251 | DllCall(NumGet(NumGet(ISimpleAudioVolume+0)+3*A_PtrSize), "UPtr", ISimpleAudioVolume, "Float", MasterVolume/100.0, "UPtr", 0, "UInt") 1252 | ObjRelease(ISimpleAudioVolume) 1253 | } 1254 | ObjRelease(IAudioSessionControl2) 1255 | } 1256 | ObjRelease(IAudioSessionEnumerator) 1257 | } 1258 | 1259 | : 1260 | WinGet, pid, PID, A 1261 | SetAppVolume(pid, 100 - GetAppVolume(pid)) 1262 | return 1263 | -------------------------------------------------------------------------------- /Plugins/MicrosoftExcel/InputColor.ahk: -------------------------------------------------------------------------------- 1 | /* 2 | 颜色选择器:弹出菜单由用户选择颜色,返回值为16进制rgb颜色值 3 | color 可被传递给调用者 4 | default 用户按下ESC时的默认颜色值 5 | 注意:Excel使用BGR格式色值,使用前请用ToBGR转换 6 | 7 | 2013-12-26 杜立涛 8 | ----------------------- 9 | 初步创建,后续计划: 10 | * 提供更多标准颜色 11 | * 在颜色方块上标准A-Z导航--希望能有高手认领此任务 12 | 13 | */ 14 | InputColor(ByRef color) 15 | { 16 | color = null 17 | Menu, MyMenu, Add, [&T]ransparent, MenuHandler 18 | Menu, MyMenu, Add, [&H]Black, MenuHandler 19 | Menu, MyMenu, Add, [&W]White, MenuHandler 20 | Menu, MyMenu, Add, [&C]Gray, MenuHandler 21 | Menu, MyMenu, Add, [&R]ed, MenuHandler 22 | Menu, MyMenu, Add, [&O]range, MenuHandler 23 | Menu, MyMenu, Add, [&Y]ellow, MenuHandler 24 | Menu, MyMenu, Add, [&G]reen, MenuHandler 25 | Menu, MyMenu, Add, [&B]lue, MenuHandler 26 | Menu, MyMenu, Add, [&P]urple, MenuHandler 27 | 28 | Menu, MyMenu, Show, 500, 300 29 | return ; 脚本的自动运行段结束. 30 | 31 | MenuHandler: 32 | if A_ThisMenuItem = [&T]ransparent 33 | color = Transparent 34 | else if A_ThisMenuItem = [&H]Black 35 | color := 0x000000 36 | else if A_ThisMenuItem = [&W]White 37 | color := 0xffffff 38 | else if A_ThisMenuItem = [&C]Gray 39 | color := 0x545454 40 | else if A_ThisMenuItem = [&R]ed 41 | color := 0xff0000 42 | else if A_ThisMenuItem = [&O]range 43 | color := 0xe47833 44 | else if A_ThisMenuItem = [&Y]ellow 45 | color := 0xffff00 46 | else if A_ThisMenuItem = [&G]reen 47 | color := 0x00ff00 48 | else if A_ThisMenuItem = [&B]lue 49 | color := 0x0000ff 50 | else if A_ThisMenuItem = [&P]urple 51 | color := 0x9932cd 52 | else 53 | color = null 54 | return 55 | } 56 | 57 | ;为什么有这个方法? 58 | ; --Microsoft Excel使用的颜色值为BGR 59 | ;将RGB颜色值转换为BGR颜色值 60 | ;该函数同样可以将BGR颜色值转换为RGB颜色值 61 | ToBGR( color ) 62 | { 63 | 64 | RedByte := ( color & 0xFF0000 ) >> 16 65 | 66 | GreenByte := color & 0x00FF00 67 | 68 | BlueByte := ( color & 0x0000FF ) << 16 69 | 70 | return BlueByte | GreenByte | RedByte 71 | 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /Plugins/MicrosoftExcel/readme.ini: -------------------------------------------------------------------------------- 1 | [Plugin] 2 | ;插件基本信息 3 | Name=VIM Mode AT EXCEL 4 | Comment=在Excel应用程序中应用VIM模式 5 | Author=多爱英,杜立涛,北溟其它提交者自行跟帖 6 | Version=2014-1-9 7 | Url=https://github.com/victorwoo/vimdesktop/blob/master/src/VimDesktop/Plugins/MicrosoftExcel/MicrosoftExcel.ahk 8 | 9 | [Help] 10 | ;简单实用帮助 11 | 关于模式: 12 | * 默认打开即为normal模式 13 | * i 进入insert模式 14 | * ESC 返回normal模式 15 | 16 | normal模式下默认常用快捷键: 17 | * h/l/j/k 方向导航 18 | * H/L/J/K选择导航 19 | * u/ctrl+z 撤销、重做 20 | * ... 更多热键,通过VimDesktop--显示热键 21 | 22 | 23 | 24 | ;=====Microsoft Excel快捷键配置============= 25 | ;自定义快捷键: 26 | ; * 请将下面代码拷贝至vimd.ini中并自行修改:注意此处代码仅进行示例,修改无效 27 | ; * 更多功能,通过VimDesktop--显示热键 28 | [XLMAIN] 29 | 30 | ;进入insert模式,正常使用Excel:默认为i,可修改为其它快捷键 31 | i=[=normal] 32 | 33 | 34 | 35 | [Log] 36 | ;更新日志--倒序排列 37 | ;更新注意事项--Excel的操作请优先使用默认的快捷键实现,通过vba操作时将无法执行撤销操作 38 | 2014-1-9 @北冥 39 | 根据vim命令+对象的模式对excel模块做了大的改动 40 | 1、一些可以用excel本身完成且用vimd不宜实现或占用大量快捷键的,均通过excel本身实现 41 | 比如查找是^f,这个没必要映射。另外2007版以上均支持alt键调用命令,这个对一些很不常用的功能可以满足需要 42 | 用alt命令时请确保处于insert模式,不然会与vimd-excel冲突 43 | 2、新增I模式,进入insert模式并输入alt,然后直接键入命令即可 44 | 3、命令主要包括 45 | Z保存与退出 46 | d删除 47 | o插入 48 | s选择 49 | f过滤命令 50 | p粘贴 51 | space翻页 52 | x剪切 53 | y复制 54 | g位置跳转 55 | F填充 56 | r重命名/替换 57 | w宽高/W指定值 58 | `字体命令 59 | (名称 60 | /查找 61 | 4、对象主要包括:r=row行,c=colomn列,w=worksheet表 62 | 5、同一字母重复与大写是同一个作用,都是那类最常用的功能,比如D=dd=Delete 63 | 操作时请使用命令+对象,比如dr删除一行,dc删除一列,sr选择一行,sc选择一列 64 | 65 | 2013-12-30 @杜立涛 66 | ---------------------- 67 | 68 | 靠拢Vim: 69 | * i 进入insert模式 70 | * iu/id/il/ir 调整为F + hjkl 71 | 72 | 填充颜色改进: 73 | * ' 填充字体颜色 74 | * ; 填充表格 75 | * " 同时用上次颜色填充颜色和表格 76 | * 颜色值增加为:透明、黑、白、灰、红、橙、黄、绿、蓝、紫 77 | 78 | 完善跳转类方法: 79 | * gg/G 跳转至工作区首尾 80 | * grh/gre 跳转至当前列首行、尾行 81 | * gch/gce 跳转至当前行首列、尾列 82 | * gj/gk/gh/gl 跳转至当前工作区的四个边缘 83 | * gJ/gK/gH/gL 选择至当前工作区的四个边缘 84 | 85 | 2013-12-26 @杜立涛 86 | ---------------------- 87 | * 修复工作表重命名Bug 88 | * go 可输入行列值跳转到指定的表格 89 | * ZZ 保存退出 90 | * ZQ 放弃修改退出 91 | * ys/yy/yc 复制功能 92 | * p/P 粘贴功能 93 | 94 | 2013-12-24 @杜立涛 95 | --------------------- 96 | * 测试整理多爱英提供的Excel插件,修正bug 97 | * 添加u/^z,调整选择导航为H/L/J/K,增加h/l/j/k为方向导航 98 | * 使用快捷键替代部分使用vba实现的操作:删除行、隐藏行等 99 | -------------------------------------------------------------------------------- /Plugins/Plugins.ahk: -------------------------------------------------------------------------------- 1 | #include *i %A_ScriptDir%\plugins\BeyondCompare4\BeyondCompare4.ahk 2 | #include *i %A_ScriptDir%\plugins\DoubleCommander\DoubleCommander.ahk 3 | #include *i %A_ScriptDir%\plugins\Explorer\Explorer.ahk 4 | #include *i %A_ScriptDir%\plugins\Foobar2000\Foobar2000.ahk 5 | #include *i %A_ScriptDir%\plugins\General\General.ahk 6 | #include *i %A_ScriptDir%\plugins\MicrosoftExcel\MicrosoftExcel.ahk 7 | #include *i %A_ScriptDir%\plugins\TCCompare\TCCompare.ahk 8 | #include *i %A_ScriptDir%\plugins\TCDialog\TCDialog.ahk 9 | #include *i %A_ScriptDir%\plugins\TotalCommander\TotalCommander.ahk 10 | #include *i %A_ScriptDir%\plugins\WinMerge\WinMerge.ahk 11 | /* 12 | [ExtensionsTime] 13 | BeyondCompare4=20160624155836 14 | DoubleCommander=20200601232105 15 | Explorer=20200213135938 16 | Foobar2000=20200415143434 17 | General=20200531141557 18 | MicrosoftExcel=20180422004419 19 | TCCompare=20200213135938 20 | TCDialog=20200213135938 21 | TotalCommander=20200601194451 22 | WinMerge=20160624155836 23 | */ 24 | -------------------------------------------------------------------------------- /Plugins/Readme.txt: -------------------------------------------------------------------------------- 1 | 如果需要增加新插件,请在此目录新增 插件名/插件名.ahk 文件。添加后,重启 vimd 可自动生效。 2 | -------------------------------------------------------------------------------- /Plugins/TCCompare/TCCompare.ahk: -------------------------------------------------------------------------------- 1 | ; Total Commander 内置的文件比较工具 2 | 3 | TCCompare: 4 | ; 定义注释 5 | vim.comment("", "进入normal模式") 6 | vim.comment("", "进入insert模式") 7 | vim.comment("", "下一处不同") 8 | vim.comment("", "上一处不同") 9 | vim.comment("", "跳转到文件开头") 10 | vim.comment("", "跳转到文件结尾") 11 | vim.comment("", "搜索内容") 12 | vim.comment("", "复制到左侧") 13 | vim.comment("", "复制到右侧") 14 | vim.comment("", "进入可编辑模式") 15 | vim.comment("", "重新比较") 16 | vim.comment("", "进入二进制比较模式") 17 | vim.comment("", "修改所使用的文件编码") 18 | 19 | vim.SetWin("TCCompare", "TFileCompForm") 20 | 21 | ; insert模式 22 | vim.mode("insert", "TCCompare") 23 | 24 | vim.map("", "", "TCCompare") 25 | 26 | ; normal模式 27 | vim.mode("normal", "TCCompare") 28 | 29 | vim.map("i", "", "TCCompare") 30 | 31 | vim.map("", "", "TCCompare") 32 | 33 | vim.map("j", "", "TCCompare") 34 | vim.map("k", "", "TCCompare") 35 | vim.map("n", "", "TCCompare") 36 | vim.map("p", "", "TCCompare") 37 | vim.map("gg", "", "TCCompare") 38 | vim.map("G", "", "TCCompare") 39 | vim.map("/", "", "TCCompare") 40 | vim.map("h", "", "TCCompare") 41 | vim.map("l", "", "TCCompare") 42 | vim.map("m", "", "TCCompare") 43 | vim.map("c", "", "TCCompare") 44 | vim.map("b", "", "TCCompare") 45 | vim.map("-", "", "TCCompare") 46 | return 47 | 48 | 49 | /* 50 | ; 对符合条件的控件使用insert模式,而不是normal模式 51 | ; 此段代码可以直接复制,但请修改AHK_CLASS的值和RegExMatch的第二个参数 52 | TCCompare_CheckMode() 53 | { 54 | ControlGetFocus, ctrl, AHK_CLASS TCCompare 55 | ; msgbox, ctrl 56 | if RegExMatch(ctrl, "Edit1") 57 | return true 58 | return false 59 | } 60 | */ 61 | 62 | : 63 | vim.mode("normal", "TCCompare") 64 | return 65 | 66 | : 67 | vim.mode("insert", "TCCompare") 68 | return 69 | 70 | : 71 | Send, !n 72 | return 73 | 74 | : 75 | Send, !p 76 | return 77 | 78 | : 79 | Send, ^{home} 80 | return 81 | 82 | : 83 | Send, ^{end} 84 | return 85 | 86 | : 87 | Send, ^f 88 | return 89 | 90 | : 91 | Send, !+< 92 | return 93 | 94 | : 95 | Send, !+> 96 | return 97 | 98 | : 99 | Send, !m 100 | return 101 | 102 | : 103 | Send, !c 104 | return 105 | 106 | : 107 | Send, !b 108 | return 109 | 110 | : 111 | Send, !- 112 | return 113 | -------------------------------------------------------------------------------- /Plugins/TCDialog/Readme.md: -------------------------------------------------------------------------------- 1 | ## 帮助 2 | 3 | ### 可用命令 4 | * ``:打开 TC 进行文件选择,默认绑定到 `Win + o` 5 | 6 | ### 快捷键 7 | * `Win + o`:在文件对话框或任意文字编辑界面按下快捷键跳转至 TC,再次按下快捷键选择当前文件(或已选文件)返回调用者 8 | * `Esc`:离开 TC,回到调用者 9 | * `Shift + 回车`: 当前目录返回调用者(一般用于保存文件) 10 | 11 | ## 更新历史 12 | 13 | ``` 14 | 2020-06-03 @陌辞寒 15 | -------------------------- 16 | 去除自动跳转功能,简化按键绑定。因为之前用法复杂、容易出问题,我几乎不用。现在改简单些,可以会用一用。 17 | 18 | 2016-04-14 @杜立涛 19 | -------------------------- 20 | 优化将当前目录返回调用方的实现方法:方便保存文件时改名 21 | 修正路径名过长时,选定文件的字符串被截断的问题: 22 | * 第一步:粘贴文件夹路径,回车 23 | * 第二部:粘贴不带路径的文件名,回车 24 | 25 | 2016-02-23 @陌辞寒 26 | -------------------------- 27 | 不再新增 select 模式,改为重新映射快捷键,返回调用方前再清除快捷键,绕过 normal 模式下快捷键依然有效的 bug 28 | 支持将当前目录返回调用方(用于保存文件对话框) 29 | 30 | 2014-08-08 @杜立涛 31 | -------------------------- 32 | 跳过对标题栏为空的文件选择对话框——如 Eclipse 的已打开文件的列表 33 | 34 | 2014-03-12 @杜立涛 35 | -------------------------- 36 | 初步实现,并增加帮助说明 37 | ``` 38 | -------------------------------------------------------------------------------- /Plugins/TCDialog/TCDialog.ahk: -------------------------------------------------------------------------------- 1 | TCDialog: 2 | ; 用于记录文件打开对话框所属窗体 3 | global CallerId := 0 4 | 5 | global vim 6 | 7 | vim.Comment("", "用 TC 选择文件或者目录") 8 | 9 | return 10 | 11 | : 12 | vim.Mode("normal", "TTOTAL_CMD") 13 | vim.Map("", "", "TTOTAL_CMD") 14 | vim.Map("", "", "TTOTAL_CMD") 15 | return 16 | 17 | : 18 | vim.Mode("normal", "TTOTAL_CMD") 19 | vim.Map("", "", "TTOTAL_CMD") 20 | vim.Map("", "", "TTOTAL_CMD") 21 | return 22 | 23 | ; 返回调用者 24 | : 25 | gosub 26 | 27 | WinActivate, ahk_id %CallerId% 28 | 29 | CallerId := 0 30 | return 31 | 32 | ; 非 TC 窗口按下后激活 TC 窗口 33 | ; TC 窗口按下后复制当前选中文件返回原窗口后粘贴 34 | : 35 | WinGetClass, name, A 36 | 37 | ; 在Total Commander 按下快捷键时,激活调用窗体并执行粘贴操作 38 | if (name == "TTOTAL_CMD") { 39 | if (CallerId != 0) { 40 | gosub 41 | CallerId := 0 42 | } 43 | } else { 44 | CallerId := WinExist("A") 45 | if (CallerId == 0) { 46 | return 47 | } 48 | 49 | gosub 50 | gosub 51 | } 52 | return 53 | 54 | : 55 | gosub 56 | 57 | Clipboard := "" 58 | gosub 59 | ClipWait 60 | pwd := Clipboard 61 | 62 | Clipboard := "" 63 | gosub 64 | ClipWait 65 | 66 | WinActivate, ahk_id %CallerId% 67 | WinWait, ahk_id %CallerId% 68 | CallerId := 0 69 | 70 | if (!InStr(Clipboard, "`n")) { 71 | Clipboard := pwd . "\" . Clipboard 72 | Send, {Home} 73 | Send, ^v 74 | Send, {Enter} 75 | 76 | return 77 | } 78 | 79 | ; 多选 80 | 81 | files := "" 82 | Loop, parse, Clipboard, `n, `r 83 | files .= """" . A_LoopField . """ " 84 | 85 | ; 第一步:跳转到当前路径 86 | Clipboard := pwd 87 | Send, ^a 88 | Send, ^v 89 | Send, {Enter} 90 | sleep, 100 91 | 92 | ; 第二步:提交文件名 93 | Clipboard := files 94 | Send, ^v 95 | Send, {Enter} 96 | return 97 | 98 | : 99 | gosub 100 | 101 | if (callerId == 0) { 102 | return 103 | } 104 | 105 | Clipboard := "" 106 | gosub 107 | ClipWait 108 | 109 | ; 添加默认路径不带反斜杠,添加之 110 | Clipboard .= "\" 111 | 112 | WinActivate, ahk_id %CallerId% 113 | WinWait, ahk_id %CallerId% 114 | CallerId := 0 115 | 116 | Send, {Home} 117 | Send, ^v 118 | Send, {Enter} 119 | return 120 | -------------------------------------------------------------------------------- /Plugins/TotalCommander/GenerateCommands.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | all=$1 4 | chn=$2 5 | 6 | (($# == 2)) || { 7 | all=/mnt/c/mine/app/totalcmd/Totalcmd.inc 8 | chn=/mnt/c/mine/app/totalcmd/Language/Wcmd_chn.inc 9 | } 10 | 11 | cat $all | grep '^cm_' | sed 's/=\(.*\);.*/\n\1/g' > cmdlist.txt 12 | cat $chn | iconv -f gbk -t utf-8 | grep '^[0-9]\+=' | sed "s/\r$//g" > chn.zsh 13 | 14 | . ./chn.zsh 15 | 16 | { 17 | echo -n '\xEF\xBB\xBF' 18 | echo TCCommand: 19 | 20 | while {read name; read pos} { 21 | [[ -n ${(P)pos} ]] && echo " vim.Comment(\"<$name>\", \"${(P)pos}\")" 22 | } < cmdlist.txt 23 | 24 | cat <:\n SendPos($pos)\nreturn\n" 35 | } < cmdlist.txt 36 | } > TCCommand.ahk 37 | 38 | rm cmdlist.txt chn.zsh 39 | -------------------------------------------------------------------------------- /Plugins/TotalCommander/a-zhistory.icl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goreliu/vimdesktop/eff9f52f41be39185c8d894b058785617a655c34/Plugins/TotalCommander/a-zhistory.icl -------------------------------------------------------------------------------- /Plugins/WinMerge/WinMerge.ahk: -------------------------------------------------------------------------------- 1 | WinMerge: 2 | ; 定义注释 3 | vim.comment("", "进入normal模式") 4 | vim.comment("", "进入insert模式") 5 | vim.comment("", "下一处不同") 6 | vim.comment("", "上一处不同") 7 | vim.comment("", "第一处不同") 8 | vim.comment("", "最后一处不同") 9 | vim.comment("", "打开搜索窗口") 10 | vim.comment("", "复制到左侧") 11 | vim.comment("", "复制到右侧") 12 | vim.comment("", "复制到左侧并继续") 13 | vim.comment("", "复制到右侧并继续") 14 | vim.comment("", "全部复制到左侧") 15 | vim.comment("", "全部复制到右侧") 16 | 17 | vim.SetWin("WinMerge", "WinMergeWindowClassW") 18 | 19 | ; insert模式 20 | vim.mode("insert", "WinMerge") 21 | 22 | vim.map("", "", "WinMerge") 23 | vim.map("", "", "WinMerge") 24 | 25 | ; normal模式 26 | vim.mode("normal", "WinMerge") 27 | 28 | vim.map("i", "", "WinMerge") 29 | 30 | vim.map("", "", "WinMerge") 31 | 32 | vim.map("j", "", "WinMerge") 33 | vim.map("k", "", "WinMerge") 34 | vim.map("gg", "", "WinMerge") 35 | vim.map("G", "", "WinMerge") 36 | vim.map("/", "", "WinMerge") 37 | vim.map("h", "", "WinMerge") 38 | vim.map("l", "", "WinMerge") 39 | vim.map("H", "", "WinMerge") 40 | vim.map("L", "", "WinMerge") 41 | vim.map("", "", "WinMerge") 42 | vim.map("", "", "WinMerge") 43 | return 44 | 45 | /* 46 | ; 对符合条件的控件使用insert模式,而不是normal模式 47 | ; 此段代码可以直接复制,但请修改AHK_CLASS的值和RegExMatch的第二个参数 48 | WinMerge_CheckMode() 49 | { 50 | ControlGetFocus, ctrl, AHK_CLASS WinMerge 51 | ; msgbox, ctrl 52 | If RegExMatch(ctrl, "Afx") 53 | return true 54 | return false 55 | } 56 | */ 57 | 58 | : 59 | vim.mode("normal", "WinMerge") 60 | return 61 | 62 | : 63 | vim.mode("insert", "WinMerge") 64 | return 65 | 66 | : 67 | Send, !{down} 68 | return 69 | 70 | : 71 | Send, !{up} 72 | return 73 | 74 | : 75 | Send, !{home} 76 | return 77 | 78 | : 79 | Send, !{end} 80 | return 81 | 82 | : 83 | Send, ^f 84 | return 85 | 86 | : 87 | Send, !{left} 88 | return 89 | 90 | : 91 | Send, !{right} 92 | return 93 | 94 | : 95 | Send, ^!{left} 96 | return 97 | 98 | : 99 | Send, ^!{right} 100 | return 101 | 102 | : 103 | Send, !my 104 | return 105 | 106 | : 107 | Send, !ma 108 | return 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ![icon](Doc/Images/vimdesktop_32.jpg) VimDesktop 2 | 3 | 让所有 Windows 桌面程序拥有 Vim 操作风格的辅助工具。 4 | 5 | ### 链接 6 | 7 | [详细介绍](https://github.com/goreliu/vimdesktop/wiki) 8 | 9 | [Introduction](https://github.com/goreliu/vimdesktop/wiki/VimDesktop-Introduction) 10 | 11 | [下载地址](https://github.com/goreliu/vimdesktop/releases/latest) 12 | 13 | [文档首页](https://github.com/goreliu/vimdesktop/wiki) 14 | 15 | [TC 快捷键列表](https://github.com/goreliu/vimdesktop/wiki/TC%E5%BF%AB%E6%8D%B7%E9%94%AE%E5%88%97%E8%A1%A8) 16 | 17 | [API 列表](https://github.com/goreliu/vimdesktop/wiki/API%E5%88%97%E8%A1%A8) 18 | 19 | [更新历史](https://github.com/goreliu/vimdesktop/wiki/HISTORY) 20 | 21 | ### VimDesktop 历史 22 | 23 | VimDesktop 的前身是 [linxinhong](http://git.oschina.net/linxinhong) 的 ViATc (现已停止更新):[github地址](https://github.com/linxinhong/ViATc) [sourceforge地址](https://sourceforge.net/p/viatc/home/%E4%B8%BB%E9%A1%B5/) 24 | 25 | 之后 [linxinhong](http://git.oschina.net/linxinhong) 将其升级为 [VimDesktop 1](https://github.com/victorwoo/vimdesktop),该版本由 [linxinhong](http://git.oschina.net/linxinhong)、[victorwoo](https://github.com/victorwoo)、[wideweide](https://github.com/wideweide) 等人协同开发。 26 | 27 | 再之后 [linxinhong](http://git.oschina.net/linxinhong) 又将其升级为 [VimDesktop 2](http://git.oschina.net/linxinhong/VimDesktop),2版本的核心文件和1版本相比改动较大,配置文件格式也有所不同。 28 | 29 | 目前 [linxinhong](http://git.oschina.net/linxinhong) 将主要精力放在 [QuickZ](http://git.oschina.net/linxinhong/QuickZ) 上, [VimDesktop 2](http://git.oschina.net/linxinhong/VimDesktop) 已有较长时间没有更新。 30 | 31 | ### 此版本 VimDesktop 的历史和缘由 32 | 33 | 我 2016 年 1 月接触到的 VimDesktop,当时在网上搜到了两个版本的 VimDesktop,如上所述。我分别试用后感觉 [VimDesktop 1](https://github.com/victorwoo/vimdesktop) 版本的好用些,主要是 `TotalCommander_Dialog` 插件很有用,配置文件也更方便些,当时并未考虑过修改代码。但使用过程中慢慢发现一些问题,或者有功能缺失,改了很多代码。修改过程中,发现这个版本的核心文件 `lib/vimcore.ahk` 缺陷比较多,功能也相对薄弱,而 [VimDesktop 2](http://git.oschina.net/linxinhong/VimDesktop) 的`lib/class_vim.ahk` 是 `lib/vimcore.ahk` 的升级版,功能更强大,缺陷也少些。于是改用 [VimDesktop 2](http://git.oschina.net/linxinhong/VimDesktop) 的部分核心文件,而插件部分还是沿用之前的代码,除了必要的兼容性改动。 34 | 35 | 此版本包含 [VimDesktop 1](https://github.com/victorwoo/vimdesktop) 和 [VimDesktop 2](http://git.oschina.net/linxinhong/VimDesktop) 的全部功能。 36 | 37 | 2020 年起,我不再发布新版本,不再保证原有功能继续保留,不再保证配置的向后兼容性,不再回答任何功能相关问题,不再维护文档,我会根据自己的需求随意修改代码,请不要随意更新。因为很多陈旧代码的功能我并不需要,也无力测试,放在那里会让软件的维护变得十分困难,所以我已经几年时间没有大改了。为了让这个软件继续活下去(即使只有我一个人用),我必须放弃向后兼容的包袱,大刀阔斧地修改。另外我已经用 [Double Commander](https://doublecmd.sourceforge.io/) 替代了 [Total Commander](https://www.ghisler.com/),所以不再维护 TC 插件(但不会删除代码)。而我写的 DC 插件,依赖 DC 本身的代码修改和配置定制,仅供自用。 38 | 39 | 如果有人想维护该软件的公共版本,可以通过 ly50247@126.com 联系我。 40 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | latest 2 | -------------------------------------------------------------------------------- /VimD.ahk: -------------------------------------------------------------------------------- 1 | #NoEnv 2 | #SingleInstance, Force 3 | #MaxHotkeysPerInterval 200 4 | 5 | CoordMode, Tooltip, Screen 6 | CoordMode, Mouse, Screen 7 | CoordMode, Menu, Window 8 | SetControlDelay, -1 9 | SetKeyDelay, -1 10 | ; DetectHiddenWindows, On 11 | FileEncoding, UTF-8 12 | SendMode, Input 13 | 14 | Menu, Tray, Icon, %A_ScriptDir%\vimd.ico 15 | Menu, Tray, NoStandard 16 | Menu, Tray, Add, 热键 &K, 17 | Menu, Tray, Add, 插件 &P, 18 | Menu, Tray, Add, 配置 &C, 19 | Menu, Tray, Add, 20 | Menu, Tray, Add, 禁用 &S, 21 | Menu, Tray, Add, 重启 &R, 22 | Menu, Tray, Add, 退出 &X, 23 | Menu, Tray, Default, 热键 &K 24 | Menu, Tray, Click, 1 25 | 26 | VimdRun() 27 | 28 | return 29 | 30 | #Include %A_ScriptDir%\core\Main.ahk 31 | #Include %A_ScriptDir%\core\Vim.ahk 32 | #Include %A_ScriptDir%\core\VimDConfig.ahk 33 | #Include %A_ScriptDir%\lib\EasyIni.ahk 34 | #Include %A_ScriptDir%\lib\Acc.ahk 35 | #Include %A_ScriptDir%\lib\GDIP.ahk 36 | #Include %A_ScriptDir%\lib\Logger.ahk 37 | #Include %A_ScriptDir%\plugins\Plugins.ahk 38 | ; 用户自定义配置 39 | #Include *i %A_ScriptDir%\custom.ahk 40 | -------------------------------------------------------------------------------- /VimD.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goreliu/vimdesktop/eff9f52f41be39185c8d894b058785617a655c34/VimD.ico --------------------------------------------------------------------------------