Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Problems with touch.state

edited February 2015 in Bugs Posts: 34

Here is some code to illustrate the first problem.

Problem #1

function touched(touch)
    if touch.state ~= MOVING then
        print(touch.state)
    end
end

Swipe a single finger onto the screen at the screen corners. The following results appear in the output section. (0, 3, 0, 2).

There are two BEGAN states (0), one CANCELLED state (3), and one ENDED state (2). The problem with the CANCELLED state being triggered also sometimes occurs at the top middle of the screen, when Apple's notification bar arrow appears on the screen. As far as I know, this problem does not occur at the bottom or right sides of the screen. I can't test the results for the left side of the screen due to the swipe escape gesture.

Problem #2

This problem is related to the previous example and can have huge implications when using touch input in projects, if a user touches near the edge of the screen.

Open the example project named "Multi Touch" and run it, then swipe onto the screen with a single finger at the screen corners. A circle remains displayed on the screen even though all fingers have been removed from the screen. So not all "touch.id" keys have been removed from the "touches" table. The CANCELLED touch state that I demonstrated in the previous example is most likely the cause of this, since it causes a second BEGAN state to be created instead of just one. These problems also sometimes occur at the top middle of the screen, like in the previous example.

This is just a theory, but this could be the reason why using the swipe escape gesture at the left side of the screen to go back to the editor sometimes crashes Codea.

