Replacement of standard neighborhood at return from a host

Discuss and announce Total Commander plugins, addons and other useful tools here, both their usage and their development.

Moderators: white, Hacker, petermad, Stefan2

Post Reply
Hank
Junior Member
Junior Member
Posts: 8
Joined: 2010-04-16, 08:11 UTC

Replacement of standard neighborhood at return from a host

Post by *Hank »

Hi all.

The non-standard question is on a subject of job with a remote host.

Let's assume that we pass to a remote host the type command:
cd \\<ip-address or NetBIOS-name>,
entering it in the command line of TC.

Having worked on a remote host, “we come back”, repeatedly clicking the button of the mouse or pressing Enter key on [..] - return level upwards. When we reach "top level" of a host, by default we come back in “regular network neighborhood” of the Commander - workgroup by Windows Browser.

Whether there is a way to call substitution (or somehow differently) other plugin (either the button, or the command) instead of “regular network neighborhood” ?

There is a decision by means of AutoHotKey:

Code: Select all

#IfWinActive, ahk_class TTOTAL_CMD

LButton::
    If not(A_ThisHotkey = A_PriorHotkey and A_TimeSincePriorHotkey < 300) {
        Click Down
        KeyWait, LButton
        Click Up
        return
    }
Enter::
NumpadEnter::
      ControlGetFocus, Active_Panel, ahk_class TTOTAL_CMD
      If Active_Panel = TMyListBox2
          ControlGetText, Panel_Text, TPathPanel1
      If Active_Panel = TMyListBox1
          ControlGetText, Panel_Text, TPathPanel2
      FoundPos := RegExMatch(Panel_Text, "\\\\[a-zA-Z0-9_-\s\(\)]+\\\*\.\*")
      If (FoundPos = 1) {
        SendMessage, 1075, 4003,,, ahk_class TTOTAL_CMD
        ControlSend, Edit1, ^{Enter}+{Home}^{Ins}, ahk_class TTOTAL_CMD
        SendMessage, 1075, 2004,,, ahk_class TTOTAL_CMD
        StringTrimRight, Host, clipboard, 1
        If (Host = "..") {
          SendMessage, 1075, 1001,,, ahk_class TTOTAL_CMD
          ControlSetText,  Edit1, cd \\\net, ahk_class TTOTAL_CMD
          ControlSend, Edit1, {Enter}, ahk_class TTOTAL_CMD
        }
        else
          SendMessage, 1075, 1001,,, ahk_class TTOTAL_CMD

        clipboard =
      }
      else
        ControlSend, Edit1, {Enter}, ahk_class TTOTAL_CMD
But it does not suit me. This decision contains a superfluous external code, ugly, slowly etc.

Shortly the question sounds so:
"To catch the moment of return from a host and automatic to transfer control not on regular network neighborhood, but to other plugin".
User avatar
MVV
Power Member
Power Member
Posts: 8702
Joined: 2008-08-03, 12:51 UTC
Location: Russian Federation

Post by *MVV »

Maybe you should track change of path bar path instead of tracking mouse and keyboard events? E.g. you have flag that is set when user changes dir to network path and is removed when user changes dir to local folder. So, when flag is set and path is to be changed to “regular network neighborhood” - it is time to change dir to right one!
Also you may extract path from command line's path field (it works even if command line is hidden) - it always shows active panel's path.
Hank
Junior Member
Junior Member
Posts: 8
Joined: 2010-04-16, 08:11 UTC

Post by *Hank »

MVV wrote:Maybe you should track change of path bar path instead of tracking mouse and keyboard events? E.g. you have flag that is set when user changes dir to network path and is removed when user changes dir to local folder. So, when flag is set and path is to be changed to “regular network neighborhood” - it is time to change dir to right one!
Also you may extract path from command line's path field (it works even if command line is hidden) - it always shows active panel's path.
Thanks MVV for a quick reply!

I fine understand your approach. It is transparent. Actually, it is the same approach which I already stated by means of the above-stated AHK-script.
If you attentively look at a code of my script, you will see that except events of pressing of the left mouse button or key Enter, the analysis of "position" of pressing events is in addition made.

