android: simple rumble support
This commit is contained in:
parent
a39503dd56
commit
c37dbae4e4
|
@ -93,6 +93,7 @@ protected:
|
|||
InputMapping *input_mapper;
|
||||
std::map<u32, int> axis_min_values;
|
||||
std::map<u32, unsigned int> axis_ranges;
|
||||
bool _rumble_enabled = true;
|
||||
|
||||
private:
|
||||
int get_axis_min_value(u32 axis);
|
||||
|
@ -105,8 +106,6 @@ private:
|
|||
input_detected_cb _input_detected;
|
||||
bool _remappable;
|
||||
|
||||
bool _rumble_enabled = true;
|
||||
|
||||
static std::vector<std::shared_ptr<GamepadDevice>> _gamepads;
|
||||
static std::mutex _gamepads_mutex;
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.reicast.emulator;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v7.app.AppCompatDelegate;
|
||||
|
@ -10,6 +11,8 @@ import android.util.Log;
|
|||
import com.reicast.emulator.emu.JNIdc;
|
||||
|
||||
public class Emulator extends Application {
|
||||
private static Context context;
|
||||
|
||||
public static final String pref_dynarecopt = "dynarec_opt";
|
||||
public static final String pref_unstable = "unstable_opt";
|
||||
public static final String pref_dynsafemode = "dyn_safemode";
|
||||
|
@ -262,6 +265,16 @@ public class Emulator extends Application {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Emulator.context = getApplicationContext();
|
||||
}
|
||||
|
||||
public static Context getAppContext() {
|
||||
return Emulator.context;
|
||||
}
|
||||
|
||||
static {
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
||||
}
|
||||
|
|
|
@ -2,9 +2,11 @@ package com.reicast.emulator.periph;
|
|||
|
||||
import android.content.Context;
|
||||
import android.hardware.input.InputManager;
|
||||
import android.util.Log;
|
||||
import android.os.Vibrator;
|
||||
import android.view.InputDevice;
|
||||
|
||||
import com.reicast.emulator.Emulator;
|
||||
|
||||
public final class InputDeviceManager implements InputManager.InputDeviceListener {
|
||||
public static final int VIRTUAL_GAMEPAD_ID = 0x12345678;
|
||||
|
||||
|
@ -13,6 +15,11 @@ public final class InputDeviceManager implements InputManager.InputDeviceListene
|
|||
private InputManager inputManager;
|
||||
private int maple_port = 0;
|
||||
|
||||
public InputDeviceManager()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
public void startListening(Context applicationContext)
|
||||
{
|
||||
maple_port = 0;
|
||||
|
@ -55,10 +62,34 @@ public final class InputDeviceManager implements InputManager.InputDeviceListene
|
|||
public void onInputDeviceChanged(int i) {
|
||||
}
|
||||
|
||||
// Called from native code
|
||||
private boolean Rumble(int i, float power, float inclination, int duration_ms) {
|
||||
Vibrator vibrator;
|
||||
if (i == VIRTUAL_GAMEPAD_ID) {
|
||||
vibrator = (Vibrator)Emulator.getAppContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
}
|
||||
else {
|
||||
InputDevice device = InputDevice.getDevice(i);
|
||||
if (device == null)
|
||||
return false;
|
||||
vibrator = device.getVibrator();
|
||||
if (!vibrator.hasVibrator())
|
||||
return false;
|
||||
}
|
||||
// TODO API >= 26 (Android 8.0)
|
||||
if (power == 0)
|
||||
vibrator.cancel();
|
||||
else
|
||||
vibrator.vibrate(duration_ms);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static InputDeviceManager getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public native void init();
|
||||
public native void virtualGamepadEvent(int kcode, int joyx, int joyy, int lt, int rt);
|
||||
public native boolean joystickButtonEvent(int id, int button, boolean pressed);
|
||||
public native boolean joystickAxisEvent(int id, int button, int value);
|
||||
|
|
|
@ -22,6 +22,50 @@
|
|||
#include "reios/reios.h"
|
||||
#include "imgread/common.h"
|
||||
#include "rend/gui.h"
|
||||
|
||||
JavaVM* g_jvm;
|
||||
|
||||
// Convenience class to get the java environment for the current thread.
|
||||
// Also attach the threads, and detach it on destruction, if needed. This is probably not very efficient
|
||||
// but shouldn't be needed except for error reporting.
|
||||
class JVMAttacher {
|
||||
public:
|
||||
JVMAttacher() : env(NULL), detach_thread(false) {
|
||||
if (g_jvm == NULL) {
|
||||
log_error("g_jvm == NULL");
|
||||
return;
|
||||
}
|
||||
int rc = g_jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
|
||||
if (rc == JNI_EDETACHED) {
|
||||
if (g_jvm->AttachCurrentThread(&env, NULL) != 0) {
|
||||
log_error("AttachCurrentThread failed");
|
||||
return;
|
||||
}
|
||||
detach_thread = true;
|
||||
}
|
||||
else if (rc == JNI_EVERSION) {
|
||||
log_error("JNI version error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
~JVMAttacher()
|
||||
{
|
||||
if (detach_thread)
|
||||
g_jvm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
void log_error(const char *reason)
|
||||
{
|
||||
LOGE("JVMAttacher cannot attach to JVM: %s", reason);
|
||||
}
|
||||
|
||||
bool failed() { return env == NULL; }
|
||||
|
||||
JNIEnv *env;
|
||||
bool detach_thread = false;
|
||||
};
|
||||
|
||||
#include "android_gamepad.h"
|
||||
|
||||
#define SETTINGS_ACCESSORS(jsetting, csetting, type) \
|
||||
|
@ -101,6 +145,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_screenDpi(JNIEnv *env
|
|||
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_guiOpenSettings(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
|
||||
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_guiIsOpen(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_init(JNIEnv *env, jobject obj) __attribute__((visibility("default")));
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickAdded(JNIEnv *env, jobject obj, jint id, jstring name, jint maple_port) __attribute__((visibility("default")));
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickRemoved(JNIEnv *env, jobject obj, jint id) __attribute__((visibility("default")));
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_virtualGamepadEvent(JNIEnv *env, jobject obj, jint kcode, jint joyx, jint joyy, jint lt, jint rt) __attribute__((visibility("default")));
|
||||
|
@ -151,7 +196,6 @@ extern u32 mo_buttons;
|
|||
extern bool print_stats;
|
||||
|
||||
//stuff for saving prefs
|
||||
JavaVM* g_jvm;
|
||||
jobject g_emulator;
|
||||
jmethodID saveSettingsMid;
|
||||
static ANativeWindow *g_window = 0;
|
||||
|
@ -341,47 +385,6 @@ jobject vmulcd = NULL;
|
|||
jbyteArray jpix = NULL;
|
||||
jmethodID updatevmuscreen;
|
||||
|
||||
// Convenience class to get the java environment for the current thread.
|
||||
// Also attach the threads, and detach it on destruction, if needed. This is probably not very efficient
|
||||
// but shouldn't be needed except for error reporting.
|
||||
class JVMAttacher {
|
||||
public:
|
||||
JVMAttacher() : env(NULL), detach_thread(false) {
|
||||
if (g_jvm == NULL) {
|
||||
log_error("g_jvm == NULL");
|
||||
return;
|
||||
}
|
||||
int rc = g_jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
|
||||
if (rc == JNI_EDETACHED) {
|
||||
if (g_jvm->AttachCurrentThread(&env, NULL) != 0) {
|
||||
log_error("AttachCurrentThread failed");
|
||||
return;
|
||||
}
|
||||
detach_thread = true;
|
||||
}
|
||||
else if (rc == JNI_EVERSION) {
|
||||
log_error("JNI version error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
~JVMAttacher()
|
||||
{
|
||||
if (detach_thread)
|
||||
g_jvm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
void log_error(const char *reason)
|
||||
{
|
||||
LOGE("JVMAttacher cannot attach to JVM: %s", reason);
|
||||
}
|
||||
|
||||
bool failed() { return env == NULL; }
|
||||
|
||||
JNIEnv *env;
|
||||
bool detach_thread = false;
|
||||
};
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_query(JNIEnv *env,jobject obj,jobject emu_thread)
|
||||
{
|
||||
jmethodID reiosInfoMid=env->GetMethodID(env->GetObjectClass(emu_thread),"reiosInfo","(Ljava/lang/String;Ljava/lang/String;)V");
|
||||
|
@ -709,6 +712,12 @@ void os_DebugBreak()
|
|||
for(;;) ;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_init(JNIEnv *env, jobject obj)
|
||||
{
|
||||
input_device_manager = env->NewGlobalRef(obj);
|
||||
input_device_manager_rumble = env->GetMethodID(env->GetObjectClass(obj), "Rumble", "(IFFI)Z");
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickAdded(JNIEnv *env, jobject obj, jint id, jstring name, jint maple_port)
|
||||
{
|
||||
const char* joyname = env->GetStringUTFChars(name,0);
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
|
||||
#include "input/gamepad_device.h"
|
||||
|
||||
static jobject input_device_manager;
|
||||
static jmethodID input_device_manager_rumble;
|
||||
|
||||
enum {
|
||||
AXIS_X = 0,
|
||||
AXIS_Y = 1,
|
||||
|
@ -138,6 +141,15 @@ public:
|
|||
previous_kcode = kcode;
|
||||
}
|
||||
|
||||
void rumble(float power, float inclination, u32 duration_ms) override
|
||||
{
|
||||
JVMAttacher jvm_attacher;
|
||||
if (jvm_attacher.failed())
|
||||
return;
|
||||
jboolean has_vibrator = jvm_attacher.env->CallBooleanMethod(input_device_manager, input_device_manager_rumble, android_id, power, inclination, duration_ms);
|
||||
_rumble_enabled = has_vibrator;
|
||||
}
|
||||
|
||||
static const int VIRTUAL_GAMEPAD_ID = 0x12345678; // must match the Java definition
|
||||
|
||||
protected:
|
||||
|
|
Loading…
Reference in New Issue