Merge pull request #42 from TouchController/v3_openjdk

TouchController touch input integration
This commit is contained in:
alexytomi 2025-07-23 01:15:52 +08:00 committed by GitHub
commit 456f50acd6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 195 additions and 7 deletions

View File

@ -228,6 +228,8 @@ dependencies {
// implementation 'net.sourceforge.streamsupport:streamsupport-cfuture:1.7.0'
implementation 'top.fifthlight.touchcontroller:proxy-client-android:0.0.4'
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
implementation project(":MobileGlues")

View File

@ -20,6 +20,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:name=".PojavApplication"

View File

@ -63,6 +63,7 @@ import net.kdt.pojavlaunch.prefs.QuickSettingSideDialog;
import net.kdt.pojavlaunch.services.GameService;
import net.kdt.pojavlaunch.utils.JREUtils;
import net.kdt.pojavlaunch.utils.MCOptionUtils;
import net.kdt.pojavlaunch.utils.TouchControllerUtils;
import net.kdt.pojavlaunch.value.MinecraftAccount;
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
@ -102,8 +103,14 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
minecraftProfile = LauncherProfiles.getCurrentProfile();
MCOptionUtils.load(Tools.getGameDirPath(minecraftProfile).getAbsolutePath());
String gameDirPath = Tools.getGameDirPath(minecraftProfile).getAbsolutePath();
MCOptionUtils.load(gameDirPath);
if (Tools.hasTouchController(new File(gameDirPath)) || LauncherPreferences.PREF_FORCE_ENABLE_TOUCHCONTROLLER) {
TouchControllerUtils.initialize(this);
}
Intent gameServiceIntent = new Intent(this, GameService.class);
// Start the service a bit early

View File

@ -39,6 +39,7 @@ import net.kdt.pojavlaunch.customcontrols.mouse.TouchEventProcessor;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.utils.JREUtils;
import net.kdt.pojavlaunch.utils.MCOptionUtils;
import net.kdt.pojavlaunch.utils.TouchControllerUtils;
import org.lwjgl.glfw.CallbackBridge;
@ -202,6 +203,7 @@ public class MinecraftGLSurface extends View implements GrabListener, DirectGame
CallbackBridge.sendCursorPos( e.getX(i) * LauncherPreferences.PREF_SCALE_FACTOR, e.getY(i) * LauncherPreferences.PREF_SCALE_FACTOR);
return true; //mouse event handled successfully
}
TouchControllerUtils.processTouchEvent(e, this);
if (mIngameProcessor == null || mInGUIProcessor == null) return true;
return mCurrentTouchProcessor.processTouchEvent(e);
}

View File

