1 /**************************************************************************** 2 Copyright (c) 2011-2012 cocos2d-x.org 3 Copyright (c) 2013-2014 Chukong Technologies Inc. 4 5 http://www.cocos2d-x.org 6 7 Permission is hereby granted, free of charge, to any person obtaining a copy 8 of this software and associated documentation files (the "Software"), to deal 9 in the Software without restriction, including without limitation the rights 10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 copies of the Software, and to permit persons to whom the Software is 12 furnished to do so, subject to the following conditions: 13 14 The above copyright notice and this permission notice shall be included in 15 all copies or substantial portions of the Software. 16 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 THE SOFTWARE. 24 ****************************************************************************/ 25 26 /** 27 * ignore 28 */ 29 cc.UIInterfaceOrientationLandscapeLeft = -90; 30 31 cc.UIInterfaceOrientationLandscapeRight = 90; 32 33 cc.UIInterfaceOrientationPortraitUpsideDown = 180; 34 35 cc.UIInterfaceOrientationPortrait = 0; 36 37 /** 38 * <p> 39 * This class manages all events of input. include: touch, mouse, accelerometer, keyboard <br/> 40 * </p> 41 * @namespace 42 */ 43 cc.inputManager = /** @lends cc.inputManager# */{ 44 _mousePressed: false, 45 46 _isRegisterEvent: false, 47 48 _preTouchPoint: cc.p(0,0), 49 _prevMousePoint: cc.p(0,0), 50 51 _preTouchPool: [], 52 _preTouchPoolPointer: 0, 53 54 _touches: [], 55 _touchesIntegerDict:{}, 56 57 _indexBitsUsed: 0, 58 _maxTouches: 5, 59 60 _accelEnabled: false, 61 _accelInterval: 1/30, 62 _accelMinus: 1, 63 _accelCurTime: 0, 64 _acceleration: null, 65 _accelDeviceEvent: null, 66 67 _getUnUsedIndex: function () { 68 var temp = this._indexBitsUsed; 69 70 for (var i = 0; i < this._maxTouches; i++) { 71 if (!(temp & 0x00000001)) { 72 this._indexBitsUsed |= (1 << i); 73 return i; 74 } 75 temp >>= 1; 76 } 77 78 // all bits are used 79 return -1; 80 }, 81 82 _removeUsedIndexBit: function (index) { 83 if (index < 0 || index >= this._maxTouches) 84 return; 85 86 var temp = 1 << index; 87 temp = ~temp; 88 this._indexBitsUsed &= temp; 89 }, 90 91 _glView: null, 92 93 handleTouchesBegin: function (touches) { 94 var selTouch, index, curTouch, touchID, handleTouches = [], locTouchIntDict = this._touchesIntegerDict; 95 for(var i = 0, len = touches.length; i< len; i ++){ 96 selTouch = touches[i]; 97 touchID = selTouch.getID(); 98 index = locTouchIntDict[touchID]; 99 100 if(index == null){ 101 var unusedIndex = this._getUnUsedIndex(); 102 if (unusedIndex == -1) { 103 cc.log(cc._LogInfos.inputManager_handleTouchesBegin, unusedIndex); 104 continue; 105 } 106 curTouch = this._touches[unusedIndex] = selTouch; 107 locTouchIntDict[touchID] = unusedIndex; 108 handleTouches.push(curTouch); 109 } 110 } 111 if(handleTouches.length > 0){ 112 this._glView._convertTouchesWithScale(handleTouches); 113 var touchEvent = new cc.EventTouch(handleTouches); 114 touchEvent._eventCode = cc.EventTouch.EventCode.BEGAN; 115 cc.eventManager.dispatchEvent(touchEvent); 116 } 117 }, 118 119 handleTouchesMove: function(touches){ 120 var selTouch, index, touchID, handleTouches = [], locTouches = this._touches; 121 for(var i = 0, len = touches.length; i< len; i ++){ 122 selTouch = touches[i]; 123 touchID = selTouch.getID(); 124 index = this._touchesIntegerDict[touchID]; 125 126 if(index == null){ 127 //cc.log("if the index doesn't exist, it is an error"); 128 continue; 129 } 130 if(locTouches[index]){ 131 locTouches[index]._setPoint(selTouch._point); 132 locTouches[index]._setPrevPoint(selTouch._prevPoint); 133 handleTouches.push(locTouches[index]); 134 } 135 } 136 if(handleTouches.length > 0){ 137 this._glView._convertTouchesWithScale(handleTouches); 138 var touchEvent = new cc.EventTouch(handleTouches); 139 touchEvent._eventCode = cc.EventTouch.EventCode.MOVED; 140 cc.eventManager.dispatchEvent(touchEvent); 141 } 142 }, 143 144 handleTouchesEnd: function(touches){ 145 var handleTouches = this.getSetOfTouchesEndOrCancel(touches); 146 if(handleTouches.length > 0) { 147 this._glView._convertTouchesWithScale(handleTouches); 148 var touchEvent = new cc.EventTouch(handleTouches); 149 touchEvent._eventCode = cc.EventTouch.EventCode.ENDED; 150 cc.eventManager.dispatchEvent(touchEvent); 151 } 152 }, 153 154 handleTouchesCancel: function(touches){ 155 var handleTouches = this.getSetOfTouchesEndOrCancel(touches); 156 if(handleTouches.length > 0) { 157 this._glView._convertTouchesWithScale(handleTouches); 158 var touchEvent = new cc.EventTouch(handleTouches); 159 touchEvent._eventCode = cc.EventTouch.EventCode.CANCELLED; 160 cc.eventManager.dispatchEvent(touchEvent); 161 } 162 }, 163 164 getSetOfTouchesEndOrCancel: function(touches) { 165 var selTouch, index, touchID, handleTouches = [], locTouches = this._touches, locTouchesIntDict = this._touchesIntegerDict; 166 for(var i = 0, len = touches.length; i< len; i ++){ 167 selTouch = touches[i]; 168 touchID = selTouch.getID(); 169 index = locTouchesIntDict[touchID]; 170 171 if(index == null){ 172 continue; //cc.log("if the index doesn't exist, it is an error"); 173 } 174 if(locTouches[index]){ 175 locTouches[index]._setPoint(selTouch._point); 176 locTouches[index]._setPrevPoint(selTouch._prevPoint); //TODO 177 handleTouches.push(locTouches[index]); 178 this._removeUsedIndexBit(index); 179 delete locTouchesIntDict[touchID]; 180 } 181 } 182 return handleTouches; 183 }, 184 185 getHTMLElementPosition: function (element) { 186 var docElem = document.documentElement; 187 var win = window; 188 var box = null; 189 if (typeof element.getBoundingClientRect === 'function') { 190 box = element.getBoundingClientRect(); 191 } else { 192 if (element instanceof HTMLCanvasElement) { 193 box = { 194 left: 0, 195 top: 0, 196 width: element.width, 197 height: element.height 198 }; 199 } else { 200 box = { 201 left: 0, 202 top: 0, 203 width: parseInt(element.style.width), 204 height: parseInt(element.style.height) 205 }; 206 } 207 } 208 return { 209 left: box.left + win.pageXOffset - docElem.clientLeft, 210 top: box.top + win.pageYOffset - docElem.clientTop, 211 width: box.width, 212 height: box.height 213 }; 214 }, 215 216 getPreTouch: function(touch){ 217 var preTouch = null; 218 var locPreTouchPool = this._preTouchPool; 219 var id = touch.getId(); 220 for (var i = locPreTouchPool.length - 1; i >= 0; i--) { 221 if (locPreTouchPool[i].getId() == id) { 222 preTouch = locPreTouchPool[i]; 223 break; 224 } 225 } 226 if (!preTouch) 227 preTouch = touch; 228 return preTouch; 229 }, 230 231 setPreTouch: function(touch){ 232 var find = false; 233 var locPreTouchPool = this._preTouchPool; 234 var id = touch.getId(); 235 for (var i = locPreTouchPool.length - 1; i >= 0; i--) { 236 if (locPreTouchPool[i].getId() == id) { 237 locPreTouchPool[i] = touch; 238 find = true; 239 break; 240 } 241 } 242 if (!find) { 243 if (locPreTouchPool.length <= 50) { 244 locPreTouchPool.push(touch); 245 } else { 246 locPreTouchPool[this._preTouchPoolPointer] = touch; 247 this._preTouchPoolPointer = (this._preTouchPoolPointer + 1) % 50; 248 } 249 } 250 }, 251 252 getTouchByXY: function(tx, ty, pos){ 253 var locPreTouch = this._preTouchPoint; 254 var location = this._glView.convertToLocationInView(tx, ty, pos); 255 var touch = new cc.Touch(location.x, location.y); 256 touch._setPrevPoint(locPreTouch.x, locPreTouch.y); 257 locPreTouch.x = location.x; 258 locPreTouch.y = location.y; 259 return touch; 260 }, 261 262 getMouseEvent: function(location, pos, eventType){ 263 var locPreMouse = this._prevMousePoint; 264 this._glView._convertMouseToLocationInView(location, pos); 265 var mouseEvent = new cc.EventMouse(eventType); 266 mouseEvent.setLocation(location.x, location.y); 267 mouseEvent._setPrevCursor(locPreMouse.x, locPreMouse.y); 268 locPreMouse.x = location.x; 269 locPreMouse.y = location.y; 270 return mouseEvent; 271 }, 272 273 getPointByEvent: function(event, pos){ 274 if (event.pageX != null) //not avalable in <= IE8 275 return {x: event.pageX, y: event.pageY}; 276 277 pos.left -= document.body.scrollLeft; 278 pos.top -= document.body.scrollTop; 279 return {x: event.clientX, y: event.clientY}; 280 }, 281 282 getTouchesByEvent: function(event, pos){ 283 var touchArr = [], locView = this._glView; 284 var touch_event, touch, preLocation; 285 var locPreTouch = this._preTouchPoint; 286 287 var length = event.changedTouches.length; 288 for (var i = 0; i < length; i++) { 289 touch_event = event.changedTouches[i]; 290 if (touch_event) { 291 var location; 292 if (cc.sys.BROWSER_TYPE_FIREFOX === cc.sys.browserType) 293 location = locView.convertToLocationInView(touch_event.pageX, touch_event.pageY, pos); 294 else 295 location = locView.convertToLocationInView(touch_event.clientX, touch_event.clientY, pos); 296 if (touch_event.identifier != null) { 297 touch = new cc.Touch(location.x, location.y, touch_event.identifier); 298 //use Touch Pool 299 preLocation = this.getPreTouch(touch).getLocation(); 300 touch._setPrevPoint(preLocation.x, preLocation.y); 301 this.setPreTouch(touch); 302 } else { 303 touch = new cc.Touch(location.x, location.y); 304 touch._setPrevPoint(locPreTouch.x, locPreTouch.y); 305 } 306 locPreTouch.x = location.x; 307 locPreTouch.y = location.y; 308 touchArr.push(touch); 309 } 310 } 311 return touchArr; 312 }, 313 314 registerSystemEvent: function(element){ 315 if(this._isRegisterEvent) return; 316 317 var locView = this._glView = cc.view; 318 var selfPointer = this; 319 var supportMouse = ('mouse' in cc.sys.capabilities), supportTouches = ('touches' in cc.sys.capabilities); 320 321 //register touch event 322 if (supportMouse) { 323 cc._addEventListener(window, 'mousedown', function () { 324 selfPointer._mousePressed = true; 325 }, false); 326 327 cc._addEventListener(window, 'mouseup', function (event) { 328 var savePressed = selfPointer._mousePressed; 329 selfPointer._mousePressed = false; 330 331 if(!savePressed) 332 return; 333 334 var pos = selfPointer.getHTMLElementPosition(element); 335 var location = selfPointer.getPointByEvent(event, pos); 336 if (!cc.rectContainsPoint(new cc.Rect(pos.left, pos.top, pos.width, pos.height), location)){ 337 if(!supportTouches) 338 selfPointer.handleTouchesEnd([selfPointer.getTouchByXY(location.x, location.y, pos)]); 339 340 var mouseEvent = selfPointer.getMouseEvent(location,pos,cc.EventMouse.UP); 341 mouseEvent.setButton(event.button); 342 cc.eventManager.dispatchEvent(mouseEvent); 343 } 344 }, false); 345 346 //register canvas mouse event 347 cc._addEventListener(element,"mousedown", function (event) { 348 selfPointer._mousePressed = true; 349 350 var pos = selfPointer.getHTMLElementPosition(element); 351 var location = selfPointer.getPointByEvent(event, pos); 352 if(!supportTouches) 353 selfPointer.handleTouchesBegin([selfPointer.getTouchByXY(location.x, location.y, pos)]); 354 355 var mouseEvent = selfPointer.getMouseEvent(location,pos,cc.EventMouse.DOWN); 356 mouseEvent.setButton(event.button); 357 cc.eventManager.dispatchEvent(mouseEvent); 358 359 event.stopPropagation(); 360 event.preventDefault(); 361 }, false); 362 363 cc._addEventListener(element, "mouseup", function (event) { 364 selfPointer._mousePressed = false; 365 366 var pos = selfPointer.getHTMLElementPosition(element); 367 var location = selfPointer.getPointByEvent(event, pos); 368 369 if(!supportTouches) 370 selfPointer.handleTouchesEnd([selfPointer.getTouchByXY(location.x, location.y, pos)]); 371 372 var mouseEvent = selfPointer.getMouseEvent(location,pos,cc.EventMouse.UP); 373 mouseEvent.setButton(event.button); 374 cc.eventManager.dispatchEvent(mouseEvent); 375 376 event.stopPropagation(); 377 event.preventDefault(); 378 }, false); 379 380 cc._addEventListener(element, "mousemove", function (event) { 381 //if(!selfPointer._mousePressed) 382 // return; 383 384 var pos = selfPointer.getHTMLElementPosition(element); 385 var location = selfPointer.getPointByEvent(event, pos); 386 387 if(!supportTouches) 388 selfPointer.handleTouchesMove([selfPointer.getTouchByXY(location.x, location.y, pos)]); 389 390 var mouseEvent = selfPointer.getMouseEvent(location,pos,cc.EventMouse.MOVE); 391 if(selfPointer._mousePressed) 392 mouseEvent.setButton(event.button); 393 else 394 mouseEvent.setButton(null); 395 cc.eventManager.dispatchEvent(mouseEvent); 396 397 event.stopPropagation(); 398 event.preventDefault(); 399 }, false); 400 401 cc._addEventListener(element, "mousewheel", function (event) { 402 var pos = selfPointer.getHTMLElementPosition(element); 403 var location = selfPointer.getPointByEvent(event, pos); 404 405 var mouseEvent = selfPointer.getMouseEvent(location,pos,cc.EventMouse.SCROLL); 406 mouseEvent.setButton(event.button); 407 mouseEvent.setScrollData(0, event.wheelDelta); 408 cc.eventManager.dispatchEvent(mouseEvent); 409 410 event.stopPropagation(); 411 event.preventDefault(); 412 }, false); 413 414 /* firefox fix */ 415 cc._addEventListener(element, "DOMMouseScroll", function(event) { 416 var pos = selfPointer.getHTMLElementPosition(element); 417 var location = selfPointer.getPointByEvent(event, pos); 418 419 var mouseEvent = selfPointer.getMouseEvent(location,pos,cc.EventMouse.SCROLL); 420 mouseEvent.setButton(event.button); 421 mouseEvent.setScrollData(0, event.detail * -120); 422 cc.eventManager.dispatchEvent(mouseEvent); 423 424 event.stopPropagation(); 425 event.preventDefault(); 426 }, false); 427 } 428 429 if(window.navigator.msPointerEnabled){ 430 var _pointerEventsMap = { 431 "MSPointerDown" : selfPointer.handleTouchesBegin, 432 "MSPointerMove" : selfPointer.handleTouchesMove, 433 "MSPointerUp" : selfPointer.handleTouchesEnd, 434 "MSPointerCancel" : selfPointer.handleTouchesCancel 435 }; 436 437 for(var eventName in _pointerEventsMap){ 438 (function(_pointerEvent, _touchEvent){ 439 cc._addEventListener(element, _pointerEvent, function (event){ 440 var pos = selfPointer.getHTMLElementPosition(element); 441 pos.left -= document.documentElement.scrollLeft; 442 pos.top -= document.documentElement.scrollTop; 443 444 _touchEvent.call(selfPointer, [selfPointer.getTouchByXY(event.clientX, event.clientY, pos)]); 445 event.stopPropagation(); 446 event.preventDefault(); 447 }, false); 448 })(eventName, _pointerEventsMap[eventName]); 449 } 450 } 451 452 if(supportTouches) { 453 //register canvas touch event 454 cc._addEventListener(element,"touchstart", function (event) { 455 if (!event.changedTouches) return; 456 457 var pos = selfPointer.getHTMLElementPosition(element); 458 pos.left -= document.body.scrollLeft; 459 pos.top -= document.body.scrollTop; 460 selfPointer.handleTouchesBegin(selfPointer.getTouchesByEvent(event, pos)); 461 event.stopPropagation(); 462 event.preventDefault(); 463 }, false); 464 465 cc._addEventListener(element, "touchmove", function (event) { 466 if (!event.changedTouches) return; 467 468 var pos = selfPointer.getHTMLElementPosition(element); 469 pos.left -= document.body.scrollLeft; 470 pos.top -= document.body.scrollTop; 471 selfPointer.handleTouchesMove(selfPointer.getTouchesByEvent(event, pos)); 472 event.stopPropagation(); 473 event.preventDefault(); 474 }, false); 475 476 cc._addEventListener(element, "touchend", function (event) { 477 if (!event.changedTouches) return; 478 479 var pos = selfPointer.getHTMLElementPosition(element); 480 pos.left -= document.body.scrollLeft; 481 pos.top -= document.body.scrollTop; 482 selfPointer.handleTouchesEnd(selfPointer.getTouchesByEvent(event, pos)); 483 event.stopPropagation(); 484 event.preventDefault(); 485 }, false); 486 487 cc._addEventListener(element, "touchcancel", function (event) { 488 if (!event.changedTouches) return; 489 490 var pos = selfPointer.getHTMLElementPosition(element); 491 pos.left -= document.body.scrollLeft; 492 pos.top -= document.body.scrollTop; 493 locView.handleTouchesCancel(selfPointer.getTouchesByEvent(event, pos)); 494 event.stopPropagation(); 495 event.preventDefault(); 496 }, false); 497 } 498 499 //register keyboard event 500 this._registerKeyboardEvent(); 501 502 //register Accelerometer event 503 this._registerAccelerometerEvent(); 504 505 this._isRegisterEvent = true; 506 }, 507 508 _registerKeyboardEvent: function(){}, 509 510 _registerAccelerometerEvent: function(){}, 511 512 update:function(dt){ 513 if(this._accelCurTime > this._accelInterval){ 514 this._accelCurTime -= this._accelInterval; 515 cc.eventManager.dispatchEvent(new cc.EventAcceleration(this._acceleration)); 516 } 517 this._accelCurTime += dt; 518 } 519 }; 520