iTGB 1.2 BUG: onMouseUp not called when sliding finger/mouse off
by BeyondtheTech · in iTorque 2D · 06/01/2009 (5:47 am) · 45 replies
I have a game where I put an action button on the bottom of the screen with two behaviors for onMouseUp and onMouseDown. When I tap on the button, it works great as a modifier or toggle, but if I slide my finger up off the button or onto a nearby button, it still remains locked in the onMouseDown mode. If I slide my finger down off the screen (and obviously off the digitizer), the onMouseUp does finally get called.
I call this the "Shift key" effect, reminiscent of doing keyboard entry on a touchscreen Windows Mobile device. But, I'd rather not have it, as it would probably confuse the user, especially if they're frantically tapping the screen.
Any workaround or fix, script or source code-wise, to get this resolved?
I call this the "Shift key" effect, reminiscent of doing keyboard entry on a touchscreen Windows Mobile device. But, I'd rather not have it, as it would probably confuse the user, especially if they're frantically tapping the screen.
Any workaround or fix, script or source code-wise, to get this resolved?
#2
I'm not using it in a GUI control, so no Command= for me.
06/01/2009 (6:31 am)
Yes, perhaps I entered in his source code changes wrong. I'm looking into that right now...I'm not using it in a GUI control, so no Command= for me.
#3
What I need is the ability to set a particular value as long as the button is held down. The command= sounds like a good idea if you can't replicate the problem I'm having, but how would I use it?
i.e., if the "Run" button is held down, command would be "$running=1;" but how do I set it back to 0 when he's not running?
06/01/2009 (8:46 am)
I verified that the multitouch resources in my source code match up with what was posted (were there any prerequisites to adding it?). How do you have it implemented? Can you try adding an onscreen button, not GUI, and adding those mouse events to it to see if it sticks when you slide your finger off of it?What I need is the ability to set a particular value as long as the button is held down. The command= sounds like a good idea if you can't replicate the problem I'm having, but how would I use it?
i.e., if the "Run" button is held down, command would be "$running=1;" but how do I set it back to 0 when he's not running?
#4
In my game all buttons are done via Images using the onmousedown and onmouseup callbacks, I have tried adding onmouseenter and onmouseleave callbacks but they did not solve the problem.
I did initially try using the gui system but it wasn't working for what I was attempting. Also I couldn't get the ondown and onup callbacks working for gui's at all, only the onenter and onleave.
06/01/2009 (8:58 am)
I am currently having the same issues as Raphael. I have also implemented the multi-touch resource, this is the only problem I am having with it so far.In my game all buttons are done via Images using the onmousedown and onmouseup callbacks, I have tried adding onmouseenter and onmouseleave callbacks but they did not solve the problem.
I did initially try using the gui system but it wasn't working for what I was attempting. Also I couldn't get the ondown and onup callbacks working for gui's at all, only the onenter and onleave.
#5
06/01/2009 (9:19 am)
I think it's a bug in the engine and not the multitouch resource. I just tried my game in the editor, and when I click on my on-screen button and slide my mouse out of it, it remains on.
#6
06/01/2009 (9:23 am)
I'm at my day job right now, but I'll post in a few hours to say for sure whether or not I'm having the same problems. I know that I am using a custom GUI button where I have it execute a second command if the button has been held down for x milliseconds, so that may have fixed it without me even knowing it.
#7
06/01/2009 (2:58 pm)
After playing with it some more, I can definitely say that if I select a button, slide my finger (or the mouse) off it, then release, the button does not get pressed. When you implemented the multitouch resource, did you implement any of my changes? The one method in particular that I think might help is modifying processScreenTouchEvent from Dave's resource. Of course, in order for that method to work you're going to have to modify everything that I placed above it, but I think it might be worth a try. Or like you said, it could be the engine, and just the "Command =" method works better than behaviors.
#8
06/02/2009 (5:32 am)
I'm using the standard genericButton.cs from TDN and applied it as a behavior. While the behavior doesn't look at all complicated to begin with, I'm wondering how yours would be really any different from that one. I'll give it a try within the hour and post my results.
#9
Ok, I started from scratch
- with a blank level, I added a small sprite.
- I named it "test" under Scripting
- I added a checkmark for "Use Mouse Events."
Simple enough.
I went into game.cs and added:
Launching the scene, when I clicked on the sprite and released the mouse button, the console appropriately said:
However, when I clicked on the sprite, held the mouse button down, slid the mouse pointer up and off the sprite, then let go of the mouse, the console only reports:
UPDATE: On a whim, I added this and it worked:
I just didn't think I would have needed that.
06/02/2009 (6:15 am)
Aha, I knew I wasn't going mad!Ok, I started from scratch
- with a blank level, I added a small sprite.
- I named it "test" under Scripting
- I added a checkmark for "Use Mouse Events."
Simple enough.
I went into game.cs and added:
function test::onMouseDown()
{
echo( "Pressed" );
}
function test::onMouseUp()
{
echo( "Released" );
}Launching the scene, when I clicked on the sprite and released the mouse button, the console appropriately said:
Pressed Released
However, when I clicked on the sprite, held the mouse button down, slid the mouse pointer up and off the sprite, then let go of the mouse, the console only reports:
Pressed
UPDATE: On a whim, I added this and it worked:
function test::onMouseLeave()
{
echo( "Finally released" );
}I just didn't think I would have needed that.
#10
06/02/2009 (6:26 am)
You want to lock the mouse (test.setMouseLocked(true)) on the sprite. That will allow the sprite to receive the mouseUp event even in the case that the cursor is no longer over the sprite itself.
#11
06/02/2009 (6:52 am)
I'm not familiar with that attribute. Should I be using it in conjunction or as a replacement for my onMouseLeave behavior? Is one better than the other in terms of CPU cycles? I'm obviously trying to scrimp and save anyway I can.
#12
This is an industry standard and you can even see this behavior in your browser and other software.
When you lock the mouse it tells the event system that you are interested in seeing ALL mouse events even if the mouse leaves the normal scope of that object.
So typically for the functionality you want you lock the mouse in the mousedown event and then unlock it in the mouse up. Be aware that this will prevent other objects from receiving mouse events while that object has the mouse "locked".
06/02/2009 (8:02 am)
The reason you need that is that Mouse events are generally only sent to those objects the mouse is over, in the case of up/down events. So if you click down on a button and slide off and do your mouse up on a different button then the first button gets the mouse down and the second button gets the mouse up. This is why you generally listen for "mouse click" events instead of down/up events if you want button click like behavior.This is an industry standard and you can even see this behavior in your browser and other software.
When you lock the mouse it tells the event system that you are interested in seeing ALL mouse events even if the mouse leaves the normal scope of that object.
So typically for the functionality you want you lock the mouse in the mousedown event and then unlock it in the mouse up. Be aware that this will prevent other objects from receiving mouse events while that object has the mouse "locked".
#13
I'm concerned about the last sentence you wrote: "be aware that this will prevent other objects from receiving mouse events..."
I'm taking advantage of multitouch with Dave's changes. Since I'm at work, I can't test it, but if I it'll prevent other touches on other objects, would that knock out multitouch capability unless it's on the same object?
06/04/2009 (9:13 am)
That OnMouseLeave function does not appear to work on the device using my finger. It still stays Pressed.I'm concerned about the last sentence you wrote: "be aware that this will prevent other objects from receiving mouse events..."
I'm taking advantage of multitouch with Dave's changes. Since I'm at work, I can't test it, but if I it'll prevent other touches on other objects, would that knock out multitouch capability unless it's on the same object?
#14
More info to report as I dig through this...
08/26/2009 (1:50 am)
I need to get this working in a project I'm doing as the beta testers and my client are all bringing it up, so I'm on the case (plus you can imagine what this does to the characters with the on-screen joystick...). Already dug in a bit and found a number of reasons why it might not be working. With and without my code implemented, sliding a finger off does not properly call onMouseLeave / onMouseUp (though my code may have broken it further). We shall soon find out!More info to report as I dig through this...
#15
I used the mouseOverGrow behaviour tdn.garagegames.com/wiki/TGB/Behaviors/Mouse_Over_Grow that normally works fine but in simulator onMouseEnter and onMouseLeave don't react as they should...
08/26/2009 (6:55 am)
I have the same issue:I used the mouseOverGrow behaviour tdn.garagegames.com/wiki/TGB/Behaviors/Mouse_Over_Grow that normally works fine but in simulator onMouseEnter and onMouseLeave don't react as they should...
#16
The primary culprit was onScreenTouchDown in guiCanvas.cc. Here's the updated code:
Since the iPhone only detects a change in the touch screen when you change what you are doing (IE: Move the finger, touch another finger, etc) and is not constantly detecting actions, we treated the iPhone input using the existing onMouseDown. This works great, but we also need to watch our locked control. So while you move your finger, we check to see if the control we just touched is the same as the locked control. If not, we then call that objects onMouseLeave method.
Then in your input control, you can treat the input as needed. For my project, I had to modify guiButtonBaseCtrl.cc to support this functionality. The change there was simple...
Originally, mouseUnlock(); and setUpdate(); were at the very top. As you might imagine, since we unlock the mouse as soon as we entered the function, mDepressed never gets set to false. So we needed to fix that.
Now I can rub my screen all I want, and buttons get properly selected and deselected like I'm playing a piano! And since I'm using onMouseLeave to handle this, then all of my custom gui controls work fine. So, for example, I have an on-screen joystick control I made, which I do not want to lose the input whenever we press the jump or attack button. Now I can handle that separately.
I'm going to also update my resource, but that might take a bit more work as I suspect this really should go through and modify every GUI control to support it... need to think about how to advertise there the best way to do this. Maybe just copy/paste what I said here, we'll see, heh...
Enjoy!
08/27/2009 (2:10 am)
Annnd... fixed!The primary culprit was onScreenTouchDown in guiCanvas.cc. Here's the updated code:
void GuiCanvas::rootScreenTouchDown(const GuiEvent &event)
{
mPrevMouseTime = Platform::getVirtualMilliseconds();
mMouseButtonDown = true;
iterator i;
i = end();
while (i != begin())
{
i--;
GuiControl *ctrl = static_cast<GuiControl *>(*i);
GuiControl *controlHit = ctrl->findHitControl(event.mousePoint);
//If the control we hit is not the same one that is locked,
// then unlock the existing control.
if (bool(mMouseCapturedControl))
{
if(mMouseCapturedControl->isMouseLocked())
{
if(mMouseCapturedControl != controlHit)
{
mMouseCapturedControl->onMouseLeave(event);
}
}
}
//see if the controlHit is a modeless dialog...
if ((! controlHit->mActive) && (! controlHit->mProfile->mModal))
continue;
else
{
controlHit->onMouseDown(event);
break;
}
}
if (bool(mMouseControl))
mMouseControlClicked = true;
}Since the iPhone only detects a change in the touch screen when you change what you are doing (IE: Move the finger, touch another finger, etc) and is not constantly detecting actions, we treated the iPhone input using the existing onMouseDown. This works great, but we also need to watch our locked control. So while you move your finger, we check to see if the control we just touched is the same as the locked control. If not, we then call that objects onMouseLeave method.
Then in your input control, you can treat the input as needed. For my project, I had to modify guiButtonBaseCtrl.cc to support this functionality. The change there was simple...
void GuiButtonBaseCtrl::onMouseLeave(const GuiEvent &)
{
if(isMouseLocked())
mDepressed = false;
mouseUnlock();
setUpdate();
if(mUseMouseEvents)
Con::executef( this, 1, "onMouseLeave" );
mMouseOver = false;
}Originally, mouseUnlock(); and setUpdate(); were at the very top. As you might imagine, since we unlock the mouse as soon as we entered the function, mDepressed never gets set to false. So we needed to fix that.
Now I can rub my screen all I want, and buttons get properly selected and deselected like I'm playing a piano! And since I'm using onMouseLeave to handle this, then all of my custom gui controls work fine. So, for example, I have an on-screen joystick control I made, which I do not want to lose the input whenever we press the jump or attack button. Now I can handle that separately.
I'm going to also update my resource, but that might take a bit more work as I suspect this really should go through and modify every GUI control to support it... need to think about how to advertise there the best way to do this. Maybe just copy/paste what I said here, we'll see, heh...
Enjoy!
#18
03/03/2010 (2:12 pm)
Unlocking the mouse there causes the game to crash if you click and drag the button. Why was mouseUnlock placed there anyway?
#19
03/03/2010 (3:06 pm)
Ask the tribes devs as that code likely dates back to Tribes2 and the V12 as most of the TGE code
#20
03/25/2010 (11:48 pm)
Just a heads up. If doing mouse drag from a GUI button the GuiButtonBaseCtrl::onMouseLeave(const GuiEvent &) fix will break the mouse drag.
Torque Owner Justin Mosiman
Opsive