1 (изменено: Androgen, 2007-03-16 13:05:25)

Тема: AHK. Открыть в Total Commander'е (пункт контекстного меню и не только)

Гислер следит за мной! К такому параноидальному и маниявеличному выводу я пришел после того, как он внедрил в Тотал уже пятую фишку, которую я реализовал скриптами. Вот и сейчас: не успел я как следует погонять предлагаемый ниже скрипт, как он р-раз, и вроде как добавил его функционал в ТС. Правда, работает этот функционал в Тотале из рук вон плохо. Надеюсь, этот добрый мужчина доведёт фишку до ума. Но поскольку ждать этого можно долго, то скрипт я решил всё же выложить.
Короче, идея скрипта такая: во многих прогах, работающих с файлами/папками, есть такой пункт "Открыть в Проводнике" (как бы он там ни назывался). Это здорово, но я Проводник недолюбливаю (мягко говоря), а Тотал - наоборот (и тоже, говоря мягко). Вот чтобы такая очень нужная (мне) возможность открытия была бы и для Тотала, я и накатал скриптец.
Его можно зарегистрировать в реестре (это необязательно, см. комменты в теле скрипта) и в контекстном меню всяких файлов/папок, появится пункт "Открыть в Total Commander'е" (название можно изменить). И при работе в каком нибудь приложении, (скажем, в ACDSee) можно этот пункт выбрать и откроется Тотал, а в нём курсор встанет на выбранный файл. Это очень удобно.
Другой вариант применения: скрипт можно поставить как внешний инструмент в те проги, которые позволяют это делать (ну, например, в Foobar) и опять таки открывать файлы в Тотале.
Третий вариант такой: можно повесить скрипт на кнопку в самом Тотале и (допустим, после результатов поиска) нажатием на кнопку открывать файл в противоположной панели. Или скопировать в буфер какой-нибудь путь откуда-нибудь, нажать кнопку в ТС и открыть его там, где хочется и как хочется. Под "открыть, где хочется" я имею в виду не запуск файла, а переход к нему в указанной панели. А под "как хочется" то, что дополнительно можно передавать команды, которые понимает Тотал. Например, переключиться на пользовательские колонки. Или даже выполнить какую-нибудь пользовательскую команду (ну те, что em_abc).
В общем, я нахожу скрипт рульным. Если его таким найдёте и вы - буду рад. А найдёте не рульным, а ошибку - дайте знать. Будут вопросы, комментарии - не стесняйтесь.

Скрипт нужно поместить рядом с Totalcmd.exe или в какую нибудь из подпапок (у меня, скажем, в папке с Тоталом есть папка AutoTotal, где я держу всякие скрипты для понятно чего). Чтобы добавить скрипт в контекстное меню файлов/папок, его нужно запустить с параметром /reg. Для удаления из контекстного меню, с параметром /unreg.

Примерчик добавления скрипта в качестве внешнего инструмента в FastStone Image Viewer (гляделка такая).
1. Кликаем правой кнопкой по рисунку и в конт. меню выбираем пункт "Правка во внешней программе" - "Добавить/удалить программу".
2. Жмём кнопку "добавить" и в появившееся поле вписываем путь к скрипту (путь нужно именно вписать, т.к. выбрать неоткомпилированный скрипт FastStone не позволит, но если его сюда вписать, или вставить, то всё будет ОК)
3. Даём название инструменту (то, какое хотите)
4. В "параметры" вписываем (filename) /O /T
5. Подтверждаем
Всё. Теперь можно нажать на рисунке E (английскую) и рисунок откроется в Тотале.

;*************************************************************************************************************
; AutoHotkey Version:        1.0.45.04+
; Автор:                     Androgen Belkin
; Имя скрипта:               OpenInTC.ahk (v.1.0)
; Total Commander Version:   7.0+
;*************************************************************************************************************
; Скрипт переходит в ТС по переданному пути. Может переходить по адресу, содержащемуся в буфере обмена.
; Путь передаётся в ком. строке, или берётся из буфера обмена (см. возможные параметры ниже).
; Если передана папка - она открывается в панели ТС (ТС и сам так может).
; Если передан файл - открывается родительская папка и курсор позиционируется на этот файл (а так не может).
; Переданный путь открывается в активной вкладке (если не указано иначе).

; Если командная строка передаётся в уже запущенный ТС и в нём открыто какое-либо модальное окно,
; то скрипт прервёт свою работу. Это сделано для того, чтобы не помешать работе ТС.

