Implement proper saving on Android

This commit is contained in:
Lorenzooone 2025-04-30 16:49:38 +02:00
parent 77872ecf56
commit 405bba1cb8
6 changed files with 129 additions and 71 deletions

View File

@ -4,9 +4,6 @@
<uses-feature android:glEsVersion="0x00010001" />
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application android:label="@string/app_name"
android:icon="@drawable/sfml_logo"
android:hasCode="false"

View File

@ -5,6 +5,20 @@
#include <condition_variable>
#include <chrono>
#ifdef SFML_SYSTEM_ANDROID
#define ANDROID_COMPILATION
#else
// Possible to add more stuff here...
#ifdef ANDROID_COMPILATION
#undef ANDROID_COMPILATION
#endif
#endif
#ifdef ANDROID_COMPILATION
// These headers are needed for direct NDK/JDK interaction
#include <android/native_activity.h>
#endif
#if _MSC_VER && !__INTEL_COMPILER
#define PACKED
#define ALIGNED(x) alignas(x)
@ -17,6 +31,12 @@
#define NAME "cc3dsfs"
#ifdef ANDROID_COMPILATION
#define PRINT_FUNCTION(...) __android_log_print(ANDROID_LOG_INFO, NAME, __VA_ARGS__)
#else
#define PRINT_FUNCTION(...) printf(__VA_ARGS__)
#endif
// This isn't precise, however we can use it...
// Use these to properly sleep, with small wakes to check if data is ready
#define USB_FPS 60
@ -28,7 +48,12 @@
#define SIMPLE_RESET_DATA_INDEX -2
#define CREATE_NEW_FILE_INDEX -3
#ifdef ANDROID_COMPILATION
ANativeActivity* getAndroidNativeActivity();
#endif
std::string get_version_string(bool get_letter = true);
void ActualConsoleOutTextError(std::string out_string);
void ActualConsoleOutText(std::string out_string);
std::string LayoutNameGenerator(int index);
std::string LayoutPathGenerator(int index, bool created_proper_folder);
std::string load_layout_name(int index, bool created_proper_folder, bool &success);

View File

