Information: Touch on iPhone 6S sends "moved" events of 0 pixels

Like in some Android devices, the touch on an iPhone 6S sends “moved” events of 0 pixels, even if you don’t move.

This generated bugs for us, since we have buttons in scrollview and manually forward the touch event to it (using group:takeFocus) when we detect a move, thus aborting the click.

The problem being that the user didn’t actually move, so our button was never clickable. We added a security (which we had already put for Android but not for iPhones) that just checks if the device moved for more than 5 pixels.

Also, I’d say that a “moved” event of 0 pixels is pretty much a bug.

Hi @corona4182,

Does this only occur on the 6S? If so, does it only occur when you use the “3D touch” feature? Please provide some more detail and we can do a little testing on our side.

Thanks,

Brent

Only on 6S, since all our other devices in iOS 9 didn’t have this problem. It started happening on a 6S, so most likely due to 3D touch.

As for the code, it happens with the “onEvent” of a button. You get events with a phase “moved” at the same position the phase “began” was sent. Since our code forwards the event to the parent group (due to scrollview things), so we detect a move but the user hasn’t actually moved.

Hi @corona4182,

Can you do a print of the event.x and event.y at the same time, to distinguish how (or if) those change between the regular tap and “force touched” events? Remember that a “moved” phase can occur on just the very slightest x/y position change, so that might be what is actually happening… but if the x and y are identical between these two events, then I’ll need to ponder a solution or workaround.

Brent

I meant that neither X or Y changes. I didn’t keep the logs, but the x and y values stayed the same on 6S with force touch, so the total move was 0. While on other devices, I didn’t have a move until there was actually a change in value.

The only difference between the two events (I stored them in json and made a file diff with them to be sure) was the event phase.

I heard from native developers that it also happens on native, the 6S triggers moved events of 0 pixels, which bugs a lot of apps. Maybe you could just ignore events when the move has a 0 pixels difference.

In my case I just check if the total moved distance is > to 5 pixels before forwarding the event to my scrollview

Hi @corona4182,

Thanks for your notes and observations, especially that this seems to affect native-built apps as well.

I will discuss a potential solution with the engineering team. We probably will not just globally dismiss/ignore all subsequent “moved” phase events with the same x/y position, because that is (in effect) a way to actually support 3D Touch, and some developers clearly want that already. More likely, it would be a “system.activate()” setting to toggle the option on/off, and so users who did not care about using any 3D touch functionality in their app could safely turn that option off (most likely, the default would be off, and enabling it would be exception since 3D touch is isolated to only the new iPhones).

In the meantime, I think you can work around this in your own code, perhaps like this:

[lua]

local function touchListener( event )

    local objTouched = event.target

    if not ( objTouched.prevTouch ) then

        objTouched.prevTouch = { x=event.x, y=event.y, touch3D=false }

    else

        if ( event.x == objTouched.prevTouch[“x”] and event.y == objTouched.prevTouch[“y”] and “moved” == event.phase ) then

            – If a moved phase is registered on the exact same X/Y, then set the boolean 3D touch flag

            objTouched.prevTouch[“touch3D”] = true

        elseif ( ( event.x ~= objTouched.prevTouch[“x”] or event.y ~= objTouched.prevTouch[“y”] ) and “moved” == event.phase ) then

            – If an actual move occurs, for example if the user (even following a 3D touch)

            – moves the touch point, reset the boolean flag to false

            objTouched.prevTouch[“touch3D”] = false

        end

        if ( “moved” == event.phase and objTouched.prevTouch[“touch3D”] == true ) then

            print( “THERE WAS A 3D TOUCH!” )

        elseif ( “moved” == event.phase and objTouched.prevTouch[“touch3D”] == false ) then

            print( “NORMAL MOVED EVENT!” )

        elseif ( “ended” == event.phase or “cancelled” == event.phase ) then

            objTouched.prevTouch = nil

        end

    end

    return true

end

[/lua]

Note that I just hacked this code out and haven’t tested it on a 6S. In fact, if you could test this on your end and see if it works, I’d appreciate it, and if I didn’t take into account some conditions, then provide your input and I can tune this up for others who might be facing the same issue.

Thanks,

Brent

Well you don’t have to dismiss it, you could just add a new event for 3D touch (just a new phase, like “forcetouch” or whatever) that would contain the amount of pressure or something.

That way you can keep the “move” events for when the user actually moved. Otherwise, it’ll be really unclear to developers because moving 0 pixels is not intuitive at all.

Also, as far as I see there is currently no information about the 3D touch in the events, so I don’t see what people could do with a move event of 0 pixels, if they don’t have any pressure information anyway. This event of 0 pixels seem to be fired all the time, as soon as you touch the button, so it would be worthless. Even if you try to lightly touch the button and release it, you will get the 0 pixels move. I suppose it’s fired as soon as there is even a tiny bit of pressure.

