Android: Add support for cursor icons

This commit is contained in:
thebestnom 2020-11-04 23:55:28 +02:00
parent 169268ae20
commit f5b5e00a01
7 changed files with 110 additions and 4 deletions

View file

@ -36,8 +36,6 @@
#include "java_godot_wrapper.h" #include "java_godot_wrapper.h"
#include "os_android.h" #include "os_android.h"
#include <android/input.h>
#if defined(VULKAN_ENABLED) #if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h" #include "drivers/vulkan/rendering_device_vulkan.h"
#include "platform/android/vulkan/vulkan_context_android.h" #include "platform/android/vulkan/vulkan_context_android.h"
@ -51,7 +49,7 @@ DisplayServerAndroid *DisplayServerAndroid::get_singleton() {
bool DisplayServerAndroid::has_feature(Feature p_feature) const { bool DisplayServerAndroid::has_feature(Feature p_feature) const {
switch (p_feature) { switch (p_feature) {
//case FEATURE_CONSOLE_WINDOW: //case FEATURE_CONSOLE_WINDOW:
//case FEATURE_CURSOR_SHAPE: case FEATURE_CURSOR_SHAPE:
//case FEATURE_CUSTOM_CURSOR_SHAPE: //case FEATURE_CUSTOM_CURSOR_SHAPE:
//case FEATURE_GLOBAL_MENU: //case FEATURE_GLOBAL_MENU:
//case FEATURE_HIDPI: //case FEATURE_HIDPI:
@ -829,6 +827,12 @@ void DisplayServerAndroid::mouse_set_mode(MouseMode p_mode) {
return; return;
} }
if (p_mode == MouseMode::MOUSE_MODE_HIDDEN) {
OS_Android::get_singleton()->get_godot_java()->get_godot_view()->set_pointer_icon(CURSOR_TYPE_NULL);
} else {
cursor_set_shape(cursor_shape);
}
if (p_mode == MouseMode::MOUSE_MODE_CAPTURED) { if (p_mode == MouseMode::MOUSE_MODE_CAPTURED) {
OS_Android::get_singleton()->get_godot_java()->get_godot_view()->request_pointer_capture(); OS_Android::get_singleton()->get_godot_java()->get_godot_view()->request_pointer_capture();
} else { } else {
@ -870,3 +874,19 @@ int DisplayServerAndroid::_android_button_mask_to_godot_button_mask(int android_
return godot_button_mask; return godot_button_mask;
} }
void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) {
if (cursor_shape == p_shape) {
return;
}
cursor_shape = p_shape;
if (mouse_mode == MouseMode::MOUSE_MODE_VISIBLE || mouse_mode == MouseMode::MOUSE_MODE_CONFINED) {
OS_Android::get_singleton()->get_godot_java()->get_godot_view()->set_pointer_icon(android_cursors[cursor_shape]);
}
}
DisplayServer::CursorShape DisplayServerAndroid::cursor_get_shape() const {
return cursor_shape;
}

View file

@ -70,6 +70,28 @@ private:
int buttons_state; int buttons_state;
// https://developer.android.com/reference/android/view/PointerIcon
// mapping between Godot's cursor shape to Android's'
int android_cursors[CURSOR_MAX] = {
1000, //CURSOR_ARROW
1008, //CURSOR_IBEAM
1002, //CURSOR_POINTIN
1007, //CURSOR_CROSS
1004, //CURSOR_WAIT
1004, //CURSOR_BUSY
1021, //CURSOR_DRAG
1021, //CURSOR_CAN_DRO
1000, //CURSOR_FORBIDD (no corresponding icon in Android's icon so fallback to default)
1015, //CURSOR_VSIZE
1014, //CURSOR_HSIZE
1017, //CURSOR_BDIAGSI
1016, //CURSOR_FDIAGSI
1020, //CURSOR_MOVE
1015, //CURSOR_VSPLIT
1014, //CURSOR_HSPLIT
1003, //CURSOR_HELP
};
const int CURSOR_TYPE_NULL = 0;
MouseMode mouse_mode; MouseMode mouse_mode;
bool keep_screen_on; bool keep_screen_on;
@ -78,6 +100,8 @@ private:
Point2 hover_prev_pos; // needed to calculate the relative position on hover events Point2 hover_prev_pos; // needed to calculate the relative position on hover events
Point2 scroll_prev_pos; // needed to calculate the relative position on scroll events Point2 scroll_prev_pos; // needed to calculate the relative position on scroll events
CursorShape cursor_shape = CursorShape::CURSOR_ARROW;
#if defined(VULKAN_ENABLED) #if defined(VULKAN_ENABLED)
VulkanContextAndroid *context_vulkan; VulkanContextAndroid *context_vulkan;
RenderingDeviceVulkan *rendering_device_vulkan; RenderingDeviceVulkan *rendering_device_vulkan;
@ -180,6 +204,9 @@ public:
void process_joy_event(JoypadEvent p_event); void process_joy_event(JoypadEvent p_event);
void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed); void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed);
virtual void cursor_set_shape(CursorShape p_shape);
virtual CursorShape cursor_get_shape() const;
void mouse_set_mode(MouseMode p_mode); void mouse_set_mode(MouseMode p_mode);
MouseMode mouse_get_mode() const; MouseMode mouse_get_mode() const;

View file

@ -44,11 +44,15 @@ import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.opengl.GLSurfaceView; import android.opengl.GLSurfaceView;
import android.os.Build;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.SurfaceView; import android.view.SurfaceView;
import androidx.annotation.Keep;
/** /**
* A simple GLSurfaceView sub-class that demonstrate how to perform * A simple GLSurfaceView sub-class that demonstrate how to perform
* OpenGL ES 2.0 rendering into a GL Surface. Note the following important * OpenGL ES 2.0 rendering into a GL Surface. Note the following important
@ -72,6 +76,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
private final GodotInputHandler inputHandler; private final GodotInputHandler inputHandler;
private final GestureDetector detector; private final GestureDetector detector;
private final GodotRenderer godotRenderer; private final GodotRenderer godotRenderer;
private PointerIcon pointerIcon;
public GodotGLRenderView(Context context, Godot godot, XRMode xrMode, boolean p_use_32_bits, public GodotGLRenderView(Context context, Godot godot, XRMode xrMode, boolean p_use_32_bits,
boolean p_use_debug_opengl) { boolean p_use_debug_opengl) {
@ -83,6 +88,9 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
this.inputHandler = new GodotInputHandler(this); this.inputHandler = new GodotInputHandler(this);
this.detector = new GestureDetector(context, new GodotGestureHandler(this)); this.detector = new GestureDetector(context, new GodotGestureHandler(this));
this.godotRenderer = new GodotRenderer(); this.godotRenderer = new GodotRenderer();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
}
init(xrMode, false, 16, 0); init(xrMode, false, 16, 0);
} }
@ -149,6 +157,21 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
return inputHandler.onGenericMotionEvent(event); return inputHandler.onGenericMotionEvent(event);
} }
/**
* called from JNI to change pointer icon
*/
@Keep
public void setPointerIcon(int pointerType) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
}
}
@Override
public PointerIcon onResolvePointerIcon(MotionEvent me, int pointerIndex) {
return pointerIcon;
}
private void init(XRMode xrMode, boolean translucent, int depth, int stencil) { private void init(XRMode xrMode, boolean translucent, int depth, int stencil) {
setPreserveEGLContextOnPause(true); setPreserveEGLContextOnPause(true);
setFocusableInTouchMode(true); setFocusableInTouchMode(true);

View file

@ -47,4 +47,6 @@ public interface GodotRenderView {
abstract public void onBackPressed(); abstract public void onBackPressed();
abstract public GodotInputHandler getInputHandler(); abstract public GodotInputHandler getInputHandler();
abstract public void setPointerIcon(int pointerType);
} }

View file

@ -37,17 +37,22 @@ import org.godotengine.godot.vulkan.VkSurfaceView;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.os.Build;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.SurfaceView; import android.view.SurfaceView;
import androidx.annotation.Keep;
public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView { public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
private final Godot godot; private final Godot godot;
private final GodotInputHandler mInputHandler; private final GodotInputHandler mInputHandler;
private final GestureDetector mGestureDetector; private final GestureDetector mGestureDetector;
private final VkRenderer mRenderer; private final VkRenderer mRenderer;
private PointerIcon pointerIcon;
public GodotVulkanRenderView(Context context, Godot godot) { public GodotVulkanRenderView(Context context, Godot godot) {
super(context); super(context);
@ -56,7 +61,9 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
mInputHandler = new GodotInputHandler(this); mInputHandler = new GodotInputHandler(this);
mGestureDetector = new GestureDetector(context, new GodotGestureHandler(this)); mGestureDetector = new GestureDetector(context, new GodotGestureHandler(this));
mRenderer = new VkRenderer(); mRenderer = new VkRenderer();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
}
setFocusableInTouchMode(true); setFocusableInTouchMode(true);
startRenderer(mRenderer); startRenderer(mRenderer);
} }
@ -124,6 +131,21 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
return mInputHandler.onGenericMotionEvent(event); return mInputHandler.onGenericMotionEvent(event);
} }
/**
* called from JNI to change pointer icon
*/
@Keep
public void setPointerIcon(int pointerType) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
}
}
@Override
public PointerIcon onResolvePointerIcon(MotionEvent me, int pointerIndex) {
return pointerIcon;
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();

View file

@ -43,6 +43,7 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
if (android_get_device_api_level() >= __ANDROID_API_O__) { if (android_get_device_api_level() >= __ANDROID_API_O__) {
_request_pointer_capture = env->GetMethodID(_cls, "requestPointerCapture", "()V"); _request_pointer_capture = env->GetMethodID(_cls, "requestPointerCapture", "()V");
_release_pointer_capture = env->GetMethodID(_cls, "releasePointerCapture", "()V"); _release_pointer_capture = env->GetMethodID(_cls, "releasePointerCapture", "()V");
_set_pointer_icon = env->GetMethodID(_cls, "setPointerIcon", "(I)V");
} }
} }
@ -64,6 +65,15 @@ void GodotJavaViewWrapper::release_pointer_capture() {
} }
} }
void GodotJavaViewWrapper::set_pointer_icon(int pointer_type) {
if (_set_pointer_icon != 0) {
JNIEnv *env = get_jni_env();
ERR_FAIL_COND(env == nullptr);
env->CallVoidMethod(_godot_view, _set_pointer_icon, pointer_type);
}
}
GodotJavaViewWrapper::~GodotJavaViewWrapper() { GodotJavaViewWrapper::~GodotJavaViewWrapper() {
JNIEnv *env = get_jni_env(); JNIEnv *env = get_jni_env();
ERR_FAIL_COND(env == nullptr); ERR_FAIL_COND(env == nullptr);

View file

@ -45,12 +45,14 @@ private:
jmethodID _request_pointer_capture = 0; jmethodID _request_pointer_capture = 0;
jmethodID _release_pointer_capture = 0; jmethodID _release_pointer_capture = 0;
jmethodID _set_pointer_icon = 0;
public: public:
GodotJavaViewWrapper(jobject godot_view); GodotJavaViewWrapper(jobject godot_view);
void request_pointer_capture(); void request_pointer_capture();
void release_pointer_capture(); void release_pointer_capture();
void set_pointer_icon(int pointer_type);
~GodotJavaViewWrapper(); ~GodotJavaViewWrapper();
}; };