; Список возможных параметров (параметры нечувствительны к регистру):
;--------------- стандартные для ТС параметры ----------------------------------------------------------------
; /O  - используем запущенный ТС
; /N  - запускаем новый экземпляр TC (независимо от запрещающей это настройки ТС)
; /T  - открыть в новой вкладке,
; /L= - открыть в левой панели
; /R= - открыть в правой панели
; /i= - путь к wincmd.ini (если используется отличный от по умолчанию, например, i=.\MyProfile\MyWincmd.ini)
; /F= - путь к wcx_ftp.ini (если используется отличный от по умолчанию, например, f=.\MyProfile\Mywcx_ftp.ini)
;-------------------------------------------------------------------------------------------------------------
;--------------- дополнительные параметры скрипта ------------------------------------------------------------
; /CB или /ClipBoard - открыть путь, содержащийся в буфере
; /trg               - открыть в неактивной панели
; /reg               - добавить соответствующий пункт в конт. меню всех файлов и папок
; /unreg             - удалить соответствующий пункт из конт. меню всех файлов и папок
;*************************************************************************************************************

; ========== НАСТРОЙКИ ПОЛЬЗОВАТЕЛЯ ===============
TCParam = /O                 ; вписать сюда параметры, которые скрипт будет использовать по умолчанию
TotalCmd_Name = Totalcmd.exe ; на случай, если Totalcmd.exe зачем-то переименован
DebugIn = 0  ; вписать сюда число 1 для того, чтобы вместо открытия пути посмотреть ПОЛУЧЕННУЮ ком.строку
DebugOut = 0 ; вписать сюда число 1 для того, чтобы вместо открытия пути посмотреть ОБРАБОТАННУЮ ком.строку
NameInShell = Открыть в Total Commander'е ; имя для пункта контекстного меню
; ========== КОНЕЦ НАСТРОЕК ПОЛЬЗОВАТЕЛЯ ==========


#NoTrayIcon       ; не отображать значок скрипта в трее
#NoEnv            ; запрещаем имена переменных как у переменных окружения
SendMode Input    ; новый режим высылки без задержки и повышенной надежности
SetBatchLines, -1 ; указываем максимальную скорость для скрипта


; ПРОВЕРКА ПРАВИЛЬНОСТИ ПУТИ ЗАПУСКА СКРИПТА
SetWorkingDir, %A_ScriptDir% ; для начала ищем Totalcmd.exe в папке, где запущен этот скрипт
IfNotExist, %TotalCmd_Name% ; если в текущей папке НЕ найден Totalcmd.exe, то...
{
    SetWorkingDir, .. ; теперь ищем Totalcmd.exe в папке на уровень выше
    IfNotExist, %TotalCmd_Name% ; если и здесь НЕ найден Totalcmd.exe, то...
    {
        MsgBox, 64, Total Commander не найден!, ; показываем сообщение
        ( LTrim
        Скрипт следует поместить в папку, содержащую файл "%TotalCmd_Name%".
        Или в любую из её подпапок.
        )
        ExitApp ; конец скрипта
    }
}
TotalCmd_Path = %A_WorkingDir%\%TotalCmd_Name% ; запоминаем путь к Totalcmd.exe
; ПРОВЕРКА ВЕРСИИ ТС
FileGetVersion, TCVersion, %TotalCmd_Path% ; проверяем версию ТС
If TCVersion < 7.0
{
    MsgBox, 64, Внимание!, ; показываем сообщение
    ( LTrim
    Total Commander должен быть версии 7.0 или выше.
    Текущая версия %TCVersion%
    )
    ExitApp ; конец скрипта
}
; ПРОВЕРКА НАЛИЧИЯ ПЕРЕДАННЫХ ПАРАМЕТРОВ
If 0 = 0 ; если скрипт запущен без параметров
{
    SplashImage,, B1 CT000080,, Запускай меня с параметрами ; показать сообщение (чтоб не думалось)
    Sleep, 800
    ExitApp ; закончить скрипт
}
; ОТЛАДОЧНЫЙ БЛОК 1
If DebugIn ; если указано, что нужно показать полученную ком.строку
{
    Loop, %0% ; лопатим полученную ком. строку
        Param := Param A_Space %A_Index% ; соединяем все параметры через пробел
    MsgBox, Param=%Param% ; показываем полученную строку
    If NOT DebugOut ; если не нужно показывать ком. строку после обработки
        ExitApp ; закончить скрипт
}

; СОРТИРОВКА ПОЛУЧЕННЫХ ПАРАМЕТРОВ
IfInString, TCParam, /T ; если этот параметр задан в настройках скрипта как параметр по умолчанию
    NewTab := True ; будем открывать новую вкладку
