Bug 138151

Summary: Can't reliably detect tap from JavaScript
Product: WebKit Reporter: Rick Byers <rbyers>
Component: UI EventsAssignee: Benjamin Poulain <benjamin>
Status: NEW ---    
Severity: Normal CC: redux, simon.fraser
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: iOS 7.0   

Description Rick Byers 2014-10-28 15:03:57 PDT
JS libraries may want to detect a tap without using the 'click' event - for example in order to work around the 300ms click delay.

Typically the guidance is something like "look for a touchstart, followed by 0 or more touchmove events that don't move beyond N pixels from the touchstart, then a touchend".  The problem with this is that there's no reliable way to determine the value for 'N'.  If you choose too low than it may be too hard to trigger a tap (compared to the browser's default behavior).  If you choose a value that's too large then you may detect a tap when the browser triggers scrolling.  Since the ideal value can change across different devices / versions of iOS, web code can be brittle to iOS gesture detection changes.

The same problem applies when trying to write code which consumes touch events in one axis but not the other (eg. a horizontal image carousel on a vertically scrolling page).

The problem is a little easier in Chromium due to a touchmove suppressing hack we've got - see https://docs.google.com/a/chromium.org/document/d/12k_LL_Ot9GjF8zGWP9eI_3IMbSizD72susba0frg44Y/edit#heading=h.vluzqx9pk2bm.  But if we can agree on an API to let pages do this properly, I'd ideally like to change chromium's behavior to match Safari's here (suppressing touchmove events is potentially evil).
Comment 1 Benjamin Poulain 2014-10-28 21:03:50 PDT
Not sure that's even possible but let's assume it is:

What do you think of:
    eventCanStartDefault= ["foo", "bar"]
or
    eventCanStartDefault = TouchEvent.Foo | TouchEvent.Bar

The values would be:
-Tap.
-Pan.
-Pinch.
-DoubleTap?

That way you can (1) Cancel those gestures if needed (2) Have the exact device threshold for those gestures.

This should also simplify the problem of pan->throw->tap which stop the scrolling instead of clicking.

What's your opinion on this solution?
Can this be implemented in blink?
Comment 2 Rick Byers 2014-10-29 00:05:31 PDT
Nice, I like it!  Yes, I think that would be relatively straight forward to implement in chromium/blink.  The 'Tap' (and 'DoubleTap' value would apply to touchend events, while 'Tap' and 'Pan' would apply to touchmove, right?

Rather than use bit flags or arrays of strings, I'd personally have a slight preference for an API shape where eventCanStartDefault was an object with boolean properties, eg: "eventCanStartDefault.Tap".

What about splitting Pan into Pan-X and Pan-Y?  If you want to allow scrolling in one axis only you can't necessarily know perfectly which events to ignore (eg. for near diagonal cases).  Plus it may be valuable to have some consistency with the touch-action values (i.e. the actions prohibited by the effective touch-action would never show up here).
Comment 3 Benjamin Poulain 2014-10-29 00:25:01 PDT
(In reply to comment #2)
> Nice, I like it!  Yes, I think that would be relatively straight forward to
> implement in chromium/blink.  The 'Tap' (and 'DoubleTap' value would apply
> to touchend events, while 'Tap' and 'Pan' would apply to touchmove, right?

I assume you meant 'Pinch' and 'Pan' for TouchMove?

I am not sure we need to create a formal definition of which gesture can happen on which touch event. For example, you may want to start pinch on touch start if two fingers are present on screen. This can be left as defined by the user agent.

> Rather than use bit flags or arrays of strings, I'd personally have a slight
> preference for an API shape where eventCanStartDefault was an object with
> boolean properties, eg: "eventCanStartDefault.Tap".

Do you know any precedent to guide the API here?

> What about splitting Pan into Pan-X and Pan-Y?  If you want to allow
> scrolling in one axis only you can't necessarily know perfectly which events
> to ignore (eg. for near diagonal cases).  Plus it may be valuable to have
> some consistency with the touch-action values (i.e. the actions prohibited
> by the effective touch-action would never show up here).

Yep, that's a good point.

BUT, this one is definitely not possible with the current gesture graph. I'll need to investigate.
Comment 4 Rick Byers 2014-11-25 18:54:59 PST
(In reply to comment #3)
> (In reply to comment #2)
> > Nice, I like it!  Yes, I think that would be relatively straight forward to
> > implement in chromium/blink.  The 'Tap' (and 'DoubleTap' value would apply
> > to touchend events, while 'Tap' and 'Pan' would apply to touchmove, right?
> 
> I assume you meant 'Pinch' and 'Pan' for TouchMove?

Yes, indeed.

> I am not sure we need to create a formal definition of which gesture can
> happen on which touch event. For example, you may want to start pinch on
> touch start if two fingers are present on screen. This can be left as
> defined by the user agent.

Sounds good to me.

> > Rather than use bit flags or arrays of strings, I'd personally have a slight
> > preference for an API shape where eventCanStartDefault was an object with
> > boolean properties, eg: "eventCanStartDefault.Tap".
> 
> Do you know any precedent to guide the API here?

Well I guess even APIs like the modifiers on a MouseEvent (we have altKey, ctrlKey, shiftKey, etc. all as boolean properties as opposed to trying to pack them into flags like many native APIs do).  That's probably the simplest pattern.  A counter example is MouseEvent.buttons which is a bit field (although I've seen it called out as un-webby since bit fields are rare in web APIs).  I don't have any example better than that and don't have too strong of an opinion myself.  
 
> > What about splitting Pan into Pan-X and Pan-Y?  If you want to allow
> > scrolling in one axis only you can't necessarily know perfectly which events
> > to ignore (eg. for near diagonal cases).  Plus it may be valuable to have
> > some consistency with the touch-action values (i.e. the actions prohibited
> > by the effective touch-action would never show up here).
> 
> Yep, that's a good point.
> 
> BUT, this one is definitely not possible with the current gesture graph.
> I'll need to investigate.

FYI we're tracking propagating this information with our touch events internally at http://crbug.com/432605.  Exposing it (if we can agree on an API) would be simple on top of that.
Comment 5 Rick Byers 2015-01-22 08:06:47 PST
Note related public API discussion here: https://lists.w3.org/Archives/Public/public-touchevents/2015Jan/0084.html