Detecting cancelled button press.

In a nutshell I have some code similar to this:

ball:addEventListener( “touch”, function( event )
if event.type == “began” then
ball.alpha = 0.5
elseif event.type == “cancelled” then
ball.alpha = 1
end
end)

The problem is that when a user presses down on the ball, then drags their finger off of the side of the ipad, or off of the ball itself, I get no further events telling me that the touch was actually cancelled. That is, the last event that I get from that ball is “moved”, but since I never see a touch canceled event I never have the dimming removed from the ball.

I’ve thought of a way around this where I could set an event listener on my background that tells me if the user dragged their finger off of the ball and ended a touch on the background, but I can’t think of any work around at all of the user going off of the screen, since once their finger is off of the screen I can get no further events.

Is this a bug in the cancelled event type or am I misusing it? Is there a better way that I should go about solving this problem?

Thanks! [import]uid: 70 topic_id: 782 reply_id: 300782[/import]

Anybody have any ideas on this? I’m still at a complete loss.

I’m unable to come up with any solution to the problem of a user dragging their fingers off of the edge of the device, as a cancelled event is never called in the case of a user simply dragging their finger off of the object which fired event in the first place.

Thanks! [import]uid: 70 topic_id: 782 reply_id: 1684[/import]

get back to you shortly on this

carlos [import]uid: 24 topic_id: 782 reply_id: 1687[/import]

Imo this is not a Corona problem but the way how the Iphone handles this. How about this solution:

  1. Start with a counter = 0
  2. Each frame substract 1. (Counter = -1)
  3. Even touch even add 1 (Counter = 0)

Whenever counter equals -2, you know that there was no touchevent in the last frame and so act on this. [import]uid: 5712 topic_id: 782 reply_id: 1690[/import]

Thanks for the response Mike.

I’ve considered an approach similar to that, but during implementation I ran into a few problems.

Basically the enterFrame event fires ~ 30 times per second, but the touch events happen much less frequently.
Actually I’ve noticed that when a touch occurs (at least on the ipad) it only seems to respond to the move, began and ended phases. I haven’t seen stationary or any of the other phases come through.

Because of that I stopped heading down that route. Have you had success with that approach on the ipad?

I thought I remembered touchesCancelled (or whatever it was) getting called when the user drug their finger away from the object that the event was initially fired on. [import]uid: 70 topic_id: 782 reply_id: 1697[/import]

>>Basically the enterFrame event fires ~ 30 times per second, but the touch events happen much less frequently.

Mmmh, still the approach should work around that quirk.
>>Because of that I stopped heading down that route. Have you had success with that approach on the ipad?

Sorry, ni IPad avalable here in gemarny atm.

>>I thought I remembered touchesCancelled (or whatever it was) getting called when the user drug their finger away from the object that the event was initially fired on.

I thought so too, maybe worth a bug report. Or lets wait for 2.0 and see if it behaves like it should. [import]uid: 5712 topic_id: 782 reply_id: 1702[/import]

Maybe I’m misunderstanding your suggested approach. Are you referring to something similar to this?

local counter = 0  
ball:addEventListener( "touch", function( event )  
 if event.phase == "began" then  
 ball.alpha = 0.4  
 end  
 counter = counter + 1  
end)  
Runtime:addEventListener( "enterFrame", function( event )  
 counter = counter - 1  
 if counter \<= -2 then  
 ball.alpha = 1  
 counter = 0  
 end  
end)  

I guess the problem I’m having is that when you hold your finger down on the ball it doesn’t register as another ball touch event. Nothing gets sent. Therefore the counter would be really far into the negatives due to how frequently the enterFrame event fires. I think something like that could work if the stationary event was being called but that doesn’t seem to be the case.

Am I understanding you correctly? [import]uid: 70 topic_id: 782 reply_id: 1716[/import]

This might be over-simplifying, but if enterframe fires too often, make another timer that you start/stop to “count” your time spent with the button down? [import]uid: 5659 topic_id: 782 reply_id: 1728[/import]

If anybody is curious, here is my current work around that does exactly what I want:

Runtime:addEventListener("touch", function(event)  
 if not game.paused and not game.over and table.count(dimmedBalls) \> 0 then  
 endCarving()  
 end  
end)  

I initially went to this approach thinking it’d work for everything but when a user pulls their finger off of the ipad, but it turns out that (mostly) works as well. dimmedBalls is just a table containing balls that have been dimmed.

