From: badlogicgames Date: Mon, 13 Dec 2010 00:16:46 +0000 (+0000) Subject: [added] experimental lockless input classes for touch and key input. all hail. to... X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=3c3463a92edca3afc1bc6ac837838ea22083c214;p=mikumikustudio%2Flibgdx-mikumikustudio.git [added] experimental lockless input classes for touch and key input. all hail. to use them change AndroidInput --- diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidInput.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidInput.java index 4af71805f..5f4bd93f5 100644 --- a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidInput.java +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidInput.java @@ -21,6 +21,7 @@ import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Handler; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnKeyListener; @@ -48,6 +49,7 @@ public final class AndroidInput implements Input, OnKeyListener, OnTouchListener static final int KEY_UP = 1; static final int KEY_TYPED = 2; + long timeStamp; int type; int keyCode; char keyChar; @@ -58,6 +60,7 @@ public final class AndroidInput implements Input, OnKeyListener, OnTouchListener static final int TOUCH_UP = 1; static final int TOUCH_DRAGGED = 2; + long timeStamp; int type; int x; int y; @@ -265,7 +268,9 @@ public final class AndroidInput implements Input, OnKeyListener, OnTouchListener } else { int len = touchEvents.size(); for(int i=0; i < len; i++) { - freeTouchEvents.free(touchEvents.get(i)); + TouchEvent e = touchEvents.get(i); +// Log.d("AndroidInput", "synch touch: " + (System.nanoTime() - e.timeStamp) / 1000000.0f); + freeTouchEvents.free(e); } len = keyEvents.size(); diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidLocklessInput.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidLocklessInput.java new file mode 100644 index 000000000..740c4339d --- /dev/null +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidLocklessInput.java @@ -0,0 +1,342 @@ +/* + * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" + * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +package com.badlogic.gdx.backends.android; + +import java.util.ArrayList; +import java.util.HashSet; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.Handler; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnKeyListener; +import android.view.View.OnTouchListener; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; + +import com.badlogic.gdx.Input; +import com.badlogic.gdx.InputProcessor; +import com.badlogic.gdx.utils.AtomicQueue; +import com.badlogic.gdx.utils.Pool; +import com.badlogic.gdx.utils.Pool.PoolObjectFactory; + +/** + * An implementation of the {@link Input} interface for Android. + * + * @author mzechner + * + */ +public final class AndroidLocklessInput implements Input, OnKeyListener, OnTouchListener, SensorEventListener { + static class KeyEvent { + static final int KEY_DOWN = 0; + static final int KEY_UP = 1; + static final int KEY_TYPED = 2; + + long timeStamp; + int type; + int keyCode; + char keyChar; + } + + static class TouchEvent { + static final int TOUCH_DOWN = 0; + static final int TOUCH_UP = 1; + static final int TOUCH_DRAGGED = 2; + + long timeStamp; + int type; + int x; + int y; + int pointer; + } + + AtomicQueue keyEvents = new AtomicQueue(); + AtomicQueue freeKeyEvents = new AtomicQueue(); + + AtomicQueue touchEvents = new AtomicQueue(); + AtomicQueue freeTouchEvents = new AtomicQueue(); + + int[] touchX = new int[10]; + int[] touchY = new int[10]; + boolean[] touched = new boolean[10]; + final boolean hasMultitouch; + private HashSet keys = new HashSet(); + private SensorManager manager; + public boolean accelerometerAvailable = false; + private final float[] accelerometerValues = new float[3]; + private String text = null; + private TextInputListener textListener = null; + private Handler handle; + final AndroidApplication app; + private final AndroidLocklessTouchHandler touchHandler; + private int sleepTime = 0; + private boolean catchBack = false; + + private InputProcessor processor; + + public AndroidLocklessInput (AndroidApplication activity, View view, int sleepTime) { + view.setOnKeyListener(this); + view.setOnTouchListener(this); + view.setFocusable(true); + view.setFocusableInTouchMode(true); + view.requestFocus(); + view.requestFocusFromTouch(); + + manager = (SensorManager)activity.getSystemService(Context.SENSOR_SERVICE); + if (manager.getSensorList(Sensor.TYPE_ACCELEROMETER).size() == 0) { + accelerometerAvailable = false; + } else { + Sensor accelerometer = manager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0); + if (!manager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME)) + accelerometerAvailable = false; + else + accelerometerAvailable = true; + } + + handle = new Handler(); + this.app = activity; + this.sleepTime = sleepTime; + int sdkVersion = Integer.parseInt(android.os.Build.VERSION.SDK); + if (sdkVersion >= 5) + touchHandler = new AndroidLocklessMultiTouchHandler(); + else + touchHandler = new AndroidLocklessSingleTouchHandler(); + hasMultitouch = touchHandler instanceof AndroidLocklessMultiTouchHandler + && ((AndroidLocklessMultiTouchHandler)touchHandler).supportsMultitouch(activity); + } + + @Override public float getAccelerometerX () { + return accelerometerValues[0]; + } + + @Override public float getAccelerometerY () { + return accelerometerValues[1]; + } + + @Override public float getAccelerometerZ () { + return accelerometerValues[2]; + } + + @Override public void getTextInput (final TextInputListener listener, final String title, final String text) { + handle.post(new Runnable() { + public void run () { + AlertDialog.Builder alert = new AlertDialog.Builder(AndroidLocklessInput.this.app); + alert.setTitle(title); + final EditText input = new EditText(AndroidLocklessInput.this.app); + input.setText(text); + input.setSingleLine(); + alert.setView(input); + alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() { + public void onClick (DialogInterface dialog, int whichButton) { + listener.input(input.getText().toString()); + } + }); + alert.show(); + } + }); + } + + @Override public int getX () { + return touchX[0]; + } + + @Override public int getY () { + return touchY[0]; + } + + @Override public int getX (int pointer) { + return touchX[pointer]; + } + + @Override public int getY (int pointer) { + return touchY[pointer]; + } + + public boolean isTouched (int pointer) { + return touched[pointer]; + } + + @Override public boolean isAccelerometerAvailable () { + return accelerometerAvailable; + } + + @Override public boolean isKeyPressed (int key) { + synchronized (this) { + if (key == Input.Keys.ANY_KEY) + return keys.size() > 0; + else + return keys.contains(key); + } + } + + @Override public boolean isTouched () { + return touched[0]; + } + + public void setInputProcessor (InputProcessor processor) { + synchronized (this) { + this.processor = processor; + } + } + + void processEvents () { + InputProcessor processor; + synchronized (this) { + processor = this.processor; + } + + if (processor != null) { + KeyEvent e; + while ((e = keyEvents.poll()) != null) { + switch (e.type) { + case KeyEvent.KEY_DOWN: + processor.keyDown(e.keyCode); + break; + case KeyEvent.KEY_UP: + processor.keyUp(e.keyCode); + break; + case KeyEvent.KEY_TYPED: + processor.keyTyped(e.keyChar); + } + freeKeyEvents.put(e); + } + + TouchEvent te = null; + while ((te = touchEvents.poll()) != null) { + switch (te.type) { + case TouchEvent.TOUCH_DOWN: + processor.touchDown(te.x, te.y, te.pointer); + break; + case TouchEvent.TOUCH_UP: + processor.touchUp(te.x, te.y, te.pointer); + break; + case TouchEvent.TOUCH_DRAGGED: + processor.touchDragged(te.x, te.y, te.pointer); + } + freeTouchEvents.put(te); + } + } else { + TouchEvent e = null; + while ((e = touchEvents.poll()) != null) { + Log.d("AndroidInput", "lockless touch: " + (System.nanoTime() - e.timeStamp) / 1000000.0f); + freeTouchEvents.put(e); + } + + KeyEvent ke = null; + while ((ke = keyEvents.poll()) != null) { + freeKeyEvents.put(ke); + } + } + } + + boolean requestFocus = true; + + @Override public boolean onTouch (View view, MotionEvent event) { + if (requestFocus) { + view.requestFocus(); + view.requestFocusFromTouch(); + requestFocus = false; + } + + touchHandler.onTouch(event, this); + + if (sleepTime != 0) { + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + } + } + return true; + } + + @Override public boolean onKey (View v, int keyCode, android.view.KeyEvent e) { + char character = (char)e.getUnicodeChar(); + // Android doesn't report a unicode char for back space. hrm... + if (keyCode == 67) character = '\b'; + + KeyEvent event = null; + switch (e.getAction()) { + case android.view.KeyEvent.ACTION_DOWN: + event = freeKeyEvents.poll(); + if (event == null) event = new KeyEvent(); + event.keyChar = 0; + event.keyCode = e.getKeyCode(); + event.type = KeyEvent.KEY_DOWN; + keyEvents.put(event); + synchronized(this) { + keys.add(event.keyCode); + } + break; + case android.view.KeyEvent.ACTION_UP: + event = freeKeyEvents.poll(); + if (event == null) event = new KeyEvent(); + event.keyChar = 0; + event.keyCode = e.getKeyCode(); + event.type = KeyEvent.KEY_UP; + keyEvents.put(event); + + event = freeKeyEvents.poll(); + if (event == null) event = new KeyEvent(); + event.keyChar = character; + event.keyCode = 0; + event.type = KeyEvent.KEY_TYPED; + keyEvents.put(event); + + synchronized(this) { + keys.remove(e.getKeyCode()); + } + } + + if (catchBack && keyCode == android.view.KeyEvent.KEYCODE_BACK) return true; + return false; + } + + @Override public void onAccuracyChanged (Sensor arg0, int arg1) { + + } + + @Override public void onSensorChanged (SensorEvent event) { + if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { + System.arraycopy(event.values, 0, accelerometerValues, 0, accelerometerValues.length); + } + } + + @Override public boolean supportsMultitouch () { + return hasMultitouch; + } + + @Override public void setOnscreenKeyboardVisible (boolean visible) { + InputMethodManager manager = (InputMethodManager)app.getSystemService(Context.INPUT_METHOD_SERVICE); + if (visible) { + manager.showSoftInput(((AndroidGraphics)app.getGraphics()).getView(), 0); + } else { + manager.hideSoftInputFromWindow(((AndroidGraphics)app.getGraphics()).getView().getWindowToken(), 0); + } + } + + @Override public boolean supportsOnscreenKeyboard () { + return true; + } + + @Override public void setCatchBackKey (boolean catchBack) { + this.catchBack = catchBack; + } +} diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidLocklessMultiTouchHandler.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidLocklessMultiTouchHandler.java new file mode 100644 index 000000000..e2d988cc8 --- /dev/null +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidLocklessMultiTouchHandler.java @@ -0,0 +1,89 @@ +/* + * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" + * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +package com.badlogic.gdx.backends.android; + +import android.view.MotionEvent; + +import com.badlogic.gdx.backends.android.AndroidLocklessInput.TouchEvent; + + +/** + * Multitouch handler for devices running Android >= 2.0. If device is capable of (fake) multitouch this will report additional + * pointers. + * + * @author badlogicgames@gmail.com + * + */ +public class AndroidLocklessMultiTouchHandler implements AndroidLocklessTouchHandler { + public void onTouch (MotionEvent event, AndroidLocklessInput input) { + final int action = event.getAction() & MotionEvent.ACTION_MASK; + int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT; + int pointerId = event.getPointerId(pointerIndex); + + int x = 0, y = 0; + + switch (action) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + x = (int)event.getX(pointerIndex); + y = (int)event.getY(pointerIndex); + postTouchEvent(input, TouchEvent.TOUCH_DOWN, x, y, pointerId); + input.touchX[pointerId] = x; + input.touchY[pointerId] = y; + input.touched[pointerId] = true; + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_OUTSIDE: + case MotionEvent.ACTION_CANCEL: + x = (int)event.getX(pointerIndex); + y = (int)event.getY(pointerIndex); + postTouchEvent(input, TouchEvent.TOUCH_UP, x, y, pointerId); + input.touchX[pointerId] = x; + input.touchY[pointerId] = y; + input.touched[pointerId] = false; + break; + + case MotionEvent.ACTION_MOVE: + int pointerCount = event.getPointerCount(); + for (int i = 0; i < pointerCount; i++) { + pointerIndex = i; + pointerId = event.getPointerId(pointerIndex); + x = (int)event.getX(pointerIndex); + y = (int)event.getY(pointerIndex); + postTouchEvent(input, TouchEvent.TOUCH_DRAGGED, x, y, pointerId); + input.touchX[pointerId] = x; + input.touchY[pointerId] = y; + } + break; + } + } + + private void postTouchEvent (AndroidLocklessInput input, int type, int x, int y, int pointer) { + TouchEvent event = input.freeTouchEvents.poll(); + if(event == null) + event = new TouchEvent(); + event.timeStamp = System.nanoTime(); + event.pointer = pointer; + event.x = x; + event.y = y; + event.type = type; + input.touchEvents.put(event); + } + + public boolean supportsMultitouch (AndroidApplication activity) { + return activity.getPackageManager().hasSystemFeature("android.hardware.touchscreen.multitouch"); + } +} diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidLocklessSingleTouchHandler.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidLocklessSingleTouchHandler.java new file mode 100644 index 000000000..5cac23f81 --- /dev/null +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidLocklessSingleTouchHandler.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" + * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +package com.badlogic.gdx.backends.android; + +import com.badlogic.gdx.backends.android.AndroidLocklessInput.TouchEvent; + +import android.view.MotionEvent; + + +/** + * Single touch handler for devices running <= 1.6 + * + * @author badlogicgames@gmail.com + * + */ +public class AndroidLocklessSingleTouchHandler implements AndroidLocklessTouchHandler { + public void onTouch (MotionEvent event, AndroidLocklessInput input) { + int x = (int)event.getX(); + int y = (int)event.getY(); + input.touchX[0] = x; + input.touchY[0] = y; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + postTouchEvent(input, TouchEvent.TOUCH_DOWN, x, y, 0); + input.touched[0] = true; + } + + if (event.getAction() == MotionEvent.ACTION_MOVE) { + postTouchEvent(input, TouchEvent.TOUCH_DRAGGED, x, y, 0); + input.touched[0] = true; + } + if (event.getAction() == MotionEvent.ACTION_UP) { + postTouchEvent(input, TouchEvent.TOUCH_UP, x, y, 0); + input.touched[0] = false; + } + + if (event.getAction() == MotionEvent.ACTION_CANCEL) { + postTouchEvent(input, TouchEvent.TOUCH_UP, x, y, 0); + input.touched[0] = false; + } + } + + private void postTouchEvent (AndroidLocklessInput input, int type, int x, int y, int pointer) { + TouchEvent event = input.freeTouchEvents.poll(); + if(event == null) + event = new TouchEvent(); + event.timeStamp = System.nanoTime(); + event.pointer = 0; + event.x = x; + event.y = y; + event.type = type; + input.touchEvents.put(event); + } +} diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidLocklessTouchHandler.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidLocklessTouchHandler.java new file mode 100644 index 000000000..3cdfbc9fa --- /dev/null +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidLocklessTouchHandler.java @@ -0,0 +1,20 @@ +/* + * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" + * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +package com.badlogic.gdx.backends.android; + +import android.view.MotionEvent; + +public interface AndroidLocklessTouchHandler { + public void onTouch (MotionEvent event, AndroidLocklessInput input); +} diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidMultiTouchHandler.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidMultiTouchHandler.java index 47c2d9796..72c128580 100644 --- a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidMultiTouchHandler.java +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidMultiTouchHandler.java @@ -71,8 +71,10 @@ public class AndroidMultiTouchHandler implements AndroidTouchHandler { } private void postTouchEvent (AndroidInput input, int type, int x, int y, int pointer) { + long timeStamp = System.nanoTime(); synchronized (input) { TouchEvent event = input.freeTouchEvents.newObject(); + event.timeStamp = timeStamp; event.pointer = pointer; event.x = x; event.y = y; diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidSingleTouchHandler.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidSingleTouchHandler.java index 71dc0425b..5ed95e7b2 100644 --- a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidSingleTouchHandler.java +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidSingleTouchHandler.java @@ -49,9 +49,11 @@ public class AndroidSingleTouchHandler implements AndroidTouchHandler { } } - private void postTouchEvent (AndroidInput input, int type, int x, int y, int pointer) { + private void postTouchEvent (AndroidInput input, int type, int x, int y, int pointer) { + long timeStamp = System.nanoTime(); synchronized (input) { TouchEvent event = input.freeTouchEvents.newObject(); + event.timeStamp = timeStamp; event.pointer = 0; event.x = x; event.y = y;