Skip to content

Commit

Permalink
Feat[gamepad]: add gamepad passthrough
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
isXander committed Jan 10, 2025
1 parent 208b92b commit a50595e
Show file tree
Hide file tree
Showing 20 changed files with 93 additions and 11 deletions.
2 changes: 1 addition & 1 deletion app_pojavlauncher/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'])
}
Binary file added app_pojavlauncher/libs/SDL3-3.1.9.aar
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1687691695196
1736466767190
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1692525087345
1736466767180
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1732218529630
1736466767185
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@
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;
Expand Down Expand Up @@ -66,12 +65,14 @@
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";

Expand All @@ -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());

Expand Down Expand Up @@ -281,31 +289,40 @@ protected void onPause() {
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();
}

@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
sdlActivityComponent.onConfigurationChanged(newConfig);
super.onConfigurationChanged(newConfig);

if(mGyroControl != null) mGyroControl.updateOrientation();
Expand All @@ -330,6 +347,7 @@ protected void onPostResume() {

@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) {
Expand Down Expand Up @@ -421,6 +439,10 @@ public static void toggleMouse(Context ctx) {

@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);
Expand Down Expand Up @@ -570,4 +592,39 @@ public boolean dispatchTrackballEvent(MotionEvent ev) {
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();
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -214,7 +215,7 @@ private void createGamepad(View contextView, InputDevice inputDevice) {
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);
Expand Down Expand Up @@ -252,6 +253,10 @@ public boolean dispatchGenericMotionEvent(MotionEvent event) {

/** 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -190,14 +195,14 @@ public static void sendInput(short[] keycodes, boolean isDown){
}

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;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -84,6 +85,7 @@ public static void loadPreferences(Context ctx) {
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", "");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
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;
Expand Down
4 changes: 3 additions & 1 deletion app_pojavlauncher/src/main/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Binary file modified app_pojavlauncher/src/main/jniLibs/arm64-v8a/libjnidispatch.so
Binary file not shown.
Binary file modified app_pojavlauncher/src/main/jniLibs/armeabi-v7a/libjnidispatch.so
Binary file not shown.
Binary file modified app_pojavlauncher/src/main/jniLibs/x86/libjnidispatch.so
Binary file not shown.
Binary file modified app_pojavlauncher/src/main/jniLibs/x86_64/libjnidispatch.so
Binary file not shown.
2 changes: 2 additions & 0 deletions app_pojavlauncher/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
7 changes: 7 additions & 0 deletions app_pojavlauncher/src/main/res/xml/pref_control.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">

Expand Down

0 comments on commit a50595e

Please sign in to comment.