diff options
| author | JMC47 <JMC4789@gmail.com> | 2025-09-28 14:03:50 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-28 14:03:50 -0400 |
| commit | e1c7734ee44e1f49089c8f4e3c2496e573e7cae6 (patch) | |
| tree | 7d4b541822867ff58287a21155208ed9f4289956 /Source/Core/InputCommon | |
| parent | cbdb7ac38ef9336c20c0ddccf106d42151c84c15 (diff) | |
| parent | 8524e725a8e883a0c763b6d791095aba5ff5e5ab (diff) | |
Merge pull request #13260 from JosJuice/android-gcadapter-hotplug-callback
Android: Detect GCAdapter hotplug using BroadcastReceiver
Diffstat (limited to 'Source/Core/InputCommon')
| -rw-r--r-- | Source/Core/InputCommon/GCAdapter.cpp | 98 |
1 files changed, 53 insertions, 45 deletions
diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index 5cfe513935..df212e8f4e 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -66,13 +66,7 @@ static void AddGCAdapter(libusb_device* device); static void ResetRumbleLockNeeded(); #endif -enum class CalledFromReadThread -{ - No, - Yes, -}; - -static void Reset(CalledFromReadThread called_from_read_thread); +static void Reset(); static void Setup(); static void ProcessInputPayload(const u8* data, std::size_t size); static void ReadThreadFunc(); @@ -129,24 +123,22 @@ static std::atomic<int> s_controller_write_payload_size{0}; static std::thread s_read_adapter_thread; static Common::Flag s_read_adapter_thread_running; -static Common::Flag s_read_adapter_thread_needs_joining; static std::thread s_write_adapter_thread; static Common::Flag s_write_adapter_thread_running; static Common::Event s_write_happened; -static std::mutex s_read_mutex; -#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION static std::mutex s_init_mutex; -#elif GCADAPTER_USE_ANDROID_IMPLEMENTATION +static std::mutex s_read_mutex; +#if GCADAPTER_USE_ANDROID_IMPLEMENTATION static std::mutex s_write_mutex; #endif static std::thread s_adapter_detect_thread; static Common::Flag s_adapter_detect_thread_running; -#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION static Common::Event s_hotplug_event; +#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION static std::function<void(void)> s_detect_callback; #if defined(__FreeBSD__) && __FreeBSD__ >= 11 @@ -180,14 +172,14 @@ static void ReadThreadFunc() bool first_read = true; JNIEnv* const env = IDCache::GetEnvForThread(); - const jfieldID payload_field = env->GetStaticFieldID(s_adapter_class, "controller_payload", "[B"); + const jfieldID payload_field = env->GetStaticFieldID(s_adapter_class, "controllerPayload", "[B"); jobject payload_object = env->GetStaticObjectField(s_adapter_class, payload_field); auto* const java_controller_payload = reinterpret_cast<jbyteArray*>(&payload_object); // Get function pointers - const jmethodID getfd_func = env->GetStaticMethodID(s_adapter_class, "GetFD", "()I"); - const jmethodID input_func = env->GetStaticMethodID(s_adapter_class, "Input", "()I"); - const jmethodID openadapter_func = env->GetStaticMethodID(s_adapter_class, "OpenAdapter", "()Z"); + const jmethodID getfd_func = env->GetStaticMethodID(s_adapter_class, "getFd", "()I"); + const jmethodID input_func = env->GetStaticMethodID(s_adapter_class, "input", "()I"); + const jmethodID openadapter_func = env->GetStaticMethodID(s_adapter_class, "openAdapter", "()Z"); const bool connected = env->CallStaticBooleanMethod(s_adapter_class, openadapter_func); @@ -279,7 +271,7 @@ static void WriteThreadFunc() int size = 0; #elif GCADAPTER_USE_ANDROID_IMPLEMENTATION JNIEnv* const env = IDCache::GetEnvForThread(); - const jmethodID output_func = env->GetStaticMethodID(s_adapter_class, "Output", "([B)I"); + const jmethodID output_func = env->GetStaticMethodID(s_adapter_class, "output", "([B)I"); #endif while (s_write_adapter_thread_running.IsSet()) @@ -331,7 +323,7 @@ static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotpl else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { if (s_handle != nullptr && libusb_get_device(s_handle) == dev) - Reset(CalledFromReadThread::No); + Reset(); // Reset a potential error status now that the adapter is unplugged if (s_status == AdapterStatus::Error) @@ -344,6 +336,25 @@ static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotpl return 0; } #endif +#elif GCADAPTER_USE_ANDROID_IMPLEMENTATION +extern "C" { + +JNIEXPORT void JNICALL +Java_org_dolphinemu_dolphinemu_utils_GCAdapter_onAdapterConnected(JNIEnv* env, jclass) +{ + INFO_LOG_FMT(CONTROLLERINTERFACE, "GC adapter connected"); + if (!s_detected) + s_hotplug_event.Set(); +} + +JNIEXPORT void JNICALL +Java_org_dolphinemu_dolphinemu_utils_GCAdapter_onAdapterDisconnected(JNIEnv* env, jclass) +{ + INFO_LOG_FMT(CONTROLLERINTERFACE, "GC adapter disconnected"); + if (s_detected) + Reset(); +} +} #endif static void ScanThreadFunc() @@ -393,15 +404,23 @@ static void ScanThreadFunc() #elif GCADAPTER_USE_ANDROID_IMPLEMENTATION JNIEnv* const env = IDCache::GetEnvForThread(); - const jmethodID queryadapter_func = - env->GetStaticMethodID(s_adapter_class, "QueryAdapter", "()Z"); + const jmethodID enable_hotplug_callback_func = + env->GetStaticMethodID(s_adapter_class, "enableHotplugCallback", "()V"); + env->CallStaticVoidMethod(s_adapter_class, enable_hotplug_callback_func); + + const jmethodID is_usb_device_available_func = + env->GetStaticMethodID(s_adapter_class, "isUsbDeviceAvailable", "()Z"); while (s_adapter_detect_thread_running.IsSet()) { if (!s_detected && UseAdapter() && - env->CallStaticBooleanMethod(s_adapter_class, queryadapter_func)) + env->CallStaticBooleanMethod(s_adapter_class, is_usb_device_available_func)) + { + std::lock_guard lk(s_init_mutex); Setup(); - Common::SleepCurrentThread(1000); + } + + s_hotplug_event.Wait(); } #endif @@ -456,7 +475,7 @@ void Init() #elif GCADAPTER_USE_ANDROID_IMPLEMENTATION JNIEnv* const env = IDCache::GetEnvForThread(); - const jclass adapter_class = env->FindClass("org/dolphinemu/dolphinemu/utils/Java_GCAdapter"); + const jclass adapter_class = env->FindClass("org/dolphinemu/dolphinemu/utils/GCAdapter"); s_adapter_class = reinterpret_cast<jclass>(env->NewGlobalRef(adapter_class)); #endif @@ -484,9 +503,7 @@ void StopScanThread() { if (s_adapter_detect_thread_running.TestAndClear()) { -#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION s_hotplug_event.Set(); -#endif s_adapter_detect_thread.join(); } } @@ -523,11 +540,8 @@ static void Setup() s_detected = true; // Make sure the thread isn't in the middle of shutting down while starting a new one - if (s_read_adapter_thread_needs_joining.TestAndClear() || - s_read_adapter_thread_running.TestAndClear()) - { + if (s_read_adapter_thread_running.TestAndClear()) s_read_adapter_thread.join(); - } s_read_adapter_thread_running.Set(true); s_read_adapter_thread = std::thread(ReadThreadFunc); @@ -691,8 +705,13 @@ void Shutdown() if (s_libusb_context && s_libusb_context->IsValid() && s_libusb_hotplug_enabled) libusb_hotplug_deregister_callback(*s_libusb_context, s_hotplug_handle); #endif +#elif GCADAPTER_USE_ANDROID_IMPLEMENTATION + JNIEnv* const env = IDCache::GetEnvForThread(); + const jmethodID disable_hotplug_callback_func = + env->GetStaticMethodID(s_adapter_class, "disableHotplugCallback", "()V"); + env->CallStaticVoidMethod(s_adapter_class, disable_hotplug_callback_func); #endif - Reset(CalledFromReadThread::No); + Reset(); #if GCADAPTER_USE_LIBUSB_IMPLEMENTATION s_libusb_context.reset(); @@ -706,12 +725,12 @@ void Shutdown() } } -static void Reset(CalledFromReadThread called_from_read_thread) +static void Reset() { -#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION std::unique_lock lock(s_init_mutex, std::defer_lock); if (!lock.try_lock()) return; +#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION if (s_status != AdapterStatus::Detected) return; #elif GCADAPTER_USE_ANDROID_IMPLEMENTATION @@ -719,16 +738,8 @@ static void Reset(CalledFromReadThread called_from_read_thread) return; #endif - if (called_from_read_thread == CalledFromReadThread::No) - { - if (s_read_adapter_thread_running.TestAndClear()) - s_read_adapter_thread.join(); - } - else - { - s_read_adapter_thread_needs_joining.Set(); - s_read_adapter_thread_running.Clear(); - } + if (s_read_adapter_thread_running.TestAndClear()) + s_read_adapter_thread.join(); // The read thread will close the write thread s_port_states.fill({}); @@ -807,9 +818,6 @@ void ProcessInputPayload(const u8* data, std::size_t size) // This can occur for a few frames on initialization. ERROR_LOG_FMT(CONTROLLERINTERFACE, "error reading payload (size: {}, type: {:02x})", size, data[0]); -#if GCADAPTER_USE_ANDROID_IMPLEMENTATION - Reset(CalledFromReadThread::Yes); -#endif } else { |
