diff --git a/app_pojavlauncher/build.gradle b/app_pojavlauncher/build.gradle
index a6421dc10..99caaa7bf 100644
--- a/app_pojavlauncher/build.gradle
+++ b/app_pojavlauncher/build.gradle
@@ -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")
diff --git a/app_pojavlauncher/src/main/AndroidManifest.xml b/app_pojavlauncher/src/main/AndroidManifest.xml
index 7cd3261d0..a25fb0d92 100644
--- a/app_pojavlauncher/src/main/AndroidManifest.xml
+++ b/app_pojavlauncher/src/main/AndroidManifest.xml
@@ -20,6 +20,7 @@
+
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.
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java
index d6f168f24..d6dfc112b 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java
@@ -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)) {
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceControlFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceControlFragment.java
index 7002f8452..bc793cba0 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceControlFragment.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceControlFragment.java
@@ -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);
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/TouchControllerUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/TouchControllerUtils.java
new file mode 100644
index 000000000..c999a283e
--- /dev/null
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/TouchControllerUtils.java
@@ -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);
+ }
+ }
+}
diff --git a/app_pojavlauncher/src/main/res/values-zh-rCN/strings.xml b/app_pojavlauncher/src/main/res/values-zh-rCN/strings.xml
index 2bc458563..c422d6ccb 100644
--- a/app_pojavlauncher/src/main/res/values-zh-rCN/strings.xml
+++ b/app_pojavlauncher/src/main/res/values-zh-rCN/strings.xml
@@ -399,4 +399,10 @@
启用实验性的 Compute Shader 扩展
可能有助于解决光影渲染异常。非必要请禁用,可能会导致错误。
OpenGL 报错设置
+
+ TouchController 设置
+ 强制启用 TouchController
+ 启用 TouchController 集成,即使没有找到模组文件。
+ TouchController 震动长度
+ 设置使用 TouchController 时的震动长度。
diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml
index 2104b8d3a..874252e46 100644
--- a/app_pojavlauncher/src/main/res/values/strings.xml
+++ b/app_pojavlauncher/src/main/res/values/strings.xml
@@ -456,4 +456,10 @@
Create Neoforge profile
Select NeoForge version
Sorry, but this version of NeoForge does not have an installer, which is not yet supported.
+
+ TouchController Settings
+ Force enable TouchController
+ Force enable TouchController integration, even if mod file is not found.
+ TouchController vibrate length
+ Set the length of the vibration when using TouchController.
diff --git a/app_pojavlauncher/src/main/res/values/values.xml b/app_pojavlauncher/src/main/res/values/values.xml
index 3220345b6..95eaf3533 100644
--- a/app_pojavlauncher/src/main/res/values/values.xml
+++ b/app_pojavlauncher/src/main/res/values/values.xml
@@ -34,4 +34,6 @@
8
256
+ 10
+ 1000
\ No newline at end of file
diff --git a/app_pojavlauncher/src/main/res/xml/pref_control.xml b/app_pojavlauncher/src/main/res/xml/pref_control.xml
index 0d2778e17..77c02f91c 100644
--- a/app_pojavlauncher/src/main/res/xml/pref_control.xml
+++ b/app_pojavlauncher/src/main/res/xml/pref_control.xml
@@ -164,7 +164,21 @@
-
+
+
+
+
\ No newline at end of file