But this approach is not pleasant to me. We are compelled to react to pressing of mouse or keyboard buttons and to make the additional analysis of in what particularly active TC’s window these pressing occur. All told by you contains the basic lacks and stipulated by me earlier.
It is a superfluous exe-code of a trap which should be loaded separately, instability of operation of a trap on double cliques of the mouse. Besides, the window with regular network neighborhood has time to appear till the moment when it will be blocked by a window of my plugin. The history of commands and contents of the clipboard are broken. And so on.

The best approach consists in application hack or direct substitution of my plugin instead of regular network neighborhood.
A question in, whether is it possible to carry out such substitution? For example, in the manner of the link, bar or any different way. Certainly, provided that such possibility exists. The key moment for me is also automatic transition for my own network neighborhood.
Hank
Junior Member
Junior Member
Posts: 8
Joined: 2010-04-16, 08:11 UTC

Post by *Hank »

Question to a moderator.

I suspect that the legitimate decision of my problem does not exist.
Whether prompt, please, is there a way to address to author TC directly with my question?

Thanks in advance.
User avatar
MVV
Power Member
Power Member
Posts: 8702
Joined: 2008-08-03, 12:51 UTC
Location: Russian Federation

Post by *MVV »

Mr. Ghisler reads topics and answers questions when he has time, so I think he will answer you.
Also you may try to write to support service (e-mail is in TC About window).

I have another idea. I think here some kind of message hook may be used to prevent opening “regular network neighborhood” folder. E.g. if you install mouse events hook and you see that user double-clicked ".." item and going to NN folder, you may remove this mouse event (so TC won't receive it at all) and open another folder instead - so if you choose roght hook you will catch tries but not changes so NN folder won't be opened at all!
Hank
Junior Member
Junior Member
Posts: 8
Joined: 2010-04-16, 08:11 UTC

Post by *Hank »

MVV wrote:Mr. Ghisler reads topics and answers questions when he has time, so I think he will answer you.
I'm very glad to hear that.
MVV wrote:I have another idea...
You have not understood me again. Give then more in detail. My concept consists in the following:

1. I write the scanner of a network in the form of the simplified FS-plugin. It is called from panel TC. (However, the scanner it is a separate subject of discussion. If will seem interesting, I can write more in detail.) The plugin quickly scans a heterogeneous network and gives out hosts on the panel.
2. The plugin carries out substitution and "passes" in TC the command: cd \\<host> after a choice of the necessary host.
3. At my approach we use all power of the TC for manipulate with file system on a remote host.
4. A back of my concept is that there is “a rupture in control”. Accordingly, we cannot in the simple way "catch" the return moment on “last pressing” [..] from a remote host. For this purpose, obviously, it is possible to use a trap. As an example, I have resulted realisation of the named approach on AHK in the first post of a topic. The approach with a trap on the basis of scripts is unacceptable. I have listed the reasons of it two posts above. Except told, it is possible to imagine a situation when in both panels TC there will be remote hosts. Efforts on their catching will generate unnecessary collisions.
5. I do not NEED STANDARD NETWORK NEIGHBORHOOD because the browsing mechanism of operational system does not allow to display my network correctly: it is a question about different subnets etc.
User avatar
MVV
Power Member
Power Member
Posts: 8702
Joined: 2008-08-03, 12:51 UTC
Location: Russian Federation

Post by *MVV »

I understood you and may definitely say that hooks will save you:) if you have FS plugin, you may install hook within it, so hook will be non-system and it will catch e.g. Enter pressing (or mouse dblclick) when cursor is on ".." item. So, OS sends to TC keypess message, your hook analyzes message and sees that it is a bad message (i.e. TC will open NN after processing this message) - so hook procedure loses message (i.e. returns non-zero instead of calling CallNextHookEx) and sends "cd" command. In result, instead of changing dir to NN TC will change dir to your plugin's root (or something else) w/o entering NN at all since TC won't receive Enter keypess on ".." item! All you need - to choose right hook event to scan.
You may install hook during loading your plugin and remove it when unloading.
Microsoft Help wrote:To prevent Windows from passing the message to the rest of the hook chain or to the target window procedure, the return value must be a nonzero value.
So you don't need AHK or any other script at all, your plugin will do all work - and it will do it inside of TC environment!
Hank
Junior Member
Junior Member
Posts: 8
Joined: 2010-04-16, 08:11 UTC

