Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android: Add support for cursor icons #44201

Merged
merged 1 commit into from
May 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions platform/android/display_server_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@
#include "java_godot_wrapper.h"
#include "os_android.h"

#include <android/input.h>

#if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h"
#include "platform/android/vulkan/vulkan_context_android.h"
Expand All @@ -51,7 +49,7 @@ DisplayServerAndroid *DisplayServerAndroid::get_singleton() {
bool DisplayServerAndroid::has_feature(Feature p_feature) const {
switch (p_feature) {
//case FEATURE_CONSOLE_WINDOW:
//case FEATURE_CURSOR_SHAPE:
case FEATURE_CURSOR_SHAPE:
//case FEATURE_CUSTOM_CURSOR_SHAPE:
//case FEATURE_GLOBAL_MENU:
//case FEATURE_HIDPI:
Expand Down Expand Up @@ -829,6 +827,12 @@ void DisplayServerAndroid::mouse_set_mode(MouseMode p_mode) {
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) {
OS_Android::get_singleton()->get_godot_java()->get_godot_view()->request_pointer_capture();
} else {
Expand Down Expand Up @@ -870,3 +874,19 @@ int DisplayServerAndroid::_android_button_mask_to_godot_button_mask(int android_

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;
}
27 changes: 27 additions & 0 deletions platform/android/display_server_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,28 @@ class DisplayServerAndroid : public DisplayServer {

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;

bool keep_screen_on;
Expand All @@ -78,6 +100,8 @@ class DisplayServerAndroid : public DisplayServer {
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

CursorShape cursor_shape = CursorShape::CURSOR_ARROW;

#if defined(VULKAN_ENABLED)
VulkanContextAndroid *context_vulkan;
RenderingDeviceVulkan *rendering_device_vulkan;
Expand Down Expand Up @@ -180,6 +204,9 @@ class DisplayServerAndroid : public DisplayServer {
void process_joy_event(JoypadEvent p_event);
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);
MouseMode mouse_get_mode() const;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,15 @@
import android.content.Context;
import android.graphics.PixelFormat;
import android.opengl.GLSurfaceView;
import android.os.Build;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.SurfaceView;

import androidx.annotation.Keep;

/**
* A simple GLSurfaceView sub-class that demonstrate how to perform
* OpenGL ES 2.0 rendering into a GL Surface. Note the following important
Expand All @@ -72,6 +76,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
private final GodotInputHandler inputHandler;
private final GestureDetector detector;
private final GodotRenderer godotRenderer;
private PointerIcon pointerIcon;

public GodotGLRenderView(Context context, Godot godot, XRMode xrMode, boolean p_use_32_bits,
boolean p_use_debug_opengl) {
Expand All @@ -83,6 +88,9 @@ public GodotGLRenderView(Context context, Godot godot, XRMode xrMode, boolean p_
this.inputHandler = new GodotInputHandler(this);
this.detector = new GestureDetector(context, new GodotGestureHandler(this));
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);
}

Expand Down Expand Up @@ -149,6 +157,21 @@ public boolean onCapturedPointerEvent(MotionEvent 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) {
setPreserveEGLContextOnPause(true);
setFocusableInTouchMode(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,6 @@ public interface GodotRenderView {
abstract public void onBackPressed();

abstract public GodotInputHandler getInputHandler();

abstract public void setPointerIcon(int pointerType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,22 @@

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.view.GestureDetector;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.SurfaceView;

import androidx.annotation.Keep;

public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
private final Godot godot;
private final GodotInputHandler mInputHandler;
private final GestureDetector mGestureDetector;
private final VkRenderer mRenderer;
private PointerIcon pointerIcon;

public GodotVulkanRenderView(Context context, Godot godot) {
super(context);
Expand All @@ -56,7 +61,9 @@ public GodotVulkanRenderView(Context context, Godot godot) {
mInputHandler = new GodotInputHandler(this);
mGestureDetector = new GestureDetector(context, new GodotGestureHandler(this));
mRenderer = new VkRenderer();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
}
setFocusableInTouchMode(true);
startRenderer(mRenderer);
}
Expand Down Expand Up @@ -124,6 +131,21 @@ public boolean onCapturedPointerEvent(MotionEvent event) {
return mInputHandler.onGenericMotionEvent(event);
}

/**
* called from JNI to change pointer icon
*/
@Keep
public void setPointerIcon(int pointerType) {
thebestnom marked this conversation as resolved.
Show resolved Hide resolved
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
public void onResume() {
super.onResume();
Expand Down
10 changes: 10 additions & 0 deletions platform/android/java_godot_view_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
if (android_get_device_api_level() >= __ANDROID_API_O__) {
_request_pointer_capture = env->GetMethodID(_cls, "requestPointerCapture", "()V");
_release_pointer_capture = env->GetMethodID(_cls, "releasePointerCapture", "()V");
_set_pointer_icon = env->GetMethodID(_cls, "setPointerIcon", "(I)V");
}
}

Expand All @@ -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() {
JNIEnv *env = get_jni_env();
ERR_FAIL_COND(env == nullptr);
Expand Down
2 changes: 2 additions & 0 deletions platform/android/java_godot_view_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ class GodotJavaViewWrapper {

jmethodID _request_pointer_capture = 0;
jmethodID _release_pointer_capture = 0;
jmethodID _set_pointer_icon = 0;

public:
GodotJavaViewWrapper(jobject godot_view);

void request_pointer_capture();
void release_pointer_capture();
void set_pointer_icon(int pointer_type);

~GodotJavaViewWrapper();
};
Expand Down