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