Post by *Hank »

MVV wrote:I understood you and may definitely say that hooks will save you:) ... So you don't need AHK ...
Thanks, MVV.

Thus, you assert that having transferred control from a FS-plugin into TC for a manipulation remote files, a FS-plugin (Dll-lib) is necessary to "live" in RAM and is not hurt. So?
And you suggest to use internal, more flexible and faster hook-agent of mouse and keboard events.

There is one trouble. I could not write similar traps earlier. :(

Can you recommend samples of ready templates with a code of a similar trap for Visual C ++ 6.0?

Also I hope very much for the answer of Mr. Ghisler. I would like to manage smaller labour expenses. :D
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48021
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Currently it's not possible to configure where to go when going up from the view of a server. Total commander browses the virtual folder provided by the system, and just lists its parent when you go one directory up.
Author of Total Commander
https://www.ghisler.com
User avatar
MVV
Power Member
Power Member
Posts: 8702
Joined: 2008-08-03, 12:51 UTC
Location: Russian Federation

Post by *MVV »

Well, this is a little (:roll:) sample:

Code: Select all

#define TSIZE(X) (sizeof(X)/sizeof(X[0]))

// main TC window handle
HWND hMainWnd;

// window handles for file panels and path panel
HWND mylb1=0, mylb2=0, stpath=0;

// hook handles
HHOOK hMouseHook=0, hKeybHook=0;

// this function may be used to find current TC's main window handle (run it before initializing hooks)
bool GetMainWnd(bool Override=0) {
	if (hMainWnd&&!Override) return 0;
	HWND hwnd=0;
	DWORD pid=GetCurrentProcessId(), wndpid;
	while (hwnd=FindWindowEx(0, hwnd, L"TTOTAL_CMD", 0)) {
		GetWindowThreadProcessId(hwnd, &wndpid);
		if (pid!=wndpid) continue;

		hMainWnd=hwnd;
		return 1;
	}

	return 0;
}

// this function should be run only ONCE (from FsSetDefaultParams or DllMain on DLL_PROCESS_ATTACH)
void InitializeHooks() {
	hKeybHook=SetWindowsHookEx(WH_KEYBOARD, &CallKeybHookProc, 0, GetWindowThreadProcessId(hMainWnd, 0));
	hMouseHook=SetWindowsHookEx(WH_MOUSE, &CallMouseHookProc, 0, GetWindowThreadProcessId(hMainWnd, 0));
	mylb1=FindWindowEx(hMainWnd, 0, L"TMyListBox", 0);
	mylb2=FindWindowEx(hMainWnd, mylb1, L"TMyListBox", 0);

	HWND cmdpanel=0;
	wchar_t buf[1024];
	while (1) {
		if (!(cmdpanel=FindWindowEx(hMainWnd, cmdpanel, L"TMyPanel", L""))) break;
		if (FindWindowEx(cmdpanel, 0, L"TMyComboBox", L"") || FindWindowEx(cmdpanel, 0, L"TComboBox", L"")) {
			HWND pathpanel=FindWindowEx(cmdpanel, 0, L"TMyPanel", 0);
			int k=GetWindowText(pathpanel, buf, TSIZE(buf));
			if (k&&buf[k-1]=='>') { stpath=pathpanel; break; }
		}
	}
}

// call this in DllMain on DLL_PROCESS_DETACH
void FinalizeHooks() {
	if (hKeybHook) { UnhookWindowsHookEx(hKeybHook); hKeybHook=0; }
	if (hMouseHook) { UnhookWindowsHookEx(hMouseHook); hMouseHook=0; }
}

// this function does action that should be performed instead of opening NN
void DoMyAction() {
	// TODO: ...
	MessageBeep(0);
}

// get panel that has focus
HWND GetActivePanel() {
	return GetFocus()==mylb1 ? mylb1 : mylb2;
}

// this function checks if 'level up' command should be refused
bool IsForbiddenLevelUp() {
	wchar_t buf[1024];
	GetWindowText(stpath, buf, TSIZE(buf));
	if (*(int*)buf!='\\\0\\' || buf[2]=='\\') return 0; // path is not started with \\ or started with \\\ (plugin)
	for (wchar_t* p=buf+2; *p; ++p) if (*p=='\\') return 0; // it is not root network path because it has additional level
	return 1;
}

LRESULT CALLBACK CallKeybHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
	if (wParam==VK_RETURN || wParam==VK_BACK) {
		bool released=lParam&(1<<30); // if button is released we ignore message
		if (!released) {
			int index=wParam==VK_BACK ? 0 : SendMessage(GetActivePanel(), LB_GETCARETINDEX, 0, 0); // get item index or zero if Backspace is pressed
			if (!index&&IsForbiddenLevelUp()) { // it is ".." item and we should refuse 'level up'
				DoMyAction();
				return 1; // kill keyboard event:)
			}
		}
	}
	return CallNextHookEx(hKeybHook, nCode, wParam, lParam);
}

