diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java index 5c3d303ab5..fc05da90d6 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java @@ -40,7 +40,9 @@ import android.view.ScaleGestureDetector; import android.view.View; import com.jme3.input.JoyInput; +import com.jme3.input.MouseInput; import com.jme3.input.TouchInput; +import com.jme3.input.dummy.DummyMouseInput; import com.jme3.system.AppSettings; import java.util.logging.Logger; @@ -60,11 +62,12 @@ public class AndroidInputHandler implements View.OnTouchListener, protected GLSurfaceView view; protected AndroidTouchInput touchInput; protected AndroidJoyInput joyInput; - + protected MouseInput mouseInput; public AndroidInputHandler() { touchInput = new AndroidTouchInput(this); joyInput = new AndroidJoyInput(this); + mouseInput = new DummyMouseInput(); } public void setView(View view) { @@ -118,6 +121,10 @@ public JoyInput getJoyInput() { return joyInput; } + public MouseInput getMouseInput() { + return mouseInput; + } + /* * Android input events include the source from which the input came from. * We must look at the source of the input event to determine which type diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java index 5ee0f757b2..7274a857ad 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java @@ -37,6 +37,9 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; + +import com.jme3.system.AppSettings; + import java.util.logging.Logger; /** @@ -55,6 +58,7 @@ public class AndroidInputHandler14 extends AndroidInputHandler implements View.O public AndroidInputHandler14() { touchInput = new AndroidTouchInput14(this); joyInput = new AndroidJoyInput14(this); + mouseInput = new AndroidMouseInput14(this); } @Override @@ -71,6 +75,12 @@ protected void addListeners(GLSurfaceView view) { view.setOnGenericMotionListener(this); } + @Override + public void loadSettings(AppSettings settings) { + super.loadSettings(settings); + ((AndroidMouseInput14)mouseInput).loadSettings(settings); + } + @Override public boolean onHover(View view, MotionEvent event) { if (view != getView()) { @@ -91,6 +101,12 @@ public boolean onHover(View view, MotionEvent event) { consumed = ((AndroidTouchInput14)touchInput).onHover(event); } + boolean isMouse = ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE); + if (isMouse && mouseInput != null) { + // send the event to the mouse processor + consumed = ((AndroidMouseInput14)mouseInput).onHover(event); + } + return consumed; } @@ -116,6 +132,28 @@ public boolean onGenericMotion(View view, MotionEvent event) { consumed = consumed || ((AndroidJoyInput14)joyInput).onGenericMotion(event); } + if((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) { + consumed = consumed || ((AndroidMouseInput14)mouseInput).onGenericMotion(event); + } + + return consumed; + } + + @Override + public boolean onTouch(View view, MotionEvent event) { + if (view != getView()) { + return false; + } + + boolean consumed = super.onTouch(view, event); + + // Mouse movement while button down is received as onTouch event instead + boolean isMouse = ((event.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE); + if (isMouse && mouseInput != null) { + // send the event to the mouse processor + consumed |= ((AndroidMouseInput14)mouseInput).onGenericMotion(event); + } + return consumed; } @@ -154,7 +192,6 @@ public boolean onKey(View view, int keyCode, KeyEvent event) { } return consumed; - } } diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler24.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler24.java new file mode 100644 index 0000000000..ce405ec3f4 --- /dev/null +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler24.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2009-2026 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.input.android; + +/** + * AndroidInputHandler24 extends AndroidInputHandler14 to + * use AndroidMouseInput24 which adds usage of newer events and also enables cursor visibility + * and cursor image change. + * + * @author joliver82 + */ +public class AndroidInputHandler24 extends AndroidInputHandler14 { + + public AndroidInputHandler24() { + super(); + mouseInput = new AndroidMouseInput24(this); + } + +} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler26.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler26.java new file mode 100644 index 0000000000..f5b9c5e875 --- /dev/null +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler26.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2009-2026 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.input.android; + +import android.opengl.GLSurfaceView; +import android.view.InputDevice; +import android.view.MotionEvent; +import android.view.View; + +/** + * AndroidInputHandler26 extends AndroidInputHandler24 to + * add the onCapturedPointer events that where added in Android rev 26.
+ * The onCapturedPointer events are received when mouse is grabbed/captured. + * + * @author joliver82 + */ +public class AndroidInputHandler26 extends AndroidInputHandler24 implements View.OnCapturedPointerListener { + + public AndroidInputHandler26() { + super(); + mouseInput = new AndroidMouseInput26(this); + } + + protected void removeListeners(GLSurfaceView view) { + super.removeListeners(view); + view.setOnCapturedPointerListener(null); + } + + @Override + protected void addListeners(GLSurfaceView view) { + super.addListeners(view); + view.setOnCapturedPointerListener(this); + } + + @Override + public boolean onCapturedPointer(View view, MotionEvent event) { + if (view != getView()) { + return false; + } + + boolean consumed = false; + boolean isMouse = ((event.getSource() & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE); + if (isMouse && mouseInput != null) { + consumed = ((AndroidMouseInput26)mouseInput).onCapturedPointer(event); + } + + return consumed; + } +} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidMouseInput14.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidMouseInput14.java new file mode 100644 index 0000000000..e93f69ac95 --- /dev/null +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidMouseInput14.java @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2009-2026 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.input.android; + +import android.view.MotionEvent; + +import com.jme3.cursors.plugins.JmeCursor; +import com.jme3.input.MouseInput; +import com.jme3.input.RawInputListener; +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; +import com.jme3.system.AppSettings; + +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * AndroidMouseInput14 implements MouseInput to add mouse support for jME3 + * uses the onGenericMotion events that where added in Android rev 12 and MotionEvent.getButtonState + * from Android rev 14 so added "14" suffix to the class to specify the Android required rev and + * match other classes naming + * + * @author joliver82 + */ +public class AndroidMouseInput14 implements MouseInput { + private static final Logger logger = Logger.getLogger(AndroidMouseInput14.class.getName()); + + protected AndroidInputHandler inputHandler; + + private boolean initialized = false; + private RawInputListener listener = null; + private ConcurrentLinkedQueue eventQueue = new ConcurrentLinkedQueue<>(); + private float scaleX = 1f; + private float scaleY = 1f; + + protected class MouseState { + int x, y, wheel; + boolean left, right, center; + + protected void setStartPosition(int startingX,int startingY) { + x = startingX; + y = startingY; + } + + protected int updateX(int newX) { + int deltaX=newX-x; + x=newX; + return deltaX; + } + + protected int incrementX(int deltaX) { + x+=deltaX; + return x; + } + + protected int updateY(int newY) { + int deltaY=newY-y; + y=newY; + return deltaY; + } + + protected int incrementY(int deltaY) { + y+=deltaY; + return y; + } + + protected int incrementWheel(int deltaWheel) { + wheel+=deltaWheel; + return wheel; + } + + protected boolean updateLeftButton(boolean left) { + if(this.left == left) { + return false; + } + this.left = left; + return true; + } + + protected boolean updateRightButton(boolean right) { + if(this.right == right) { + return false; + } + this.right = right; + return true; + } + + protected boolean updateCenterButton(boolean center) { + if(this.center == center) { + return false; + } + this.center = center; + return true; + } + } + + MouseState currentMouseState = new MouseState(); + + public AndroidMouseInput14(AndroidInputHandler inputHandler) { + this.inputHandler = inputHandler; + } + + protected int getJmeX(float origX) { + return (int) (origX * scaleX); + } + + protected int getJmeY(float origY) { + return (int) (origY * scaleY); + } + + public void loadSettings(AppSettings settings) { + // view width and height are 0 until the view is displayed on the screen + if (inputHandler.getView().getWidth() != 0 && inputHandler.getView().getHeight() != 0) { + scaleX = settings.getWidth() / (float)inputHandler.getView().getWidth(); + scaleY = settings.getHeight() / (float)inputHandler.getView().getHeight(); + currentMouseState.setStartPosition(inputHandler.getView().getWidth()/2, inputHandler.getView().getHeight()/2); + } + + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Setting input scaling, scaleX: {0}, scaleY: {1}", + new Object[]{scaleX, scaleY}); + } + + } + + protected void addMouseMotionEventFixedPositions(int x, int y, int deltaWheel) { + int deltaX=currentMouseState.updateX(x); + int deltaY=currentMouseState.updateY(y); + int wheel=currentMouseState.incrementWheel(deltaWheel); + + logger.log(Level.INFO, "Mouse motion event: " + x + "x" + y + " wheel: " + wheel); + + eventQueue.add(new MouseMotionEvent(x, y, deltaX, deltaY, wheel, deltaWheel)); + } + + protected void addMouseMotionEventRelativePositions(int deltaX, int deltaY, int deltaWheel) { + int x=currentMouseState.incrementX(deltaX); + int y=currentMouseState.incrementY(deltaY); + int wheel=currentMouseState.incrementWheel(deltaWheel); + + logger.log(Level.INFO, "Mouse motion event: " + x + "x" + y + " wheel: " + wheel); + + eventQueue.add(new MouseMotionEvent(x, y, deltaX, deltaY, wheel, deltaWheel)); + } + + protected boolean addMouseButtonEvent(boolean left, boolean right, boolean center, int x, int y) { + boolean eventAdded = false; + if(currentMouseState.updateLeftButton(left)) { + eventQueue.add(new MouseButtonEvent(MouseInput.BUTTON_LEFT, left, x, y)); + logger.log(Level.INFO, "Mouse button left: " + left); + eventAdded = true; + } + if(currentMouseState.updateRightButton(right)) { + eventQueue.add(new MouseButtonEvent(MouseInput.BUTTON_RIGHT, right, x, y)); + logger.log(Level.INFO, "Mouse button right: " + right); + eventAdded = true; + } + if(currentMouseState.updateCenterButton(center)) { + eventQueue.add(new MouseButtonEvent(MouseInput.BUTTON_MIDDLE, center, x, y)); + logger.log(Level.INFO, "Mouse button center: " + center); + eventAdded = true; + } + return eventAdded; + } + + public boolean onHover(MotionEvent event) { + boolean consumed = false; + + switch (event.getAction()) { + case MotionEvent.ACTION_SCROLL: + case MotionEvent.ACTION_MOVE: + case MotionEvent.ACTION_HOVER_MOVE: + case MotionEvent.ACTION_HOVER_EXIT: + case MotionEvent.ACTION_HOVER_ENTER: + addMouseMotionEventFixedPositions(getJmeX(event.getX()), getJmeY(event.getY()), (int) event.getAxisValue(MotionEvent.AXIS_VSCROLL)); + consumed = true; + break; + } + + return consumed; + } + + public boolean onGenericMotion(MotionEvent event) { + boolean consumed = false; + boolean btnEventReceived = false; + boolean leftPressed = false, rightPressed = false, centerPressed = false; + + int btnState = event.getButtonState(); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if((btnState & MotionEvent.BUTTON_PRIMARY) == MotionEvent.BUTTON_PRIMARY) { + leftPressed = true; + } + if((btnState & MotionEvent.BUTTON_SECONDARY) == MotionEvent.BUTTON_SECONDARY) { + rightPressed = true; + } + if((btnState & MotionEvent.BUTTON_TERTIARY) == MotionEvent.BUTTON_TERTIARY) { + centerPressed = true; + } + btnEventReceived = true; + break; + + case MotionEvent.ACTION_UP: + if((btnState & MotionEvent.BUTTON_PRIMARY) == MotionEvent.BUTTON_PRIMARY) { + leftPressed = false; + } + if((btnState & MotionEvent.BUTTON_SECONDARY) == MotionEvent.BUTTON_SECONDARY) { + rightPressed = false; + } + if((btnState & MotionEvent.BUTTON_TERTIARY) == MotionEvent.BUTTON_TERTIARY) { + centerPressed = false; + } + btnEventReceived = true; + break; + + case MotionEvent.ACTION_HOVER_EXIT: + case MotionEvent.ACTION_HOVER_ENTER: + case MotionEvent.ACTION_SCROLL: + case MotionEvent.ACTION_MOVE: + case MotionEvent.ACTION_HOVER_MOVE: + addMouseMotionEventFixedPositions(getJmeX(event.getX()), getJmeY(event.getY()), (int) event.getAxisValue(MotionEvent.AXIS_VSCROLL)); + consumed = true; + break; + } + + if (btnEventReceived) { + consumed = addMouseButtonEvent(leftPressed, rightPressed, centerPressed, getJmeX(event.getX()), getJmeY(event.getY())); + } + + return consumed; + } + + @Override + public void setCursorVisible(boolean visible) { + logger.log(Level.FINE, "Cannot hide mouse till API 24"); + } + + + @Override + public int getButtonCount() { + return 3; // No way to get the number of buttons, defaulting to 3 buttons + } + + @Override + public void setNativeCursor(JmeCursor cursor) { + logger.log(Level.FINE, "Cannot change cursor till API 24"); + } + + @Override + public void initialize() { + initialized = true; + } + + @Override + public void update() { + if (listener != null) { + InputEvent inputEvent; + + while ((inputEvent = eventQueue.poll()) != null) { + if (inputEvent instanceof MouseMotionEvent) { + listener.onMouseMotionEvent((MouseMotionEvent)inputEvent); + } else if (inputEvent instanceof MouseButtonEvent) { + listener.onMouseButtonEvent((MouseButtonEvent)inputEvent); + } + } + } + + } + + @Override + public void destroy() { + initialized = false; + } + + @Override + public boolean isInitialized() { + return initialized; + } + + @Override + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + @Override + public long getInputTimeNanos() { + return System.nanoTime(); + } +} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidMouseInput24.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidMouseInput24.java new file mode 100644 index 0000000000..bdc1c5fef7 --- /dev/null +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidMouseInput24.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2009-2026 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.input.android; + +import android.graphics.Bitmap; +import android.view.MotionEvent; +import android.view.PointerIcon; + +import com.jme3.cursors.plugins.JmeCursor; + +import java.nio.IntBuffer; +import java.util.logging.Logger; + +/** + * AndroidMouseInput24 extends AndroidMouseInput14 to improve mouse support + * using new events defined in API rev 24 and adding support for cursor change and cursor visibility + * + * @author joliver82 + */ +public class AndroidMouseInput24 extends AndroidMouseInput14{ + private static final Logger logger = Logger.getLogger(AndroidMouseInput24.class.getName()); + + public AndroidMouseInput24(AndroidInputHandler inputHandler) { + super(inputHandler); + } + + @Override + public boolean onGenericMotion(MotionEvent event) { + + boolean consumed = super.onGenericMotion(event); + + if (!consumed) { + boolean leftPressed = false, rightPressed = false, centerPressed = false; + boolean btnEventReceived = false; + int btnAction = event.getActionButton(); + + switch (event.getAction()) { + case MotionEvent.ACTION_BUTTON_PRESS: + if(btnAction == MotionEvent.BUTTON_PRIMARY) { + leftPressed = true; + } + if(btnAction == MotionEvent.BUTTON_SECONDARY) { + rightPressed = true; + } + if(btnAction == MotionEvent.BUTTON_TERTIARY) { + centerPressed = true; + } + btnEventReceived = true; + break; + + case MotionEvent.ACTION_BUTTON_RELEASE: + if(btnAction == MotionEvent.BUTTON_PRIMARY) { + leftPressed = false; + } + if(btnAction == MotionEvent.BUTTON_SECONDARY) { + rightPressed = false; + } + if(btnAction == MotionEvent.BUTTON_TERTIARY) { + centerPressed = false; + } + btnEventReceived = true; + break; + } + + if (btnEventReceived) { + consumed = addMouseButtonEvent(leftPressed, rightPressed, centerPressed, getJmeX(event.getX()), getJmeY(event.getY())); + } + } + return consumed; + } + + @Override + public void setCursorVisible(boolean visible) { + if(inputHandler.getView()!=null) { + if(visible) { + inputHandler.getView().setPointerIcon(null); + } else { + inputHandler.getView().setPointerIcon(PointerIcon.getSystemIcon(inputHandler.getView().getContext(), PointerIcon.TYPE_NULL)); + } + } + } + + @Override + public void setNativeCursor(JmeCursor cursor) { + if(inputHandler.getView()!=null) { + if(cursor!=null) { + // Translate into Android Bitmap format ARGB888. Assuming input image as RGBA + int bufferSize = cursor.getHeight()*cursor.getWidth(); + int[] outputBitmap=new int[bufferSize]; + IntBuffer inputImage = cursor.getImagesData().asReadOnlyBuffer(); + inputImage.clear(); + int[] tmpPixel = new int[4]; + for(int i=0 ; i< bufferSize; ++i) { + inputImage.get(tmpPixel); + outputBitmap[i] = (tmpPixel[3] & 0xff) << 24 | (tmpPixel[0] & 0xff) << 16 | (tmpPixel[1] & 0xff) << 8 | (tmpPixel[2] & 0xff); + } + PointerIcon pointer = PointerIcon.create( + Bitmap.createBitmap(outputBitmap, cursor.getWidth(), cursor.getHeight(), Bitmap.Config.ARGB_8888), + cursor.getXHotSpot(), + cursor.getYHotSpot()); + inputHandler.getView().setPointerIcon(pointer); + } else { + inputHandler.getView().setPointerIcon(null); + } + } + } + +} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidMouseInput26.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidMouseInput26.java new file mode 100644 index 0000000000..34240f0104 --- /dev/null +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidMouseInput26.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2009-2026 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.input.android; + +import android.graphics.Bitmap; +import android.view.MotionEvent; +import android.view.PointerIcon; + +import com.jme3.cursors.plugins.JmeCursor; + +import java.nio.IntBuffer; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * AndroidMouseInput26 extends AndroidMouseInput24 to improve mouse support + * adding grab/capture support using onCapturedPointer events. + * + * @author joliver82 + */ +public class AndroidMouseInput26 extends AndroidMouseInput24{ + private static final Logger logger = Logger.getLogger(AndroidMouseInput26.class.getName()); + + public AndroidMouseInput26(AndroidInputHandler inputHandler) { + super(inputHandler); + } + + public boolean onCapturedPointer(MotionEvent event) { + boolean consumed = false; + boolean btnEventReceived = false; + boolean leftPressed = false, rightPressed = false, centerPressed = false; + + int btnAction = event.getActionButton(); + + switch (event.getAction()) { + case MotionEvent.ACTION_BUTTON_PRESS: + if(btnAction == MotionEvent.BUTTON_PRIMARY) { + leftPressed = true; + } + if(btnAction == MotionEvent.BUTTON_SECONDARY) { + rightPressed = true; + } + if(btnAction == MotionEvent.BUTTON_TERTIARY) { + centerPressed = true; + } + btnEventReceived = true; + break; + + case MotionEvent.ACTION_BUTTON_RELEASE: + if(btnAction == MotionEvent.BUTTON_PRIMARY) { + leftPressed = false; + } + if(btnAction == MotionEvent.BUTTON_SECONDARY) { + rightPressed = false; + } + if(btnAction == MotionEvent.BUTTON_TERTIARY) { + centerPressed = false; + } + btnEventReceived = true; + break; + + case MotionEvent.ACTION_HOVER_EXIT: + case MotionEvent.ACTION_HOVER_ENTER: + case MotionEvent.ACTION_SCROLL: + case MotionEvent.ACTION_MOVE: + case MotionEvent.ACTION_HOVER_MOVE: + addMouseMotionEventRelativePositions(getJmeX(event.getX()), getJmeY(event.getY()), (int) event.getAxisValue(MotionEvent.AXIS_VSCROLL)); + consumed = true; + break; + } + + if (btnEventReceived) { + consumed = addMouseButtonEvent(leftPressed, rightPressed, centerPressed, getJmeX(event.getX()), getJmeY(event.getY())); + } + + return consumed; + } + + @Override + public void setCursorVisible(boolean visible) { + if(!visible) { + inputHandler.getView().requestPointerCapture(); + } else { + inputHandler.getView().releasePointerCapture(); + } + } + +} diff --git a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java index 70911d855a..6d8cf0962b 100644 --- a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java +++ b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java @@ -51,9 +51,10 @@ import com.jme3.input.*; import com.jme3.input.android.AndroidInputHandler; import com.jme3.input.android.AndroidInputHandler14; +import com.jme3.input.android.AndroidInputHandler24; +import com.jme3.input.android.AndroidInputHandler26; import com.jme3.input.controls.SoftTextDialogInputListener; import com.jme3.input.dummy.DummyKeyInput; -import com.jme3.input.dummy.DummyMouseInput; import com.jme3.renderer.android.AndroidGL; import com.jme3.renderer.opengl.*; import com.jme3.system.*; @@ -125,7 +126,11 @@ public GLSurfaceView createView(Context context) { GLSurfaceView view = new GLSurfaceView(context); logger.log(Level.INFO, "Android Build Version: {0}", Build.VERSION.SDK_INT); if (androidInput == null) { - if (Build.VERSION.SDK_INT >= 14) { + if (Build.VERSION.SDK_INT >= 26) { + androidInput = new AndroidInputHandler26(); + } else if (Build.VERSION.SDK_INT >= 24) { + androidInput = new AndroidInputHandler24(); + } else if (Build.VERSION.SDK_INT >= 14) { androidInput = new AndroidInputHandler14(); } else if (Build.VERSION.SDK_INT >= 9) { androidInput = new AndroidInputHandler(); @@ -141,6 +146,9 @@ public GLSurfaceView createView(Context context) { view.setFocusableInTouchMode(true); view.setFocusable(true); + view.setFocusedByDefault(true); + view.requestFocus(); + //view.setClickable(true); // setFormat must be set before AndroidConfigChooser is called by the surfaceview. // if setFormat is called after ConfigChooser is called, then execution @@ -310,7 +318,7 @@ public com.jme3.renderer.Renderer getRenderer() { @Override public MouseInput getMouseInput() { - return new DummyMouseInput(); + return androidInput.getMouseInput(); } @Override