Game Development Community

Double click?

by Manoel Neto · in Torque Game Engine · 01/21/2005 (5:23 am) · 19 replies

Hi,

The search feature hates me, and I couldn't find nothing on binding different commands for single clicks and double clicks. Is there are resource/tutorial/thread on this somewhere? I need the double click to do something different on my game.

#1
01/21/2005 (5:45 am)
Ideally the binding syntax would let you just bind a different function to single and double clicks. I don't know whether it does that. If not, here is my workaround.

Create a function called leftmouse(newclick). Bind a function called leftmouse(true) to your left click. The leftmouse function will have a static variable indicating the last time the mouse has been clicked.

If it is called with true (a mouse has been clicked) then it checks whether the previous mouseclick was recent. If so, then activate your doubleclick() function. If not, well this could be the first click of a double click. So update the previousclicktime variable and schedule a second run of this function: leftmouse(false). The time you choose depends on how fast the user needs to click for double click to work.

If it is called with false, look at previousclicktime and answer this question. Was that time set by the same function call that scheduled this call of leftmouse(false)? If so, then a second click didn't come, and it's time to call your singleclick() function. If not, then abort without doing anything because the same function call that changed previousclicktime most recently has already called the doubleclick() function.
#2
01/21/2005 (6:11 am)
... or you could use the "GuiMouseEventCtrl" which explicitly exposes mouse inputs.

Returned values are modifier (ctrl/shift/alt etc), mouse-position and number of mouse clicks.
function MyGuiMouseEventCtrl::onMouseDown( %this, %modifier, %worldPosition, %mouseClicks )
{
}
- Melv.
#3
01/21/2005 (9:03 am)
So, I'd just put a large GuiMouseEventCtrl covering the whole screen and use that for mouse click handling instead?
#4
01/21/2005 (9:20 am)
No, that is not what you want to do. Modify the gui control you are using to implement onMouseDown.

Edit: Also, if what you are doing is in-game, then it's not using GUI events to drive the actions, it's using Triggers. I would have to doublecheck, but I think every mouse-down event increments the trigger count. So if you tested for something and there were 2 counts on the trigger that would mean a double click. I am not looking at code right now and going off some fuzzy memory.
#5
01/21/2005 (9:30 am)
It would be possible to trigger a double click with an unlimited delay betwen both clicks using the triggers...

I'll go with Eric's suggestion. Here's the plan:


- In the left click function, I schedule the "real" left click function to be triggered after a small time, and activate the doubleClick package;

- The doubleClick package overrides the left click function, making it call the double click function;

- The double click function cancels the "real" left click function schedule;

- When The "real" left click function is called, it deactivates the doubleClick package;


It might work...
#6
12/21/2006 (11:45 pm)
Did any of you guys come up with a decent working double click system? I made one and well it sucks. Hoping to see if someone had a better way of doing it.
#7
12/22/2006 (5:14 am)
I implemented a relatively simple system Ron, but it's your call if it works for your situation.

Let's have a look at how TGE counts mouse clicks in the engine.

If you have a look at engine\gui\core\guiTypes.h, you'll find the struct for GuiEvent. This struct contains the member mouseClickCount. Sounds like we are on the correct path, right?

I needed double clicking in-game, so I went to engine\game\gameTSCtrl.cc and found the function GameTSCtrl::onMouseDown(const GuiEvent &evt).

Just before the end of the function, I perform the following:

if(evt.mouseClickCount > 1)
{
      Con::executef(this, 1, "onDoubleClick");
}

Then, to make use of this handy new feature, in example\starter.fps\client\scripts\playGui.cs, add this function:

function PlayGui::onDoubleClick(%this)
{
       echo("Double Click Occurred!");
       //   Do whatever you want because of the double click. . .
}
That's my code, and I'm sticking to it =)

#8
12/22/2006 (7:48 am)
Excellent! That is exactly what I was looking for. Thanks a lot.
#9
12/22/2006 (8:26 am)
Wait a minute, I don't have a GameTSCtrl::onMouseDown(const GuiEvent &evt) in my gameTSCtrl.cc. What version are you using because I checked my copy of 1.4 and it isn't there either?
#10
12/22/2006 (8:42 am)
"Oh noez"!

Sorry, I'm in a silly mood right now.

Quick fix for that Ron....write it in =)

In engine\game\gameTSCtrl.h, under the public section for GameTSCtrl
void onMouseDown(const GuiEvent &evt);

In engine\game\gameTSCtrl.cc:
void GameTSCtrl::onMouseDown(const GuiEvent &evt)
{
        //...SEE LAST POST FOR WHAT TO PUT HERE
}

#11
12/22/2006 (9:35 am)
Nice, michael!

thanks for sharing.
#12
12/22/2006 (11:39 am)
Well I went a different route than that and I guess I have opened it to all GUI control items. I added the code to the void GuiControl::onMouseDown(const GuiEvent &event) in guiControl.cc. It works great. I also felt the rate between mouse clicks was a little long so I cut it in half by changing this:

In bool GuiCanvas::processInputEvent(const InputEvent *event) I changed

//if it was within the double click time count the clicks
                  if (curTime - mLastMouseDownTime <=500)

to

//if it was within the double click time count the clicks
                  if (curTime - mLastMouseDownTime <= 250)