Really I’d say the best way would be a new phase specifically for pressure, so that it doesn’t change anything to users who just want classic touch.

As for your code, I don’t have the 6S with me so can’t try it. I suppose it would work, but I prefer my way of checking the pixels distance, seems a bit more safe.

My code’s like that:

self.info.onEvent = function (event) local phase = event.phase if phase == "began" then self.previousTouch = {x = event.x, y = event.y} elseif phase == "moved" then if self.group.takeFocus and self.previousTouch then -- This is where I forward my event to a scrollview if there was a move. The distPoints function just calculates the distance between two vectors -- I have 5 pixels of safety, which avoids false events and also adds a bit of tolerance if the user moved their finger a bit but still wanted to actually click if utils.distPoints(self.previousTouch, event) \> 5 then self.group:takeFocus(event) end end elseif phase == "ended" then if self.clickCallback and self.active then self:toggle() end end return false end

Hi @corona4182,

Good points, we’re still looking into what the best solution is. If this is affecting native-built apps too, I wonder if Apple intends to do anything like expose a system-wide “this feature exists” or not, since asking every iOS developer to suddenly update their apps based on this odd handling of the 3D touch is a bit odd, to say the least.

As for getting a “moved” event when you lightly ( not 3D touch) an object in Corona, that absolutely should not be happening, unless that is also a new behavior isolated to the 6S line. Up until this point, Corona has never triggered a “moved” event until the touch actually moves by a perceptible (according to the OS) amount. I’ll do a little testing to see if this has changed on 6S.

Best regards,

Brent

Hi @corona4182,

I just did a little testing on an iPhone 6S and, unfortunately, my “should not happen” case actually does happen… merely touching on the screen without any movement whatsoever (same exact x/y position) generates a constant stream of “moved” events. We’re going to explore what the best solution is, but in the meantime, I suggest you add a workaround like I suggested, or what you did with checking the pixel distance.

Brent

On that note, it looks like your code workaround is the only one that will solve this in the short term, because my previously-suggested workaround won’t distinguish between the user simply touching down (and not moving) and the user actually pressing harder for a 3D touch.

Brent

Just to understand this (as I don’t yet have a 6S, but do have customers on who’s 6s my app isn’t seeing certain touch events): 

On the 6S are we saying that NO touch event is generated, just a Move event of 0 px?

-Tom

Hi Tom,

Specifically, “moved” is a phase of the “touch” event… so if no touch event is generated, that’s not a 6S issue, it’s something in your code.

Brent

D’oh! Of course. It’s been a couple of years since I looked at that code.

So to confirm: in other phones, for a touch we see:

  began

  ended

For a move, we see:

  began

  moved

  moved

  … (as long as finger is moving)

  ended

but on the iPhone 6s, we see:

  began  

  moved

  moved

  … (as long as finger is still touching)

  ended

?

-Tom

Hi Tom,

Essentially, in the 6S, you get this:

– TOUCH BEGINS

  1. “began” phase

  2. “moved” phase (with x/y position change of 0)

  3. “moved” phase (with x/y position change of 0) when a 3D touch is made

– TOUCH MOVES

  1. “moved” phase

– TOUCH LIFTS OFF

  1. “ended” phase

So on earlier phones, #2 and #3 did not occur. We’re looking into how to properly handle this, so I’ll update this thread when I know more.

Best regards,

Brent

Perhaps a better way to look at it is that on certain devices you get not just X/Y touch, but X/Y/Z touch. You just don’t get the “force” property (Z axis) from Corona yet. So a “3D touch” isn’t only when you move 0/0 in X/Y. You can move in Z to do a force touch while also moving in the X/Y directions. A force touch is just a threshold in the Z direction before you trigger some special UI.

Thanks for the details. This has helped me identify where the likely problem is in my code.

-Tom

Is there any difference on the 6s with Tap events?

I’m using code borrowed from the widgetLibrary/widget_tableview code of several years ago to deal with taps on possibly moving objects. My 6s users are finding that it is virtually unresponsive to taps, even when carefully not moving. I think I’ve dealt with code that might get upset with lots of moved events with dy < a threshhold, but obviously I haven’t done enough or there’s another problem.

Short of dropping $1000 to grab a new phone, any thoughts on what else might have changed?

-Tom

Hi Tom,

Well, tap events don’t have phases, so I can only assume that there’s a touch event that might be overriding it. Can you post the most simple code block here so I can test it on a 6S?

Brent

Daily build 2775 has some new data on touch events that should show why you’re getting more events. Namely, as said before, touch events are triggered when x, y, or pressure are changed.

Read more about the new pressure information here: https://docs.coronalabs.com/daily/api/event/touch/pressure.html

Any updates regarding this issue?