diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java index 6038afe0f3..96480ab69c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java @@ -67,7 +67,8 @@ public final class ControllerInterface /** * {@link DolphinSensorEventListener} calls this for each axis of a received SensorEvent. */ - public static native void dispatchSensorEvent(String axisName, float value); + public static native void dispatchSensorEvent(String deviceQualifier, String axisName, + float value); /** * Enables delivering sensor events to native code. diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java index f72a97d113..21d533a430 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java @@ -6,6 +6,7 @@ import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Build; +import android.view.InputDevice; import android.view.Surface; import androidx.annotation.Keep; @@ -55,6 +56,10 @@ public class DolphinSensorEventListener implements SensorEventListener private final HashMap mSensorDetails = new HashMap<>(); + private final boolean mRotateCoordinatesForScreenOrientation; + + private String mDeviceQualifier = ""; + private SensorEventRequester mRequester = null; // The fastest sampling rate Android lets us use without declaring the HIGH_SAMPLING_RATE_SENSORS @@ -66,10 +71,28 @@ public class DolphinSensorEventListener implements SensorEventListener { mSensorManager = (SensorManager) DolphinApplication.getAppContext().getSystemService(Context.SENSOR_SERVICE); + mRotateCoordinatesForScreenOrientation = true; addSensors(); } + @Keep + public DolphinSensorEventListener(InputDevice inputDevice) + { + mRotateCoordinatesForScreenOrientation = false; + + if (Build.VERSION.SDK_INT >= 31) + { + mSensorManager = inputDevice.getSensorManager(); + + addSensors(); + } + else + { + mSensorManager = null; + } + } + private void addSensors() { tryAddSensor(Sensor.TYPE_ACCELEROMETER, new String[]{"Accel Right", "Accel Left", @@ -201,7 +224,8 @@ public class DolphinSensorEventListener implements SensorEventListener axisSetDetails[detailsAxisSetIndex].firstAxisOfSet == eventAxisIndex) { int rotation = Surface.ROTATION_0; - if (axisSetDetails[detailsAxisSetIndex].axisSetType == AXIS_SET_TYPE_DEVICE_COORDINATES) + if (mRotateCoordinatesForScreenOrientation && + axisSetDetails[detailsAxisSetIndex].axisSetType == AXIS_SET_TYPE_DEVICE_COORDINATES) { rotation = mRequester.getDisplay().getRotation(); } @@ -230,12 +254,17 @@ public class DolphinSensorEventListener implements SensorEventListener float z = values[eventAxisIndex + 2]; - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex], x); - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 1], x); - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 2], y); - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 3], y); - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 4], z); - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 5], z); + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex], x); + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 1], + x); + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 2], + y); + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 3], + y); + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 4], + z); + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 5], + z); eventAxisIndex += 3; detailsAxisIndex += 6; @@ -243,7 +272,7 @@ public class DolphinSensorEventListener implements SensorEventListener } else { - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex], + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex], values[eventAxisIndex]); eventAxisIndex++; @@ -258,6 +287,16 @@ public class DolphinSensorEventListener implements SensorEventListener // We don't care about this } + /** + * The device qualifier set here will be passed on to native code, + * for the purpose of letting native code identify which device this object belongs to. + */ + @Keep + public void setDeviceQualifier(String deviceQualifier) + { + mDeviceQualifier = deviceQualifier; + } + /** * Enables delivering sensor events to native code. * @@ -275,9 +314,12 @@ public class DolphinSensorEventListener implements SensorEventListener mRequester = requester; - for (Sensor sensor : mSensorDetails.keySet()) + if (mSensorManager != null) { - mSensorManager.registerListener(this, sensor, SAMPLING_PERIOD_US); + for (Sensor sensor : mSensorDetails.keySet()) + { + mSensorManager.registerListener(this, sensor, SAMPLING_PERIOD_US); + } } } @@ -291,7 +333,10 @@ public class DolphinSensorEventListener implements SensorEventListener { mRequester = null; - mSensorManager.unregisterListener(this); + if (mSensorManager != null) + { + mSensorManager.unregisterListener(this); + } } @Keep diff --git a/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp b/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp index 71b99f9ef3..cf7e602a77 100644 --- a/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp @@ -65,6 +65,8 @@ jmethodID s_controller_interface_unregister_input_device_listener; jclass s_sensor_event_listener_class; jmethodID s_sensor_event_listener_constructor; +jmethodID s_sensor_event_listener_constructor_input_device; +jmethodID s_sensor_event_listener_set_device_qualifier; jmethodID s_sensor_event_listener_enable_sensor_events; jmethodID s_sensor_event_listener_disable_sensor_events; jmethodID s_sensor_event_listener_get_axis_names; @@ -76,7 +78,6 @@ using Clock = std::chrono::steady_clock; constexpr Clock::duration ACTIVE_INPUT_TIMEOUT = std::chrono::milliseconds(1000); std::unordered_map s_device_id_to_device_qualifier; -ciface::Core::DeviceQualifier s_sensor_device_qualifier; constexpr int MAX_KEYCODE = AKEYCODE_PROFILE_SWITCH; // Up to date as of SDK 31 @@ -502,7 +503,7 @@ class AndroidDevice final : public Core::Device { public: AndroidDevice(JNIEnv* env, jobject input_device) - : m_sensor_event_listener(nullptr), + : m_sensor_event_listener(AddSensors(env, input_device)), m_source(env->CallIntMethod(input_device, s_input_device_get_sources)), m_controller_number(env->CallIntMethod(input_device, s_input_device_get_controller_number)) { @@ -519,7 +520,7 @@ public: // Constructor for the device added by Dolphin to contain sensor inputs AndroidDevice(JNIEnv* env, std::string name) - : m_sensor_event_listener(AddSensors(env)), m_source(AINPUT_SOURCE_SENSOR), + : m_sensor_event_listener(AddSensors(env, nullptr)), m_source(AINPUT_SOURCE_SENSOR), m_controller_number(0), m_name(std::move(name)) { } @@ -608,10 +609,20 @@ private: env->DeleteLocalRef(motion_ranges_list); } - jobject AddSensors(JNIEnv* env) + jobject AddSensors(JNIEnv* env, jobject input_device) { - jobject sensor_event_listener = - env->NewObject(s_sensor_event_listener_class, s_sensor_event_listener_constructor); + jobject sensor_event_listener; + if (input_device) + { + sensor_event_listener = + env->NewObject(s_sensor_event_listener_class, + s_sensor_event_listener_constructor_input_device, input_device); + } + else + { + sensor_event_listener = + env->NewObject(s_sensor_event_listener_class, s_sensor_event_listener_constructor); + } jobjectArray j_axis_names = reinterpret_cast( env->CallObjectMethod(sensor_event_listener, s_sensor_event_listener_get_axis_names)); @@ -720,6 +731,10 @@ void Init() reinterpret_cast(env->NewGlobalRef(sensor_event_listener_class)); s_sensor_event_listener_constructor = env->GetMethodID(s_sensor_event_listener_class, "", "()V"); + s_sensor_event_listener_constructor_input_device = + env->GetMethodID(s_sensor_event_listener_class, "", "(Landroid/view/InputDevice;)V"); + s_sensor_event_listener_set_device_qualifier = env->GetMethodID( + s_sensor_event_listener_class, "setDeviceQualifier", "(Ljava/lang/String;)V"); s_sensor_event_listener_enable_sensor_events = env->GetMethodID(s_sensor_event_listener_class, "enableSensorEvents", "(Lorg/dolphinemu/dolphinemu/features/input/model/SensorEventRequester;)V"); @@ -775,6 +790,11 @@ static void AddDevice(JNIEnv* env, int device_id) INFO_LOG_FMT(CONTROLLERINTERFACE, "Added device ID {} as {}", device_id, device->GetQualifiedName()); s_device_id_to_device_qualifier.emplace(device_id, qualifier); + + jstring j_qualifier = ToJString(env, qualifier.ToString()); + env->CallVoidMethod(device->GetSensorEventListener(), + s_sensor_event_listener_set_device_qualifier, j_qualifier); + env->DeleteLocalRef(j_qualifier); } static void AddSensorDevice(JNIEnv* env) @@ -793,7 +813,11 @@ static void AddSensorDevice(JNIEnv* env) qualifier.FromDevice(device.get()); INFO_LOG_FMT(CONTROLLERINTERFACE, "Added sensor device as {}", device->GetQualifiedName()); - s_sensor_device_qualifier = qualifier; + + jstring j_qualifier = ToJString(env, qualifier.ToString()); + env->CallVoidMethod(device->GetSensorEventListener(), + s_sensor_event_listener_set_device_qualifier, j_qualifier); + env->DeleteLocalRef(j_qualifier); } void PopulateDevices() @@ -912,10 +936,12 @@ Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_dispatch JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_dispatchSensorEvent( - JNIEnv* env, jclass, jstring j_axis_name, jfloat value) + JNIEnv* env, jclass, jstring j_device_qualifier, jstring j_axis_name, jfloat value) { + ciface::Core::DeviceQualifier device_qualifier; + device_qualifier.FromString(GetJString(env, j_device_qualifier)); const std::shared_ptr device = - g_controller_interface.FindDevice(s_sensor_device_qualifier); + g_controller_interface.FindDevice(device_qualifier); if (!device) return; @@ -936,28 +962,24 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_enableSensorEvents( JNIEnv* env, jclass, jobject j_sensor_event_requester) { - const std::shared_ptr device = - g_controller_interface.FindDevice(s_sensor_device_qualifier); - if (!device) - return; - - env->CallVoidMethod( - static_cast(device.get())->GetSensorEventListener(), - s_sensor_event_listener_enable_sensor_events, j_sensor_event_requester); + for (std::shared_ptr& device : g_controller_interface.GetAllDevices()) + { + env->CallVoidMethod( + static_cast(device.get())->GetSensorEventListener(), + s_sensor_event_listener_enable_sensor_events, j_sensor_event_requester); + } } JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_disableSensorEvents( JNIEnv* env, jclass) { - const std::shared_ptr device = - g_controller_interface.FindDevice(s_sensor_device_qualifier); - if (!device) - return; - - env->CallVoidMethod( - static_cast(device.get())->GetSensorEventListener(), - s_sensor_event_listener_disable_sensor_events); + for (std::shared_ptr& device : g_controller_interface.GetAllDevices()) + { + env->CallVoidMethod( + static_cast(device.get())->GetSensorEventListener(), + s_sensor_event_listener_disable_sensor_events); + } } JNIEXPORT void JNICALL diff --git a/Source/Core/InputCommon/ControllerInterface/CoreDevice.cpp b/Source/Core/InputCommon/ControllerInterface/CoreDevice.cpp index 4e46179fc6..222791f03f 100644 --- a/Source/Core/InputCommon/ControllerInterface/CoreDevice.cpp +++ b/Source/Core/InputCommon/ControllerInterface/CoreDevice.cpp @@ -242,6 +242,18 @@ std::shared_ptr DeviceContainer::FindDevice(const DeviceQualifier& devq) return nullptr; } +std::vector> DeviceContainer::GetAllDevices() const +{ + std::lock_guard lk(m_devices_mutex); + + std::vector> devices; + + for (const auto& d : m_devices) + devices.emplace_back(d); + + return devices; +} + std::vector DeviceContainer::GetAllDeviceStrings() const { std::lock_guard lk(m_devices_mutex); diff --git a/Source/Core/InputCommon/ControllerInterface/CoreDevice.h b/Source/Core/InputCommon/ControllerInterface/CoreDevice.h index 2280ddac3b..a2176637ab 100644 --- a/Source/Core/InputCommon/ControllerInterface/CoreDevice.h +++ b/Source/Core/InputCommon/ControllerInterface/CoreDevice.h @@ -226,6 +226,7 @@ public: Device::Input* FindInput(std::string_view name, const Device* def_dev) const; Device::Output* FindOutput(std::string_view name, const Device* def_dev) const; + std::vector> GetAllDevices() const; std::vector GetAllDeviceStrings() const; bool HasDefaultDevice() const; std::string GetDefaultDeviceString() const;