@ -227,6 +227,27 @@ public final class Tools {
return false;
}
/**
* Search for TouchController mod to automatically enable TouchController mod support.
*
* @param gameDir current game directory
* @return whether TouchController is found
*/
public static boolean hasTouchController(File gameDir) {
File modsDir = new File(gameDir, "mods");
File[] mods = modsDir.listFiles(file -> file.isFile() && file.getName().endsWith(".jar"));
if (mods == null) {
return false;
}
for (File file : mods) {
String name = file.getName().toLowerCase(Locale.ROOT);
if (name.contains("touchcontroller")) {
return true;
}
}
return false;
}
/**
* Initialize OpenGL and do checks to see if the GPU of the device is affected by the render
* distance issue.

View File

@ -70,6 +70,8 @@ public class LauncherPreferences {
public static String PREF_DOWNLOAD_SOURCE = "default";
public static boolean PREF_SKIP_NOTIFICATION_PERMISSION_CHECK = false;
public static boolean PREF_VSYNC_IN_ZINK = true;
public static boolean PREF_FORCE_ENABLE_TOUCHCONTROLLER = false;
public static int PREF_TOUCHCONTROLLER_VIBRATE_LENGTH = 100;
public static void loadPreferences(Context ctx) {
@ -112,6 +114,8 @@ public class LauncherPreferences {
PREF_VERIFY_MANIFEST = DEFAULT_PREF.getBoolean("verifyManifest", true);
PREF_SKIP_NOTIFICATION_PERMISSION_CHECK = DEFAULT_PREF.getBoolean(PREF_KEY_SKIP_NOTIFICATION_CHECK, false);
PREF_VSYNC_IN_ZINK = DEFAULT_PREF.getBoolean("vsync_in_zink", true);
PREF_FORCE_ENABLE_TOUCHCONTROLLER = DEFAULT_PREF.getBoolean("forceEnableTouchController", false);
PREF_TOUCHCONTROLLER_VIBRATE_LENGTH = DEFAULT_PREF.getInt("touchControllerVibrateLength", 100);
String argLwjglLibname = "-Dorg.lwjgl.opengl.libname=";
for (String arg : JREUtils.parseJavaArguments(PREF_CUSTOM_JAVA_ARGS)) {

View File

@ -13,6 +13,7 @@ import net.kdt.pojavlaunch.prefs.LauncherPreferences;
public class LauncherPreferenceControlFragment extends LauncherPreferenceFragment {
private boolean mGyroAvailable = false;
@Override
public void onCreatePreferences(Bundle b, String str) {
// Get values
@ -20,6 +21,7 @@ public class LauncherPreferenceControlFragment extends LauncherPreferenceFragmen
int prefButtonSize = (int) LauncherPreferences.PREF_BUTTONSIZE;
int mouseScale = (int) (LauncherPreferences.PREF_MOUSESCALE * 100);
int gyroSampleRate = LauncherPreferences.PREF_GYRO_SAMPLE_RATE;
int touchControllerVibrateLength = LauncherPreferences.PREF_TOUCHCONTROLLER_VIBRATE_LENGTH;
float mouseSpeed = LauncherPreferences.PREF_MOUSESPEED;
float gyroSpeed = LauncherPreferences.PREF_GYRO_SENSITIVITY;
float joystickDeadzone = LauncherPreferences.PREF_DEADZONE_SCALE;
@ -45,7 +47,7 @@ public class LauncherPreferenceControlFragment extends LauncherPreferenceFragmen
CustomSeekBarPreference seek6 = requirePreference("mousespeed",
CustomSeekBarPreference.class);
seek6.setValue((int)(mouseSpeed *100f));
seek6.setValue((int) (mouseSpeed * 100f));
seek6.setSuffix(" %");
CustomSeekBarPreference deadzoneSeek = requirePreference("gamepad_deadzone_scale",
@ -55,22 +57,29 @@ public class LauncherPreferenceControlFragment extends LauncherPreferenceFragmen
Context context = getContext();
if(context != null) {
if (context != null) {
mGyroAvailable = Tools.deviceSupportsGyro(context);
}
PreferenceCategory gyroCategory = requirePreference("gyroCategory",
PreferenceCategory gyroCategory = requirePreference("gyroCategory",
PreferenceCategory.class);
gyroCategory.setVisible(mGyroAvailable);
CustomSeekBarPreference gyroSensitivitySeek = requirePreference("gyroSensitivity",
CustomSeekBarPreference.class);
gyroSensitivitySeek.setValue((int) (gyroSpeed*100f));
gyroSensitivitySeek.setValue((int) (gyroSpeed * 100f));
gyroSensitivitySeek.setSuffix(" %");
CustomSeekBarPreference gyroSampleRateSeek = requirePreference("gyroSampleRate",
CustomSeekBarPreference.class);
gyroSampleRateSeek.setValue(gyroSampleRate);
gyroSampleRateSeek.setSuffix(" ms");
CustomSeekBarPreference touchControllerVibrateLengthSeek = requirePreference(
"touchControllerVibrateLength",
CustomSeekBarPreference.class);
touchControllerVibrateLengthSeek.setValue(touchControllerVibrateLength);
touchControllerVibrateLengthSeek.setSuffix(" ms");
computeVisibility();
}
@ -80,7 +89,7 @@ public class LauncherPreferenceControlFragment extends LauncherPreferenceFragmen
computeVisibility();
}
private void computeVisibility(){
private void computeVisibility() {
requirePreference("timeLongPressTrigger").setVisible(!LauncherPreferences.PREF_DISABLE_GESTURES);
requirePreference("gyroSensitivity").setVisible(LauncherPreferences.PREF_ENABLE_GYRO);
requirePreference("gyroSampleRate").setVisible(LauncherPreferences.PREF_ENABLE_GYRO);

View File

@ -0,0 +1,114 @@
package net.kdt.pojavlaunch.utils;
import android.content.Context;
import android.os.Vibrator;
import top.fifthlight.touchcontroller.proxy.client.LauncherProxyClient;
import top.fifthlight.touchcontroller.proxy.client.MessageTransport;
import top.fifthlight.touchcontroller.proxy.client.android.transport.UnixSocketTransportKt;
import top.fifthlight.touchcontroller.proxy.message.VibrateMessage;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
public class TouchControllerUtils {
private TouchControllerUtils() {
}
public static LauncherProxyClient proxyClient;
private static final String socketName = "Amethyst";
private static class VibrationHandler implements LauncherProxyClient.VibrationHandler {
private final Vibrator vibrator;
public VibrationHandler(Vibrator vibrator) {
this.vibrator = vibrator;
}
@Override
@SuppressWarnings("DEPRECATION")
public void vibrate(@NonNull VibrateMessage.Kind kind) {
vibrator.vibrate(LauncherPreferences.PREF_TOUCHCONTROLLER_VIBRATE_LENGTH);
}
}
private static final SparseIntArray pointerIdMap = new SparseIntArray();
private static int nextPointerId = 1;
public static void processTouchEvent(MotionEvent motionEvent, View view) {
if (proxyClient == null) {
return;
}
int pointerId;
switch (motionEvent.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
pointerId = nextPointerId++;
pointerIdMap.put(motionEvent.getPointerId(0), pointerId);
proxyClient.addPointer(pointerId, motionEvent.getX(0) / view.getWidth(), motionEvent.getY(0) / view.getHeight());
break;
case MotionEvent.ACTION_POINTER_DOWN:
pointerId = nextPointerId++;
int actionIndex = motionEvent.getActionIndex();
pointerIdMap.put(motionEvent.getPointerId(actionIndex), pointerId);
proxyClient.addPointer(pointerId, motionEvent.getX(actionIndex) / view.getWidth(), motionEvent.getY(actionIndex) / view.getHeight());
break;
case MotionEvent.ACTION_MOVE:
for (int i = 0; i < motionEvent.getPointerCount(); i++) {
pointerId = pointerIdMap.get(motionEvent.getPointerId(i));
if (pointerId == 0) {
Log.d("TouchController", "Move pointerId is 0");
continue;
}
proxyClient.addPointer(pointerId, motionEvent.getX(i) / view.getWidth(), motionEvent.getY(i) / view.getHeight());
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (proxyClient != null) {
proxyClient.clearPointer();
pointerIdMap.clear();
}
break;
case MotionEvent.ACTION_POINTER_UP:
if (proxyClient != null) {
int i = motionEvent.getActionIndex();
pointerId = pointerIdMap.get(motionEvent.getPointerId(i));
if (pointerId == 0) {
Log.d("TouchController", "Pointer up pointerId is 0");
break;
}
pointerIdMap.delete(pointerId);
proxyClient.removePointer(pointerId);
}
break;
}
}
public static void initialize(Context context) {
if (proxyClient != null) {
return;
}
try {
Os.setenv("TOUCH_CONTROLLER_PROXY_SOCKET", socketName, true);
} catch (ErrnoException e) {
Log.w("TouchController", "Failed to set TouchController environment variable", e);
}
MessageTransport transport = UnixSocketTransportKt.UnixSocketTransport(socketName);
proxyClient = new LauncherProxyClient(transport);
proxyClient.run();
Vibrator vibrator = ContextCompat.getSystemService(context, Vibrator.class);
if (vibrator != null) {
LauncherProxyClient.VibrationHandler vibrationHandler = new VibrationHandler(vibrator);
proxyClient.setVibrationHandler(vibrationHandler);
}
}
}

View File

@ -399,4 +399,10 @@
<string name="mg_renderer_title_computeShaderext">启用实验性的 Compute Shader 扩展</string>
<string name="mg_renderer_summary_computeShaderext">可能有助于解决光影渲染异常。非必要请禁用,可能会导致错误。</string>
<string name="mg_renderer_title_errorSetting">OpenGL 报错设置</string>
<string name="preference_category_touchcontroller_settings">TouchController 设置</string>
<string name="preference_force_enable_touchcontroller_title">强制启用 TouchController</string>
<string name="preference_force_enable_touchcontroller_description">启用 TouchController 集成,即使没有找到模组文件。</string>
<string name="preference_touchcontroller_vibrate_length_title">TouchController 震动长度</string>
<string name="preference_touchcontroller_vibrate_length_description">设置使用 TouchController 时的震动长度。</string>
</resources>

View File

@ -456,4 +456,10 @@
<string name="modloader_dl_install_neoforge">Create Neoforge profile</string>
<string name="neoforge_dl_select_version">Select NeoForge version</string>
<string name="neoforge_dl_no_installer">Sorry, but this version of NeoForge does not have an installer, which is not yet supported.</string>
<string name="preference_category_touchcontroller_settings">TouchController Settings</string>
<string name="preference_force_enable_touchcontroller_title">Force enable TouchController</string>
<string name="preference_force_enable_touchcontroller_description">Force enable TouchController integration, even if mod file is not found.</string>
<string name="preference_touchcontroller_vibrate_length_title">TouchController vibrate length</string>
<string name="preference_touchcontroller_vibrate_length_description">Set the length of the vibration when using TouchController.</string>
</resources>

View File

@ -34,4 +34,6 @@
<integer name="memory_seekbar_increment">8</integer>
<integer name="memory_seekbar_min">256</integer>
<integer name="touchcontrller_vibrate_length_min">10</integer>
<integer name="touchcontrller_vibrate_length_max">1000</integer>
</resources>

View File

@ -164,7 +164,21 @@
</PreferenceCategory>
<PreferenceCategory
android:title="@string/preference_category_touchcontroller_settings">
<SwitchPreference
android:key="forceEnableTouchController"
android:title="@string/preference_force_enable_touchcontroller_title"
android:summary="@string/preference_force_enable_touchcontroller_description"/>
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="touchControllerVibrateLength"
android:title="@string/preference_touchcontroller_vibrate_length_title"
android:summary="@string/preference_touchcontroller_vibrate_length_description"
app2:selectable="false"
app2:min="@integer/touchcontrller_vibrate_length_min"
android:max="@integer/touchcontrller_vibrate_length_max"
app2:showSeekBarValue="true"/>
</PreferenceCategory>
</PreferenceScreen>