• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright 2011 See AUTHORS file.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  ******************************************************************************/
16 
17 package com.badlogic.gdx.backends.gwt;
18 
19 import com.badlogic.gdx.Gdx;
20 import com.badlogic.gdx.Input;
21 import com.badlogic.gdx.InputProcessor;
22 import com.badlogic.gdx.Input.Buttons;
23 import com.badlogic.gdx.backends.gwt.widgets.TextInputDialogBox;
24 import com.badlogic.gdx.backends.gwt.widgets.TextInputDialogBox.TextInputDialogListener;
25 import com.badlogic.gdx.utils.IntMap;
26 import com.badlogic.gdx.utils.IntSet;
27 import com.badlogic.gdx.utils.TimeUtils;
28 import com.gargoylesoftware.htmlunit.javascript.host.Navigator;
29 import com.google.gwt.core.client.JavaScriptObject;
30 import com.google.gwt.core.client.JsArray;
31 import com.google.gwt.dom.client.CanvasElement;
32 import com.google.gwt.dom.client.Document;
33 import com.google.gwt.dom.client.Element;
34 import com.google.gwt.dom.client.NativeEvent;
35 import com.google.gwt.dom.client.Touch;
36 import com.google.gwt.event.dom.client.KeyCodes;
37 import com.google.gwt.logging.client.ConsoleLogHandler;
38 
39 public class GwtInput implements Input {
40 	static final int MAX_TOUCHES = 20;
41 	boolean justTouched = false;
42 	private IntMap<Integer> touchMap = new IntMap<Integer>(20);
43 	private boolean[] touched = new boolean[MAX_TOUCHES];
44 	private int[] touchX = new int[MAX_TOUCHES];
45 	private int[] touchY = new int[MAX_TOUCHES];
46 	private int[] deltaX = new int[MAX_TOUCHES];
47 	private int[] deltaY = new int[MAX_TOUCHES];
48 	IntSet pressedButtons = new IntSet();
49 	int pressedKeyCount = 0;
50 	boolean[] pressedKeys = new boolean[256];
51 	boolean keyJustPressed = false;
52 	boolean[] justPressedKeys = new boolean[256];
53 	InputProcessor processor;
54 	char lastKeyCharPressed;
55 	float keyRepeatTimer;
56 	long currentEventTimeStamp;
57 	final CanvasElement canvas;
58 	boolean hasFocus = true;
59 
GwtInput(CanvasElement canvas)60 	public GwtInput (CanvasElement canvas) {
61 		this.canvas = canvas;
62 		hookEvents();
63 	}
64 
reset()65 	void reset () {
66 		justTouched = false;
67 		if (keyJustPressed) {
68 			keyJustPressed = false;
69 			for (int i = 0; i < justPressedKeys.length; i++) {
70 				justPressedKeys[i] = false;
71 			}
72 		}
73 	}
74 
75 	@Override
getAccelerometerX()76 	public float getAccelerometerX () {
77 		return 0;
78 	}
79 
80 	@Override
getAccelerometerY()81 	public float getAccelerometerY () {
82 		return 0;
83 	}
84 
85 	@Override
getAccelerometerZ()86 	public float getAccelerometerZ () {
87 		return 0;
88 	}
89 
90 	@Override
getGyroscopeX()91 	public float getGyroscopeX () {
92 		// TODO Auto-generated method stub
93 		return 0;
94 	}
95 
96 	@Override
getGyroscopeY()97 	public float getGyroscopeY () {
98 		// TODO Auto-generated method stub
99 		return 0;
100 	}
101 
102 	@Override
getGyroscopeZ()103 	public float getGyroscopeZ () {
104 		// TODO Auto-generated method stub
105 		return 0;
106 	}
107 
108 	@Override
getX()109 	public int getX () {
110 		return touchX[0];
111 	}
112 
113 	@Override
getX(int pointer)114 	public int getX (int pointer) {
115 		return touchX[pointer];
116 	}
117 
118 	@Override
getDeltaX()119 	public int getDeltaX () {
120 		return deltaX[0];
121 	}
122 
123 	@Override
getDeltaX(int pointer)124 	public int getDeltaX (int pointer) {
125 		return deltaX[pointer];
126 	}
127 
128 	@Override
getY()129 	public int getY () {
130 		return touchY[0];
131 	}
132 
133 	@Override
getY(int pointer)134 	public int getY (int pointer) {
135 		return touchY[pointer];
136 	}
137 
138 	@Override
getDeltaY()139 	public int getDeltaY () {
140 		return deltaY[0];
141 	}
142 
143 	@Override
getDeltaY(int pointer)144 	public int getDeltaY (int pointer) {
145 		return deltaY[pointer];
146 	}
147 
148 	@Override
isTouched()149 	public boolean isTouched () {
150 		for (int pointer = 0; pointer < MAX_TOUCHES; pointer++) {
151 			if (touched[pointer]) {
152 				return true;
153 			}
154 		}
155 		return false;
156 	}
157 
158 	@Override
justTouched()159 	public boolean justTouched () {
160 		return justTouched;
161 	}
162 
163 	@Override
isTouched(int pointer)164 	public boolean isTouched (int pointer) {
165 		return touched[pointer];
166 	}
167 
168 	@Override
isButtonPressed(int button)169 	public boolean isButtonPressed (int button) {
170 		return pressedButtons.contains(button) && touched[0];
171 	}
172 
173 	@Override
isKeyPressed(int key)174 	public boolean isKeyPressed (int key) {
175 		if (key == Keys.ANY_KEY) {
176 			return pressedKeyCount > 0;
177 		}
178 		if (key < 0 || key > 255) {
179 			return false;
180 		}
181 		return pressedKeys[key];
182 	}
183 
184 	@Override
isKeyJustPressed(int key)185 	public boolean isKeyJustPressed (int key) {
186 		if (key == Keys.ANY_KEY) {
187 			return keyJustPressed;
188 		}
189 		if (key < 0 || key > 255) {
190 			return false;
191 		}
192 		return justPressedKeys[key];
193 	}
194 
getTextInput(TextInputListener listener, String title, String text, String hint)195 	public void getTextInput (TextInputListener listener, String title, String text, String hint) {
196 		TextInputDialogBox dialog = new TextInputDialogBox(title, text, hint);
197 		final TextInputListener capturedListener = listener;
198 		dialog.setListener(new TextInputDialogListener() {
199 			@Override
200 			public void onPositive (String text) {
201 				if (capturedListener != null) {
202 					capturedListener.input(text);
203 				}
204 			}
205 
206 			@Override
207 			public void onNegative () {
208 				if (capturedListener != null) {
209 					capturedListener.canceled();
210 				}
211 			}
212 		});
213 	}
214 
215 	@Override
setOnscreenKeyboardVisible(boolean visible)216 	public void setOnscreenKeyboardVisible (boolean visible) {
217 	}
218 
219 	@Override
vibrate(int milliseconds)220 	public void vibrate (int milliseconds) {
221 	}
222 
223 	@Override
vibrate(long[] pattern, int repeat)224 	public void vibrate (long[] pattern, int repeat) {
225 	}
226 
227 	@Override
cancelVibrate()228 	public void cancelVibrate () {
229 	}
230 
231 	@Override
getAzimuth()232 	public float getAzimuth () {
233 		return 0;
234 	}
235 
236 	@Override
getPitch()237 	public float getPitch () {
238 		return 0;
239 	}
240 
241 	@Override
getRoll()242 	public float getRoll () {
243 		return 0;
244 	}
245 
246 	@Override
getRotationMatrix(float[] matrix)247 	public void getRotationMatrix (float[] matrix) {
248 	}
249 
250 	@Override
getCurrentEventTime()251 	public long getCurrentEventTime () {
252 		return currentEventTimeStamp;
253 	}
254 
255 	@Override
setCatchBackKey(boolean catchBack)256 	public void setCatchBackKey (boolean catchBack) {
257 	}
258 
259 	@Override
isCatchBackKey()260 	public boolean isCatchBackKey () {
261 		return false;
262 	}
263 
264 	@Override
setCatchMenuKey(boolean catchMenu)265 	public void setCatchMenuKey (boolean catchMenu) {
266 	}
267 
268 	@Override
isCatchMenuKey()269 	public boolean isCatchMenuKey () {
270 		return false;
271 	}
272 
273 	@Override
setInputProcessor(InputProcessor processor)274 	public void setInputProcessor (InputProcessor processor) {
275 		this.processor = processor;
276 	}
277 
278 	@Override
getInputProcessor()279 	public InputProcessor getInputProcessor () {
280 		return processor;
281 	}
282 
283 	@Override
isPeripheralAvailable(Peripheral peripheral)284 	public boolean isPeripheralAvailable (Peripheral peripheral) {
285 		if (peripheral == Peripheral.Accelerometer) return false;
286 		if (peripheral == Peripheral.Compass) return false;
287 		if (peripheral == Peripheral.HardwareKeyboard) return true;
288 		if (peripheral == Peripheral.MultitouchScreen) return isTouchScreen();
289 		if (peripheral == Peripheral.OnscreenKeyboard) return false;
290 		if (peripheral == Peripheral.Vibrator) return false;
291 		return false;
292 	}
293 
294 	@Override
getRotation()295 	public int getRotation () {
296 		return 0;
297 	}
298 
299 	@Override
getNativeOrientation()300 	public Orientation getNativeOrientation () {
301 		return Orientation.Landscape;
302 	}
303 
304 	/** from https://github.com/toji/game-shim/blob/master/game-shim.js
305 	 * @return is Cursor catched */
isCursorCatchedJSNI()306 	private native boolean isCursorCatchedJSNI () /*-{
307 		if (!navigator.pointer) {
308 			navigator.pointer = navigator.webkitPointer || navigator.mozPointer;
309 		}
310 		if (navigator.pointer) {
311 			if (typeof (navigator.pointer.isLocked) === "boolean") {
312 				// Chrome initially launched with this interface
313 				return navigator.pointer.isLocked;
314 			} else if (typeof (navigator.pointer.isLocked) === "function") {
315 				// Some older builds might provide isLocked as a function
316 				return navigator.pointer.isLocked();
317 			} else if (typeof (navigator.pointer.islocked) === "function") {
318 				// For compatibility with early Firefox build
319 				return navigator.pointer.islocked();
320 			}
321 		}
322 		return false;
323 	}-*/;
324 
325 	/** from https://github.com/toji/game-shim/blob/master/game-shim.js
326 	 * @param element Canvas */
setCursorCatchedJSNI(CanvasElement element)327 	private native void setCursorCatchedJSNI (CanvasElement element) /*-{
328 		// Navigator pointer is not the right interface according to spec.
329 		// Here for backwards compatibility only
330 		if (!navigator.pointer) {
331 			navigator.pointer = navigator.webkitPointer || navigator.mozPointer;
332 		}
333 		// element.requestPointerLock
334 		if (!element.requestPointerLock) {
335 			element.requestPointerLock = (function() {
336 				return element.webkitRequestPointerLock
337 						|| element.mozRequestPointerLock || function() {
338 							if (navigator.pointer) {
339 								navigator.pointer.lock(element);
340 							}
341 						};
342 			})();
343 		}
344 		element.requestPointerLock();
345 	}-*/;
346 
347 	/** from https://github.com/toji/game-shim/blob/master/game-shim.js */
exitCursorCatchedJSNI()348 	private native void exitCursorCatchedJSNI () /*-{
349 		if (!$doc.exitPointerLock) {
350 			$doc.exitPointerLock = (function() {
351 				return $doc.webkitExitPointerLock || $doc.mozExitPointerLock
352 						|| function() {
353 							if (navigator.pointer) {
354 								var elem = this;
355 								navigator.pointer.unlock();
356 							}
357 						};
358 			})();
359 		}
360 	}-*/;
361 
362 	/** from https://github.com/toji/game-shim/blob/master/game-shim.js
363 	 * @param event JavaScript Mouse Event
364 	 * @return movement in x direction */
getMovementXJSNI(NativeEvent event)365 	private native float getMovementXJSNI (NativeEvent event) /*-{
366 		return event.movementX || event.webkitMovementX || 0;
367 	}-*/;
368 
369 	/** from https://github.com/toji/game-shim/blob/master/game-shim.js
370 	 * @param event JavaScript Mouse Event
371 	 * @return movement in y direction */
getMovementYJSNI(NativeEvent event)372 	private native float getMovementYJSNI (NativeEvent event) /*-{
373 		return event.movementY || event.webkitMovementY || 0;
374 	}-*/;
375 
isTouchScreen()376 	private static native boolean isTouchScreen () /*-{
377 		return (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0));
378 	}-*/;
379 
380 	/** works only for Chrome > Version 18 with enabled Mouse Lock enable in about:flags or start Chrome with the
381 	 * --enable-pointer-lock flag */
382 	@Override
setCursorCatched(boolean catched)383 	public void setCursorCatched (boolean catched) {
384 		if (catched)
385 			setCursorCatchedJSNI(canvas);
386 		else
387 			exitCursorCatchedJSNI();
388 	}
389 
390 	@Override
isCursorCatched()391 	public boolean isCursorCatched () {
392 		return isCursorCatchedJSNI();
393 	}
394 
395 	@Override
setCursorPosition(int x, int y)396 	public void setCursorPosition (int x, int y) {
397 		// FIXME??
398 	}
399 
400 	// kindly borrowed from our dear playn friends...
addEventListener(JavaScriptObject target, String name, GwtInput handler, boolean capture)401 	static native void addEventListener (JavaScriptObject target, String name, GwtInput handler, boolean capture) /*-{
402 		target
403 				.addEventListener(
404 						name,
405 						function(e) {
406 							handler.@com.badlogic.gdx.backends.gwt.GwtInput::handleEvent(Lcom/google/gwt/dom/client/NativeEvent;)(e);
407 						}, capture);
408 	}-*/;
409 
getMouseWheelVelocity(NativeEvent evt)410 	private static native float getMouseWheelVelocity (NativeEvent evt) /*-{
411 		var delta = 0.0;
412 		var agentInfo = @com.badlogic.gdx.backends.gwt.GwtApplication::agentInfo()();
413 
414 		if (agentInfo.isFirefox) {
415 			if (agentInfo.isMacOS) {
416 				delta = 1.0 * evt.detail;
417 			} else {
418 				delta = 1.0 * evt.detail / 3;
419 			}
420 		} else if (agentInfo.isOpera) {
421 			if (agentInfo.isLinux) {
422 				delta = -1.0 * evt.wheelDelta / 80;
423 			} else {
424 				// on mac
425 				delta = -1.0 * evt.wheelDelta / 40;
426 			}
427 		} else if (agentInfo.isChrome || agentInfo.isSafari) {
428 			delta = -1.0 * evt.wheelDelta / 120;
429 			// handle touchpad for chrome
430 			if (Math.abs(delta) < 1) {
431 				if (agentInfo.isWindows) {
432 					delta = -1.0 * evt.wheelDelta;
433 				} else if (agentInfo.isMacOS) {
434 					delta = -1.0 * evt.wheelDelta / 3;
435 				}
436 			}
437 		}
438 		return delta;
439 	}-*/;
440 
441 	/** Kindly borrowed from PlayN. **/
getMouseWheelEvent()442 	protected static native String getMouseWheelEvent () /*-{
443 		if (navigator.userAgent.toLowerCase().indexOf('firefox') != -1) {
444 			return "DOMMouseScroll";
445 		} else {
446 			return "mousewheel";
447 		}
448 	}-*/;
449 
450 	/** Kindly borrowed from PlayN. **/
getRelativeX(NativeEvent e, CanvasElement target)451 	protected int getRelativeX (NativeEvent e, CanvasElement target) {
452 		float xScaleRatio = target.getWidth() * 1f / target.getClientWidth(); // Correct for canvas CSS scaling
453 		return Math.round(xScaleRatio
454 			* (e.getClientX() - target.getAbsoluteLeft() + target.getScrollLeft() + target.getOwnerDocument().getScrollLeft()));
455 	}
456 
457 	/** Kindly borrowed from PlayN. **/
getRelativeY(NativeEvent e, CanvasElement target)458 	protected int getRelativeY (NativeEvent e, CanvasElement target) {
459 		float yScaleRatio = target.getHeight() * 1f / target.getClientHeight(); // Correct for canvas CSS scaling
460 		return Math.round(yScaleRatio
461 			* (e.getClientY() - target.getAbsoluteTop() + target.getScrollTop() + target.getOwnerDocument().getScrollTop()));
462 	}
463 
getRelativeX(Touch touch, CanvasElement target)464 	protected int getRelativeX (Touch touch, CanvasElement target) {
465 		float xScaleRatio = target.getWidth() * 1f / target.getClientWidth(); // Correct for canvas CSS scaling
466 		return Math.round(xScaleRatio * touch.getRelativeX(target));
467 	}
468 
getRelativeY(Touch touch, CanvasElement target)469 	protected int getRelativeY (Touch touch, CanvasElement target) {
470 		float yScaleRatio = target.getHeight() * 1f / target.getClientHeight(); // Correct for canvas CSS scaling
471 		return Math.round(yScaleRatio * touch.getRelativeY(target));
472 	}
473 
hookEvents()474 	private void hookEvents () {
475 		addEventListener(canvas, "mousedown", this, true);
476 		addEventListener(Document.get(), "mousedown", this, true);
477 		addEventListener(canvas, "mouseup", this, true);
478 		addEventListener(Document.get(), "mouseup", this, true);
479 		addEventListener(canvas, "mousemove", this, true);
480 		addEventListener(Document.get(), "mousemove", this, true);
481 		addEventListener(canvas, getMouseWheelEvent(), this, true);
482 		addEventListener(Document.get(), "keydown", this, false);
483 		addEventListener(Document.get(), "keyup", this, false);
484 		addEventListener(Document.get(), "keypress", this, false);
485 
486 		addEventListener(canvas, "touchstart", this, true);
487 		addEventListener(canvas, "touchmove", this, true);
488 		addEventListener(canvas, "touchcancel", this, true);
489 		addEventListener(canvas, "touchend", this, true);
490 
491 	}
492 
getButton(int button)493 	private int getButton (int button) {
494 		if (button == NativeEvent.BUTTON_LEFT) return Buttons.LEFT;
495 		if (button == NativeEvent.BUTTON_RIGHT) return Buttons.RIGHT;
496 		if (button == NativeEvent.BUTTON_MIDDLE) return Buttons.MIDDLE;
497 		return Buttons.LEFT;
498 	}
499 
handleEvent(NativeEvent e)500 	private void handleEvent (NativeEvent e) {
501 		if (e.getType().equals("mousedown")) {
502 			if (!e.getEventTarget().equals(canvas) || touched[0]) {
503 				float mouseX = getRelativeX(e, canvas);
504 				float mouseY = getRelativeY(e, canvas);
505 				if (mouseX < 0 || mouseX > Gdx.graphics.getWidth() || mouseY < 0 || mouseY > Gdx.graphics.getHeight()) {
506 					hasFocus = false;
507 				}
508 				return;
509 			}
510 			hasFocus = true;
511 			this.justTouched = true;
512 			this.touched[0] = true;
513 			this.pressedButtons.add(getButton(e.getButton()));
514 			this.deltaX[0] = 0;
515 			this.deltaY[0] = 0;
516 			if (isCursorCatched()) {
517 				this.touchX[0] += getMovementXJSNI(e);
518 				this.touchY[0] += getMovementYJSNI(e);
519 			} else {
520 				this.touchX[0] = getRelativeX(e, canvas);
521 				this.touchY[0] = getRelativeY(e, canvas);
522 			}
523 			this.currentEventTimeStamp = TimeUtils.nanoTime();
524 			if (processor != null) processor.touchDown(touchX[0], touchY[0], 0, getButton(e.getButton()));
525 		}
526 
527 		if (e.getType().equals("mousemove")) {
528 			if (isCursorCatched()) {
529 				this.deltaX[0] = (int)getMovementXJSNI(e);
530 				this.deltaY[0] = (int)getMovementYJSNI(e);
531 				this.touchX[0] += getMovementXJSNI(e);
532 				this.touchY[0] += getMovementYJSNI(e);
533 			} else {
534 				this.deltaX[0] = getRelativeX(e, canvas) - touchX[0];
535 				this.deltaY[0] = getRelativeY(e, canvas) - touchY[0];
536 				this.touchX[0] = getRelativeX(e, canvas);
537 				this.touchY[0] = getRelativeY(e, canvas);
538 			}
539 			this.currentEventTimeStamp = TimeUtils.nanoTime();
540 			if (processor != null) {
541 				if (touched[0])
542 					processor.touchDragged(touchX[0], touchY[0], 0);
543 				else
544 					processor.mouseMoved(touchX[0], touchY[0]);
545 			}
546 		}
547 
548 		if (e.getType().equals("mouseup")) {
549 			if (!touched[0]) return;
550 			this.pressedButtons.remove(getButton(e.getButton()));
551 			this.touched[0] = pressedButtons.size > 0;
552 			if (isCursorCatched()) {
553 				this.deltaX[0] = (int)getMovementXJSNI(e);
554 				this.deltaY[0] = (int)getMovementYJSNI(e);
555 				this.touchX[0] += getMovementXJSNI(e);
556 				this.touchY[0] += getMovementYJSNI(e);
557 			} else {
558 				this.deltaX[0] = getRelativeX(e, canvas) - touchX[0];
559 				this.deltaY[0] = getRelativeY(e, canvas) - touchY[0];
560 				this.touchX[0] = getRelativeX(e, canvas);
561 				this.touchY[0] = getRelativeY(e, canvas);
562 			}
563 			this.currentEventTimeStamp = TimeUtils.nanoTime();
564 			this.touched[0] = false;
565 			if (processor != null) processor.touchUp(touchX[0], touchY[0], 0, getButton(e.getButton()));
566 		}
567 		if (e.getType().equals(getMouseWheelEvent())) {
568 			if (processor != null) {
569 				processor.scrolled((int)getMouseWheelVelocity(e));
570 			}
571 			this.currentEventTimeStamp = TimeUtils.nanoTime();
572 			e.preventDefault();
573 		}
574 		if (e.getType().equals("keydown") && hasFocus) {
575 			// System.out.println("keydown");
576 			int code = keyForCode(e.getKeyCode());
577 			if (code == 67) {
578 				e.preventDefault();
579 				if (processor != null) {
580 					processor.keyDown(code);
581 					processor.keyTyped('\b');
582 				}
583 			} else {
584 				if (!pressedKeys[code]) {
585 					pressedKeyCount++;
586 					pressedKeys[code] = true;
587 					keyJustPressed = true;
588 					justPressedKeys[code] = true;
589 					if (processor != null) {
590 						processor.keyDown(code);
591 					}
592 				}
593 			}
594 		}
595 
596 		if (e.getType().equals("keypress") && hasFocus) {
597 			// System.out.println("keypress");
598 			char c = (char)e.getCharCode();
599 			if (processor != null) processor.keyTyped(c);
600 		}
601 
602 		if (e.getType().equals("keyup") && hasFocus) {
603 			// System.out.println("keyup");
604 			int code = keyForCode(e.getKeyCode());
605 			if (pressedKeys[code]) {
606 				pressedKeyCount--;
607 				pressedKeys[code] = false;
608 			}
609 			if (processor != null) {
610 				processor.keyUp(code);
611 			}
612 		}
613 
614 		if (e.getType().equals("touchstart")) {
615 			this.justTouched = true;
616 			JsArray<Touch> touches = e.getChangedTouches();
617 			for (int i = 0, j = touches.length(); i < j; i++) {
618 				Touch touch = touches.get(i);
619 				int real = touch.getIdentifier();
620 				int touchId;
621 				touchMap.put(real, touchId = getAvailablePointer());
622 				touched[touchId] = true;
623 				touchX[touchId] = getRelativeX(touch, canvas);
624 				touchY[touchId] = getRelativeY(touch, canvas);
625 				deltaX[touchId] = 0;
626 				deltaY[touchId] = 0;
627 				if (processor != null) {
628 					processor.touchDown(touchX[touchId], touchY[touchId], touchId, Buttons.LEFT);
629 				}
630 			}
631 			this.currentEventTimeStamp = TimeUtils.nanoTime();
632 			e.preventDefault();
633 		}
634 		if (e.getType().equals("touchmove")) {
635 			JsArray<Touch> touches = e.getChangedTouches();
636 			for (int i = 0, j = touches.length(); i < j; i++) {
637 				Touch touch = touches.get(i);
638 				int real = touch.getIdentifier();
639 				int touchId = touchMap.get(real);
640 				deltaX[touchId] = getRelativeX(touch, canvas) - touchX[touchId];
641 				deltaY[touchId] = getRelativeY(touch, canvas) - touchY[touchId];
642 				touchX[touchId] = getRelativeX(touch, canvas);
643 				touchY[touchId] = getRelativeY(touch, canvas);
644 				if (processor != null) {
645 					processor.touchDragged(touchX[touchId], touchY[touchId], touchId);
646 				}
647 			}
648 			this.currentEventTimeStamp = TimeUtils.nanoTime();
649 			e.preventDefault();
650 		}
651 		if (e.getType().equals("touchcancel")) {
652 			JsArray<Touch> touches = e.getChangedTouches();
653 			for (int i = 0, j = touches.length(); i < j; i++) {
654 				Touch touch = touches.get(i);
655 				int real = touch.getIdentifier();
656 				int touchId = touchMap.get(real);
657 				touchMap.remove(real);
658 				touched[touchId] = false;
659 				deltaX[touchId] = getRelativeX(touch, canvas) - touchX[touchId];
660 				deltaY[touchId] = getRelativeY(touch, canvas) - touchY[touchId];
661 				touchX[touchId] = getRelativeX(touch, canvas);
662 				touchY[touchId] = getRelativeY(touch, canvas);
663 				if (processor != null) {
664 					processor.touchUp(touchX[touchId], touchY[touchId], touchId, Buttons.LEFT);
665 				}
666 			}
667 			this.currentEventTimeStamp = TimeUtils.nanoTime();
668 			e.preventDefault();
669 		}
670 		if (e.getType().equals("touchend")) {
671 			JsArray<Touch> touches = e.getChangedTouches();
672 			for (int i = 0, j = touches.length(); i < j; i++) {
673 				Touch touch = touches.get(i);
674 				int real = touch.getIdentifier();
675 				int touchId = touchMap.get(real);
676 				touchMap.remove(real);
677 				touched[touchId] = false;
678 				deltaX[touchId] = getRelativeX(touch, canvas) - touchX[touchId];
679 				deltaY[touchId] = getRelativeY(touch, canvas) - touchY[touchId];
680 				touchX[touchId] = getRelativeX(touch, canvas);
681 				touchY[touchId] = getRelativeY(touch, canvas);
682 				if (processor != null) {
683 					processor.touchUp(touchX[touchId], touchY[touchId], touchId, Buttons.LEFT);
684 				}
685 			}
686 			this.currentEventTimeStamp = TimeUtils.nanoTime();
687 			e.preventDefault();
688 		}
689 // if(hasFocus) e.preventDefault();
690 	}
691 
getAvailablePointer()692 	private int getAvailablePointer () {
693 		for (int i = 0; i < MAX_TOUCHES; i++) {
694 			if (!touchMap.containsValue(i, false)) return i;
695 		}
696 		return -1;
697 	}
698 
699 	/** borrowed from PlayN, thanks guys **/
keyForCode(int keyCode)700 	private static int keyForCode (int keyCode) {
701 		switch (keyCode) {
702 		case KeyCodes.KEY_ALT:
703 			return Keys.ALT_LEFT;
704 		case KeyCodes.KEY_BACKSPACE:
705 			return Keys.BACKSPACE;
706 		case KeyCodes.KEY_CTRL:
707 			return Keys.CONTROL_LEFT;
708 		case KeyCodes.KEY_DELETE:
709 			return Keys.DEL;
710 		case KeyCodes.KEY_DOWN:
711 			return Keys.DOWN;
712 		case KeyCodes.KEY_END:
713 			return Keys.END;
714 		case KeyCodes.KEY_ENTER:
715 			return Keys.ENTER;
716 		case KeyCodes.KEY_ESCAPE:
717 			return Keys.ESCAPE;
718 		case KeyCodes.KEY_HOME:
719 			return Keys.HOME;
720 		case KeyCodes.KEY_LEFT:
721 			return Keys.LEFT;
722 		case KeyCodes.KEY_PAGEDOWN:
723 			return Keys.PAGE_DOWN;
724 		case KeyCodes.KEY_PAGEUP:
725 			return Keys.PAGE_UP;
726 		case KeyCodes.KEY_RIGHT:
727 			return Keys.RIGHT;
728 		case KeyCodes.KEY_SHIFT:
729 			return Keys.SHIFT_LEFT;
730 		case KeyCodes.KEY_TAB:
731 			return Keys.TAB;
732 		case KeyCodes.KEY_UP:
733 			return Keys.UP;
734 
735 		case KEY_PAUSE:
736 			return Keys.UNKNOWN; // FIXME
737 		case KEY_CAPS_LOCK:
738 			return Keys.UNKNOWN; // FIXME
739 		case KEY_SPACE:
740 			return Keys.SPACE;
741 		case KEY_INSERT:
742 			return Keys.INSERT;
743 		case KEY_0:
744 			return Keys.NUM_0;
745 		case KEY_1:
746 			return Keys.NUM_1;
747 		case KEY_2:
748 			return Keys.NUM_2;
749 		case KEY_3:
750 			return Keys.NUM_3;
751 		case KEY_4:
752 			return Keys.NUM_4;
753 		case KEY_5:
754 			return Keys.NUM_5;
755 		case KEY_6:
756 			return Keys.NUM_6;
757 		case KEY_7:
758 			return Keys.NUM_7;
759 		case KEY_8:
760 			return Keys.NUM_8;
761 		case KEY_9:
762 			return Keys.NUM_9;
763 		case KEY_A:
764 			return Keys.A;
765 		case KEY_B:
766 			return Keys.B;
767 		case KEY_C:
768 			return Keys.C;
769 		case KEY_D:
770 			return Keys.D;
771 		case KEY_E:
772 			return Keys.E;
773 		case KEY_F:
774 			return Keys.F;
775 		case KEY_G:
776 			return Keys.G;
777 		case KEY_H:
778 			return Keys.H;
779 		case KEY_I:
780 			return Keys.I;
781 		case KEY_J:
782 			return Keys.J;
783 		case KEY_K:
784 			return Keys.K;
785 		case KEY_L:
786 			return Keys.L;
787 		case KEY_M:
788 			return Keys.M;
789 		case KEY_N:
790 			return Keys.N;
791 		case KEY_O:
792 			return Keys.O;
793 		case KEY_P:
794 			return Keys.P;
795 		case KEY_Q:
796 			return Keys.Q;
797 		case KEY_R:
798 			return Keys.R;
799 		case KEY_S:
800 			return Keys.S;
801 		case KEY_T:
802 			return Keys.T;
803 		case KEY_U:
804 			return Keys.U;
805 		case KEY_V:
806 			return Keys.V;
807 		case KEY_W:
808 			return Keys.W;
809 		case KEY_X:
810 			return Keys.X;
811 		case KEY_Y:
812 			return Keys.Y;
813 		case KEY_Z:
814 			return Keys.Z;
815 		case KEY_LEFT_WINDOW_KEY:
816 			return Keys.UNKNOWN; // FIXME
817 		case KEY_RIGHT_WINDOW_KEY:
818 			return Keys.UNKNOWN; // FIXME
819 			// case KEY_SELECT_KEY: return Keys.SELECT_KEY;
820 		case KEY_NUMPAD0:
821 			return Keys.NUMPAD_0;
822 		case KEY_NUMPAD1:
823 			return Keys.NUMPAD_1;
824 		case KEY_NUMPAD2:
825 			return Keys.NUMPAD_2;
826 		case KEY_NUMPAD3:
827 			return Keys.NUMPAD_3;
828 		case KEY_NUMPAD4:
829 			return Keys.NUMPAD_4;
830 		case KEY_NUMPAD5:
831 			return Keys.NUMPAD_5;
832 		case KEY_NUMPAD6:
833 			return Keys.NUMPAD_6;
834 		case KEY_NUMPAD7:
835 			return Keys.NUMPAD_7;
836 		case KEY_NUMPAD8:
837 			return Keys.NUMPAD_8;
838 		case KEY_NUMPAD9:
839 			return Keys.NUMPAD_9;
840 		case KEY_MULTIPLY:
841 			return Keys.UNKNOWN; // FIXME
842 		case KEY_ADD:
843 			return Keys.PLUS;
844 		case KEY_SUBTRACT:
845 			return Keys.MINUS;
846 		case KEY_DECIMAL_POINT_KEY:
847 			return Keys.PERIOD;
848 		case KEY_DIVIDE:
849 			return Keys.UNKNOWN; // FIXME
850 		case KEY_F1:
851 			return Keys.F1;
852 		case KEY_F2:
853 			return Keys.F2;
854 		case KEY_F3:
855 			return Keys.F3;
856 		case KEY_F4:
857 			return Keys.F4;
858 		case KEY_F5:
859 			return Keys.F5;
860 		case KEY_F6:
861 			return Keys.F6;
862 		case KEY_F7:
863 			return Keys.F7;
864 		case KEY_F8:
865 			return Keys.F8;
866 		case KEY_F9:
867 			return Keys.F9;
868 		case KEY_F10:
869 			return Keys.F10;
870 		case KEY_F11:
871 			return Keys.F11;
872 		case KEY_F12:
873 			return Keys.F12;
874 		case KEY_NUM_LOCK:
875 			return Keys.NUM;
876 		case KEY_SCROLL_LOCK:
877 			return Keys.UNKNOWN; // FIXME
878 		case KEY_SEMICOLON:
879 			return Keys.SEMICOLON;
880 		case KEY_EQUALS:
881 			return Keys.EQUALS;
882 		case KEY_COMMA:
883 			return Keys.COMMA;
884 		case KEY_DASH:
885 			return Keys.MINUS;
886 		case KEY_PERIOD:
887 			return Keys.PERIOD;
888 		case KEY_FORWARD_SLASH:
889 			return Keys.SLASH;
890 		case KEY_GRAVE_ACCENT:
891 			return Keys.UNKNOWN; // FIXME
892 		case KEY_OPEN_BRACKET:
893 			return Keys.LEFT_BRACKET;
894 		case KEY_BACKSLASH:
895 			return Keys.BACKSLASH;
896 		case KEY_CLOSE_BRACKET:
897 			return Keys.RIGHT_BRACKET;
898 		case KEY_SINGLE_QUOTE:
899 			return Keys.APOSTROPHE;
900 		default:
901 			return Keys.UNKNOWN;
902 		}
903 	}
904 
905 	// these are absent from KeyCodes; we know not why...
906 	private static final int KEY_PAUSE = 19;
907 	private static final int KEY_CAPS_LOCK = 20;
908 	private static final int KEY_SPACE = 32;
909 	private static final int KEY_INSERT = 45;
910 	private static final int KEY_0 = 48;
911 	private static final int KEY_1 = 49;
912 	private static final int KEY_2 = 50;
913 	private static final int KEY_3 = 51;
914 	private static final int KEY_4 = 52;
915 	private static final int KEY_5 = 53;
916 	private static final int KEY_6 = 54;
917 	private static final int KEY_7 = 55;
918 	private static final int KEY_8 = 56;
919 	private static final int KEY_9 = 57;
920 	private static final int KEY_A = 65;
921 	private static final int KEY_B = 66;
922 	private static final int KEY_C = 67;
923 	private static final int KEY_D = 68;
924 	private static final int KEY_E = 69;
925 	private static final int KEY_F = 70;
926 	private static final int KEY_G = 71;
927 	private static final int KEY_H = 72;
928 	private static final int KEY_I = 73;
929 	private static final int KEY_J = 74;
930 	private static final int KEY_K = 75;
931 	private static final int KEY_L = 76;
932 	private static final int KEY_M = 77;
933 	private static final int KEY_N = 78;
934 	private static final int KEY_O = 79;
935 	private static final int KEY_P = 80;
936 	private static final int KEY_Q = 81;
937 	private static final int KEY_R = 82;
938 	private static final int KEY_S = 83;
939 	private static final int KEY_T = 84;
940 	private static final int KEY_U = 85;
941 	private static final int KEY_V = 86;
942 	private static final int KEY_W = 87;
943 	private static final int KEY_X = 88;
944 	private static final int KEY_Y = 89;
945 	private static final int KEY_Z = 90;
946 	private static final int KEY_LEFT_WINDOW_KEY = 91;
947 	private static final int KEY_RIGHT_WINDOW_KEY = 92;
948 	private static final int KEY_SELECT_KEY = 93;
949 	private static final int KEY_NUMPAD0 = 96;
950 	private static final int KEY_NUMPAD1 = 97;
951 	private static final int KEY_NUMPAD2 = 98;
952 	private static final int KEY_NUMPAD3 = 99;
953 	private static final int KEY_NUMPAD4 = 100;
954 	private static final int KEY_NUMPAD5 = 101;
955 	private static final int KEY_NUMPAD6 = 102;
956 	private static final int KEY_NUMPAD7 = 103;
957 	private static final int KEY_NUMPAD8 = 104;
958 	private static final int KEY_NUMPAD9 = 105;
959 	private static final int KEY_MULTIPLY = 106;
960 	private static final int KEY_ADD = 107;
961 	private static final int KEY_SUBTRACT = 109;
962 	private static final int KEY_DECIMAL_POINT_KEY = 110;
963 	private static final int KEY_DIVIDE = 111;
964 	private static final int KEY_F1 = 112;
965 	private static final int KEY_F2 = 113;
966 	private static final int KEY_F3 = 114;
967 	private static final int KEY_F4 = 115;
968 	private static final int KEY_F5 = 116;
969 	private static final int KEY_F6 = 117;
970 	private static final int KEY_F7 = 118;
971 	private static final int KEY_F8 = 119;
972 	private static final int KEY_F9 = 120;
973 	private static final int KEY_F10 = 121;
974 	private static final int KEY_F11 = 122;
975 	private static final int KEY_F12 = 123;
976 	private static final int KEY_NUM_LOCK = 144;
977 	private static final int KEY_SCROLL_LOCK = 145;
978 	private static final int KEY_SEMICOLON = 186;
979 	private static final int KEY_EQUALS = 187;
980 	private static final int KEY_COMMA = 188;
981 	private static final int KEY_DASH = 189;
982 	private static final int KEY_PERIOD = 190;
983 	private static final int KEY_FORWARD_SLASH = 191;
984 	private static final int KEY_GRAVE_ACCENT = 192;
985 	private static final int KEY_OPEN_BRACKET = 219;
986 	private static final int KEY_BACKSLASH = 220;
987 	private static final int KEY_CLOSE_BRACKET = 221;
988 	private static final int KEY_SINGLE_QUOTE = 222;
989 
990 }
991