LiteStep Developer Journal Downloads News Archive Home Page

Contact me at :
FahimF@email.com

check out my sponsor!
ContentZone

11 December 1999

Just updated the downloads page with the latest build of DarkStep (0.914), Desktop.dll (2.0) and a DarkStep port of SysVWM that gets rid of the background images not showing problem - and perhaps is a bit faster and uses less memory as well (the last two facts aren't statistically proven however <g> I just cleaned up the code a bit and expect it to be faster and less heavy on resource usage ...) I haven't included the source for SysVWM however as I intend to do some more work and make it a proper DarkStep native module first as currently it still has to have its settings in the [LiteStep] section. There is no documentation included as nothing has changed from the original as far as usage and settings go.

I intend to start working on a dynamic string class which would allow me to improve upon memory allocation, utilization and deallocation as I notice that the memory consumption of DarkStep (and the other modules I code - notably Desktop.dll has been going up since we started). This is just an idea I have but if the string class does prove effective and does not present any resource or speed overheads, it probably will become a standard in the DarkStep core and all modules that I write. But more on that once I've got some coding done ...


10 December 1999

It has turned out to be a really interesting week though I didn't get much accomplished except to get one module out the door ... and a few more things fixed in the DarkStep API and a few other things investigated regarding module compatibility :-) But the biggest thing was the module - or rather the jumping of desktop.dll from version 1.0 to 2.0. So what was involved in this major leap of a version by one whole digit you may ask? (Or you may just ignore this whole thing and go on to another page, who knows? <vbg>) The new additions are the binding of !bang commands or executables to mouse-clicks (both single and double) and the emulation of the middle-button for those having only two buttons on their rodent of choice :-) This involved a hefty amount of coding I can tell ya ... and if you are not programmatically inclined, go somewhere else as the rest is all going to be about how I achieved this marvel of coding (who am I kidding? <g>)

At first, it looked pretty simple enough - add a new Step.Rc value for each button click so that the user can specify a command or a set of commands to be executed, read the commands in when loading desktop.dll, intercept the mouse-clicks via the WM_xBUTTONUP, WM_xBUTTONDOWN and WM_xBUTTONDBLCLK messages and then execute the command for the specific mouse-click. How about the middle-button emulation you ask? Well, define another Step.Rc variable which defines whether emulation is on or not and if emulation is on, simply check the WPARAM value of the window message for the key flags and if it has got MK_LBUTTON when the message was WM_RBUTTONx or if it was MK_RBUTTON when the message was WM_LBUTTONx, then both mouse keys were pressed together and so take that as a middle-button click. Simple enough, huh? I wish ...

I first started off by defining an enumerated data type which would define all the different mouse-click types as this would make it programmatically easier for me - as I hope you will see. This is the enumerated type I came up with:

enum ClikType {

	mc_rs,		// right single-click

	mc_rd,		// right double-click

	mc_ls,		// left single-click

	mc_ld,		// left double-click

	mc_ms,		// middle single-click

	mc_md,		// middle double-click

	mc_no		// no clicks at all

};

Then all I had to do was define an array to hold the different commands for each click and then I could simply load the values for each click type thus:

TCHAR btnCmd[6][LINE_MAX];



_tcscpy(btnCmd[mc_rs], RCReadString(RCfile, _T("Desktop"), _T("RightSingleClick"), _T("")));

_tcscpy(btnCmd[mc_ls], RCReadString(RCfile, _T("Desktop"), _T("LeftSingleClick"), _T("")));

_tcscpy(btnCmd[mc_ms], RCReadString(RCfile, _T("Desktop"), _T("MiddleSingleClick"), _T("")));

_tcscpy(btnCmd[mc_rd], RCReadString(RCfile, _T("Desktop"), _T("RightDoubleClick"), _T("")));

_tcscpy(btnCmd[mc_ld], RCReadString(RCfile, _T("Desktop"), _T("LeftDoubleClick"), _T("")));

_tcscpy(btnCmd[mc_md], RCReadString(RCfile, _T("Desktop"), _T("MiddleDoubleClick"), _T("")));

That was the easy part :-) Then I had to bind the mouse clicks to the commands that I'd read from the Step.Rc and now my troubles started ... The first iteration of my code started with something like the following:

