diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.kt index 360800d656..71b37ff513 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.kt @@ -95,11 +95,6 @@ object ControllerInterface { deviceQualifier: String, axisNames: Array, suspended: Boolean ) - /** - * Rescans for input devices. - */ - external fun refreshDevices() - external fun getAllDeviceStrings(): Array external fun getDevice(deviceString: String): CoreDevice? @@ -193,13 +188,10 @@ object ControllerInterface { } private class InputDeviceListener : InputManager.InputDeviceListener { - // Simple implementation for now. We could do something fancier if we wanted to. - override fun onInputDeviceAdded(deviceId: Int) = refreshDevices() + override external fun onInputDeviceAdded(deviceId: Int) - // Simple implementation for now. We could do something fancier if we wanted to. - override fun onInputDeviceRemoved(deviceId: Int) = refreshDevices() + override external fun onInputDeviceRemoved(deviceId: Int) - // Simple implementation for now. We could do something fancier if we wanted to. - override fun onInputDeviceChanged(deviceId: Int) = refreshDevices() + override external fun onInputDeviceChanged(deviceId: Int) } } diff --git a/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp b/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp index a0a3f7c8c2..0b0609f010 100644 --- a/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp @@ -31,6 +31,8 @@ namespace { +std::string SOURCE = "Android"; + jclass s_list_class; jmethodID s_list_get; jmethodID s_list_size; @@ -468,13 +470,13 @@ namespace ciface::Android class InputBackend final : public ciface::InputBackend { public: - InputBackend(ControllerInterface* controller_interface); + explicit InputBackend(ControllerInterface* controller_interface); ~InputBackend(); void PopulateDevices() override; -private: - void AddDevice(JNIEnv* env, int device_id); - void AddSensorDevice(JNIEnv* env); + static void AddDevice(JNIEnv* env, int device_id); + static void AddSensorDevice(JNIEnv* env); + static void RemoveDevice(int device_id); }; std::unique_ptr CreateInputBackend(ControllerInterface* controller_interface) @@ -611,10 +613,11 @@ private: class AndroidDevice final : public Core::Device { public: - AndroidDevice(JNIEnv* env, jobject input_device) + AndroidDevice(JNIEnv* env, jint device_id, jobject input_device) : 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)) + m_controller_number(env->CallIntMethod(input_device, s_input_device_get_controller_number)), + m_device_id(device_id) { jstring j_name = reinterpret_cast(env->CallObjectMethod(input_device, s_input_device_get_name)); @@ -631,7 +634,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, nullptr)), m_source(AINPUT_SOURCE_SENSOR), - m_controller_number(0), m_name(std::move(name)) + m_controller_number(0), m_device_id(std::nullopt), m_name(std::move(name)) { AddSystemMotors(env); } @@ -644,7 +647,7 @@ public: std::string GetName() const override { return m_name; } - std::string GetSource() const override { return "Android"; } + std::string GetSource() const override { return SOURCE; } std::optional GetPreferredId() const override { @@ -666,6 +669,8 @@ public: return -3; } + std::optional GetDeviceID() const { return m_device_id; } + jobject GetSensorEventListener() { return m_sensor_event_listener; } private: @@ -801,6 +806,7 @@ private: const jobject m_sensor_event_listener; const int m_source; const int m_controller_number; + const std::optional m_device_id; std::string m_name; }; @@ -944,8 +950,12 @@ InputBackend::~InputBackend() env->DeleteGlobalRef(s_keycodes_array); } -void InputBackend::AddDevice(JNIEnv* env, int device_id) +void InputBackend::AddDevice(JNIEnv* env, jint device_id) { + // Remove the device in case it already exists (maybe it's possible for a device to connect, + // be processed by PopulateDevices, and then be processed by onInputDeviceAdded) + RemoveDevice(device_id); + jobject input_device = env->CallStaticObjectMethod(s_input_device_class, s_input_device_get_device, device_id); @@ -955,14 +965,14 @@ void InputBackend::AddDevice(JNIEnv* env, int device_id) return; } - auto device = std::make_shared(env, input_device); + auto device = std::make_shared(env, device_id, input_device); env->DeleteLocalRef(input_device); if (device->Inputs().empty() && device->Outputs().empty()) return; - GetControllerInterface().AddDevice(device); + g_controller_interface.AddDevice(device); Core::DeviceQualifier qualifier; qualifier.FromDevice(device.get()); @@ -987,7 +997,7 @@ void InputBackend::AddSensorDevice(JNIEnv* env) if (device->Inputs().empty() && device->Outputs().empty()) return; - GetControllerInterface().AddDevice(device); + g_controller_interface.AddDevice(device); Core::DeviceQualifier qualifier; qualifier.FromDevice(device.get()); @@ -1000,6 +1010,16 @@ void InputBackend::AddSensorDevice(JNIEnv* env) env->DeleteLocalRef(j_qualifier); } +void InputBackend::RemoveDevice(jint device_id) +{ + g_controller_interface.RemoveDevice([device_id](const ciface::Core::Device* device) { + return device->GetSource() == SOURCE && + static_cast(device)->GetDeviceID() == device_id; + }); + + s_device_id_to_device_qualifier.erase(device_id); +} + void InputBackend::PopulateDevices() { INFO_LOG_FMT(CONTROLLERINTERFACE, "Android populating devices"); @@ -1163,10 +1183,25 @@ Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_notifySe } JNIEXPORT void JNICALL -Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_refreshDevices(JNIEnv* env, - jclass) +Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_00024InputDeviceListener_onInputDeviceAdded( + JNIEnv* env, jobject, jint device_id) { - g_controller_interface.RefreshDevices(); + ciface::Android::InputBackend::AddDevice(env, device_id); +} + +JNIEXPORT void JNICALL +Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_00024InputDeviceListener_onInputDeviceRemoved( + JNIEnv*, jobject, jint device_id) +{ + ciface::Android::InputBackend::RemoveDevice(device_id); +} + +JNIEXPORT void JNICALL +Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_00024InputDeviceListener_onInputDeviceChanged( + JNIEnv* env, jobject, jint device_id) +{ + // AddDevice will automatically remove the existing device + ciface::Android::InputBackend::AddDevice(env, device_id); } JNIEXPORT jobjectArray JNICALL