Considering almost everything, if not all, GUI elements are some form of gui control I felt for the most broad usage this was the better placement and hey no new functions in the code.

But I guess it wouldn't hurt to add it in the areas Michael stated as well. I think his method adds the ability to in-game stuff (considering the only additional place I could find in the project that used game/gameTSCtrl.h was fluidRender.cc) where I only needed the functionality in the GUI system.
#13
12/22/2006 (12:02 pm)
Glad you adapted a solution that works for you. . .One little quirk in your statement, though.

Quote:
considering the only additional place I could find in the project that used game/gameTSCtrl.h was fluidRender.cc

Once you are in a mission (actually playing the game), you are in PlayGui, which is the exposed instantiation of GameTSCTrl. The reason I need double clicking is for my custom Mission Editor for end-users.

Most everyone else would probably use it in non-game GUIs, so your adaptation might be better considering it's implemented at a lower level than my approach.

Good on ya'.

#14
12/22/2006 (12:30 pm)
Thanks Michael, although the "quirk" I was talking about is that if you look at almost every GUI element, it uses guiControl, GameTSCtrl pretty much is its own thing. But yeah we both have helpful parts. Thank you for your help as well.

I decided to add both as well as a right mouse button click function to both areas.
#15
03/02/2008 (5:29 am)
I had a related problem. I was getting multiple clicks on a button when people double-clicked. To prevent this, I changed GuiButtonBaseCtrl::onMouseDown() in guiButtonBaseCtrl.cc as follows:

void GuiButtonBaseCtrl::onMouseDown(const GuiEvent &event)
{
   if (! mActive)
      return;

[b]   // ERZ mod, ignore double clicks on buttons
   static lastButtonClicked = 0;
   if ((getId() == lastButtonClicked) && (event.mouseClickCount > 1)) {
      Con::printf("Ignored repeat click on button [%ld] with clickCount [%d]", getId(), event.mouseClickCount);
      return;
   }
   lastButtonClicked = getId();
   // end ERZ mod
[/b]
   if (mProfile->mCanKeyFocus)
      setFirstResponder();
#16
03/02/2008 (6:26 am)
@Ed - Thanks for that. I want to test this out in my AFX Creator tool. This issue happens in some of the worst places, such as Terrain Texture Editor. When you double click to create a new algorithm, you get two...

Gonna implement this later
#17
09/24/2008 (2:27 pm)
If you define an AltCommand for a guiControl, that command will be executed on a double-click.

new GuiTextListCtrl(myList) {
[...]
AltCommand = "myFunction();";
};
#18
09/28/2008 (10:21 pm)
This is how I handle double clicks on buttons in script for Warscale. Allows to adjust your double click speed on script also.

function btnServer::onClick(%this) {
%thisTime = getRealTime();
//if the time between licks is low, this is a dbkl click and should enter the server
%delta = %thisTime - btnServer.lastTime;
if(%delta < 450) {
//Do something for double click here
....
return;
}

//Mark the last click time
btnServer.lastTime = %thisTime;
}

Of course for a better solution you should modify the engine as recommended.
#19
12/04/2011 (2:35 pm)
I’m trying to implement a double click for mouse button, I have tried what you have suggested. Yet I have ran into some issues.

RE:
Well I went a different route than that and I guess I have opened it to all GUI control items. I added the code to the void GuiControl::onMouseDown(const GuiEvent &event) in guiControl.cc. It works great. I also felt the rate between mouse clicks was a little long so I cut it in half by changing this:

In bool GuiCanvas::processInputEvent(const InputEvent *event) I changed

view plainprint?

//if it was within the double click time count the clicks
if (curTime - mLastMouseDownTime <=500)


to

view plainprint?

//if it was within the double click time count the clicks
if (curTime - mLastMouseDownTime <= 250)

This does not exist in the T3D guiControl.cc

we have:
//-----------------------------------------------------------------------------
// ON INOPUT EVENT
//-----------------------------------------------------------------------------
bool GuiControl::onInputEvent(const InputEventInfo &event)
{
//if (curTime - mLastMouseDownTime <= 250)
// Do nothing by default...
return( false );
}

void GuiControl::onMouseDown(const GuiEvent &event)
{
if ( !mVisible || !mAwake )
return;

execConsoleCallback();
}

in guiCanvas.cc we have:

//------------------------------------------------------------------------------------------
// PROCESS INPUT EVENT
//------------------------------------------------------------------------------------------
bool GuiCanvas::processInputEvent(InputEventInfo &inputEvent)
{
// First call the general input handler (on the extremely off-chance that it will be handled):
if (mFirstResponder && mFirstResponder->onInputEvent(inputEvent))
{
return(true);
}

switch (inputEvent.deviceType)
{
case KeyboardDeviceType:
return processKeyboardEvent(inputEvent);
break;

case GamepadDeviceType:
return processGamepadEvent(inputEvent);
break;

case MouseDeviceType:
if (mCursorEnabled || mForceMouseToGUI)
{
return processMouseEvent(inputEvent);
}
break;
default:
break;
}

return false;
}

which then goes to.. bool GuiCanvas::processMouseEvent(InputEventInfo &inputEvent) but the script is to large to post. I’m not finding the place to change the milliseconds to insure a double click.

I really would like players to be able to double click on objects, I posted here:
http://www.garagegames.com/community/forums/viewthread/129011

but have got no response. Any help would be great thankyou.