1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 /**
 28  * @constant
 29  * @type Number
 30  */
 31 cc.TouchSelectorBeganBit = 1 << 0;
 32 
 33 /**
 34  * @constant
 35  * @type Number
 36  */
 37 cc.TouchSelectorMovedBit = 1 << 1;
 38 
 39 /**
 40  * @constant
 41  * @type Number
 42  */
 43 cc.TouchSelectorEndedBit = 1 << 2;
 44 
 45 /**
 46  * @constant
 47  * @type Number
 48  */
 49 cc.TouchSelectorCancelledBit = 1 << 3;
 50 
 51 /**
 52  * @constant
 53  * @type Number
 54  */
 55 cc.TouchSelectorAllBits = (cc.TouchSelectorBeganBit | cc.TouchSelectorMovedBit | cc.TouchSelectorEndedBit | cc.TouchSelectorCancelledBit);
 56 
 57 /**
 58  * @constant
 59  * @type Number
 60  */
 61 cc.TOUCH_BEGAN = 0;
 62 
 63 /**
 64  * @constant
 65  * @type Number
 66  */
 67 cc.TOUCH_MOVED = 1;
 68 
 69 /**
 70  * @constant
 71  * @type Number
 72  */
 73 cc.TOUCH_ENDED = 2;
 74 
 75 /**
 76  * @constant
 77  * @type Number
 78  */
 79 cc.TOUCH_CANCELLED = 3;
 80 
 81 /**
 82  * @constant
 83  * @type Number
 84  */
 85 cc.TouchMax = 4;
 86 
 87 /**
 88  * @function
 89  * @param {cc.TouchHandler} p1
 90  * @param {cc.TouchHandler} p2
 91  * @return {Boolean}
 92  */
 93 cc.less = function (p1, p2) {
 94     return p1.getPriority() > p2.getPriority();
 95 };
 96 
 97 /**
 98  * @param {Number} type
 99  * Constructor
100  */
101 cc.TouchHandlerHelperData = function (type) {
102     // we only use the type
103     this.type = type;
104 };
105 
106 /**
107  * cc.TouchDispatcher.
108  * Singleton that handles all the touch events.
109  * The dispatcher dispatches events to the registered TouchHandlers.
110  * There are 2 different type of touch handlers:
111  * - Standard Touch Handlers
112  * - Targeted Touch Handlers
113  *
114  * The Standard Touch Handlers work like the CocoaTouch touch handler: a set of touches is passed to the delegate.
115  * On the other hand, the Targeted Touch Handlers only receive 1 touch at the time, and they can "swallow" touches (avoid the propagation of the event).
116  *
117  * Firstly, the dispatcher sends the received touches to the targeted touches.
118  * These touches can be swallowed by the Targeted Touch Handlers. If there are still remaining touches, then the remaining touches will be sent
119  * to the Standard Touch Handlers.
120  * @class
121  * @extends cc.Class
122  */
123 cc.TouchDispatcher = cc.Class.extend(/** @lends cc.TouchDispatcher# */ {
124     _mousePressed:false,
125     _targetedHandlers:null,
126     _standardHandlers:null,
127     _locked:false,
128     _toAdd:false,
129     _toRemove:false,
130     _handlersToAdd:null,
131     _handlersToRemove:null,
132     _toQuit:false,
133     _dispatchEvents:false,
134     _handlerHelperData:[new cc.TouchHandlerHelperData(cc.TOUCH_BEGAN), new cc.TouchHandlerHelperData(cc.TOUCH_MOVED), new cc.TouchHandlerHelperData(cc.TOUCH_ENDED), new cc.TouchHandlerHelperData(cc.TOUCH_CANCELLED)],
135 
136     /**
137      * @return {Boolean}
138      */
139     init:function () {
140         this._dispatchEvents = true;
141         this._targetedHandlers = [];
142         this._standardHandlers = [];
143         this._handlersToAdd = [];
144         this._handlersToRemove = [];
145         this._toRemove = false;
146         this._toAdd = false;
147         this._toQuit = false;
148         this._locked = false;
149         this._mousePressed = false;
150         cc.TouchDispatcher.registerHtmlElementEvent(cc.canvas);
151         return true;
152     },
153 
154     _setMousePressed:function (pressed) {
155         this._mousePressed = pressed;
156     },
157 
158     _getMousePressed:function () {
159         return this._mousePressed;
160     },
161 
162     /**
163      * Whether or not the events are going to be dispatched. Default: true
164      * @return {Boolean}
165      */
166     isDispatchEvents:function () {
167         return this._dispatchEvents;
168     },
169 
170     /**
171      * @param {Boolean} dispatchEvents
172      */
173     setDispatchEvents:function (dispatchEvents) {
174         this._dispatchEvents = dispatchEvents;
175     },
176 
177     /**
178      * Adds a standard touch delegate to the dispatcher's list.
179      * See StandardTouchDelegate description.
180      * IMPORTANT: The delegate will be retained.
181      * @param {Object} delegate
182      * @param {Number} [priority=0]
183      */
184     _addStandardDelegate:function (delegate, priority) {
185         priority = priority || 0;
186         var handler = cc.StandardTouchHandler.create(delegate, priority);
187 
188         if (!this._locked) {
189             this._standardHandlers = this.forceAddHandler(handler, this._standardHandlers);
190         } else {
191             /* If handler is contained in m_pHandlersToRemove, if so remove it from m_pHandlersToRemove and retrun.
192              * Refer issue #752(cocos2d-x)
193              */
194             if (this._handlersToRemove.indexOf(delegate) != -1) {
195                 cc.ArrayRemoveObject(this._handlersToRemove, delegate);
196                 return;
197             }
198 
199             this._handlersToAdd.push(handler);
200             this._toAdd = true;
201         }
202     },
203 
204     /**
205      * @param {Object} delegate
206      * @param {Number} priority
207      * @param {Boolean} swallowsTouches
208      */
209     _addTargetedDelegate:function (delegate, priority, swallowsTouches) {
210         var handler = cc.TargetedTouchHandler.create(delegate, priority, swallowsTouches);
211         if (!this._locked) {
212             this._targetedHandlers = this.forceAddHandler(handler, this._targetedHandlers);
213         } else {
214             /* If handler is contained in m_pHandlersToRemove, if so remove it from m_pHandlersToRemove and retrun.
215              * Refer issue #752(cocos2d-x)
216              */
217             if (this._handlersToRemove.indexOf(delegate) != -1) {
218                 cc.ArrayRemoveObject(this._handlersToRemove, delegate);
219                 return;
220             }
221 
222             this._handlersToAdd.push(handler);
223             this._toAdd = true;
224         }
225     },
226 
227     /**
228      *  Force add handler
229      * @param {cc.TouchHandler} handler
230      * @param {Array} array
231      * @return {Array}
232      */
233     forceAddHandler:function (handler, array) {
234         var u = 0, h;
235 
236         for (var i = 0; i < array.length; i++) {
237             h = array[i];
238             if (h) {
239                 if (h.getPriority() < handler.getPriority())
240                     ++u;
241                 if (h.getDelegate() == handler.getDelegate()) {
242                     cc.Assert(0, "TouchDispatcher.forceAddHandler()");
243                     return array;
244                 }
245             }
246         }
247         return cc.ArrayAppendObjectToIndex(array, handler, u);
248     },
249 
250     /**
251      *  Force remove all delegates
252      */
253     forceRemoveAllDelegates:function () {
254         this._standardHandlers.length = 0;
255         this._targetedHandlers.length = 0;
256     },
257 
258     /**
259      * Removes a touch delegate.
260      * The delegate will be released
261      * @param {cc.TouchDelegate} delegate
262      */
263     _removeDelegate:function (delegate) {
264         if (delegate == null) {
265             return;
266         }
267 
268         if (!this._locked) {
269             this.forceRemoveDelegate(delegate);
270         } else {
271             /*
272              * If handler is contained in m_pHandlersToAdd, if so remove it from m_pHandlersToAdd and return.
273              */
274             var handler = this.findHandler(this._handlersToAdd, delegate);
275             if (handler) {
276                 cc.ArrayRemoveObject(this._handlersToAdd, handler);
277                 return;
278             }
279 
280             this._handlersToRemove.push(delegate);
281             this._toRemove = true;
282         }
283     },
284 
285     /**
286      * Removes all touch delegates, releasing all the delegates
287      */
288     removeAllDelegates:function () {
289         if (!this._locked) {
290             this.forceRemoveAllDelegates();
291         } else {
292             this._toQuit = true;
293         }
294     },
295 
296     /**
297      * Changes the priority of a previously added delegate. The lower the number,  the higher the priority
298      * @param {Number} priority
299      * @param {cc.TouchDelegate} delegate
300      */
301     setPriority:function (priority, delegate) {
302         cc.Assert(delegate != null, "TouchDispatcher.setPriority():Arguments is null");
303 
304         var handler = this.findHandler(delegate);
305 
306         cc.Assert(handler != null, "TouchDispatcher.setPriority():Cant find TouchHandler");
307 
308         if (handler.getPriority() != priority) {
309             handler.setPriority(priority);
310 
311             this.rearrangeHandlers(this._targetedHandlers);
312             this.rearrangeHandlers(this._standardHandlers);
313         }
314     },
315 
316     /**
317      * @param {Array} touches
318      * @param {event} event
319      * @param {Number} index
320      */
321     touches:function (touches, event, index) {
322         cc.Assert(index >= 0 && index < 4, "TouchDispatcher.touches()");
323 
324         this._locked = true;
325 
326         // optimization to prevent a mutable copy when it is not necessary
327         var targetedHandlersCount = this._targetedHandlers.length;
328         var standardHandlersCount = this._standardHandlers.length;
329         var needsMutableSet = (targetedHandlersCount && standardHandlersCount);
330 
331         var mutableTouches = (needsMutableSet ? touches.slice() : touches);
332         var helper = this._handlerHelperData[index];
333         //
334         // process the target handlers 1st
335         //
336         if (targetedHandlersCount > 0) {
337             var touch, handler, claimed;
338             for (var i = 0; i < touches.length; i++) {
339                 touch = touches[i];
340 
341                 for (var j = 0; j < this._targetedHandlers.length; j++) {
342                     handler = this._targetedHandlers[j];
343 
344                     if (!handler) {
345                         break;
346                     }
347 
348                     claimed = false;
349                     if (index == cc.TOUCH_BEGAN) {
350                         if (handler.getDelegate().onTouchBegan) {
351                             claimed = handler.getDelegate().onTouchBegan(touch, event);
352 
353                             if (claimed) {
354                                 handler.getClaimedTouches().push(touch);
355                             }
356                         }
357                         //} else if (handler.getClaimedTouches().indexOf(touch)> -1){
358                     } else if (handler.getClaimedTouches().length > 0) {
359                         // moved ended cancelled
360                         claimed = true;
361                         switch (helper.type) {
362                             case cc.TOUCH_MOVED:
363                                 if (cc.Browser.isMobile) {
364                                     if (handler.getDelegate().onTouchMoved) handler.getDelegate().onTouchMoved(touch, event);
365                                 } else {
366                                     if (this._mousePressed && handler.getDelegate().onTouchMoved) handler.getDelegate().onTouchMoved(touch, event);
367                                 }
368                                 break;
369                             case cc.TOUCH_ENDED:
370                                 if (handler.getDelegate().onTouchEnded) handler.getDelegate().onTouchEnded(touch, event);
371                                 handler.getClaimedTouches().length = 0;
372                                 //cc.ArrayRemoveObject(handler.getClaimedTouches(),touch);
373                                 break;
374                             case cc.TOUCH_CANCELLED:
375                                 if (handler.getDelegate().onTouchCancelled) handler.getDelegate().onTouchCancelled(touch, event);
376                                 handler.getClaimedTouches().length = 0;
377                                 //cc.ArrayRemoveObject(handler.getClaimedTouches(),touch);
378                                 break;
379                         }
380                     }
381 
382                     if (claimed && handler.isSwallowsTouches()) {
383                         if (needsMutableSet) {
384                             cc.ArrayRemoveObject(mutableTouches, touch);
385                         }
386                         break;
387                     }
388                 }
389             }
390         }
391 
392         //
393         // process standard handlers 2nd
394         //
395         if (standardHandlersCount > 0) {
396             for (i = 0; i < this._standardHandlers.length; i++) {
397                 handler = this._standardHandlers[i];
398 
399                 if (!handler) {
400                     break;
401                 }
402 
403                 switch (helper.type) {
404                     case cc.TOUCH_BEGAN:
405                         if (mutableTouches.length > 0) {
406                             if (handler.getDelegate().onTouchesBegan) handler.getDelegate().onTouchesBegan(mutableTouches, event);
407                         }
408                         break;
409                     case cc.TOUCH_MOVED:
410                         if (mutableTouches.length > 0) {
411                             if (cc.Browser.isMobile) {
412                                 if (handler.getDelegate().onTouchesMoved) handler.getDelegate().onTouchesMoved(mutableTouches, event);
413                             } else {
414                                 if (this._mousePressed && handler.getDelegate().onTouchesMoved) handler.getDelegate().onTouchesMoved(mutableTouches, event);
415                             }
416                         }
417                         break;
418                     case cc.TOUCH_ENDED:
419                         if (handler.getDelegate().onTouchesEnded) handler.getDelegate().onTouchesEnded(mutableTouches, event);
420                         break;
421                     case cc.TOUCH_CANCELLED:
422                         if (handler.getDelegate().onTouchesCancelled) handler.getDelegate().onTouchesCancelled(mutableTouches, event);
423                         break;
424                 }
425             }
426         }
427 
428         if (needsMutableSet) {
429             mutableTouches = null;
430         }
431 
432         //
433         // Optimization. To prevent a [handlers copy] which is expensive
434         // the add/removes/quit is done after the iterations
435         //
436         this._locked = false;
437         if (this._toRemove) {
438             this._toRemove = false;
439             for (i = 0; i < this._handlersToRemove.length; i++) {
440                 this.forceRemoveDelegate(this._handlersToRemove[i]);
441             }
442             this._handlersToRemove.length = 0;
443         }
444 
445         if (this._toAdd) {
446             this._toAdd = false;
447 
448             for (i = 0; i < this._handlersToAdd.length; i++) {
449                 handler = this._handlersToAdd[i];
450                 if (!handler) {
451                     break;
452                 }
453 
454                 if (handler instanceof cc.TargetedTouchHandler) {
455                     this._targetedHandlers = this.forceAddHandler(handler, this._targetedHandlers);
456                 } else {
457                     this._standardHandlers = this.forceAddHandler(handler, this._standardHandlers);
458                 }
459             }
460             this._handlersToAdd.length = 0;
461         }
462 
463         if (this._toQuit) {
464             this._toQuit = false;
465             this.forceRemoveAllDelegates();
466         }
467     },
468 
469     /**
470      * @param {Array} touches
471      * @param {event} event
472      */
473     touchesBegan:function (touches, event) {
474         if (this._dispatchEvents) {
475             this.touches(touches, event, cc.TOUCH_BEGAN);
476         }
477     },
478 
479     /**
480      * @param {Array} touches
481      * @param {event} event
482      */
483     touchesMoved:function (touches, event) {
484         if (this._dispatchEvents) {
485             this.touches(touches, event, cc.TOUCH_MOVED);
486         }
487     },
488 
489     /**
490      * @param {Array} touches
491      * @param {event} event
492      */
493     touchesEnded:function (touches, event) {
494         if (this._dispatchEvents) {
495             this.touches(touches, event, cc.TOUCH_ENDED);
496         }
497     },
498 
499     /**
500      * @param {Array} touches
501      * @param {event} event
502      */
503     touchesCancelled:function (touches, event) {
504         if (this._dispatchEvents) {
505             this.touches(touches, event, cc.TOUCH_CANCELLED);
506         }
507     },
508 
509     /**
510      * @param {Array||cc.TouchDelegate} array array or delegate
511      * @param {cc.TouchDelegate} delegate
512      * @return {cc.TargetedTouchHandler|cc.StandardTouchHandler|Null}
513      */
514     findHandler:function (array, delegate) {
515         switch (arguments.length) {
516             case 1:
517                 delegate = arguments[0];
518                 for (var i = 0; i < this._targetedHandlers.length; i++) {
519                     if (this._targetedHandlers[i].getDelegate() == delegate) {
520                         return this._targetedHandlers[i];
521                     }
522                 }
523                 for (i = 0; i < this._standardHandlers.length; i++) {
524                     if (this._standardHandlers[i].getDelegate() == delegate) {
525                         return this._standardHandlers[i];
526                     }
527                 }
528                 return null;
529                 break;
530             case 2:
531                 cc.Assert(array != null && delegate != null, "TouchDispatcher.findHandler():Arguments is null");
532 
533                 for (i = 0; i < array.length; i++) {
534                     if (array[i].getDelegate() == delegate) {
535                         return array[i];
536                     }
537                 }
538 
539                 return null;
540                 break;
541             default:
542                 throw "Argument must be non-nil ";
543                 break;
544         }
545     },
546 
547     /**
548      * @param {cc.TouchDelegate} delegate
549      */
550     forceRemoveDelegate:function (delegate) {
551         var handler;
552         // XXX: remove it from both handlers ???
553         // remove handler from m_pStandardHandlers
554         for (var i = 0; i < this._standardHandlers.length; i++) {
555             handler = this._standardHandlers[i];
556             if (handler && handler.getDelegate() == delegate) {
557                 cc.ArrayRemoveObject(this._standardHandlers, handler);
558                 break;
559             }
560         }
561 
562         for (i = 0; i < this._targetedHandlers.length; i++) {
563             handler = this._targetedHandlers[i];
564             if (handler && handler.getDelegate() == delegate) {
565                 cc.ArrayRemoveObject(this._targetedHandlers, handler);
566                 break;
567             }
568         }
569     },
570 
571     /**
572      * @param {Array} array
573      */
574     rearrangeHandlers:function (array) {
575         array.sort(cc.less);
576     }
577 });
578 
579 /**
580  * @type {cc.Point}
581  */
582 cc.TouchDispatcher.preTouchPoint = cc.p(0, 0);
583 
584 cc.TouchDispatcher.isRegisterEvent = false;
585 
586 cc.getHTMLElementPosition = function (element) {
587     var docElem = document.documentElement;
588     var win = window;
589     var box = null;
590     if (typeof element.getBoundingClientRect === 'function') {
591         box = element.getBoundingClientRect();
592     } else {
593         if (element instanceof HTMLCanvasElement) {
594             box = {
595                 left:0,
596                 top:0,
597                 width:element.width,
598                 height:element.height
599             };
600         } else {
601             box = {
602                 left:0,
603                 top:0,
604                 width:parseInt(element.style.width),
605                 height:parseInt(element.style.height)
606             };
607         }
608     }
609     return {
610         left:box.left + win.pageXOffset - docElem.clientLeft,
611         top:box.top + win.pageYOffset - docElem.clientTop,
612         width:box.width,
613         height:box.height
614     };
615 };
616 
617 cc.ProcessMouseupEvent = function (element, event) {
618     var pos = cc.getHTMLElementPosition(element);
619 
620     var tx, ty;
621     if (event.pageX != null) { //not avalable in <= IE8
622         tx = event.pageX;
623         ty = event.pageY;
624     } else {
625         pos.left -= document.body.scrollLeft;
626         pos.top -= document.body.scrollTop;
627         tx = event.clientX;
628         ty = event.clientY;
629     }
630 
631     var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
632 
633     var touch = new cc.Touch(location.x, location.y);
634     touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
635     cc.TouchDispatcher.preTouchPoint.x = location.x;
636     cc.TouchDispatcher.preTouchPoint.y = location.y;
637 
638     var posArr = [];
639     posArr.push(touch);
640     //csx cc.Director.getInstance().getTouchDispatcher().touchesEnded(posArr, null);
641     cc.EGLView.getInstance().touchesEnded(posArr, null);
642 };
643 
644 /**
645  * @param {HTMLCanvasElement|HTMLDivElement} element
646  */
647 cc.TouchDispatcher.registerHtmlElementEvent = function (element) {
648     if (cc.TouchDispatcher.isRegisterEvent) return;
649 
650     if (!cc.Browser.isMobile) {
651         window.addEventListener('mousedown', function (event) {
652             cc.Director.getInstance().getTouchDispatcher()._setMousePressed(true);
653         });
654 
655         window.addEventListener('mouseup', function (event) {
656             cc.Director.getInstance().getTouchDispatcher()._setMousePressed(false);
657 
658             var pos = cc.getHTMLElementPosition(element);
659 
660             var tx, ty;
661             if (event.pageX != null) { //not avalable in <= IE8
662                 tx = event.pageX;
663                 ty = event.pageY;
664             } else {
665                 pos.left -= document.body.scrollLeft;
666                 pos.top -= document.body.scrollTop;
667                 tx = event.clientX;
668                 ty = event.clientY;
669             }
670 
671             if (!cc.rectContainsPoint(new cc.Rect(pos.left, pos.top, pos.width, pos.height), cc.p(tx, ty))) {
672                 var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
673                 var touch = new cc.Touch(location.x,  location.y);
674                 touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
675                 cc.TouchDispatcher.preTouchPoint.x = location.x;
676                 cc.TouchDispatcher.preTouchPoint.y = location.y;
677 
678                 var posArr = [];
679                 posArr.push(touch);
680                 //csx cc.Director.getInstance().getTouchDispatcher().touchesEnded(posArr, null);
681                 cc.EGLView.getInstance().touchesEnded(posArr, null);
682             }
683         });
684 
685         //register canvas mouse event
686         element.addEventListener("mousedown", function (event) {
687             var pos = cc.getHTMLElementPosition(element);
688 
689             var tx, ty;
690             if (event.pageX != null) { //not avalable in <= IE8
691                 tx = event.pageX;
692                 ty = event.pageY;
693             } else {
694                 pos.left -= document.body.scrollLeft;
695                 pos.top -= document.body.scrollTop;
696                 tx = event.clientX;
697                 ty = event.clientY;
698             }
699 
700             var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
701             var touch = new cc.Touch(location.x,  location.y);
702             touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
703             cc.TouchDispatcher.preTouchPoint.x = location.x;
704             cc.TouchDispatcher.preTouchPoint.y = location.y;
705 
706             var posArr = [];
707             posArr.push(touch);
708             //csx cc.Director.getInstance().getTouchDispatcher().touchesBegan(posArr, null);
709             cc.EGLView.getInstance().touchesBegan(posArr, null);
710         });
711 
712         element.addEventListener("mouseup", function (event) {
713             cc.ProcessMouseupEvent(element, event);
714         });
715 
716         element.addEventListener("mousemove", function (event) {
717             var pos = cc.getHTMLElementPosition(element);
718 
719             var tx, ty;
720             if (event.pageX != null) { //not avalable in <= IE8
721                 tx = event.pageX;
722                 ty = event.pageY;
723             } else {
724                 pos.left -= document.body.scrollLeft;
725                 pos.top -= document.body.scrollTop;
726                 tx = event.clientX;
727                 ty = event.clientY;
728             }
729 
730             var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
731             var touch = new cc.Touch(location.x,  location.y);
732             //TODO this feature only chrome support
733             //if((event.button == 0) && (event.which == 1))
734             //    touch._setPressed(true);
735             touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
736             cc.TouchDispatcher.preTouchPoint.x = location.x;
737             cc.TouchDispatcher.preTouchPoint.y = location.y;
738 
739             var posArr = [];
740             posArr.push(touch);
741 
742             //csx cc.Director.getInstance().getTouchDispatcher().touchesMoved(posArr, null);
743             cc.EGLView.getInstance().touchesMoved(posArr, null);
744         });
745     } 
746     else if(window.navigator.msPointerEnabled){ 
747         var _pointerEventsMap = {
748             "MSPointerDown"     : "touchesBegan",
749             "MSPointerMove"     : "touchesMoved",
750             "MSPointerUp"       : "touchesEnded",
751             "MSPointerCancel"   : "touchesCancelled" 
752         };
753 
754         for(var i in _pointerEventsMap){
755             (function(_pointerEvent, _touchEvent){
756                 element.addEventListener(_pointerEvent, function (event){
757                     var pos = cc.getHTMLElementPosition(element);
758 
759                     pos.left -= document.body.scrollLeft;
760                     pos.top -= document.body.scrollTop;
761                     
762                     var tx, ty, touch, preLocation;
763                     tx = event.clientX;
764                     ty = event.clientY;
765 
766                     var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
767                     var touch = new cc.Touch(location.x,  location.y);
768                     touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
769                     cc.TouchDispatcher.preTouchPoint.x = location.x;
770                     cc.TouchDispatcher.preTouchPoint.y = location.y;
771 
772                     cc.Director.getInstance().getTouchDispatcher()[_touchEvent]([touch], null);
773                     event.stopPropagation();
774                     event.preventDefault();
775                 }, false);
776             })(i, _pointerEventsMap[i]);
777         }
778     }
779     else {
780 
781         //register canvas touch event
782         element.addEventListener("touchstart", function (event) {
783             if (!event.changedTouches) return;
784 
785             var posArr = [];
786             var pos = cc.getHTMLElementPosition(element);
787 
788             pos.left -= document.body.scrollLeft;
789             pos.top -= document.body.scrollTop;
790 
791             var touch_event, tx, ty, touch, preLocation;
792             var length = event.changedTouches.length;
793             for (var i = 0; i < length; i++) {
794                 touch_event = event.changedTouches[i];
795                 //tx = touch_event.pageX;
796                 //ty = touch_event.pageY;
797                 if (touch_event) {
798                     tx = touch_event.clientX;
799                     ty = touch_event.clientY;
800 
801                     var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
802                     touch = null;
803                     if (touch_event.hasOwnProperty("identifier")) {
804                         touch = new cc.Touch(location.x, location.y, touch_event.identifier);
805                         //use Touch Pool
806                         preLocation = cc.TouchDispatcher._getPreTouch(touch).getLocation();
807                         touch._setPrevPoint(preLocation.x, preLocation.y);
808                         cc.TouchDispatcher._setPreTouch(touch);
809                     } else {
810                         touch = new cc.Touch(location.x, location.y);
811                         touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
812                     }
813                     cc.TouchDispatcher.preTouchPoint.x = location.x;
814                     cc.TouchDispatcher.preTouchPoint.y = location.y;
815 
816                     posArr.push(touch);
817                 }
818             }
819             //csx cc.Director.getInstance().getTouchDispatcher().touchesBegan(posArr, null);
820             cc.EGLView.getInstance().touchesBegan(posArr, null);
821             event.stopPropagation();
822             event.preventDefault();
823         }, false);
824 
825         element.addEventListener("touchmove", function (event) {
826             if (!event.changedTouches) return;
827 
828             var posArr = [];
829             var pos = cc.getHTMLElementPosition(element);
830 
831             pos.left -= document.body.scrollLeft;
832             pos.top -= document.body.scrollTop;
833 
834             var touch_event, tx, ty, touch, preLocation;
835             var length = event.changedTouches.length;
836             for (var i = 0; i < length; i++) {
837                 touch_event = event.changedTouches[i];
838                 //tx = touch_event.pageX;
839                 //ty = touch_event.pageY;
840                 if (touch_event) {
841                     tx = touch_event.clientX;
842                     ty = touch_event.clientY;
843 
844                     var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
845 
846                     touch = null;
847                     if (touch_event.hasOwnProperty("identifier")) {
848                         touch = new cc.Touch(location.x, location.y, touch_event.identifier);
849                         //use Touch Pool
850                         preLocation = cc.TouchDispatcher._getPreTouch(touch).getLocation();
851                         touch._setPrevPoint(preLocation.x, preLocation.y);
852                         cc.TouchDispatcher._setPreTouch(touch);
853                     } else {
854                         touch = new cc.Touch(location.x, location.y);
855                         touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
856                     }
857                     cc.TouchDispatcher.preTouchPoint.x = location.x;
858                     cc.TouchDispatcher.preTouchPoint.y = location.y;
859 
860                     posArr.push(touch);
861                 }
862             }
863             //csx cc.Director.getInstance().getTouchDispatcher().touchesMoved(posArr, null);
864             cc.EGLView.getInstance().touchesMoved(posArr, null);
865             event.stopPropagation();
866             event.preventDefault();
867         }, false);
868 
869         element.addEventListener("touchend", function (event) {
870             if (!event.changedTouches) return;
871 
872             var posArr = [];
873             var pos = cc.getHTMLElementPosition(element);
874 
875             pos.left -= document.body.scrollLeft;
876             pos.top -= document.body.scrollTop;
877 
878             var touch_event, tx, ty, touch, preLocation;
879             var length = event.changedTouches.length;
880             for (var i = 0; i < length; i++) {
881                 touch_event = event.changedTouches[i];
882                 //tx = touch_event.pageX;
883                 //ty = touch_event.pageY;
884                 if (touch_event) {
885                     tx = touch_event.clientX;
886                     ty = touch_event.clientY;
887 
888                     var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
889 
890                     touch = null;
891                     if (touch_event.hasOwnProperty("identifier")) {
892                         touch = new cc.Touch(location.x, location.y, touch_event.identifier);
893                         //use Touch Pool
894                         preLocation = cc.TouchDispatcher._getPreTouch(touch).getLocation();
895                         touch._setPrevPoint(preLocation.x, preLocation.y);
896                         cc.TouchDispatcher._deletePreTouchWithSameId(touch);
897                     } else {
898                         touch = new cc.Touch(location.x, location.y);
899                         touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
900                     }
901                     cc.TouchDispatcher.preTouchPoint.x = location.x;
902                     cc.TouchDispatcher.preTouchPoint.y = location.y;
903 
904                     posArr.push(touch);
905                 }
906             }
907             //csx cc.Director.getInstance().getTouchDispatcher().touchesEnded(posArr, null);
908             cc.EGLView.getInstance().touchesEnded(posArr, null);
909             event.stopPropagation();
910             event.preventDefault();
911         }, false);
912 
913         element.addEventListener("touchcancel", function (event) {
914             if (!event.changedTouches) return;
915 
916             var posArr = [];
917             var pos = cc.getHTMLElementPosition(element);
918 
919             pos.left -= document.body.scrollLeft;
920             pos.top -= document.body.scrollTop;
921 
922             var touch_event, tx, ty, touch, preLocation;
923             var length = event.changedTouches.length;
924             for (var i = 0; i < length; i++) {
925                 touch_event = event.changedTouches[i];
926                 //tx = touch_event.pageX;
927                 //ty = touch_event.pageY;
928                 if (touch_event) {
929                     tx = touch_event.clientX;
930                     ty = touch_event.clientY;
931 
932                     var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
933 
934                     touch = null;
935                     if (touch_event.hasOwnProperty("identifier")) {
936                         touch = new cc.Touch(location.x, location.y, touch_event.identifier);
937                         //use Touch Pool
938                         preLocation = cc.TouchDispatcher._getPreTouch(touch).getLocation();
939                         touch._setPrevPoint(preLocation.x, preLocation.y);
940                         cc.TouchDispatcher._deletePreTouchWithSameId(touch);
941                     } else {
942                         touch = new cc.Touch(location.x, location.y);
943                         touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
944                     }
945                     cc.TouchDispatcher.preTouchPoint.x = location.x;
946                     cc.TouchDispatcher.preTouchPoint.y = location.y;
947 
948                     posArr.push(touch);
949                 }
950             }
951             //csx cc.Director.getInstance().getTouchDispatcher().touchesCancelled(posArr, null);
952             cc.EGLView.getInstance().touchesCancelled(posArr, null);
953             event.stopPropagation();
954             event.preventDefault();
955         }, false);
956     }
957 
958     cc.TouchDispatcher.isRegisterEvent = true;
959 };
960 
961 /**
962  * @param {cc.Touch} touch
963  * @return {cc.Touch} preTouch
964  */
965 cc.TouchDispatcher._getPreTouch = function (touch) {
966     var preTouch = null;
967     var preTouchPool = cc.TouchDispatcher._preTouchPool;
968     var id = touch.getId();
969     for (var i = preTouchPool.length - 1; i >= 0; i--) {
970         if (preTouchPool[i].getId() == id) {
971             preTouch = preTouchPool[i];
972             break;
973         }
974     }
975     if (!preTouch) {
976         preTouch = touch;
977     }
978     return preTouch;
979 };
980 
981 /**
982  * @param {cc.Touch} touch
983  */
984 cc.TouchDispatcher._setPreTouch = function (touch) {
985     var find = false;
986     var preTouchPool = cc.TouchDispatcher._preTouchPool;
987     var id = touch.getId();
988     for (var i = preTouchPool.length - 1; i >= 0; i--) {
989         if (preTouchPool[i].getId() == id) {
990             preTouchPool[i] = touch;
991             find = true;
992             break;
993         }
994     }
995     if (!find) {
996         //debug touches{
997         //cc.log("Pool.length: " + preTouchPool.length);
998         //}
999         if (preTouchPool.length <= 50) {
1000             preTouchPool.push(touch);
1001         } else {
1002             preTouchPool[cc.TouchDispatcher._preTouchPoolPointer] = touch;
1003             cc.TouchDispatcher._preTouchPoolPointer = (cc.TouchDispatcher._preTouchPoolPointer + 1) % 50;
1004         }
1005     }
1006 };
1007 
1008 /**
1009  * @param {cc.Touch} touch
1010  */
1011 cc.TouchDispatcher._deletePreTouchWithSameId = function (touch) {
1012     var changeTouch;
1013     var preTouchPool = cc.TouchDispatcher._preTouchPool;
1014     var id = touch.getId();
1015     for (var i = preTouchPool.length - 1; i >= 0; i--) {
1016         if (preTouchPool[i].getId() == id) {
1017             changeTouch = preTouchPool.pop();
1018             if (i != preTouchPool.length) {
1019                 preTouchPool[i] = changeTouch;
1020             }
1021             break;
1022         }
1023     }
1024 };
1025 
1026 /**
1027  * @type {Array}
1028  */
1029 cc.TouchDispatcher._preTouchPool = [];
1030 
1031 /**
1032  * @type {Number}
1033  */
1034 cc.TouchDispatcher._preTouchPoolPointer = 0;
1035 
1036 /**
1037  * register a targeted touch delegate to the dispatcher's list.
1038  * @param {Number} priority
1039  * @param {Boolean} swallowsTouches
1040  * @param {Object} delegate
1041  */
1042 cc.registerTargetedDelegate = function(priority, swallowsTouches, delegate){
1043     cc.Director.getInstance().getTouchDispatcher()._addTargetedDelegate(delegate, priority, swallowsTouches);
1044 };
1045 
1046 /**
1047  * Adds a standard touch delegate to the dispatcher's list.
1048  * See StandardTouchDelegate description.
1049  * @param {Object} delegate
1050  * @param {Number} [priority=]
1051  */
1052 cc.registerStandardDelegate = function(delegate, priority){
1053     cc.Director.getInstance().getTouchDispatcher()._addStandardDelegate(delegate, priority);
1054 };
1055 
1056 /**
1057  * Removes a touch delegate. from TouchDispatcher
1058  * @param delegate
1059  */
1060 cc.unregisterTouchDelegate = function(delegate){
1061     cc.Director.getInstance().getTouchDispatcher()._removeDelegate(delegate);
1062 };