mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2026-04-19 00:56:57 -04:00
Feat[gamepad]: add gamepad passthrough
- Add "Gamepad passthrough" option to disable Pojav controller emulation and allow games to process controllers directly. - Add SDL3 AAR and add it as a dependency. - Add SDL lifecycle events in main activity - Add support for SDL in the main activity and include it as a dependency in the `Android.mk`. - Update `libjnidispatch.so` files for all arch.
This commit is contained in:
@@ -227,5 +227,5 @@ dependencies {
|
||||
|
||||
// implementation 'net.sourceforge.streamsupport:streamsupport-cfuture:1.7.0'
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||
}
|
||||
|
||||
BIN
app_pojavlauncher/libs/SDL3-3.1.9.aar
Normal file
BIN
app_pojavlauncher/libs/SDL3-3.1.9.aar
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
1687691695196
|
||||
1736466767190
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
1692525087345
|
||||
1736466767180
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
1732218529630
|
||||
1736466767185
|
||||
@@ -24,13 +24,12 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.util.Log;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
@@ -66,12 +65,14 @@ import net.kdt.pojavlaunch.value.MinecraftAccount;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
|
||||
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
|
||||
|
||||
import org.libsdl.app.SDLActivityComponent;
|
||||
import org.libsdl.app.SDLComponentReceiver;
|
||||
import org.lwjgl.glfw.CallbackBridge;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class MainActivity extends BaseActivity implements ControlButtonMenuListener, EditorExitable, ServiceConnection {
|
||||
public class MainActivity extends BaseActivity implements ControlButtonMenuListener, EditorExitable, ServiceConnection, SDLComponentReceiver, View.OnSystemUiVisibilityChangeListener {
|
||||
public static volatile ClipboardManager GLOBAL_CLIPBOARD;
|
||||
public static final String INTENT_MINECRAFT_VERSION = "intent_version";
|
||||
|
||||
@@ -98,9 +99,16 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
|
||||
|
||||
private QuickSettingSideDialog mQuickSettingSideDialog;
|
||||
|
||||
private SDLActivityComponent sdlActivityComponent;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
sdlActivityComponent = new SDLActivityComponent(this);
|
||||
sdlActivityComponent.setLibraries(new String[] { "SDL3" });
|
||||
sdlActivityComponent.onCreate();
|
||||
|
||||
minecraftProfile = LauncherProfiles.getCurrentProfile();
|
||||
MCOptionUtils.load(Tools.getGameDirPath(minecraftProfile).getAbsolutePath());
|
||||
|
||||
@@ -281,24 +289,32 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
|
||||
mQuickSettingSideDialog.cancel();
|
||||
}
|
||||
CallbackBridge.nativeSetWindowAttrib(LwjglGlfwKeycode.GLFW_HOVERED, 0);
|
||||
|
||||
sdlActivityComponent.onPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
sdlActivityComponent.onStart();
|
||||
super.onStart();
|
||||
|
||||
CallbackBridge.nativeSetWindowAttrib(LwjglGlfwKeycode.GLFW_VISIBLE, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
CallbackBridge.nativeSetWindowAttrib(LwjglGlfwKeycode.GLFW_VISIBLE, 0);
|
||||
|
||||
sdlActivityComponent.onStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
sdlActivityComponent.onDestroy();
|
||||
super.onDestroy();
|
||||
|
||||
CallbackBridge.removeGrabListener(touchpad);
|
||||
CallbackBridge.removeGrabListener(minecraftGLView);
|
||||
ContextExecutor.clearActivity();
|
||||
@@ -306,6 +322,7 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
sdlActivityComponent.onConfigurationChanged(newConfig);
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
if(mGyroControl != null) mGyroControl.updateOrientation();
|
||||
@@ -330,6 +347,7 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
sdlActivityComponent.onActivityResult(requestCode, resultCode, data);
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (requestCode == 1 && resultCode == Activity.RESULT_OK) {
|
||||
@@ -421,6 +439,10 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (!sdlActivityComponent.dispatchKeyEvent(event)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(isInEditor) {
|
||||
if(event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
|
||||
if(event.getAction() == KeyEvent.ACTION_DOWN) mControlLayout.askToExit(this);
|
||||
@@ -570,4 +592,39 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
|
||||
return minecraftGLView.dispatchCapturedPointerEvent(ev);
|
||||
else return super.dispatchTrackballEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
sdlActivityComponent.onWindowFocusChanged(hasFocus);
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
sdlActivityComponent.onTrimMemory(level);
|
||||
super.onTrimMemory(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (sdlActivityComponent.onBackPressed()) {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
sdlActivityComponent.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSystemUiVisibilityChange(int visibility) {
|
||||
sdlActivityComponent.onSystemUiVisibilityChange(visibility);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void superOnBackPressed() {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import static net.kdt.pojavlaunch.MainActivity.touchCharInput;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_GAMEPAD_PASSTHRU;
|
||||
import static net.kdt.pojavlaunch.utils.MCOptionUtils.getMcScale;
|
||||
import static org.lwjgl.glfw.CallbackBridge.sendMouseButton;
|
||||
import static org.lwjgl.glfw.CallbackBridge.windowHeight;
|
||||
@@ -214,7 +215,7 @@ public class MinecraftGLSurface extends View implements GrabListener {
|
||||
public boolean dispatchGenericMotionEvent(MotionEvent event) {
|
||||
int mouseCursorIndex = -1;
|
||||
|
||||
if(Gamepad.isGamepadEvent(event)){
|
||||
if(Gamepad.isGamepadEvent(event) && !PREF_GAMEPAD_PASSTHRU){
|
||||
if(mGamepad == null) createGamepad(this, event.getDevice());
|
||||
|
||||
mInputManager.handleMotionEventInput(getContext(), event, mGamepad);
|
||||
@@ -252,6 +253,10 @@ public class MinecraftGLSurface extends View implements GrabListener {
|
||||
|
||||
/** The event for keyboard/ gamepad button inputs */
|
||||
public boolean processKeyEvent(KeyEvent event) {
|
||||
if (PREF_GAMEPAD_PASSTHRU) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Log.i("KeyEvent", event.toString());
|
||||
|
||||
//Filtering useless events by order of probability
|
||||
|
||||
@@ -43,6 +43,7 @@ import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTI
|
||||
import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_WEST;
|
||||
import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.isJoystickEvent;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_DEADZONE_SCALE;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_GAMEPAD_PASSTHRU;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_SCALE_FACTOR;
|
||||
import static net.kdt.pojavlaunch.utils.MCOptionUtils.getMcScale;
|
||||
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
|
||||
@@ -89,6 +90,10 @@ public class Gamepad implements GrabListener, GamepadHandler {
|
||||
private final GamepadDataProvider mMapProvider;
|
||||
|
||||
public Gamepad(View contextView, InputDevice inputDevice, GamepadDataProvider mapProvider, boolean showCursor){
|
||||
if (PREF_GAMEPAD_PASSTHRU) {
|
||||
throw new IllegalStateException("Gamepad should never have been constructed if passthru is on.");
|
||||
}
|
||||
|
||||
Settings.setDeadzoneScale(PREF_DEADZONE_SCALE);
|
||||
|
||||
mScreenChoreographer = Choreographer.getInstance();
|
||||
@@ -190,14 +195,14 @@ public class Gamepad implements GrabListener, GamepadHandler {
|
||||
}
|
||||
|
||||
public static boolean isGamepadEvent(MotionEvent event){
|
||||
return isJoystickEvent(event);
|
||||
return isJoystickEvent(event) && !PREF_GAMEPAD_PASSTHRU;
|
||||
}
|
||||
|
||||
public static boolean isGamepadEvent(KeyEvent event){
|
||||
boolean isGamepad = ((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
|
||||
|| ((event.getDevice() != null) && ((event.getDevice().getSources() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD));
|
||||
|
||||
return isGamepad && GamepadDpad.isDpadEvent(event);
|
||||
return isGamepad && GamepadDpad.isDpadEvent(event) && !PREF_GAMEPAD_PASSTHRU;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,7 @@ public class LauncherPreferences {
|
||||
public static final String PREF_VERSION_REPOS = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json";
|
||||
public static boolean PREF_CHECK_LIBRARY_SHA = true;
|
||||
public static boolean PREF_DISABLE_GESTURES = false;
|
||||
public static boolean PREF_GAMEPAD_PASSTHRU = false;
|
||||
public static boolean PREF_DISABLE_SWAP_HAND = false;
|
||||
public static float PREF_MOUSESPEED = 1f;
|
||||
public static int PREF_RAM_ALLOCATION;
|
||||
@@ -84,6 +85,7 @@ public class LauncherPreferences {
|
||||
PREF_FORCE_ENGLISH = DEFAULT_PREF.getBoolean("force_english", false);
|
||||
PREF_CHECK_LIBRARY_SHA = DEFAULT_PREF.getBoolean("checkLibraries",true);
|
||||
PREF_DISABLE_GESTURES = DEFAULT_PREF.getBoolean("disableGestures",false);
|
||||
PREF_GAMEPAD_PASSTHRU = DEFAULT_PREF.getBoolean("gamepadPassthru",false);
|
||||
PREF_DISABLE_SWAP_HAND = DEFAULT_PREF.getBoolean("disableDoubleTap", false);
|
||||
PREF_RAM_ALLOCATION = DEFAULT_PREF.getInt("allocation", findBestRAMAllocation(ctx));
|
||||
PREF_CUSTOM_JAVA_ARGS = DEFAULT_PREF.getString("javaArgs", "");
|
||||
|
||||
@@ -30,6 +30,8 @@ import net.kdt.pojavlaunch.multirt.MultiRTUtils;
|
||||
import net.kdt.pojavlaunch.multirt.Runtime;
|
||||
import net.kdt.pojavlaunch.plugins.FFmpegPlugin;
|
||||
import net.kdt.pojavlaunch.prefs.*;
|
||||
|
||||
import org.libsdl.app.SDLActivityComponent;
|
||||
import org.lwjgl.glfw.*;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
|
||||
@@ -15,11 +15,13 @@ include $(PREBUILT_SHARED_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := tinywrapper
|
||||
LOCAL_SHARED_LIBRARIES := angle_gles2
|
||||
LOCAL_SHARED_LIBRARIES := angle_gles2 SDL3 SDL3-Headers
|
||||
LOCAL_SRC_FILES := tinywrapper/main.c tinywrapper/string_utils.c
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/tinywrapper
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
$(call import-add-path,/out)
|
||||
$(call import-module,prefab/SDL3)
|
||||
$(call import-module,prefab/bytehook)
|
||||
LOCAL_PATH := $(HERE_PATH)
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -162,6 +162,8 @@
|
||||
<string name="dl_library_sha_fail">Library %s is damaged and will be redownloaded</string>
|
||||
<string name="dl_library_sha_unknown">Library %s can\'t be checked, have to assume it\'s good</string>
|
||||
<string name="dl_library_sha_pass">Library %s is fine and usable</string>
|
||||
<string name="mcl_gamepad_passthru">Gamepad passthrough</string>
|
||||
<string name="mcl_gamepad_passthru_subtitle">Designed for controller mods like Controlify; when enabled, Pojav does no controller to keyboard/mouse emulation and allows the game to process controllers.</string>
|
||||
<string name="mcl_disable_gestures">Disable gestures</string>
|
||||
<string name="mcl_disable_gestures_subtitle">Disables gestures, such as hold to break block, and tap to place a block.</string>
|
||||
<string name="mcl_disable_swap_hand">Disable double tap to swap hands</string>
|
||||
|
||||
@@ -13,6 +13,13 @@
|
||||
<intent android:targetPackage="@string/application_package" android:targetClass="net.kdt.pojavlaunch.CustomControlsActivity" android:action=".CustomControlsActivity"/>
|
||||
</Preference>
|
||||
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:icon="@drawable/ic_menu_custom_controls"
|
||||
android:key="gamepadPassthru"
|
||||
android:summary="@string/mcl_gamepad_passthru_subtitle"
|
||||
android:title="@string/mcl_gamepad_passthru"/>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/preference_category_gestures">
|
||||
|
||||
|
||||
Reference in New Issue
Block a user