summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2025-09-28 14:03:50 -0400
committerGitHub <noreply@github.com>2025-09-28 14:03:50 -0400
commite1c7734ee44e1f49089c8f4e3c2496e573e7cae6 (patch)
tree7d4b541822867ff58287a21155208ed9f4289956 /Source/Core/InputCommon
parentcbdb7ac38ef9336c20c0ddccf106d42151c84c15 (diff)
parent8524e725a8e883a0c763b6d791095aba5ff5e5ab (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.cpp98
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
{