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.log("cc.TouchDispatcher.forceAddHandler(): The handler has been added.");
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         if(!delegate)
303             throw "cc.TouchDispatcher.setPriority(): delegate should be non-null.";
304         var handler = this.findHandler(delegate);
305         if(!handler){
306             cc.log("cc.TouchDispatcher.setPriority(): Can't find TouchHandler.");
307             return;
308         }
309 
310         if (handler.getPriority() != priority) {
311             handler.setPriority(priority);
312             this.rearrangeHandlers(this._targetedHandlers);
313             this.rearrangeHandlers(this._standardHandlers);
314         }
315     },
316 
317     /**
318      * @param {Array} touches
319      * @param {event} event
320      * @param {Number} index
321      */
322     touches:function (touches, event, index) {
323         if(index< 0 || index >=4)
324             throw "cc.TouchDispatcher.touches(): invalid index";
325 
326         this._locked = true;
327 
328         // optimization to prevent a mutable copy when it is not necessary
329         var targetedHandlersCount = this._targetedHandlers.length;
330         var standardHandlersCount = this._standardHandlers.length;
331         var needsMutableSet = (targetedHandlersCount && standardHandlersCount);
332 
333         var mutableTouches = (needsMutableSet ? touches.slice() : touches);
334         var helper = this._handlerHelperData[index];
335         //
336         // process the target handlers 1st
337         //
338         if (targetedHandlersCount > 0) {
339             var touch, handler, claimed;
340             for (var i = 0; i < touches.length; i++) {
341                 touch = touches[i];
342 
343                 for (var j = 0; j < this._targetedHandlers.length; j++) {
344                     handler = this._targetedHandlers[j];
345 
346                     if (!handler) {
347                         break;
348                     }
349 
350                     claimed = false;
351                     if (index == cc.TOUCH_BEGAN) {
352                         if (handler.getDelegate().onTouchBegan) {
353                             claimed = handler.getDelegate().onTouchBegan(touch, event);
354 
355                             if (claimed) {
356                                 handler.getClaimedTouches().push(touch);
357                             }
358                         }
359                         //} else if (handler.getClaimedTouches().indexOf(touch)> -1){
360                     } else if (handler.getClaimedTouches().length > 0) {
361                         // moved ended cancelled
362                         claimed = true;
363                         switch (helper.type) {
364                             case cc.TOUCH_MOVED:
365                                 if (cc.Browser.isMobile) {
366                                     if (handler.getDelegate().onTouchMoved) handler.getDelegate().onTouchMoved(touch, event);
367                                 } else {
368                                     if (this._mousePressed && handler.getDelegate().onTouchMoved) handler.getDelegate().onTouchMoved(touch, event);
369                                 }
370                                 break;
371                             case cc.TOUCH_ENDED:
372                                 if (handler.getDelegate().onTouchEnded) handler.getDelegate().onTouchEnded(touch, event);
373                                 handler.getClaimedTouches().length = 0;
374                                 //cc.ArrayRemoveObject(handler.getClaimedTouches(),touch);
375                                 break;
376                             case cc.TOUCH_CANCELLED:
377                                 if (handler.getDelegate().onTouchCancelled) handler.getDelegate().onTouchCancelled(touch, event);
378                                 handler.getClaimedTouches().length = 0;
379                                 //cc.ArrayRemoveObject(handler.getClaimedTouches(),touch);
380                                 break;
381                         }
382                     }
383 
384                     if (claimed && handler.isSwallowsTouches()) {
385                         if (needsMutableSet) {
386                             cc.ArrayRemoveObject(mutableTouches, touch);
387                         }
388                         break;
389                     }
390                 }
391             }
392         }
393 
394         //
395         // process standard handlers 2nd
396         //
397         if (standardHandlersCount > 0) {
398             for (i = 0; i < this._standardHandlers.length; i++) {
399                 handler = this._standardHandlers[i];
400 
401                 if (!handler) {
402                     break;
403                 }
404 
405                 switch (helper.type) {
406                     case cc.TOUCH_BEGAN:
407                         if (mutableTouches.length > 0) {
408                             if (handler.getDelegate().onTouchesBegan) handler.getDelegate().onTouchesBegan(mutableTouches, event);
409                         }
410                         break;
411                     case cc.TOUCH_MOVED:
412                         if (mutableTouches.length > 0) {
413                             if (cc.Browser.isMobile) {
414                                 if (handler.getDelegate().onTouchesMoved) handler.getDelegate().onTouchesMoved(mutableTouches, event);
415                             } else {
416                                 if (this._mousePressed && handler.getDelegate().onTouchesMoved) handler.getDelegate().onTouchesMoved(mutableTouches, event);
417                             }
418                         }
419                         break;
420                     case cc.TOUCH_ENDED:
421                         if (handler.getDelegate().onTouchesEnded) handler.getDelegate().onTouchesEnded(mutableTouches, event);
422                         break;
423                     case cc.TOUCH_CANCELLED:
424                         if (handler.getDelegate().onTouchesCancelled) handler.getDelegate().onTouchesCancelled(mutableTouches, event);
425                         break;
426                 }
427             }
428         }
429 
430         if (needsMutableSet) {
431             mutableTouches = null;
432         }
433 
434         //
435         // Optimization. To prevent a [handlers copy] which is expensive
436         // the add/removes/quit is done after the iterations
437         //
438         this._locked = false;
439         if (this._toRemove) {
440             this._toRemove = false;
441             for (i = 0; i < this._handlersToRemove.length; i++) {
442                 this.forceRemoveDelegate(this._handlersToRemove[i]);
443             }
444             this._handlersToRemove.length = 0;
445         }
446 
447         if (this._toAdd) {
448             this._toAdd = false;
449 
450             for (i = 0; i < this._handlersToAdd.length; i++) {
451                 handler = this._handlersToAdd[i];
452                 if (!handler) {
453                     break;
454                 }
455 
456                 if (handler instanceof cc.TargetedTouchHandler) {
457                     this._targetedHandlers = this.forceAddHandler(handler, this._targetedHandlers);
458                 } else {
459                     this._standardHandlers = this.forceAddHandler(handler, this._standardHandlers);
460                 }
461             }
462             this._handlersToAdd.length = 0;
463         }
464 
465         if (this._toQuit) {
466             this._toQuit = false;
467             this.forceRemoveAllDelegates();
468         }
469     },
470 
471     /**
472      * @param {Array} touches
473      * @param {event} event
474      */
475     touchesBegan:function (touches, event) {
476         if (this._dispatchEvents) {
477             this.touches(touches, event, cc.TOUCH_BEGAN);
478         }
479     },
480 
481     /**
482      * @param {Array} touches
483      * @param {event} event
484      */
485     touchesMoved:function (touches, event) {
486         if (this._dispatchEvents) {
487             this.touches(touches, event, cc.TOUCH_MOVED);
488         }
489     },
490 
491     /**
492      * @param {Array} touches
493      * @param {event} event
494      */
495     touchesEnded:function (touches, event) {
496         if (this._dispatchEvents) {
497             this.touches(touches, event, cc.TOUCH_ENDED);
498         }
499     },
500 
501     /**
502      * @param {Array} touches
503      * @param {event} event
504      */
505     touchesCancelled:function (touches, event) {
506         if (this._dispatchEvents) {
507             this.touches(touches, event, cc.TOUCH_CANCELLED);
508         }
509     },
510 
511     /**
512      * @param {Array||cc.TouchDelegate} array array or delegate
513      * @param {cc.TouchDelegate} delegate
514      * @return {cc.TargetedTouchHandler|cc.StandardTouchHandler|Null}
515      */
516     findHandler:function (array, delegate) {
517         switch (arguments.length) {
518             case 1:
519                 delegate = arguments[0];
520                 if(!delegate)
521                     throw "cc.TouchDispatcher.findHandler(): delegate should be non-null.";
522                 for (var i = 0; i < this._targetedHandlers.length; i++) {
523                     if (this._targetedHandlers[i].getDelegate() == delegate) {
524                         return this._targetedHandlers[i];
525                     }
526                 }
527                 for (i = 0; i < this._standardHandlers.length; i++) {
528                     if (this._standardHandlers[i].getDelegate() == delegate) {
529                         return this._standardHandlers[i];
530                     }
531                 }
532                 return null;
533                 break;
534             case 2:
535                 if(!array)
536                     throw "cc.TouchDispatcher.findHandler(): array should be non-null.";
537                 if(!delegate)
538                     throw "cc.TouchDispatcher.findHandler(): delegate should be non-null.";
539 
540                 for (i = 0; i < array.length; i++) {
541                     if (array[i].getDelegate() == delegate) {
542                         return array[i];
543                     }
544                 }
545 
546                 return null;
547                 break;
548             default:
549                 throw "Argument must be non-nil ";
550                 break;
551         }
552     },
553 
554     /**
555      * @param {cc.TouchDelegate} delegate
556      */
557     forceRemoveDelegate:function (delegate) {
558         var handler;
559         // XXX: remove it from both handlers ???
560         // remove handler from m_pStandardHandlers
561         for (var i = 0; i < this._standardHandlers.length; i++) {
562             handler = this._standardHandlers[i];
563             if (handler && handler.getDelegate() == delegate) {
564                 cc.ArrayRemoveObject(this._standardHandlers, handler);
565                 break;
566             }
567         }
568 
569         for (i = 0; i < this._targetedHandlers.length; i++) {
570             handler = this._targetedHandlers[i];
571             if (handler && handler.getDelegate() == delegate) {
572                 cc.ArrayRemoveObject(this._targetedHandlers, handler);
573                 break;
574             }
575         }
576     },
577 
578     /**
579      * @param {Array} array
580      */
581     rearrangeHandlers:function (array) {
582         array.sort(cc.less);
583     }
584 });
585 
586 /**
587  * @type {cc.Point}
588  */
589 cc.TouchDispatcher.preTouchPoint = cc.p(0, 0);
590 
591 cc.TouchDispatcher.isRegisterEvent = false;
592 
593 cc.getHTMLElementPosition = function (element) {
594     var docElem = document.documentElement;
595     var win = window;
596     var box = null;
597     if (typeof element.getBoundingClientRect === 'function') {
598         box = element.getBoundingClientRect();
599     } else {
600         if (element instanceof HTMLCanvasElement) {
601             box = {
602                 left:0,
603                 top:0,
604                 width:element.width,
605                 height:element.height
606             };
607         } else {
608             box = {
609                 left:0,
610                 top:0,
611                 width:parseInt(element.style.width),
612                 height:parseInt(element.style.height)
613             };
614         }
615     }
616     return {
617         left:box.left + win.pageXOffset - docElem.clientLeft,
618         top:box.top + win.pageYOffset - docElem.clientTop,
619         width:box.width,
620         height:box.height
621     };
622 };
623 
624 cc.ProcessMouseupEvent = function (element, event) {
625     var pos = cc.getHTMLElementPosition(element);
626 
627     var tx, ty;
628     if (event.pageX != null) { //not avalable in <= IE8
629         tx = event.pageX;
630         ty = event.pageY;
631     } else {
632         pos.left -= document.body.scrollLeft;
633         pos.top -= document.body.scrollTop;
634         tx = event.clientX;
635         ty = event.clientY;
636     }
637 
638     var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
639 
640     var touch = new cc.Touch(location.x, location.y);
641     touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
642     cc.TouchDispatcher.preTouchPoint.x = location.x;
643     cc.TouchDispatcher.preTouchPoint.y = location.y;
644 
645     var posArr = [];
646     posArr.push(touch);
647     //csx cc.Director.getInstance().getTouchDispatcher().touchesEnded(posArr, null);
648     cc.EGLView.getInstance().touchesEnded(posArr, null);
649 };
650 
651 /**
652  * @param {HTMLCanvasElement|HTMLDivElement} element
653  */
654 cc.TouchDispatcher.registerHtmlElementEvent = function (element) {
655     if (cc.TouchDispatcher.isRegisterEvent) return;
656 
657     if (!cc.Browser.isMobile) {
658         window.addEventListener('mousedown', function (event) {
659             cc.Director.getInstance().getTouchDispatcher()._setMousePressed(true);
660         });
661 
662         window.addEventListener('mouseup', function (event) {
663             cc.Director.getInstance().getTouchDispatcher()._setMousePressed(false);
664 
665             var pos = cc.getHTMLElementPosition(element);
666 
667             var tx, ty;
668             if (event.pageX != null) { //not avalable in <= IE8
669                 tx = event.pageX;
670                 ty = event.pageY;
671             } else {
672                 pos.left -= document.body.scrollLeft;
673                 pos.top -= document.body.scrollTop;
674                 tx = event.clientX;
675                 ty = event.clientY;
676             }
677 
678             if (!cc.rectContainsPoint(new cc.Rect(pos.left, pos.top, pos.width, pos.height), cc.p(tx, ty))) {
679                 var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
680                 var touch = new cc.Touch(location.x,  location.y);
681                 touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
682                 cc.TouchDispatcher.preTouchPoint.x = location.x;
683                 cc.TouchDispatcher.preTouchPoint.y = location.y;
684 
685                 var posArr = [];
686                 posArr.push(touch);
687                 //csx cc.Director.getInstance().getTouchDispatcher().touchesEnded(posArr, null);
688                 cc.EGLView.getInstance().touchesEnded(posArr, null);
689             }
690         });
691 
692         //register canvas mouse event
693         element.addEventListener("mousedown", function (event) {
694             var pos = cc.getHTMLElementPosition(element);
695 
696             var tx, ty;
697             if (event.pageX != null) { //not avalable in <= IE8
698                 tx = event.pageX;
699                 ty = event.pageY;
700             } else {
701                 pos.left -= document.body.scrollLeft;
702                 pos.top -= document.body.scrollTop;
703                 tx = event.clientX;
704                 ty = event.clientY;
705             }
706 
707             var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
708             var touch = new cc.Touch(location.x,  location.y);
709             touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
710             cc.TouchDispatcher.preTouchPoint.x = location.x;
711             cc.TouchDispatcher.preTouchPoint.y = location.y;
712 
713             var posArr = [];
714             posArr.push(touch);
715             //csx cc.Director.getInstance().getTouchDispatcher().touchesBegan(posArr, null);
716             cc.EGLView.getInstance().touchesBegan(posArr, null);
717         });
718 
719         element.addEventListener("mouseup", function (event) {
720             cc.ProcessMouseupEvent(element, event);
721         });
722 
723         element.addEventListener("mousemove", function (event) {
724             var pos = cc.getHTMLElementPosition(element);
725 
726             var tx, ty;
727             if (event.pageX != null) { //not avalable in <= IE8
728                 tx = event.pageX;
729                 ty = event.pageY;
730             } else {
731                 pos.left -= document.body.scrollLeft;
732                 pos.top -= document.body.scrollTop;
733                 tx = event.clientX;
734                 ty = event.clientY;
735             }
736 
737             var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
738             var touch = new cc.Touch(location.x,  location.y);
739             //TODO this feature only chrome support
740             //if((event.button == 0) && (event.which == 1))
741             //    touch._setPressed(true);
742             touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
743             cc.TouchDispatcher.preTouchPoint.x = location.x;
744             cc.TouchDispatcher.preTouchPoint.y = location.y;
745 
746             var posArr = [];
747             posArr.push(touch);
748 
749             //csx cc.Director.getInstance().getTouchDispatcher().touchesMoved(posArr, null);
750             cc.EGLView.getInstance().touchesMoved(posArr, null);
751         });
752     } 
753     else if(window.navigator.msPointerEnabled){ 
754         var _pointerEventsMap = {
755             "MSPointerDown"     : "touchesBegan",
756             "MSPointerMove"     : "touchesMoved",
757             "MSPointerUp"       : "touchesEnded",
758             "MSPointerCancel"   : "touchesCancelled" 
759         };
760 
761         for(var i in _pointerEventsMap){
762             (function(_pointerEvent, _touchEvent){
763                 element.addEventListener(_pointerEvent, function (event){
764                     var pos = cc.getHTMLElementPosition(element);
765 
766                     pos.left -= document.body.scrollLeft;
767                     pos.top -= document.body.scrollTop;
768                     
769                     var tx, ty, touch, preLocation;
770                     tx = event.clientX;
771                     ty = event.clientY;
772 
773                     var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
774                     var touch = new cc.Touch(location.x,  location.y);
775                     touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
776                     cc.TouchDispatcher.preTouchPoint.x = location.x;
777                     cc.TouchDispatcher.preTouchPoint.y = location.y;
778 
779                     cc.Director.getInstance().getTouchDispatcher()[_touchEvent]([touch], null);
780                     event.stopPropagation();
781                     event.preventDefault();
782                 }, false);
783             })(i, _pointerEventsMap[i]);
784         }
785     }
786     else {
787 
788         //register canvas touch event
789         element.addEventListener("touchstart", function (event) {
790             if (!event.changedTouches) return;
791 
792             var posArr = [];
793             var pos = cc.getHTMLElementPosition(element);
794 
795             pos.left -= document.body.scrollLeft;
796             pos.top -= document.body.scrollTop;
797 
798             var touch_event, tx, ty, touch, preLocation;
799             var length = event.changedTouches.length;
800             for (var i = 0; i < length; i++) {
801                 touch_event = event.changedTouches[i];
802                 //tx = touch_event.pageX;
803                 //ty = touch_event.pageY;
804                 if (touch_event) {
805                     tx = touch_event.clientX;
806                     ty = touch_event.clientY;
807 
808                     var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
809                     touch = null;
810                     if (touch_event.hasOwnProperty("identifier")) {
811                         touch = new cc.Touch(location.x, location.y, touch_event.identifier);
812                         //use Touch Pool
813                         preLocation = cc.TouchDispatcher._getPreTouch(touch).getLocation();
814                         touch._setPrevPoint(preLocation.x, preLocation.y);
815                         cc.TouchDispatcher._setPreTouch(touch);
816                     } else {
817                         touch = new cc.Touch(location.x, location.y);
818                         touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
819                     }
820                     cc.TouchDispatcher.preTouchPoint.x = location.x;
821                     cc.TouchDispatcher.preTouchPoint.y = location.y;
822 
823                     posArr.push(touch);
824                 }
825             }
826             //csx cc.Director.getInstance().getTouchDispatcher().touchesBegan(posArr, null);
827             cc.EGLView.getInstance().touchesBegan(posArr, null);
828             event.stopPropagation();
829             event.preventDefault();
830         }, false);
831 
832         element.addEventListener("touchmove", function (event) {
833             if (!event.changedTouches) return;
834 
835             var posArr = [];
836             var pos = cc.getHTMLElementPosition(element);
837 
838             pos.left -= document.body.scrollLeft;
839             pos.top -= document.body.scrollTop;
840 
841             var touch_event, tx, ty, touch, preLocation;
842             var length = event.changedTouches.length;
843             for (var i = 0; i < length; i++) {
844                 touch_event = event.changedTouches[i];
845                 //tx = touch_event.pageX;
846                 //ty = touch_event.pageY;
847                 if (touch_event) {
848                     tx = touch_event.clientX;
849                     ty = touch_event.clientY;
850 
851                     var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
852 
853                     touch = null;
854                     if (touch_event.hasOwnProperty("identifier")) {
855                         touch = new cc.Touch(location.x, location.y, touch_event.identifier);
856                         //use Touch Pool
857                         preLocation = cc.TouchDispatcher._getPreTouch(touch).getLocation();
858                         touch._setPrevPoint(preLocation.x, preLocation.y);
859                         cc.TouchDispatcher._setPreTouch(touch);
860                     } else {
861                         touch = new cc.Touch(location.x, location.y);
862                         touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
863                     }
864                     cc.TouchDispatcher.preTouchPoint.x = location.x;
865                     cc.TouchDispatcher.preTouchPoint.y = location.y;
866 
867                     posArr.push(touch);
868                 }
869             }
870             //csx cc.Director.getInstance().getTouchDispatcher().touchesMoved(posArr, null);
871             cc.EGLView.getInstance().touchesMoved(posArr, null);
872             event.stopPropagation();
873             event.preventDefault();
874         }, false);
875 
876         element.addEventListener("touchend", function (event) {
877             if (!event.changedTouches) return;
878 
879             var posArr = [];
880             var pos = cc.getHTMLElementPosition(element);
881 
882             pos.left -= document.body.scrollLeft;
883             pos.top -= document.body.scrollTop;
884 
885             var touch_event, tx, ty, touch, preLocation;
886             var length = event.changedTouches.length;
887             for (var i = 0; i < length; i++) {
888                 touch_event = event.changedTouches[i];
889                 //tx = touch_event.pageX;
890                 //ty = touch_event.pageY;
891                 if (touch_event) {
892                     tx = touch_event.clientX;
893                     ty = touch_event.clientY;
894 
895                     var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
896 
897                     touch = null;
898                     if (touch_event.hasOwnProperty("identifier")) {
899                         touch = new cc.Touch(location.x, location.y, touch_event.identifier);
900                         //use Touch Pool
901                         preLocation = cc.TouchDispatcher._getPreTouch(touch).getLocation();
902                         touch._setPrevPoint(preLocation.x, preLocation.y);
903                         cc.TouchDispatcher._deletePreTouchWithSameId(touch);
904                     } else {
905                         touch = new cc.Touch(location.x, location.y);
906                         touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
907                     }
908                     cc.TouchDispatcher.preTouchPoint.x = location.x;
909                     cc.TouchDispatcher.preTouchPoint.y = location.y;
910 
911                     posArr.push(touch);
912                 }
913             }
914             //csx cc.Director.getInstance().getTouchDispatcher().touchesEnded(posArr, null);
915             cc.EGLView.getInstance().touchesEnded(posArr, null);
916             event.stopPropagation();
917             event.preventDefault();
918         }, false);
919 
920         element.addEventListener("touchcancel", function (event) {
921             if (!event.changedTouches) return;
922 
923             var posArr = [];
924             var pos = cc.getHTMLElementPosition(element);
925 
926             pos.left -= document.body.scrollLeft;
927             pos.top -= document.body.scrollTop;
928 
929             var touch_event, tx, ty, touch, preLocation;
930             var length = event.changedTouches.length;
931             for (var i = 0; i < length; i++) {
932                 touch_event = event.changedTouches[i];
933                 //tx = touch_event.pageX;
934                 //ty = touch_event.pageY;
935                 if (touch_event) {
936                     tx = touch_event.clientX;
937                     ty = touch_event.clientY;
938 
939                     var location = cc.EGLView.getInstance().convertToLocationInView(tx, ty, pos);
940 
941                     touch = null;
942                     if (touch_event.hasOwnProperty("identifier")) {
943                         touch = new cc.Touch(location.x, location.y, touch_event.identifier);
944                         //use Touch Pool
945                         preLocation = cc.TouchDispatcher._getPreTouch(touch).getLocation();
946                         touch._setPrevPoint(preLocation.x, preLocation.y);
947                         cc.TouchDispatcher._deletePreTouchWithSameId(touch);
948                     } else {
949                         touch = new cc.Touch(location.x, location.y);
950                         touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
951                     }
952                     cc.TouchDispatcher.preTouchPoint.x = location.x;
953                     cc.TouchDispatcher.preTouchPoint.y = location.y;
954 
955                     posArr.push(touch);
956                 }
957             }
958             //csx cc.Director.getInstance().getTouchDispatcher().touchesCancelled(posArr, null);
959             cc.EGLView.getInstance().touchesCancelled(posArr, null);
960             event.stopPropagation();
961             event.preventDefault();
962         }, false);
963     }
964 
965     cc.TouchDispatcher.isRegisterEvent = true;
966 };
967 
968 /**
969  * @param {cc.Touch} touch
970  * @return {cc.Touch} preTouch
971  */
972 cc.TouchDispatcher._getPreTouch = function (touch) {
973     var preTouch = null;
974     var preTouchPool = cc.TouchDispatcher._preTouchPool;
975     var id = touch.getId();
976     for (var i = preTouchPool.length - 1; i >= 0; i--) {
977         if (preTouchPool[i].getId() == id) {
978             preTouch = preTouchPool[i];
979             break;
980         }
981     }
982     if (!preTouch) {
983         preTouch = touch;
984     }
985     return preTouch;
986 };
987 
988 /**
989  * @param {cc.Touch} touch
990  */
991 cc.TouchDispatcher._setPreTouch = function (touch) {
992     var find = false;
993     var preTouchPool = cc.TouchDispatcher._preTouchPool;
994     var id = touch.getId();
995     for (var i = preTouchPool.length - 1; i >= 0; i--) {
996         if (preTouchPool[i].getId() == id) {
997             preTouchPool[i] = touch;
998             find = true;
999             break;
1000         }
1001     }
1002     if (!find) {
1003         //debug touches{
1004         //cc.log("Pool.length: " + preTouchPool.length);
1005         //}
1006         if (preTouchPool.length <= 50) {
1007             preTouchPool.push(touch);
1008         } else {
1009             preTouchPool[cc.TouchDispatcher._preTouchPoolPointer] = touch;
1010             cc.TouchDispatcher._preTouchPoolPointer = (cc.TouchDispatcher._preTouchPoolPointer + 1) % 50;
1011         }
1012     }
1013 };
1014 
1015 /**
1016  * @param {cc.Touch} touch
1017  */
1018 cc.TouchDispatcher._deletePreTouchWithSameId = function (touch) {
1019     var changeTouch;
1020     var preTouchPool = cc.TouchDispatcher._preTouchPool;
1021     var id = touch.getId();
1022     for (var i = preTouchPool.length - 1; i >= 0; i--) {
1023         if (preTouchPool[i].getId() == id) {
1024             changeTouch = preTouchPool.pop();
1025             if (i != preTouchPool.length) {
1026                 preTouchPool[i] = changeTouch;
1027             }
1028             break;
1029         }
1030     }
1031 };
1032 
1033 /**
1034  * @type {Array}
1035  */
1036 cc.TouchDispatcher._preTouchPool = [];
1037 
1038 /**
1039  * @type {Number}
1040  */
1041 cc.TouchDispatcher._preTouchPoolPointer = 0;
1042 
1043 /**
1044  * register a targeted touch delegate to the dispatcher's list.
1045  * @param {Number} priority
1046  * @param {Boolean} swallowsTouches
1047  * @param {Object} delegate
1048  */
1049 cc.registerTargetedDelegate = function(priority, swallowsTouches, delegate){
1050     cc.Director.getInstance().getTouchDispatcher()._addTargetedDelegate(delegate, priority, swallowsTouches);
1051 };
1052 
1053 /**
1054  * Adds a standard touch delegate to the dispatcher's list.
1055  * See StandardTouchDelegate description.
1056  * @param {Object} delegate
1057  * @param {Number} [priority=]
1058  */
1059 cc.registerStandardDelegate = function(delegate, priority){
1060     cc.Director.getInstance().getTouchDispatcher()._addStandardDelegate(delegate, priority);
1061 };
1062 
1063 /**
1064  * Removes a touch delegate. from TouchDispatcher
1065  * @param delegate
1066  */
1067 cc.unregisterTouchDelegate = function(delegate){
1068     cc.Director.getInstance().getTouchDispatcher()._removeDelegate(delegate);
1069 };