LRESULT CALLBACK CallMouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
	if (wParam==WM_LBUTTONDBLCLK) {
		HWND mylb=GetActivePanel();
		POINT pt;
		GetCursorPos(&pt);
		ScreenToClient(mylb, &pt);
		int index=SendMessage(mylb, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y)); // get item index under cursor
		if (!index&&IsForbiddenLevelUp()) { // it is ".." item and we should refuse 'level up'
			DoMyAction();
			return 1; // kill doubleclick event:)
		}
	}
	return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}

Insert your code to change TC dir into DoMyAction function.

InitializeHooks function creates hooks and finds all windows that will be used later (TC file panels and path panel in status bar).

Specified hook procedures catch enter and doubleclicks on ".." item and Backspace pressing. Since TC panels are listboxes we may use standard listbox messages to get focused item index.

Note that you may remember last opened from your plugin network path (when user opens it from plugin) and check in IsForbiddenLevelUp if user is in this dir.

Also note that user still may use '..' TC button and things like "cd .." - I don't think we should catch them too.
Hank
Junior Member
Junior Member
Posts: 8
Joined: 2010-04-16, 08:11 UTC

Post by *Hank »

I express my warm thanks to participants of discussion.

MVV:
I have inserted your code into my plugin. It has started to function. The hooks have not lowered considerably the general speed. We will continue the further discussion on wincmd.ru.

Mr. Ghisler:
Is there a possibility of a "silent" call of a plugin from a command line of TC ? I use a following code:

Code: Select all

void DoMyAction ()
{
	//focus to command line 
	SendMessage (hMainWnd, WM_USER + 51, 4003, 0); 
	//type of plugin
	SetWindowText (GetFocus (), "cd \\\\\\net");
	//ENTER-pressing
	keybd_event (VK_RETURN, 0, KEYEVENTF_EXTENDEDKEY, 0); 
}
.

I see, how there is a "cd \\\net"-line flashing. It would be desirable to get rid of this flashing.
User avatar
MVV
Power Member
Power Member
Posts: 8702
Joined: 2008-08-03, 12:51 UTC
Location: Russian Federation

Post by *MVV »

Hank wrote:Is there a possibility of a "silent" call of a plugin from a command line of TC ? I use a following code:

...

I see, how there is a "cd \\\net"-line flashing. It would be desirable to get rid of this flashing.
I sent you (on wincmd.ru) code of function that sends WM_COPYDATA message to TC that allows to change current directory w/o perversions. :)
Hank
Junior Member
Junior Member
Posts: 8
Joined: 2010-04-16, 08:11 UTC

Post by *Hank »

OK, thanks.
Post Reply