Loop, %0% ; лопатим полученную ком. строку
{
    Param := %A_Index% ; берем каждый параметр (чтобы далее не париться с синтаксисом)
    If ( Param = "/reg" )
        Goto, RegInShell
    If ( Param = "/unreg" )
        Goto, UnRegInShell
    If ( Param = "/O" )
    {
        TCParam = %TCParam% %Param% ; добавляем полученный параметр
        Continue ; идём к следующему параметру
    }
    If ( Param = "/N" )
    {
        TCParam = %TCParam% %Param% ; добавляем полученный параметр
        Continue ; идём к следующему параметру
    }
    If ( InStr( Param, "i=" ) = 1 ) OR ( InStr( Param, "i=" ) = 2 ) ; если стоит в начале (или после "/")
    {
        TCParam = %TCParam% %Param% ; добавляем полученный параметр
        Continue ; идём к следующему параметру
    }
    If ( InStr( Param, "f=" ) = 1 ) OR ( InStr( Param, "f=" ) = 2 ) ; если стоит в начале (или после "/")
    {
        TCParam = %TCParam% %Param% ; добавляем полученный параметр
        Continue ; идём к следующему параметру
    }
    If ( Param = "/T" )
    {
        NewTab := True ; будем открывать новую вкладку
        Continue ; идём к следующему параметру
    }
    If ( Param = "/L" )
    {
        Left := True ; путь будем открывать слева
        Continue ; идём к следующему параметру
    }
    If ( Param = "/R" )
    {
        Right := True ; путь будем открывать справа
        Continue ; идём к следующему параметру
    }
    If ( Param = "/trg" )
    {
        Target := True ; путь будем открывать в неактивной панели
        Continue ; идём к следующему параметру
    }

    If ( InStr( Param, "L=" ) = 1 ) OR ( InStr( Param, "L=" ) = 2 ) ; если стоит в начале (или после "/")
    {
        StringTrimLeft, Received_Path, Param, InStr( Param, "L=" ) + 1 ; отрезаем идентификатор
        Left := True ; путь будем открывать слева
        Continue ; идём к следующему параметру
    }
    If ( InStr( Param, "R=" ) = 1 ) OR ( InStr( Param, "R=" ) = 2 ) ; если стоит в начале (или после "/")
    {
        StringTrimLeft, Received_Path, Param, InStr( Param, "R=" ) + 1 ; отрезаем идентификатор
        Right := True ; путь будем открывать справа
        Continue ; идём к следующему параметру
    }
    If ( InStr( Param, "cm_" ) = 1 ) ; если строка так начинается
    {
        TCExtCom = %TCExtCom% %Param% ; добавляем полученный параметр
        Continue ; идём к следующему параметру
    }
    If ( InStr( Param, "em_" ) = 1 ) ; если строка так начинается
    {
        TCExtCom = %TCExtCom% %Param% ; добавляем полученный параметр
        Continue ; идём к следующему параметру
    }
    If ( InStr( Param, "/ClipBoard" ) = 1 ) OR ( InStr( Param, "/cb" ) = 1 )  ; если строка так начинается
    {
        Received_Path := Clipboard ; берём путь из буфера
        Continue ; идём к следующему параметру
    }
    Else If NOT Received_Path ; если в параметре нет ни одного из вышеобработанных и путь не взят из буфера
        Received_Path := Param ; считаем полученную строку - путем
}
; ОТЛАДОЧНЫЙ БЛОК 2
If DebugOut ; если указано, что нужно показать полученную ком.строку
{
    MsgBox, 64, Ком. строка после обработки, ; показываем сообщение
    ( LTrim
    Received_Path=%Received_Path%
    TCParam=%TCParam%
    NewTab=%NewTab%
    TCExtCom=%TCExtCom%
    Left=%Left%
    Right=%Right%
    Clipboard=%Clipboard%
    )
    ExitApp
}

