mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-17 02:05:46 -04:00
Android: Multiple fixes
- Fix possible crash when applying settings worker thread (no JNIEnv). - Fix settings not applying until restarting the app. - Support analog controller - auto-binding of axixes. Currently no touchscreen controller for the joysticks. - Add option to auto-hide the touchscreen controller.
This commit is contained in:
@ -3,7 +3,6 @@ set(SRCS
|
||||
android_host_interface.h
|
||||
android_settings_interface.cpp
|
||||
android_settings_interface.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_library(duckstation-native SHARED ${SRCS})
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "core/system.h"
|
||||
#include "frontend-common/opengl_host_display.h"
|
||||
#include "frontend-common/vulkan_host_display.h"
|
||||
#include "frontend-common/imgui_styles.h"
|
||||
#include <android/native_window_jni.h>
|
||||
#include <cmath>
|
||||
#include <imgui.h>
|
||||
@ -195,8 +196,18 @@ void AndroidHostInterface::RunOnEmulationThread(std::function<void()> function,
|
||||
|
||||
void AndroidHostInterface::EmulationThreadEntryPoint(ANativeWindow* initial_surface, SystemBootParameters boot_params)
|
||||
{
|
||||
JNIEnv* thread_env;
|
||||
if (s_jvm->AttachCurrentThread(&thread_env, nullptr) != JNI_OK)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to attach JNI to thread");
|
||||
m_emulation_thread_start_result.store(false);
|
||||
m_emulation_thread_started.Signal();
|
||||
return;
|
||||
}
|
||||
|
||||
CreateImGuiContext();
|
||||
m_surface = initial_surface;
|
||||
ApplySettings();
|
||||
|
||||
// Boot system.
|
||||
if (!BootSystem(boot_params))
|
||||
@ -205,6 +216,7 @@ void AndroidHostInterface::EmulationThreadEntryPoint(ANativeWindow* initial_surf
|
||||
DestroyImGuiContext();
|
||||
m_emulation_thread_start_result.store(false);
|
||||
m_emulation_thread_started.Signal();
|
||||
s_jvm->DetachCurrentThread();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -256,6 +268,7 @@ void AndroidHostInterface::EmulationThreadEntryPoint(ANativeWindow* initial_surf
|
||||
|
||||
DestroySystem();
|
||||
DestroyImGuiContext();
|
||||
s_jvm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
bool AndroidHostInterface::AcquireHostDisplay()
|
||||
@ -297,31 +310,6 @@ void AndroidHostInterface::ReleaseHostDisplay()
|
||||
m_display.reset();
|
||||
}
|
||||
|
||||
std::unique_ptr<AudioStream> AndroidHostInterface::CreateAudioStream(AudioBackend backend)
|
||||
{
|
||||
std::unique_ptr<AudioStream> stream;
|
||||
|
||||
switch (m_settings.audio_backend)
|
||||
{
|
||||
case AudioBackend::Cubeb:
|
||||
stream = AudioStream::CreateCubebAudioStream();
|
||||
break;
|
||||
|
||||
default:
|
||||
stream = AudioStream::CreateNullAudioStream();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!stream)
|
||||
{
|
||||
ReportFormattedError("Failed to create %s audio stream, falling back to null",
|
||||
Settings::GetAudioBackendName(m_settings.audio_backend));
|
||||
stream = AudioStream::CreateNullAudioStream();
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
void AndroidHostInterface::SurfaceChanged(ANativeWindow* surface, int format, int width, int height)
|
||||
{
|
||||
Log_InfoPrintf("SurfaceChanged %p %d %d %d", surface, format, width, height);
|
||||
@ -351,9 +339,16 @@ void AndroidHostInterface::CreateImGuiContext()
|
||||
{
|
||||
ImGui::CreateContext();
|
||||
|
||||
ImGui::GetIO().IniFilename = nullptr;
|
||||
// ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||||
// ImGui::GetIO().BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
const float framebuffer_scale = 2.0f;
|
||||
|
||||
auto& io = ImGui::GetIO();
|
||||
io.IniFilename = nullptr;
|
||||
io.DisplayFramebufferScale.x = framebuffer_scale;
|
||||
io.DisplayFramebufferScale.y = framebuffer_scale;
|
||||
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
|
||||
|
||||
ImGui::StyleColorsDarker();
|
||||
ImGui::AddRobotoRegularFont(15.0f * framebuffer_scale);
|
||||
}
|
||||
|
||||
void AndroidHostInterface::DestroyImGuiContext()
|
||||
@ -397,6 +392,22 @@ void AndroidHostInterface::SetControllerButtonState(u32 index, s32 button_code,
|
||||
false);
|
||||
}
|
||||
|
||||
void AndroidHostInterface::SetControllerAxisState(u32 index, s32 button_code, float value)
|
||||
{
|
||||
if (!IsEmulationThreadRunning())
|
||||
return;
|
||||
|
||||
RunOnEmulationThread(
|
||||
[this, index, button_code, value]() {
|
||||
Controller* controller = m_system->GetController(index);
|
||||
if (!controller)
|
||||
return;
|
||||
|
||||
controller->SetAxisState(button_code, value);
|
||||
},
|
||||
false);
|
||||
}
|
||||
|
||||
void AndroidHostInterface::RefreshGameList(bool invalidate_cache, bool invalidate_database)
|
||||
{
|
||||
m_game_list->SetSearchDirectoriesFromSettings(m_settings_interface);
|
||||
@ -544,6 +555,25 @@ DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getControllerButtonCode, jobje
|
||||
return code.value_or(-1);
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setControllerAxisState, jobject obj, jint index, jint button_code,
|
||||
jfloat value)
|
||||
{
|
||||
AndroidHelpers::GetNativeClass(env, obj)->SetControllerAxisState(index, button_code, value);
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getControllerAxisCode, jobject unused, jstring controller_type,
|
||||
jstring axis_name)
|
||||
{
|
||||
std::optional<ControllerType> type =
|
||||
Settings::ParseControllerTypeName(AndroidHelpers::JStringToString(env, controller_type).c_str());
|
||||
if (!type)
|
||||
return -1;
|
||||
|
||||
std::optional<s32> code =
|
||||
Controller::GetAxisCodeByName(type.value(), AndroidHelpers::JStringToString(env, axis_name));
|
||||
return code.value_or(-1);
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_refreshGameList, jobject obj, jboolean invalidate_cache, jboolean invalidate_database)
|
||||
{
|
||||
AndroidHelpers::GetNativeClass(env, obj)->RefreshGameList(invalidate_cache, invalidate_database);
|
||||
|
@ -43,6 +43,7 @@ public:
|
||||
|
||||
void SetControllerType(u32 index, std::string_view type_name);
|
||||
void SetControllerButtonState(u32 index, s32 button_code, bool pressed);
|
||||
void SetControllerAxisState(u32 index, s32 button_code, float value);
|
||||
|
||||
void RefreshGameList(bool invalidate_cache, bool invalidate_database);
|
||||
void ApplySettings();
|
||||
@ -54,7 +55,6 @@ protected:
|
||||
|
||||
bool AcquireHostDisplay() override;
|
||||
void ReleaseHostDisplay() override;
|
||||
std::unique_ptr<AudioStream> CreateAudioStream(AudioBackend backend) override;
|
||||
|
||||
private:
|
||||
void EmulationThreadEntryPoint(ANativeWindow* initial_surface, SystemBootParameters boot_params);
|
||||
|
@ -1,17 +0,0 @@
|
||||
#include "core/host_interface.h"
|
||||
#include <jni.h>
|
||||
|
||||
#define DEFINE_JNI_METHOD(return_type, name, ...) \
|
||||
extern "C" JNIEXPORT return_type JNICALL Java_com_github_stenzek_duckstation_##name(__VA_ARGS__)
|
||||
|
||||
DEFINE_JNI_METHOD(bool, createSystem)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DEFINE_JNI_METHOD(bool, bootSystem, const char* filename, const char* state_filename)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DEFINE_JNI_METHOD(void, runFrame) {}
|
Reference in New Issue
Block a user