My endCarving function just highlights and removes all of the balls in the dimmedBalls table. The table.count function is also as you’d expect.

The reason this works in my case is that since the balls are above the background, they usurp the touch event. [import]uid: 70 topic_id: 782 reply_id: 1751[/import]

I am glad you got it working [import]uid: 5712 topic_id: 782 reply_id: 1758[/import]

@Carlos:

Is there a solution to this yet?

I’m not getting a “phase=ended” event when the touch moves off a graphic. I can see how this doesn’t effect draggable objects which move with the finger, but I need to know when the user has stopped swiping at a fixed onscreen object.

Has this been filed as a bug? [import]uid: 11393 topic_id: 782 reply_id: 15005[/import]

Has not been filed as a bug and I don’t know if it is a bug or not… might as well file a bug… and we will try to figure it out.

Hmmm…

Carlos

[import]uid: 24 topic_id: 782 reply_id: 15020[/import]

Ok, thanks for the update.
[import]uid: 11393 topic_id: 782 reply_id: 15022[/import]

OderWat has a nice bit of button code towards the bottom of this post here:

http://developer.anscamobile.com/forum/2010/07/13/button-onhold

Specifically the “inside” variable. That will let you know when the users finger leaves the button at least.
Not sure about leaving the entire screen though… [import]uid: 8444 topic_id: 782 reply_id: 15023[/import]

You should be able to use stage.setFocus() to continue getting events for the button after the user has moved their finger out of the button area, e.g:

local button = display.newRect( 30, 30, 100, 100 )  
  
function doTouch( event )  
  
 if event.phase == "began" then   
 print("began phase")  
 event.target.alpha = 0.5  
 display.getCurrentStage():setFocus(event.target)  
 elseif event.phase == "ended" or event.phase == "cancelled" then  
 event.target.alpha = 1  
 print("end phase")  
 display.getCurrentStage():setFocus(nil)  
 end  
  
end  
  
button:addEventListener("touch", doTouch)  

http://developer.anscamobile.com/reference/index/stagesetfocus [import]uid: 8196 topic_id: 782 reply_id: 15039[/import]

Thanks for the sample Tim. Copied and pasted the setFocus lines verbatim and it worked instantly - awesome. Was going to try a nasty enterframe listener workaround - this is much cleaner.

Case of user error instead of Corona bug. [import]uid: 11393 topic_id: 782 reply_id: 15062[/import]

HELP! This is NOT working for me. I am using the code in the included ButtonEvents/ui.lua example. I change 1 line in this, line #47, so that it reports the current event.phase value. The code looks like this:

 print("My Phase: " .. phase)

However, it never reports on the button touch events after the mouse leaves the button. Even though I’ve been told that it should, because the line

display.getCurrentStage():setFocus(self)

sets the focus of touch events to the current button. This is not happening, tho. I am using the windows version of Corona Simulator, and am concerned that this could be a bug. Any insights would be deeply appreciated! Thanks! [import]uid: 10818 topic_id: 782 reply_id: 22152[/import]

Okay. This is definitely a bug in the Windows version of the Corona Simulator. It works fine in the Mac version, not in the Windows one.

local button = display.newRect( 30, 30, 100, 100 )  
   
function doTouch( event )  
 -- I added this one line to track behavior  
 print("current phase: " .. event.phase)  
 -- but nothing prints after the mouse leaves the button. On a   
 -- Mac version, it does. So setFocus() doesnt work in Win 7.  
 if event.phase == "began" then   
 print("began phase")  
 event.target.alpha = 0.5  
 display.getCurrentStage():setFocus(event.target)  
 elseif event.phase == "ended" or event.phase == "cancelled" then  
 event.target.alpha = 1  
 print("end phase")  
 display.getCurrentStage():setFocus(nil)  
 end  
  
end  
   
button:addEventListener("touch", doTouch)  

[import]uid: 10818 topic_id: 782 reply_id: 22156[/import]

Wow why is this bug still there, after years?
I’m using Windows 7 and I’m having the same problem, setFocus doesnt work. [import]uid: 170791 topic_id: 782 reply_id: 119845[/import]

Are you sure? I am using the setFocus everywhere, and it seems to work perfectly fine. Win7 as well. [import]uid: 160496 topic_id: 782 reply_id: 119851[/import]