@ -1,16 +1,8 @@
#include "usb_generic.hpp"
#include "utils.hpp"
#include <thread>
#include <mutex>
#ifdef SFML_SYSTEM_ANDROID
// These headers are only needed for direct NDK/JDK interaction
#include <android/native_activity.h>
#include <jni.h>
// Since we want to get the native activity from SFML, we'll have to use an
// extra header here:
#include <SFML/System/NativeActivity.hpp>
#endif
static bool usb_initialized = false;
static libusb_context* usb_ctx = NULL; // libusb session context
static int usb_thread_registered = 0;
@ -20,13 +12,13 @@ std::mutex usb_thread_mutex;
void usb_init() {
if(usb_initialized)
return;
#ifdef SFML_SYSTEM_ANDROID
// First we'll need the native activity handle
ANativeActivity& activity = *sf::getNativeActivity();
// Retrieve the JVM and JNI environment
JavaVM& vm = *activity.vm;
JNIEnv& env = *activity.env;
libusb_set_option(usb_ctx, LIBUSB_OPTION_ANDROID_JAVAVM, &vm);
#ifdef ANDROID_COMPILATION
ANativeActivity* native_activity_ptr = getAndroidNativeActivity();
if(native_activity_ptr) {
// Retrieve the JVM environment
JavaVM* vm = native_activity_ptr->vm;
libusb_set_option(usb_ctx, LIBUSB_OPTION_ANDROID_JAVAVM, vm);
}
#endif
int result = libusb_init(&usb_ctx); // open session
if (result < 0) {

View File

@ -6,7 +6,6 @@
#else
#include <experimental/filesystem>
#endif
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstring>
@ -720,7 +719,7 @@ static bool create_folder(const std::string path) {
return true;
}
catch(...) {
std::cerr << "Error creating folder " << path << std::endl;
ActualConsoleOutTextError("Error creating folder " + path);
}
return false;
}
@ -749,7 +748,7 @@ static bool parse_int_arg(int &index, int argc, char **argv, int &target, std::s
target = std::stoi(argv[index]);
}
catch(...) {
std::cerr << "Error with input for: " << to_check << std::endl;
ActualConsoleOutTextError("Error with input for: " + to_check);
}
return true;
}
@ -763,7 +762,7 @@ static bool parse_double_arg(int &index, int argc, char **argv, double &target,
target = std::stod(argv[index]);
}
catch(...) {
std::cerr << "Error with input for: " << to_check << std::endl;
ActualConsoleOutTextError("Error with input for: " + to_check);
}
return true;
}
@ -778,7 +777,7 @@ int main(int argc, char **argv) {
bool use_pud_up = true;
bool created_proper_folder = create_out_folder();
bool mono_app_default_value = false;
#ifdef SFML_SYSTEM_ANDROID
#ifdef ANDROID_COMPILATION
mono_app_default_value = true;
#endif
override_all_data override_data;
@ -846,44 +845,44 @@ int main(int argc, char **argv) {
mono_app_action_str = "Disables";
default_mono_app_strn = "Enabled";
}
std::cout << "Help:" << std::endl;
std::cout << " --mono_app "<< mono_app_action_str << " special mode for when only this application" << std::endl;
std::cout << " should run on the system. " << default_mono_app_strn << " by default." << std::endl;
std::cout << " --recovery_mode Resets to the defaults." << std::endl;
std::cout << " --pos_x_both Set default x position for the window with both screens." << std::endl;
std::cout << " --pos_y_both Set default y position for the window with both screens." << std::endl;
std::cout << " --scaling_both Overrides the scale factor for the window with both screens." << std::endl;
std::cout << " --enabled_both Overrides the presence of the window with both screens." << std::endl;
std::cout << " 1 On, 0 Off." << std::endl;
std::cout << " --pos_x_top Set default x position for the top screen's window." << std::endl;
std::cout << " --pos_y_top Set default y position for the top screen's window." << std::endl;
std::cout << " --scaling_top Overrides the top screen window's scale factor." << std::endl;
std::cout << " --enabled_top Overrides the presence of the top screen's window." << std::endl;
std::cout << " 1 On, 0 Off." << std::endl;
std::cout << " --pos_x_bot Set default x position for the bottom screen's window." << std::endl;
std::cout << " --pos_y_bot Set default y position for the bottom screen's window." << std::endl;
std::cout << " --scaling_bot Overrides the bottom screen window's scale factor." << std::endl;
std::cout << " --enabled_bot Overrides the presence of the bottom screen's window." << std::endl;
std::cout << " 1 On, 0 Off." << std::endl;
std::cout << " --no_frame_blend Disables support for frame blending shader." << std::endl;
std::cout << " May improve compatibility with lower end hardware." << std::endl;
std::cout << " --volume Overrides the saved volume for the audio. 0 - 200" << std::endl;
std::cout << " --no_audio Disables audio output and processing completely." << std::endl;
std::cout << " --no_cursor Prevents the mouse cursor from showing, unless moved." << std::endl;
std::cout << " --auto_connect Automatically connects to the first available device," << std::endl;
std::cout << " even if multiple are present." << std::endl;
std::cout << " --failure_close Automatically closes the software if the first connection" << std::endl;
std::cout << " doesn't succeed." << std::endl;
std::cout << " --auto_close Automatically closes the software on disconnect." << std::endl;
std::cout << " --profile Loads the profile with the specified ID at startup" << std::endl;
std::cout << " instead of the default one. When the program closes," << std::endl;
std::cout << " the data is also saved to the specified profile." << std::endl;
ActualConsoleOutText("Help:");
ActualConsoleOutText(" --mono_app " + mono_app_action_str + " special mode for when only this application");
ActualConsoleOutText(" should run on the system. " + default_mono_app_strn + " by default.");
ActualConsoleOutText(" --recovery_mode Resets to the defaults.");
ActualConsoleOutText(" --pos_x_both Set default x position for the window with both screens.");
ActualConsoleOutText(" --pos_y_both Set default y position for the window with both screens.");
ActualConsoleOutText(" --scaling_both Overrides the scale factor for the window with both screens.");
ActualConsoleOutText(" --enabled_both Overrides the presence of the window with both screens.");
ActualConsoleOutText(" 1 On, 0 Off.");
ActualConsoleOutText(" --pos_x_top Set default x position for the top screen's window.");
ActualConsoleOutText(" --pos_y_top Set default y position for the top screen's window.");
ActualConsoleOutText(" --scaling_top Overrides the top screen window's scale factor.");
ActualConsoleOutText(" --enabled_top Overrides the presence of the top screen's window.");
ActualConsoleOutText(" 1 On, 0 Off.");
ActualConsoleOutText(" --pos_x_bot Set default x position for the bottom screen's window.");
ActualConsoleOutText(" --pos_y_bot Set default y position for the bottom screen's window.");
ActualConsoleOutText(" --scaling_bot Overrides the bottom screen window's scale factor.");
ActualConsoleOutText(" --enabled_bot Overrides the presence of the bottom screen's window.");
ActualConsoleOutText(" 1 On, 0 Off.");
ActualConsoleOutText(" --no_frame_blend Disables support for frame blending shader.");
ActualConsoleOutText(" May improve compatibility with lower end hardware.");
ActualConsoleOutText(" --volume Overrides the saved volume for the audio. 0 - 200");
ActualConsoleOutText(" --no_audio Disables audio output and processing completely.");
ActualConsoleOutText(" --no_cursor Prevents the mouse cursor from showing, unless moved.");
ActualConsoleOutText(" --auto_connect Automatically connects to the first available device,");
ActualConsoleOutText(" even if multiple are present.");
ActualConsoleOutText(" --failure_close Automatically closes the software if the first connection");
ActualConsoleOutText(" doesn't succeed.");
ActualConsoleOutText(" --auto_close Automatically closes the software on disconnect.");
ActualConsoleOutText(" --profile Loads the profile with the specified ID at startup");
ActualConsoleOutText(" instead of the default one. When the program closes,");
ActualConsoleOutText(" the data is also saved to the specified profile.");
#ifdef RASPI
std::cout << " --pi_select ID Specifies ID for the select GPIO button." << std::endl;
std::cout << " --pi_menu ID Specifies ID for the menu GPIO button." << std::endl;
std::cout << " --pi_enter ID Specifies ID for the enter GPIO button." << std::endl;
std::cout << " --pi_power ID Specifies ID for the poweroff GPIO button." << std::endl;
std::cout << " --pi_pud_down Sets the pull-up GPIO mode to down. Default is up." << std::endl;
ActualConsoleOutText(" --pi_select ID Specifies ID for the select GPIO button.");
ActualConsoleOutText(" --pi_menu ID Specifies ID for the menu GPIO button.");
ActualConsoleOutText(" --pi_enter ID Specifies ID for the enter GPIO button.");
ActualConsoleOutText(" --pi_power ID Specifies ID for the poweroff GPIO button.");
ActualConsoleOutText(" --pi_pud_down Sets the pull-up GPIO mode to down. Default is up.");
#endif
return 0;
}

