mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-17 05:45:45 -04:00
Android: Controller binding support
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
#include "android_host_interface.h"
|
||||
#include "android_controller_interface.h"
|
||||
#include "android_progress_callback.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/audio_stream.h"
|
||||
@ -503,6 +504,27 @@ std::unique_ptr<AudioStream> AndroidHostInterface::CreateAudioStream(AudioBacken
|
||||
return CommonHostInterface::CreateAudioStream(backend);
|
||||
}
|
||||
|
||||
void AndroidHostInterface::UpdateControllerInterface()
|
||||
{
|
||||
if (m_controller_interface)
|
||||
{
|
||||
m_controller_interface->Shutdown();
|
||||
m_controller_interface.reset();
|
||||
}
|
||||
|
||||
m_controller_interface = std::make_unique<AndroidControllerInterface>();
|
||||
if (!m_controller_interface || !m_controller_interface->Initialize(this))
|
||||
{
|
||||
Log_WarningPrintf("Failed to initialize controller interface, bindings are not possible.");
|
||||
if (m_controller_interface)
|
||||
{
|
||||
m_controller_interface->Shutdown();
|
||||
m_controller_interface.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AndroidHostInterface::OnSystemPaused(bool paused)
|
||||
{
|
||||
CommonHostInterface::OnSystemPaused(paused);
|
||||
@ -637,6 +659,32 @@ void AndroidHostInterface::SetControllerAxisState(u32 index, s32 button_code, fl
|
||||
false);
|
||||
}
|
||||
|
||||
void AndroidHostInterface::HandleControllerButtonEvent(u32 controller_index, u32 button_index, bool pressed)
|
||||
{
|
||||
if (!IsEmulationThreadRunning())
|
||||
return;
|
||||
|
||||
RunOnEmulationThread(
|
||||
[this, controller_index, button_index, pressed]() {
|
||||
AndroidControllerInterface* ci = static_cast<AndroidControllerInterface*>(m_controller_interface.get());
|
||||
if (ci)
|
||||
ci->HandleButtonEvent(controller_index, button_index, pressed);
|
||||
});
|
||||
}
|
||||
|
||||
void AndroidHostInterface::HandleControllerAxisEvent(u32 controller_index, u32 axis_index, float value)
|
||||
{
|
||||
if (!IsEmulationThreadRunning())
|
||||
return;
|
||||
|
||||
RunOnEmulationThread(
|
||||
[this, controller_index, axis_index, value]() {
|
||||
AndroidControllerInterface* ci = static_cast<AndroidControllerInterface*>(m_controller_interface.get());
|
||||
if (ci)
|
||||
ci->HandleAxisEvent(controller_index, axis_index, value);
|
||||
});
|
||||
}
|
||||
|
||||
void AndroidHostInterface::SetFastForwardEnabled(bool enabled)
|
||||
{
|
||||
m_fast_forward_enabled = enabled;
|
||||
@ -656,6 +704,7 @@ void AndroidHostInterface::ApplySettings(bool display_osd_messages)
|
||||
LoadAndConvertSettings();
|
||||
CommonHostInterface::ApplyGameSettings(display_osd_messages);
|
||||
CommonHostInterface::FixIncompatibleSettings(display_osd_messages);
|
||||
UpdateInputMap();
|
||||
|
||||
// Defer renderer changes, the app really doesn't like it.
|
||||
if (System::IsValid() && g_settings.gpu_renderer != old_settings.gpu_renderer)
|
||||
@ -743,6 +792,45 @@ void AndroidHostInterface::UpdateVibration()
|
||||
SetVibration(vibration_state);
|
||||
}
|
||||
|
||||
jobjectArray AndroidHostInterface::GetInputProfileNames(JNIEnv* env) const
|
||||
{
|
||||
const InputProfileList profile_list(GetInputProfileList());
|
||||
if (profile_list.empty())
|
||||
return nullptr;
|
||||
|
||||
jobjectArray name_array = env->NewObjectArray(static_cast<u32>(profile_list.size()), s_String_class, nullptr);
|
||||
u32 name_array_index = 0;
|
||||
Assert(name_array != nullptr);
|
||||
for (const InputProfileEntry& e : profile_list)
|
||||
{
|
||||
jstring axis_name_jstr = env->NewStringUTF(e.name.c_str());
|
||||
env->SetObjectArrayElement(name_array, name_array_index++, axis_name_jstr);
|
||||
env->DeleteLocalRef(axis_name_jstr);
|
||||
}
|
||||
|
||||
return name_array;
|
||||
}
|
||||
|
||||
bool AndroidHostInterface::ApplyInputProfile(const char *profile_name)
|
||||
{
|
||||
const std::string path(GetInputProfilePath(profile_name));
|
||||
if (path.empty())
|
||||
return false;
|
||||
|
||||
Assert(!IsEmulationThreadRunning() || IsEmulationThreadPaused());
|
||||
CommonHostInterface::ApplyInputProfile(path.c_str(), m_settings_interface);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AndroidHostInterface::SaveInputProfile(const char *profile_name)
|
||||
{
|
||||
const std::string path(GetSavePathForInputProfile(profile_name));
|
||||
if (path.empty())
|
||||
return false;
|
||||
|
||||
return CommonHostInterface::SaveInputProfile(path.c_str(), m_settings_interface);
|
||||
}
|
||||
|
||||
extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||
{
|
||||
Log::SetDebugOutputParams(true, nullptr, LOGLEVEL_DEV);
|
||||
@ -938,6 +1026,82 @@ DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getControllerAxisCode, jobject
|
||||
return code.value_or(-1);
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(jobjectArray, AndroidHostInterface_getControllerButtonNames, jobject unused, jstring controller_type)
|
||||
{
|
||||
std::optional<ControllerType> type =
|
||||
Settings::ParseControllerTypeName(AndroidHelpers::JStringToString(env, controller_type).c_str());
|
||||
if (!type)
|
||||
return nullptr;
|
||||
|
||||
const Controller::ButtonList buttons(Controller::GetButtonNames(type.value()));
|
||||
if (buttons.empty())
|
||||
return nullptr;
|
||||
|
||||
jobjectArray name_array = env->NewObjectArray(static_cast<u32>(buttons.size()), s_String_class, nullptr);
|
||||
u32 name_array_index = 0;
|
||||
Assert(name_array != nullptr);
|
||||
for (const auto& [button_name, button_code] : buttons)
|
||||
{
|
||||
jstring button_name_jstr = env->NewStringUTF(button_name.c_str());
|
||||
env->SetObjectArrayElement(name_array, name_array_index++, button_name_jstr);
|
||||
env->DeleteLocalRef(button_name_jstr);
|
||||
}
|
||||
|
||||
return name_array;
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(jobjectArray, AndroidHostInterface_getControllerAxisNames, jobject unused, jstring controller_type)
|
||||
{
|
||||
std::optional<ControllerType> type =
|
||||
Settings::ParseControllerTypeName(AndroidHelpers::JStringToString(env, controller_type).c_str());
|
||||
if (!type)
|
||||
return nullptr;
|
||||
|
||||
const Controller::AxisList axes(Controller::GetAxisNames(type.value()));
|
||||
if (axes.empty())
|
||||
return nullptr;
|
||||
|
||||
jobjectArray name_array = env->NewObjectArray(static_cast<u32>(axes.size()), s_String_class, nullptr);
|
||||
u32 name_array_index = 0;
|
||||
Assert(name_array != nullptr);
|
||||
for (const auto& [axis_name, axis_code, axis_type] : axes)
|
||||
{
|
||||
jstring axis_name_jstr = env->NewStringUTF(axis_name.c_str());
|
||||
env->SetObjectArrayElement(name_array, name_array_index++, axis_name_jstr);
|
||||
env->DeleteLocalRef(axis_name_jstr);
|
||||
}
|
||||
|
||||
return name_array;
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_handleControllerButtonEvent, jobject obj, jint controller_index, jint button_index, jboolean pressed)
|
||||
{
|
||||
AndroidHelpers::GetNativeClass(env, obj)->HandleControllerButtonEvent(controller_index, button_index, pressed);
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_handleControllerAxisEvent, jobject obj, jint controller_index, jint axis_index, jfloat value)
|
||||
{
|
||||
AndroidHelpers::GetNativeClass(env, obj)->HandleControllerAxisEvent(controller_index, axis_index, value);
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(jobjectArray, AndroidHostInterface_getInputProfileNames, jobject obj)
|
||||
{
|
||||
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||
return hi->GetInputProfileNames(env);
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_loadInputProfile, jobject obj, jstring name)
|
||||
{
|
||||
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||
return hi->ApplyInputProfile(AndroidHelpers::JStringToString(env, name).c_str());
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_saveInputProfile, jobject obj, jstring name)
|
||||
{
|
||||
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||
return hi->SaveInputProfile(AndroidHelpers::JStringToString(env, name).c_str());
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_refreshGameList, jobject obj, jboolean invalidate_cache,
|
||||
jboolean invalidate_database, jobject progress_callback)
|
||||
{
|
||||
|
@ -51,6 +51,8 @@ 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 HandleControllerButtonEvent(u32 controller_index, u32 button_index, bool pressed);
|
||||
void HandleControllerAxisEvent(u32 controller_index, u32 axis_index, float value);
|
||||
void SetFastForwardEnabled(bool enabled);
|
||||
|
||||
void RefreshGameList(bool invalidate_cache, bool invalidate_database, ProgressCallback* progress_callback);
|
||||
@ -58,6 +60,10 @@ public:
|
||||
|
||||
bool ImportPatchCodesFromString(const std::string& str);
|
||||
|
||||
jobjectArray GetInputProfileNames(JNIEnv* env) const;
|
||||
bool ApplyInputProfile(const char* profile_name);
|
||||
bool SaveInputProfile(const char* profile_name);
|
||||
|
||||
protected:
|
||||
void SetUserDirectory() override;
|
||||
void LoadSettings() override;
|
||||
@ -66,6 +72,7 @@ protected:
|
||||
bool AcquireHostDisplay() override;
|
||||
void ReleaseHostDisplay() override;
|
||||
std::unique_ptr<AudioStream> CreateAudioStream(AudioBackend backend) override;
|
||||
void UpdateControllerInterface() override;
|
||||
|
||||
void OnSystemPaused(bool paused) override;
|
||||
void OnSystemDestroyed() override;
|
||||
|
@ -308,6 +308,20 @@ std::vector<std::string> AndroidSettingsInterface::GetStringList(const char* sec
|
||||
env, env->CallObjectMethod(m_java_shared_preferences, m_get_string_set, key_string.Get(), nullptr));
|
||||
if (env->ExceptionCheck())
|
||||
{
|
||||
env->ExceptionClear();
|
||||
|
||||
// this might just be a string, not a string set
|
||||
LocalRefHolder<jstring> string_object(
|
||||
env, reinterpret_cast<jstring>(env->CallObjectMethod(m_java_shared_preferences, m_get_string, key_string.Get(), nullptr)));
|
||||
|
||||
if (!env->ExceptionCheck()) {
|
||||
std::vector<std::string> ret;
|
||||
if (string_object)
|
||||
ret.push_back(AndroidHelpers::JStringToString(env, string_object));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
env->ExceptionClear();
|
||||
return {};
|
||||
}
|
||||
|
Reference in New Issue
Block a user