case WM_RBUTTONUP:

	if (wParam==MK_LBUTTON)

		CmdExec(hMainWnd, btnCmd[mc_ms], NULL, NULL);

	else

		CmdExec(hMainWnd, btnCmd[mc_rs], NULL, NULL);

	return 0;	



case WM_LBUTTONUP:

	if (wParam==MK_RBUTTON)

		CmdExec(hMainWnd, btnCmd[mc_ms], NULL, NULL);

	else 

		CmdExec(hMainWnd, btnCmd[mc_ls], NULL, NULL);

	return 0;

Actually, I tried the above first with WM_xBUTTONDOWN and that was where I first ran into problems because I discovered that the desktop window didn't receive WM_xBUTTONDOWN messages for some strange reason! I tried and tried but couldn't get any button down messages and so decided to go with the BUTTONUP message which worked well enough. But the problem I encountered here was that things worked fine with a right or left-single click but things went really wrong if I tried double-clicking or using middle-button emulation. The reason was simple enough, if I'd bothered to think first before coding :-)

Each mouse click you make is converted into two messages by Windows and sent to the relevant window a BUTTONDOWN message and a BUTTONUP message. In the case of a double-click, it is actually four messages in sequence - BUTTONDOWN, BUTTONUP, DBLCLK and BUTTONUP. Now when I use middle-button emulation and lets say I clicked the left button while holding the right button down, there would be a WM_RBUTTONUP message for the right button after the code above had executed for the left button up event and so both the left button single-click command and the right-button single click command would get executed if I tried a middle-click emulation. In the case of a double-click, I'd get the single-click command executing twice as well as the double-click command ... I was in quite a quandry :-) So I came up with another brilliant (and yet bound to fail oh so miserably <g>) solution. I wrote a function that would evaluate the mouse-click message as well as the messages that followed to see whether it was a single-click, emulation mode or a double-click that actually occurred. That particular function went through so many changes but it finally looked something like this:

void EvalClick(UINT msg, WPARAM wParam){

	MSG ms;

	int i;

	BOOL ret, dClick=FALSE;



	for (i=0; i<5; i++){

		ret = PeekMessage(&ms, hMainWnd, WM_LBUTTONDOWN, WM_MBUTTONDBLCLK, PM_REMOVE);

		if (ms.message==WM_RBUTTONDBLCLK||ms.message==WM_LBUTTONDBLCLK||ms.message==WM_MBUTTONDBLCLK){

			dClick=TRUE;

			ret = PeekMessage(&ms, hMainWnd, WM_LBUTTONDOWN, WM_MBUTTONDBLCLK, PM_REMOVE);

			break;

		} else if (ms.message==WM_LBUTTONUP||ms.message==WM_RBUTTONUP||ms.message==WM_LBUTTONUP)

			break;

	}

	if (emulateMB){

		switch (msg){

		case WM_RBUTTONUP:

			if (wParam==MK_LBUTTON && ms.message==WM_LBUTTONUP)

				CmdExec(hMainWnd, btnCmd[mc_ms], NULL, NULL);

			else if (wParam==MK_LBUTTON && dClick)

				CmdExec(hMainWnd, btnCmd[mc_md], NULL, NULL);

			else if (dClick)

				CmdExec(hMainWnd, btnCmd[mc_rd], NULL, NULL);

			else

				CmdExec(hMainWnd, btnCmd[mc_rs], NULL, NULL);

			break;



		case WM_LBUTTONUP:

			if (wParam==MK_RBUTTON && ms.message==WM_RBUTTONUP)

				CmdExec(hMainWnd, btnCmd[mc_ms], NULL, NULL);

			else if (wParam==MK_RBUTTON && dClick)

				CmdExec(hMainWnd, btnCmd[mc_md], NULL, NULL);

			else if (dClick)

				CmdExec(hMainWnd, btnCmd[mc_ld], NULL, NULL);

			else

				CmdExec(hMainWnd, btnCmd[mc_ls], NULL, NULL);

			break;

		}

	} else {

		switch (msg){

		case WM_RBUTTONUP:

			if (dClick)

				CmdExec(hMainWnd, btnCmd[mc_rd], NULL, NULL);

			else

				CmdExec(hMainWnd, btnCmd[mc_rs], NULL, NULL);

			break;



		case WM_LBUTTONUP:

			if (dClick)

				CmdExec(hMainWnd, btnCmd[mc_ld], NULL, NULL);

			else

				CmdExec(hMainWnd, btnCmd[mc_ls], NULL, NULL);

			break;



		case WM_MBUTTONUP:

			if (dClick)

				CmdExec(hMainWnd, btnCmd[mc_md], NULL, NULL);

			else

				CmdExec(hMainWnd, btnCmd[mc_ms], NULL, NULL);

			break;

		}

	}

}

