You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

332 lines
7.0 KiB

  1. define([
  2. 'js/system/events',
  3. 'js/rendering/renderer'
  4. ], function (
  5. events,
  6. renderer
  7. ) {
  8. return {
  9. axes: {
  10. horizontal: {
  11. negative: ['left', 'a', 'q', 'z'],
  12. positive: ['right', 'd', 'e', 'c']
  13. },
  14. vertical: {
  15. negative: ['up', 'w', 'q', 'e'],
  16. positive: ['down', 's', 'x', 'z', 'c']
  17. }
  18. },
  19. //Certain keys should always register even if they don't get emitted
  20. modifiers: [
  21. 'shift', 'ctrl'
  22. ],
  23. numericalKeyCodeMappings: {
  24. Digit1: 49,
  25. Digit2: 50,
  26. Digit3: 51,
  27. Digit4: 52,
  28. Digit5: 53
  29. },
  30. mappings: {
  31. 8: 'backspace',
  32. 9: 'tab',
  33. 13: 'enter',
  34. 16: 'shift',
  35. 17: 'ctrl',
  36. 27: 'esc',
  37. 37: 'left',
  38. 38: 'up',
  39. 39: 'right',
  40. 40: 'down',
  41. 46: 'del',
  42. //hacks for mac cmd key
  43. 224: 'ctrl',
  44. 91: 'ctrl',
  45. 93: 'ctrl'
  46. },
  47. mouse: {
  48. button: null,
  49. x: 0,
  50. y: 0
  51. },
  52. mouseRaw: null,
  53. keys: {},
  54. enabled: true,
  55. blacklistedKeys: [],
  56. whitelistedKeys: [],
  57. init: function () {
  58. $(window).on('keydown', this.events.keyboard.keyDown.bind(this));
  59. $(window).on('keyup', this.events.keyboard.keyUp.bind(this));
  60. events.on('onSceneMove', this.events.mouse.mouseMove.bind(this));
  61. $('.ui-container')
  62. .on('mousedown', this.events.mouse.mouseDown.bind(this))
  63. .on('mouseup', this.events.mouse.mouseUp.bind(this))
  64. .on('mousemove', this.events.mouse.mouseMove.bind(this))
  65. .on('touchstart', this.events.touch.touchStart.bind(this))
  66. .on('touchmove', this.events.touch.touchMove.bind(this))
  67. .on('touchend', this.events.touch.touchEnd.bind(this))
  68. .on('touchcancel', this.events.touch.touchCancel.bind(this));
  69. if (isMobile)
  70. require(['plugins/shake.js'], this.onLoadShake.bind(this));
  71. },
  72. blacklistKeys: function (list) {
  73. this.blacklistedKeys.push(...list);
  74. },
  75. unBlacklistKeys: function (list) {
  76. this.blacklistedKeys.spliceWhere(d => list.includes(d));
  77. },
  78. whitelistKeys: function (list) {
  79. this.whitelistedKeys.push(...list);
  80. },
  81. unWhitelistKeys: function (list) {
  82. this.whitelistedKeys.spliceWhere(d => list.includes(d));
  83. },
  84. onLoadShake: function (shake) {
  85. let shaker = new shake({
  86. threshold: 5,
  87. timeout: 1000
  88. });
  89. shaker.start();
  90. window.addEventListener('shake', this.events.mobile.onShake.bind(this), false);
  91. },
  92. resetKeys: function () {
  93. for (let k in this.keys)
  94. events.emit('onKeyUp', k);
  95. this.keys = {};
  96. },
  97. getMapping: function (charCode) {
  98. if (charCode >= 97)
  99. return (charCode - 96).toString();
  100. return (
  101. this.mappings[charCode] ||
  102. String.fromCharCode(charCode).toLowerCase()
  103. );
  104. },
  105. isKeyDown: function (key, noConsume) {
  106. if (this.keys.has(key)) {
  107. if (noConsume)
  108. return true;
  109. let down = this.keys[key];
  110. this.keys[key] = 2;
  111. return (down === 1);
  112. } return false;
  113. },
  114. getAxis: function (axisName) {
  115. let axis = this.axes[axisName];
  116. if (!axis)
  117. return 0;
  118. let result = 0;
  119. for (let i = 0; i < axis.negative.length; i++) {
  120. if (this.keys[axis.negative[i]]) {
  121. result--;
  122. break;
  123. }
  124. }
  125. for (let i = 0; i < axis.positive.length; i++) {
  126. if (this.keys[axis.positive[i]]) {
  127. result++;
  128. break;
  129. }
  130. }
  131. return result;
  132. },
  133. isKeyAllowed: function (key) {
  134. const result = (
  135. key.length > 1 ||
  136. this.whitelistedKeys.includes(key) ||
  137. (
  138. !this.blacklistedKeys.includes(key) &&
  139. !this.blacklistedKeys.includes('*')
  140. )
  141. );
  142. return result;
  143. },
  144. events: {
  145. keyboard: {
  146. /* eslint-disable-next-line max-lines-per-function */
  147. keyDown: function (e) {
  148. if (!this.enabled)
  149. return;
  150. let code = this.numericalKeyCodeMappings[e.code] || e.which;
  151. let key = this.getMapping(code);
  152. let isModifier = this.modifiers.indexOf(key) > -1;
  153. let isBody = e.target === document.body;
  154. if (!isModifier && !isBody)
  155. return true;
  156. if ((e.keyCode === 9) || (e.keyCode === 8) || (e.keyCode === 122))
  157. e.preventDefault();
  158. if (!this.isKeyAllowed(key))
  159. return;
  160. if (this.keys.has(key))
  161. this.keys[key] = 2;
  162. else {
  163. this.keys[key] = 1;
  164. if (isBody || isModifier) {
  165. let keyEvent = {
  166. key: key,
  167. consumed: false
  168. };
  169. events.emit('onUiKeyDown', keyEvent);
  170. if (!keyEvent.consumed)
  171. events.emit('onCanvasKeyDown', keyEvent);
  172. events.emit('onKeyDown', key);
  173. }
  174. }
  175. if (key === 'backspace')
  176. return false;
  177. else if (e.key === 'F11')
  178. events.emit('onToggleFullscreen');
  179. },
  180. keyUp: function (e) {
  181. if (!this.enabled)
  182. return;
  183. let key = this.getMapping(e.which);
  184. let isModifier = this.modifiers.indexOf(key) > -1;
  185. let isBody = e.target === document.body;
  186. if (!isModifier && !isBody)
  187. return;
  188. delete this.keys[key];
  189. events.emit('onKeyUp', key);
  190. }
  191. },
  192. mouse: {
  193. mouseDown: function (e) {
  194. let el = $(e.target);
  195. if ((!el.hasClass('ui-container')) || (el.hasClass('blocking')))
  196. return;
  197. let button = e.button;
  198. this.mouse.button = button;
  199. this.mouse.down = true;
  200. this.mouse.event = e;
  201. //This is needed for casting targetted spells on Mobile...it's hacky.
  202. this.mouse.worldX = e.pageX + renderer.pos.x;
  203. this.mouse.worldY = e.pageY + renderer.pos.y;
  204. events.emit('mouseDown', this.mouse);
  205. },
  206. mouseUp: function (e) {
  207. let el = $(e.target);
  208. if ((!el.hasClass('ui-container')) || (el.hasClass('blocking')))
  209. return;
  210. this.mouse.button = null;
  211. this.mouse.down = false;
  212. events.emit('mouseUp', this.mouse);
  213. },
  214. mouseMove: function (e) {
  215. if (e)
  216. this.mouseRaw = e;
  217. else
  218. e = this.mouseRaw;
  219. if (!e)
  220. return;
  221. let el = $(e.target);
  222. if ((!el.hasClass('ui-container')) || (el.hasClass('blocking')))
  223. return;
  224. this.mouse.x = e.offsetX + renderer.pos.x;
  225. this.mouse.y = e.offsetY + renderer.pos.y;
  226. }
  227. },
  228. touch: {
  229. touchStart: function (e) {
  230. let el = $(e.target);
  231. if ((!el.hasClass('ui-container')) || (el.hasClass('blocking')))
  232. return;
  233. let touch = e.touches[0];
  234. events.emit('onTouchStart', {
  235. x: touch.clientX,
  236. y: touch.clientY,
  237. worldX: touch.clientX + renderer.pos.x,
  238. worldY: touch.clientY + renderer.pos.y
  239. });
  240. },
  241. touchMove: function (e) {
  242. let el = $(e.target);
  243. if ((!el.hasClass('ui-container')) || (el.hasClass('blocking')))
  244. return;
  245. let touch = e.touches[0];
  246. events.emit('onTouchMove', {
  247. x: touch.clientX,
  248. y: touch.clientY,
  249. touches: e.touches.length
  250. });
  251. },
  252. touchEnd: function (e) {
  253. let el = $(e.target);
  254. if ((!el.hasClass('ui-container')) || (el.hasClass('blocking')))
  255. return;
  256. events.emit('onTouchEnd');
  257. },
  258. touchCancel: function (e) {
  259. let el = $(e.target);
  260. if ((!el.hasClass('ui-container')) || (el.hasClass('blocking')))
  261. return;
  262. events.emit('onTouchCancel');
  263. }
  264. },
  265. mobile: {
  266. onShake: function (e) {
  267. events.emit('onShake', e);
  268. }
  269. }
  270. }
  271. };
  272. });