; ПРОВЕРКА СУЩЕСТВОВАНИЯ ПОЛУЧЕННОГО ПУТИ
StringRight, RightSymbol, Received_Path, 1 ; берем последний символ
If RightSymbol = \ ; если последний символ в строке бэкслэш "\", то...
    StringTrimRight Received_Path, Received_Path, 1 ; удалить последний символ ("\")
SplitPath, Received_Path, Received_FileName, Received_Dir ; берём родительскую папку
IfExist, %Received_Path% ; если полученный путь существует, то...
{
    If InStr( FileExist( Received_Path ), "D" ) ; если это - папка, то...
        Received_FileName = ; сбрасываем имя "файла"
    Else ; если это - файл
        Received_Path := Received_Dir ; сначала будем открывать родительскую папку
    Goto, OpenInTC ; перейти к открытию папки в ТС
}
IfNotExist, %Received_Dir% ; если и родительской папки не существует, то...
{
    SplashImage,, B1 CT000080,, Полученный путь не существует ; показать сообщение (чтоб не думалось)
    Sleep, 800
    ExitApp ; закончить скрипт
}

; ОТКРЫВАЕМ ПОЛУЧЕННЫЙ ПУТЬ В ТС
OpenInTC:
Process, Exist, %TotalCmd_Name% ; проверяем запущен ли ТС
If ErrorLevel AND InStr( TCParam, "/O" ) ; если уже запущен, и указано открывать в имеющемся
    WaitingTime = 2 ; ждать будем недолго
Else ; если ещё не запущен, или нужно запускать новый экземпляр
    WaitingTime = 5 ; ждать будем подольше
Run, "%TotalCmd_Path%" %TCParam% ; передаём TC параметры (запускаем, если нужно)
; Особенность открытия пути через ком. строку (не Тоталовскую) в том,
; что если не указано иначе, путь открывается в панели по умолчанию.
; Чтобы он открывался в активной панели, используется ControlSetText (см. ниже).
WinWaitActive, ahk_class TTOTAL_CMD,, %WaitingTime% ; ждем активации окна ТС указанное время
If ErrorLevel ; если не дождались окна
{
    MsgBox, Не дождались окна
    ExitApp ; закончить скрипт
}
WinGet, hw_TTOTAL_CMD, ID, ahk_class TTOTAL_CMD ; получить ID окна TC (последнего активного)
If Left ; если открывать нужно слева
    SendMessage, 1075, 4001,,, ahk_id %hw_TTOTAL_CMD% ; 4001=cm_FocusLeft (перейти на левую панель)
If Right ; если открывать нужно справа
    SendMessage, 1075, 4002,,, ahk_id %hw_TTOTAL_CMD% ; 4002=cm_FocusRight (перейти на правую панель)
; если не указано открывать слева или справа, открывать будем в активной панели
WinActivate, ahk_id %hw_TTOTAL_CMD%
ControlGetFocus, Active_Panel, ahk_id %hw_TTOTAL_CMD% ; определяем какая панель активна
If (Active_Panel != "TMyListBox1" AND Active_Panel != "TMyListBox2")
{
    MsgBox, Не активны панели Тотала
    ExitApp ; закончить скрипт
}
If Target ; если было указано открывать в противоположной панели
{
    If Active_Panel = TMyListBox1 ; если активна правая панель
    {
        SendMessage, 1075, 4001,,, ahk_id %hw_TTOTAL_CMD% ; 4001=cm_FocusLeft переходим на левую панель
        Active_Panel = TMyListBox2 ; будем читать другую панель

    }
    Else
    {
        SendMessage, 1075, 4002,,, ahk_id %hw_TTOTAL_CMD% ; 4002=cm_FocusRight переходим на правую панель
        Active_Panel = TMyListBox1 ; будем читать другую панель
    }
}
If NewTab ; если было указано открывать новую вкладку
    SendMessage, 1075, 3001,,, ahk_id %hw_TTOTAL_CMD% ; 3001=cm_OpenNewTab (открываем новую вкладку)
ControlSetText, Edit1, cd %Received_Path%, ahk_id %hw_TTOTAL_CMD% ; вбиваем путь в ком. строку
ControlSend, Edit1, {Enter}, ahk_id %hw_TTOTAL_CMD% ; открываем папку
; 4 действия ниже нужны для того, чтобы привести открытую панель к виду
; из которого можно правильно получить список файлов
SendMessage, 1075, 302,,, ahk_id %hw_TTOTAL_CMD% ; 302=cm_SrcLong (вид - подробный)
SendMessage, 1075, 312,,, ahk_id %hw_TTOTAL_CMD% ; 312=cm_SrcAllFiles (вид - все файлы)
SendMessage, 1075, 325,,, ahk_id %hw_TTOTAL_CMD% ; 325=cm_SrcUnsorted (без сортировки)
SendMessage, 1075, 321,,, ahk_id %hw_TTOTAL_CMD% ; 321=cm_Sort by name (сортировать по имени)

If Received_FileName ; если был получен файл (а не папка)
{
    ControlGet, RawList, List,, %Active_Panel%, ahk_id %hw_TTOTAL_CMD% ; получаем список из активной панели
    Loop, Parse, RawList, `n ; обработать полученный список
    {
        IfInString, A_LoopField, %A_Space%< ; если текущий пункт - папка, то...
            Continue ; ищем дальше
        Else ; если текущий пункт - файл, то...
        {
            CurName := A_LoopField ; запоминаем обрабатываемую строку
            Loop, 5 ; будем отсчитывать 5-й справа пробел
            {
                ; отбрасываем последнее поле
                StringLeft, CurName, CurName, InStr( CurName, A_Space, False, 0 ) - 1
                If A_Index = 3 ; готовы проверять 4-е поле
                {
                    Check_nbsp := SubStr(CurName, InStr( CurName, A_Space, False, 0 ) +1 ) ; берём 4-е поле
                    If InStr( Check_nbsp, Chr(160) ) ; если в нём есть неразрывный пробел
                    ; (он может здесь быть, если ТС показывает размер в байтах)
                    {
                        ; отбрасываем последнее поле
                        StringLeft, CurName, CurName, InStr( CurName, A_Space, False, 0 ) - 1
                        Break ; больше лопатить не будем
                    }
                }
            }
        }
        If CurName = %Received_FileName% ; если дошли до искомого файла
        {
            SendMessage, 0x19e, A_Index-1, 0, %Active_Panel%, ahk_id %hw_TTOTAL_CMD% ; ставим курсор на файл
            ; 0x19e=LB_SETCARETINDEX, -1=отсчет идет с нуля
            Break ; выходим из цикла
        }
    }
}
; ОБРАБОТКА ДОПОЛНИТЕЛЬНЫХ (ВОЗМОЖНО ПЕРЕДАННЫХ) ПАРАМЕТРОВ
If TCExtCom ; если была передана дополнительная команда
{
    ControlSetText, Edit1, %TCExtCom%, ahk_id %hw_TTOTAL_CMD% ; вбиваем команду в ком. строку
    ControlSend, Edit1, {Enter}, ahk_id %hw_TTOTAL_CMD% ; выполняем команду
}
ExitApp ; конец скрипта

; РЕГИСРАЦИЯ И ДЕРЕГИСТРАЦИЯ В РЕЕСТРЕ
RegInShell: ; регистрация в реестре
If NOT A_IsCompiled ; если скрипт не откомпилирован
{
    ; пишем себя в контекстное меню всех файлов
    RegWrite, REG_SZ, HKCR, *\shell\OpenInTC,, %NameInShell%
    RegWrite, REG_SZ, HKCR, *\shell\OpenInTC\command,, "%A_AhkPath%" "%A_ScriptFullPath%" "`%1"
    ; пишем себя в контекстное меню папок
    RegWrite, REG_SZ, HKCR, Directory\shell\OpenInTC,, %NameInShell%
    RegWrite, REG_SZ, HKCR, Directory\shell\OpenInTC\command,, "%A_AhkPath%" "%A_ScriptFullPath%" "`%1"
}
Else
{
    ; пишем себя в контекстное меню всех файлов
    RegWrite, REG_SZ, HKCR, *\shell\OpenInTC,, %NameInShell%
    RegWrite, REG_SZ, HKCR, *\shell\OpenInTC\command,, "%A_ScriptFullPath%" "`%1"
    ; пишем себя в контекстное меню папок
    RegWrite, REG_SZ, HKCR, Directory\shell\OpenInTC,, %NameInShell%
    RegWrite, REG_SZ, HKCR, Directory\shell\OpenInTC\command,, "%A_ScriptFullPath%" "`%1"
}
If NOT ErrorLevel
    MsgBox, Теперь в контекстном меню файлов и папок есть пункт`n"%NameInShell%"
ExitApp ; конец скрипта

UnRegInShell: ; удаления из реестра
RegDelete, HKCR, *\shell\OpenInTC ; удаляем себя из контекстного меню всех файлов
RegDelete, HKCR, Directory\shell\OpenInTC ; удаляем себя из контекстного меню дисков
If NOT ErrorLevel
    MsgBox, Из контекстного меню файлов и папок удалён пункт`n"%NameInShell%"
ExitApp ; конец скрипта

Можете не копировать код, а забрать скриптец архивчиком.

Post's attachments

OpenInTC.zip 4.73 kb, 769 downloads since 2007-03-16 

You don't have the permssions to download the attachments of this post.
Крокодил, крокожу и буду крокодить! (Твёрдое обещание нетрезвого кодера).