And the above worked fine as far as resolving the middle-button emulation problem (at least I think it did ... I've since moved on to a different method and so am not sure about the code working or not anymore <g>) but try as I might, I couldn't trap the double-clicks this way. I still have no idea why ... So I resorted a to a completely different approach - for two mouse-clicks to be counted as a double-click, the second one has to occur within a certain time limit after the first one. I set a timer for this delay period after the first click-occurred, saved the type of the first click and then waited to see what happened. If another click happened while the timer was active, I ignored it as that would be either the BUTTONUP from a middle-button emulation or a double-click and when the double-click message came in, I ran the double-click command but left the timer alone so as to catch the following BUTTONUP message and this seems to work fine:

case WM_TIMER:

	KillTimer(hMainWnd, 1);

	timerOn = FALSE;

	if (clk != mc_no)

		CmdExec(hMainWnd, btnCmd[clk], NULL, NULL);

	return 0;

    

case WM_RBUTTONUP:

	if (!timerOn){

		timerOn=TRUE;

		if (emulateMB && wParam==MK_LBUTTON)

			clk=mc_ms;

		else

			clk=mc_rs;

		SetTimer(hMainWnd, 1, GetDoubleClickTime()*2, NULL);

	}

    return 0;



case WM_LBUTTONUP:

	if (!timerOn){

		timerOn=TRUE;

		if (emulateMB && wParam==MK_RBUTTON)

			clk=mc_ms;

		else

			clk=mc_ls;

		SetTimer(hMainWnd, 1, GetDoubleClickTime()*2, NULL);

	}

    return 0;



case WM_MBUTTONUP:

	if (!timerOn){

		timerOn=TRUE;

		clk=mc_ms;

		SetTimer(hMainWnd, 1, GetDoubleClickTime()*2, NULL);

	}

	return 0;



case WM_RBUTTONDBLCLK:

	if (timerOn)

		clk=mc_no;

	if (emulateMB && wParam==MK_LBUTTON)

		CmdExec(hMainWnd, btnCmd[mc_md], NULL, NULL);

	else

		CmdExec(hMainWnd, btnCmd[mc_rd], NULL, NULL);

	return 0;



case WM_LBUTTONDBLCLK:

	if (timerOn)

		clk=mc_no;

	if (emulateMB && wParam==MK_RBUTTON)

		CmdExec(hMainWnd, btnCmd[mc_md], NULL, NULL);

	else

		CmdExec(hMainWnd, btnCmd[mc_ld], NULL, NULL);

	return 0;



case WM_MBUTTONDBLCLK:

	if (timerOn)

		clk=mc_no;

	CmdExec(hMainWnd, btnCmd[mc_md], NULL, NULL);

	return 0;

There is one problem to the above solution though. There is a bit of a delay after a single-click before the command is executed. As you can see, I have the timer delay set to GetDoubleClickTime()*2 just to be safe and this delay proved to be too long :-) I have since experimented and discovered just the double-click delay works as well and doesn't result in such a long dealy either but I intend to do some more checking to find out how low I can go with the delay.


Receive email when this page changes

Powered by NetMind

Click Here

Subscribe to The Cyber Chronicle
Nedstat Counter

Site Design by : Lowspirit