View File

@ -1,7 +1,6 @@
#include "frontend.hpp"
#include <cmath>
#include <thread>
#include <iostream>
#include <SFML/System.hpp>
const CropData default_3ds_crop = {
@ -1181,7 +1180,7 @@ std::string get_name_input_colorspace_mode(InputColorspaceMode input) {
static void ConsoleOutText(std::string full_text, std::string preamble_name) {
if(full_text != "")
std::cout << "[" << preamble_name << "] " << full_text << std::endl;
ActualConsoleOutText("[" + preamble_name + "] " + full_text);
}
void ConsumeOutText(OutTextData &out_text_data, bool update_consumed) {

View File

@ -16,6 +16,17 @@
#include <queue>
#include <cmath>
#ifdef SFML_SYSTEM_ANDROID
// Since we want to get the native activity from SFML, we'll have to use an
// extra header here:
#include <SFML/System/NativeActivity.hpp>
#endif
#ifdef ANDROID_COMPILATION
#include <android/log.h>
// These headers are only needed for direct NDK/JDK interaction
#include <android/native_activity.h>
#endif
#define xstr(a) str(a)
#define str(a) #a
@ -276,24 +287,59 @@ std::string get_float_str_decimals(float value, int decimals) {
return return_text;
}
void ActualConsoleOutTextError(std::string out_string) {
#ifdef ANDROID_COMPILATION
__android_log_print(ANDROID_LOG_ERROR, NAME, "%s", out_string.c_str());
#else
std::cerr << out_string << std::endl;
#endif
}
void ActualConsoleOutText(std::string out_string) {
#ifdef ANDROID_COMPILATION
__android_log_print(ANDROID_LOG_INFO, NAME, "%s", out_string.c_str());
#else
std::cout << out_string << std::endl;
#endif
}
std::string LayoutNameGenerator(int index) {
if(index == STARTUP_FILE_INDEX)
return std::string(NAME) + ".cfg";
return "layout" + std::to_string(index) + ".cfg";
}
#ifdef ANDROID_COMPILATION
ANativeActivity* getAndroidNativeActivity() {
#ifdef SFML_SYSTEM_ANDROID
return sf::getNativeActivity();
#else
return NULL;
#endif
}
#endif
std::string LayoutPathGenerator(int index, bool created_proper_folder) {
bool success = false;
std::string cfg_dir;
#if !(defined(_WIN32) || defined(_WIN64))
const char* env_p = std::getenv("HOME");
if(created_proper_folder && env_p) {
cfg_dir = std::string(env_p) + "/.config/" + std::string(NAME);
success = true;
}
const char* env_p = NULL;
#ifdef ANDROID_COMPILATION
ANativeActivity* native_activity_ptr = getAndroidNativeActivity();
if(native_activity_ptr)
env_p = native_activity_ptr->internalDataPath;
#elif !(defined(_WIN32) || defined(_WIN64))
env_p = std::getenv("HOME");
#endif
if(!success)
cfg_dir = ".config/" + std::string(NAME);
if(!created_proper_folder)
env_p = NULL;
if(env_p != NULL)
cfg_dir = std::string(env_p) + "/";
cfg_dir += ".config/" + std::string(NAME);
if(index == STARTUP_FILE_INDEX)
return cfg_dir + "/";
return cfg_dir + "/presets/";