Comments

  • dave1707dave1707 Mod
    Posts: 9,301

    @adamskii_uk Interesting example. I don't know if the problem is with Codea or a problem with the touch screen. One thing is that Codea knows something is changing by giving you a 3 (CANCELLED). That state should be treated just like the other touch states. In the "Multi Touch" project, if the CANCELLED state is coded for, then there isn't a problem. It's just that the CANCELLED state isn't seen that often and nobody codes for it.

        if touch.state == ENDED or touch.state==CANCELLED then
            touches[touch.id] = nil
        else
            touches[touch.id] = touch
        end
    
  • SimeonSimeon Admin Mod
    Posts: 5,657

    The CANCELLED state occurs when the operating system interferes with the touch handling in some way — e.g., an alert pops up, you trigger a system-wide gesture.

    Perhaps ENDED should encompass CANCELLED. Does anyone ever explicitly handle these two cases in different ways?

  • dave1707dave1707 Mod
    Posts: 9,301

    @Simeon I don't see any of those happening ( alert, gesture ) when sliding a single finger from off the screen onto the screen in the upper right corner. As for combining ENDED and CANCELLED, that's fine with me. But I would still like CANCELLED to be detectable on its own if I have an "if CANCELLED" statement before an "if BEGAN" statement.

  • Jmv38Jmv38 Mod
    Posts: 3,297

    @Simeon well i did in my xfc program. Maybe not necessary, but here is my code
    which works fine

    function Xtouch:events(t)
        local t0 = touches[t.id]
        t.beganOnObj = t0.beganOnObj 
        t.prevOnObj = t0.prevOnObj
        t0.prevOnObj = t.curOnObj 
    
        if t.state == BEGAN then 
    
            local obj = t.beganOnObj
    
            t.Xevent = "onEnter"  
            if obj then obj:Xtouched(t) end
    
        elseif t.state == MOVING then 
    
            local obj1 = t.beganOnObj 
            local obj2 = t.prevOnObj 
            local obj3 = t.curOnObj 
    
            t.Xevent = "onLeave"  
            if obj2 and (obj3~=obj2) then obj2:Xtouched(t) end
    
            t.Xevent = "onEnter" 
            if obj3 and (obj3~=obj2) then obj3:Xtouched(t) end
    
            t.Xevent = "onDrag"  
            if obj1 then obj1:Xtouched(t) end
    
        elseif t.state == ENDED then 
    
            local obj1 = t.beganOnObj 
            local obj2 = t.prevOnObj 
            local obj3 = t.curOnObj 
            local obj4 = t.endedOnObj 
    
            t.Xevent = "onLeave"  
            if obj2 and (obj3~=obj2) then obj2:Xtouched(t) end
            if obj3 and (obj3==obj2) then obj3:Xtouched(t) end
    
            if (t.time-t0.time)<1.0 then
                local v = vec2(t.x-t0.x, t.y-t0.y)
                local d = v:len()
                local maximumDistanceForATap = 50
                if d < maximumDistanceForATap  then
                    t.Xevent = "onTap"  
                    if obj4 == obj1 and obj4 then obj4:Xtouched(t) end
                end
                local minimumDistanceForASwipe = 75
                if d > minimumDistanceForASwipe and obj1 then
                    v = v:normalize()
                    if v.x > 0.8 then
                        t.Xevent = "onSwipeRight"  
                    elseif v.x < -0.8 then
                        t.Xevent = "onSwipeLeft"  
                    elseif v.y > 0.8 then
                        t.Xevent = "onSwipeUp"  
                    elseif v.y < -0.8 then
                        t.Xevent = "onSwipeDown"  
                    end
                    if obj1 then obj1:Xtouched(t) end
                end
            end
            if obj4 ~= obj1 then
                t.Xevent = "onDrop"  
                if obj1 and obj4 then obj4:Xtouched(t) end
            end
            t.Xevent = "onFinished"  
            if obj1 then obj1:Xtouched(t) end
    
        elseif t.state == CANCELLED then 
    
            local obj1 = t.beganOnObj 
            local obj2 = t.prevOnObj 
    
            t.Xevent = "onLeave"  
            if obj2 then obj2:Xtouched(t) 
            elseif obj1 then obj1:Xtouched(t) 
            end
    
            t.Xevent = "onDrop"  
            if obj1 then obj1:Xtouched(t) end
    
            t.Xevent = "onFinished"  
            if obj1 then obj1:Xtouched(t) end
    
        end
        -- erase the finished touches
        if t.state == ENDED or t.state == CANCELLED then touches[t.id] = nil end
    end
    
  • edited February 2015 Posts: 34

    Since this problem has been created by the iPad OS rather than Codea, I think an announcement should be made to all Codea users to use the CANCELLED state in their projects if unexpected behavior occurs whilst using the touch screen. Maybe this information could be added to the built in offline documentation in the next release of Codea?

    @dave1707: As for combining ENDED and CANCELLED, that's fine with me.
    

    I don't recommend that idea since I have found problems using the CANCELLED state in the past, in one of my earlier projects. I can't give you an example right now since I removed the CANCELLED state from my project, and I can't remember which project it was.

  • dave1707dave1707 Mod
    Posts: 9,301

    @Simeon After thinking about the BEGAN and CANCELLED being combined, I changed my mind. In the first example of swiping from the corner, the result would be 2 BEGAN's which could cause more problems. I think things should be left alone and that people should learn to use the CANCELLED option.

  • Posts: 1,976

    @Simeon In all my button classes, I use ENDED to handle pressing the button, and if it's CANCELLED, nothing happens (but I store a current touch ID, so I still need to handle the part of removing the ID from memory, even if it's CANCELLED), so yes, I handle ENDED and CANCELLED differently.

  • edited March 2015 Posts: 34

    After installing the new version of Codea on my iPad, I have performed further tests on this bug. Try the following code:

    displayMode(FULLSCREEN_NO_BUTTONS)
    
    function setup()
        touch_states = {}
        fontSize(38)
        textMode(CORNER)
        textWrapWidth(WIDTH-50)
    end
    
    function draw()
        background(0)
        text(table.concat(touch_states, ",   "), 50, 50)
    end
    
    function touched(touch)
        if touch.state ~= MOVING then
            table.insert(touch_states, touch.state)
        end
    end
    

    With the iPad the correct way up in portrait mode, swipe onto the screen from the bottom right and the top right corners, and four touch states will be triggered (0, 3, 0, 2). Now try the same on the two left side corners, and either nothing is triggered, or only two touch states are tiggered (0, 2).

    Also, try swiping onto the screen from the right middle, bottom middle and top middle sides and two touch states are triggered (0, 2). If you swipe onto the screen from the left middle side nothing will happen most of the time. My theory is that Codea's left screen swipe escape gesture is somehow interfering with the two touch states (0, 2) being triggered on the left side of the screen when in full screen mode. This could be a problem if someone wanted to program a sidebar that appears on the left when swiping onto the left side of the screen, since no touch states are triggered.

    After these tests, I have come to the conclusion that it could be Codea causing the problem and not iOS, since it doesn't make sense to me that the cancelled state is only triggered on the right side of the screen and not the left side. Since, if the cancelled state was triggered by Apple's notification bar, then the cancelled state should appear on both top corners of the screen, but it appears on the two right corners instead, which is very odd.

Sign In or Register to comment.