Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webkit iphone/ipad issue with mutl-touch

In a UIWebView (multi-touch enabled) I got a page with two divs (div1 and div2), each of them having registered for the touchstart and touchend events. Everytime they are receiving touch events, I am dumping the content of:

  • event.touches: contains all current touches
  • event.targetTouches: contains touches relevant to the given target
  • event.changedTouches: contains touches having triggered the event

Consider the following scenario:

  • tap on div1: event.touches contains div1
  • without releasing div1, tap on div2: event.touches contains div1 and div2
  • release div2 but not div1: event.touches is empty, it should not as div1 is still being pressed . Also div1 received a touchend event as if it had been released
  • wait a while, still having div1 pressed, and it will receive a new touchstart event, which doesn't make sense as it has never been released.

So basically when releasing one finger, it acts like both fingers were removed. Am I missing something?

like image 610
Alio Avatar asked Sep 12 '10 14:09

Alio


1 Answers

Thanks funkybro for your comment but unfortunately I can stil observe the same erroneous behavior when intercepting touch events at the document level. Here is a trace of what is happening:

finger 1 touches elem1:
20:44:00.130 onTouchStart: 
    touches len=1 (elem1)
    changedTouches len=1 (elem1)

finger 2 touches elem2 (finger 1 still presses elem1 and has not been released):
20:44:01.066  onTouchStart: 
    touches len=2 (elem1,elem2)
    changedTouches len=1 (elem2)

finger 2 being released (finger 1 still presses elem1 and has not been released):
this is where things begin to go wrong: we receive two touchend events consecutively for
both elem1 and elem2,even though finger 1 is still holding on elem1 and has never released it.
Also the event.touches array is empty for both events, which is wrong since elem1 is still
being pressed.
20:44:08.241  onTouchEnd: touches len=0
              changedTouches len=1 (elem1)

20:44:08.251  onTouchEnd: touches len=0
              changedTouches len=1 (elem2)

after 4 seconds in the same position (finger 1 pressed on elem1, finger 2 released),
we receive a new touchstart event, as if the system wanted to undo the previous mistake
and put things back into a consistent state.   
20:44:12.511  onTouchStart: 
    touches len=1 (elem1)
    changedTouches len=1 (elem1)

now releasing finger 1 from elem1, we receive the touchend event
20:44:14.751  onTouchEnd: 
    touches len=0 
    changedTouches len=1 (elem1)

Edit: Here is a code sample, to run on Safari Mobile or inside your own UIWebView on device (not simulator).

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Multi-touch test</title>
    <style type="text/css">
        div.square {
            position:absolute;
            width:80px;
            height:80px;
            opacity:0.5;
        }
        div#elem1 {
            left:50px;
            top:50px;
            background-color:red;
        }
        div#elem2 {
            left:200px;
            top:50px;
            background-color:green;
        }
        textarea#logger {
            position:absolute;
            width100%;
            height:70%;
            top:30%;
            background-color:grey;
            color:white;
            overflow: scroll;
        }
    </style>

    <script type="text/javascript">
    function log(text) {
        logger.value = logger.value + text;
        logger.scrollTop = logger.scrollHeight;
    }

    function touchesDumpStr(touches,logPrefix) {
        var str = logPrefix + ', count=' + touches.length + ':';
        for (var i=0; i<touches.length; ++i) {
            if (typeof touches[i].target.customName != 'undefined') {
                str += touches[i].target.customName +' ';
            }
        }
        str += '\n';
        return str;
    }

    function onTouchStart(e) {
        log('onTouchStart\n');
        log(touchesDumpStr(e.touches, 'touches'));
        log(touchesDumpStr(e.targetTouches, 'targetTouches'));
        log(touchesDumpStr(e.changedTouches, 'changedTouches'));
        for (var i=0; i<e.changedTouches.length; ++i) {
            e.changedTouches[i].target.style.opacity=1.0;
        }
        e.preventDefault();
    }

    function onTouchEnd(e) {
        log('onTouchEnd\n');
        log(touchesDumpStr(e.touches, 'touches'));
        log(touchesDumpStr(e.targetTouches, 'targetTouches'));
        log(touchesDumpStr(e.changedTouches, 'changedTouches'));
        for (var i=0; i<e.changedTouches.length; ++i) {
            e.changedTouches[i].target.style.opacity=0.5;
        }
        e.preventDefault();
    }

    var logger;
    function init() {
        logger = document.getElementById('logger');
        document.getElementById('elem1').customName='elem1';
        document.getElementById('elem2').customName='elem2';
        document.addEventListener("touchstart", onTouchStart, false);
        document.addEventListener("touchend", onTouchEnd, false);   
    }
    </script>
</head>
<body onload="init();">
    <div class="square" id="elem1"></div>
    <div class="square" id="elem2"></div>
    <textarea id="logger" rows="10" cols="45" readonly></textarea>
</body>
</html>
like image 170
Alio Avatar answered Oct 05 '22 01:10

Alio