Skip to content

Commit

Permalink
Android: Add support for cursor icons
Browse files Browse the repository at this point in the history
  • Loading branch information
thebestnom committed May 19, 2021
1 parent 169268a commit f5b5e00
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 4 deletions.
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) {
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

0 comments on commit f5b5e00

Please sign in to comment.