From 2e863b0acb87beebfab51431898fae87b88947c6 Mon Sep 17 00:00:00 2001 From: "ASROCKPC\\Admin" Date: Mon, 18 Mar 2024 12:43:47 +0800 Subject: [PATCH 01/18] rename App --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9d13f4be9..2c27d1c54 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -82,8 +82,8 @@ android { buildTypes { debug { applicationIdSuffix ".debug" - resValue "string", "app_label", "Moonlight (Debug)" - resValue "string", "app_label_root", "Moonlight (Root Debug)" + resValue "string", "app_label", "Moonlight-TZJ" + resValue "string", "app_label_root", "Moonlight-TZJ" minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' From 285d628da9a0d87c5f0a5a422f8606ffced7871c Mon Sep 17 00:00:00 2001 From: "ASROCKPC\\Admin" Date: Mon, 18 Mar 2024 13:13:19 +0800 Subject: [PATCH 02/18] Re-enable native multi-touch. --- app/src/main/java/com/limelight/Game.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 42bc0c70e..b2461cfa2 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -2050,11 +2050,11 @@ else if (event.getActionMasked() == MotionEvent.ACTION_UP || event.getActionMask // TODO: Re-enable native touch when have a better solution for handling // cancelled touches from Android gestures and 3 finger taps to activate // the software keyboard. - /*if (!prefConfig.touchscreenTrackpad && trySendTouchEvent(view, event)) { + if (!prefConfig.touchscreenTrackpad && trySendTouchEvent(view, event)) { // If this host supports touch events and absolute touch is enabled, // send it directly as a touch event. return true; - }*/ + } TouchContext context = getTouchContext(actionIndex); if (context == null) { From 1c3472c7dc451f6cd5f72a6d6babb03de502ad02 Mon Sep 17 00:00:00 2001 From: True Zhuanjia Date: Mon, 6 May 2024 19:27:57 +0800 Subject: [PATCH 03/18] Enhanced touch with manipulated pointer coordinates, and long press jitter eimination. --- README.md | 10 + app/build.gradle | 4 +- app/src/main/java/com/limelight/Game.java | 83 ++++- .../input/touch/AbsoluteTouchContext.java | 3 - .../input/touch/NativeTouchHandler.java | 341 ++++++++++++++++++ .../preferences/PreferenceConfiguration.java | 32 ++ app/src/main/res/values-zh-rCN/strings.xml | 28 +- app/src/main/res/values/strings.xml | 25 +- app/src/main/res/xml/preferences.xml | 69 +++- 9 files changed, 570 insertions(+), 25 deletions(-) create mode 100644 app/src/main/java/com/limelight/binding/input/touch/NativeTouchHandler.java diff --git a/README.md b/README.md index 0b1bbe780..fce2f892e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,13 @@ +This is a fork with some manipulation on native multi-touch pointer coordinaties, allows pointer to move faster or slower on specified enhanced touch zone. +Maybe useful for tweaking view rotation sensitivity in some games. + +![image](https://github.com/TrueZhuangJia/moonlight-android-TZJ/assets/78474576/90a4a100-2786-4629-a5dc-89363d059be8) + +And some additional features like flat region to eliminate long press jitter: + +![image](https://github.com/TrueZhuangJia/moonlight-android-TZJ/assets/78474576/c91fb01e-d843-41ef-9ebf-99aafda60ea2) + + # Moonlight Android [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/232a8tadrrn8jv0k/branch/master?svg=true)](https://ci.appveyor.com/project/cgutman/moonlight-android/branch/master) diff --git a/app/build.gradle b/app/build.gradle index 2c27d1c54..076824986 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -82,8 +82,8 @@ android { buildTypes { debug { applicationIdSuffix ".debug" - resValue "string", "app_label", "Moonlight-TZJ" - resValue "string", "app_label_root", "Moonlight-TZJ" + resValue "string", "app_label", "Moonlight-搓屏砖家版" + resValue "string", "app_label_root", "Moonlight-搓屏砖家版" minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index b2461cfa2..4df6f8c38 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -9,6 +9,7 @@ import com.limelight.binding.input.capture.InputCaptureProvider; import com.limelight.binding.input.touch.AbsoluteTouchContext; import com.limelight.binding.input.touch.RelativeTouchContext; +import com.limelight.binding.input.touch.NativeTouchHandler; import com.limelight.binding.input.driver.UsbDriverService; import com.limelight.binding.input.evdev.EvdevListener; import com.limelight.binding.input.touch.TouchContext; @@ -85,6 +86,8 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Iterator; import java.util.Locale; @@ -153,6 +156,8 @@ public class Game extends Activity implements SurfaceHolder.Callback, private WifiManager.WifiLock highPerfWifiLock; private WifiManager.WifiLock lowLatencyWifiLock; + private ArrayList nativeTouchPointers = new ArrayList<>(); + private boolean connectedToUsbDriverService = false; private ServiceConnection usbDriverServiceConnection = new ServiceConnection() { @Override @@ -181,6 +186,7 @@ public void onServiceDisconnected(ComponentName componentName) { public static final String EXTRA_APP_HDR = "HDR"; public static final String EXTRA_SERVER_CERT = "ServerCert"; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -220,6 +226,17 @@ protected void onCreate(Bundle savedInstanceState) { // Read the stream preferences prefConfig = PreferenceConfiguration.readPreferences(this); tombstonePrefs = Game.this.getSharedPreferences("DecoderTombstone", 0); + // Set flat region size for long press jitter elimination. + NativeTouchHandler.INTIAL_ZONE_PIXELS = prefConfig.longPressflatRegionPixels; + NativeTouchHandler.ENABLE_ENHANCED_TOUCH = prefConfig.enableEhancedTouch; + if(prefConfig.enhancedTouchOnWhichSide){ + NativeTouchHandler.ENHANCED_TOUCH_ON_RIGHT = -1; + }else{ + NativeTouchHandler.ENHANCED_TOUCH_ON_RIGHT = 1; + } + NativeTouchHandler.ENHANCED_TOUCH_ZONE_DIVIDER = prefConfig.enhanceTouchZoneDivider * 0.01f; + NativeTouchHandler.POINTER_VELOCITY_FACTOR = prefConfig.pointerVelocityFactor * 0.01f; + NativeTouchHandler.POINTER_FIXED_X_VELOCITY = prefConfig.pointerFixedXVelocity; // Enter landscape unless we're on a square screen setPreferredOrientationForCurrentDisplay(); @@ -445,7 +462,7 @@ public void notifyCrash(Exception e) { // If the user requested frame pacing using a capped FPS, we will need to change our // desired FPS setting here in accordance with the active display refresh rate. int roundedRefreshRate = Math.round(displayRefreshRate); - int chosenFrameRate = prefConfig.fps; + int chosenFrameRate = prefConfig.fps; //将此处chosenFrameRate赋值为5时, 视频刷新率降低到5,但直接观察远端桌面可知,触控刷新率并未下降,窗口仍可流畅拖动。 if (prefConfig.framePacing == PreferenceConfiguration.FRAME_PACING_CAP_FPS) { if (prefConfig.fps >= roundedRefreshRate) { if (prefConfig.fps > roundedRefreshRate + 3) { @@ -467,7 +484,7 @@ public void notifyCrash(Exception e) { StreamConfiguration config = new StreamConfiguration.Builder() .setResolution(prefConfig.width, prefConfig.height) .setLaunchRefreshRate(prefConfig.fps) - .setRefreshRate(chosenFrameRate) + .setRefreshRate(chosenFrameRate) //将此处chosenFrameRate替换为5时, 视频刷新率降低到5,但直接观察远端桌面可知,触控刷新率并未下降,窗口仍可流畅拖动。 .setApp(app) .setBitrate(prefConfig.bitrate) .setEnableSops(prefConfig.enableSops) @@ -1560,9 +1577,14 @@ private byte getLiTouchTypeFromEvent(MotionEvent event) { } } + private float[] getStreamViewRelativeNormalizedXY(View view, MotionEvent event, int pointerIndex) { - float normalizedX = event.getX(pointerIndex); - float normalizedY = event.getY(pointerIndex); + + // Coords are replaced by NativeTouchHandler here. + float targetCoords[] = NativeTouchHandler.selectCoordsForPointer(event, pointerIndex, nativeTouchPointers); + float normalizedX = targetCoords[0]; + float normalizedY = targetCoords[1]; + // For the containing background view, we must subtract the origin // of the StreamView to get video-relative coordinates. @@ -1759,7 +1781,7 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { } private boolean sendTouchEventForPointer(View view, MotionEvent event, byte eventType, int pointerIndex) { - float[] normalizedCoords = getStreamViewRelativeNormalizedXY(view, event, pointerIndex); + float[] normalizedCoords = getStreamViewRelativeNormalizedXY(view, event, pointerIndex); //normalized Coords就是坐标占长或宽的比例,最小0,最大1 float[] normalizedContactArea = getStreamViewNormalizedContactArea(event, pointerIndex); return conn.sendTouchEvent(eventType, event.getPointerId(pointerIndex), normalizedCoords[0], normalizedCoords[1], @@ -1773,10 +1795,11 @@ private boolean trySendTouchEvent(View view, MotionEvent event) { if (eventType < 0) { return false; } - + // Log.d("nativeTouchCoordHandlers", "Length: " + nativeTouchCoordHandlers.size()); if (event.getActionMasked() == MotionEvent.ACTION_MOVE) { // Move events may impact all active pointers for (int i = 0; i < event.getPointerCount(); i++) { + NativeTouchHandler.updatePointerInList(event, i, nativeTouchPointers); if (!sendTouchEventForPointer(view, event, eventType, i)) { return false; } @@ -1790,6 +1813,16 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { MoonBridge.LI_ROT_UNKNOWN) != MoonBridge.LI_ERR_UNSUPPORTED; } else { + switch(event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + nativeTouchPointers.add(new NativeTouchHandler.Pointer(event)); //create a Pointer Instance for new touch pointer and add it to the list. + break; + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_UP: + NativeTouchHandler.safelyRemovePointerFromList(event, nativeTouchPointers); //remove pointer from the list. + break; + } // Up, Down, and Hover events are specific to the action index return sendTouchEventForPointer(view, event, eventType, event.getActionIndex()); } @@ -1797,15 +1830,16 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { // Returns true if the event was consumed // NB: View is only present if called from a view callback - private boolean handleMotionEvent(View view, MotionEvent event) { + private boolean handleMotionEvent(View view, MotionEvent event) { //handleMotionEvent, mark mark // Pass through mouse/touch/joystick input if we're not grabbing + if (!grabbedInput) { return false; } int eventSource = event.getSource(); int deviceSources = event.getDevice() != null ? event.getDevice().getSources() : 0; - if ((eventSource & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { + if ((eventSource & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { //手柄所属条件 if (controllerHandler.handleMotionEvent(event)) { return true; } @@ -1817,9 +1851,9 @@ else if ((eventSource & InputDevice.SOURCE_CLASS_POINTER) != 0 || (eventSource & InputDevice.SOURCE_CLASS_POSITION) != 0 || eventSource == InputDevice.SOURCE_MOUSE_RELATIVE) { - // This case is for mice and non-finger touch devices + // This case is for mice and non-finger touch devices, 非手指触控功能所属判断条件 if (eventSource == InputDevice.SOURCE_MOUSE || - (eventSource & InputDevice.SOURCE_CLASS_POSITION) != 0 || // SOURCE_TOUCHPAD + (eventSource & InputDevice.SOURCE_CLASS_POSITION) != 0 || // SOURCE_TOUCHPAD虚拟手柄 eventSource == InputDevice.SOURCE_MOUSE_RELATIVE || (event.getPointerCount() >= 1 && (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE || @@ -2006,8 +2040,18 @@ else if (event.getActionMasked() == MotionEvent.ACTION_UP || event.getActionMask lastButtonState = buttonState; } // This case is for fingers - else + else //abs touch 和 屏幕虚拟手柄所属的判断条件 { + // TODO: Re-enable native touch when have a better solution for handling + // cancelled touches from Android gestures and 3 finger taps to activate + // the software keyboard. + // 调整一下native touch passthrough的代码顺序 + if (!prefConfig.touchscreenTrackpad && trySendTouchEvent(view, event)) { + // If this host supports touch events and absolute touch is enabled, + // send it directly as a touch event. + return true; + } + if (virtualController != null && (virtualController.getControllerMode() == VirtualController.ControllerMode.MoveButtons || virtualController.getControllerMode() == VirtualController.ControllerMode.ResizeButtons)) { @@ -2047,14 +2091,16 @@ else if (event.getActionMasked() == MotionEvent.ACTION_UP || event.getActionMask return true; } + // TODO: Re-enable native touch when have a better solution for handling // cancelled touches from Android gestures and 3 finger taps to activate // the software keyboard. + /* if (!prefConfig.touchscreenTrackpad && trySendTouchEvent(view, event)) { // If this host supports touch events and absolute touch is enabled, // send it directly as a touch event. return true; - } + }*/ TouchContext context = getTouchContext(actionIndex); if (context == null) { @@ -2213,17 +2259,24 @@ public boolean onGenericMotion(View view, MotionEvent event) { @SuppressLint("ClickableViewAccessibility") @Override - public boolean onTouch(View view, MotionEvent event) { + public boolean onTouch(View view, MotionEvent event) { //onTouch mark mark + // Log.d("onTouchDebug","===== onTouch(View view, MotionEvent event ==========)"); + + + // 注释此段if将导致系统按显示刷新率调用onTouch()函数, 显示60Hz时,调用频率也降到60Hz。 实测发现该条件下效果反而更好, 高触控事件发送频率在60fps下对降低延迟并无帮助 + // Native Touch Passthrough的onTouch调用方式似乎仅与此处代码有关。 另一处的调用requestUnbufferedDispatch也有提到与touch相关的语句, 不能确定其实际效果 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (event.getAction() == MotionEvent.ACTION_DOWN) { // Tell the OS not to buffer input events for us // // NB: This is still needed even when we call the newer requestUnbufferedDispatch()! - view.requestUnbufferedDispatch(event); + if(!prefConfig.syncTouchEventWithDisplay) { + view.requestUnbufferedDispatch(event); + } } } - return handleMotionEvent(view, event); + return handleMotionEvent(view, event); //Y700平板上, onTouch的调用频率为120Hz } @Override diff --git a/app/src/main/java/com/limelight/binding/input/touch/AbsoluteTouchContext.java b/app/src/main/java/com/limelight/binding/input/touch/AbsoluteTouchContext.java index d5fb4708b..7c2e8a281 100644 --- a/app/src/main/java/com/limelight/binding/input/touch/AbsoluteTouchContext.java +++ b/app/src/main/java/com/limelight/binding/input/touch/AbsoluteTouchContext.java @@ -3,7 +3,6 @@ import android.os.Handler; import android.os.Looper; import android.view.View; - import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.input.MouseButtonPacket; @@ -195,13 +194,11 @@ public boolean touchMoveEvent(int eventX, int eventY, long eventTime) if (cancelled) { return true; } - if (actionIndex == 0) { if (distanceExceeds(eventX - lastTouchDownX, eventY - lastTouchDownY, LONG_PRESS_DISTANCE_THRESHOLD)) { // Moved too far since touch down. Cancel the long press timer. cancelLongPressTimer(); } - // Ignore motion within the deadzone period after touch down if (confirmedTap || distanceExceeds(eventX - lastTouchDownX, eventY - lastTouchDownY, TOUCH_DOWN_DEAD_ZONE_DISTANCE_THRESHOLD)) { tapConfirmed(); diff --git a/app/src/main/java/com/limelight/binding/input/touch/NativeTouchHandler.java b/app/src/main/java/com/limelight/binding/input/touch/NativeTouchHandler.java new file mode 100644 index 000000000..d3474b60e --- /dev/null +++ b/app/src/main/java/com/limelight/binding/input/touch/NativeTouchHandler.java @@ -0,0 +1,341 @@ +package com.limelight.binding.input.touch; + +import android.view.MotionEvent; +import android.util.Log; +import android.content.res.Resources; +import android.util.DisplayMetrics; + +import java.util.ArrayList; +import java.util.Iterator; + +class ScreenUtils { + public static float getScreenWidth() { + DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics(); + return displayMetrics.widthPixels; + } + + public static float getScreenHeight() { + DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics(); + return displayMetrics.heightPixels; + } +} + + +/** + * Pointer oriented class + * + * + * to store additional pointer info updated from Android MotionEvent object + * (stored in NativeTouchHandler.Pointer instance). + * Provides some methods to manipulate pointer coordinates (enhanced touch) before sending to Sunshine server, + */ +public class NativeTouchHandler { + /** + * Defines a (2*INTIAL_ZONE_PIXELS)^2 square flat region for long press jitter elimination. + * Config read from prefConfig in Game class + */ + public static float INTIAL_ZONE_PIXELS = 0f; + + /** + * Set true to send relative(manipulated) coords to Sunshine server. + * Config read from prefConfig in Game class + */ + public static boolean ENABLE_ENHANCED_TOUCH = true; + + /** + * 1 means enhanced-touch zone on the right side, -1 on the left side. + * Config read from prefConfig in Game class + */ + public static int ENHANCED_TOUCH_ON_RIGHT = 1; + + /** + * Defines where to divide native-touch & enchanced-touch zones, + * < 0.5f means divide from a point on the left, >0.5f means right. + * Config read from prefConfig in Game class + */ + public static float ENHANCED_TOUCH_ZONE_DIVIDER = 0.5f; + + /** + * Factor to scale pointer velocity within enhanced touch zone, + * Config read from prefConfig in Game class + */ + public static float POINTER_VELOCITY_FACTOR = 1.0f; + + /** + * Fixed horizontal velocity (in pixels) within enhanced touch zone + * Config read from prefConfig in Game class + */ + public static float POINTER_FIXED_X_VELOCITY = 8f; + + /** + * Object to store, update info & manipulate coordinates for each pointer. + * An ArrayList of NativeTouchHandler.Pointer instances is created in Game Class for all active pointers. + */ + public static class Pointer{ + /** + * poinerId, not pointerIndex. + * Use pointerId because it's consistent during the whole pointer lifecycle. + */ + private int pointerId; + + /** + * Use MotionEvent.PointerCoords from Android SDK to store coordinates. + */ + private MotionEvent.PointerCoords initialCoords = new MotionEvent.PointerCoords(); //First contact coords of a pointer. + private MotionEvent.PointerCoords latestCoords = new MotionEvent.PointerCoords(); //Latest coords of a pointer updated from MotionEvent provided by Android System. + private MotionEvent.PointerCoords previousCoords = new MotionEvent.PointerCoords(); // previous Coords of a pointer. will be updated in updatePointerCoords(). + private MotionEvent.PointerCoords latestRelativeCoords = new MotionEvent.PointerCoords(); // Coords to replace native ones from Android MotionEvents, for manipulating touch control. + private MotionEvent.PointerCoords previousRelativeCoords = new MotionEvent.PointerCoords(); // Coords to replace native ones from Android MotionEvents, for manipulating touch control. + + /** + * DeltaX & DeltaY between to 2 onTouch() callbacks. + */ + private float pointerVelocity[]; + + /** + * Flipped to true when pointer moves out of (2*INTIAL_ZONE_PIXELS)^2 square flat region. + */ + private boolean pointerLeftInitialZone = false; + + /** + * Constructor for NativeTouchHandler.Pointer. + * Pointer class instantiated in ACTION_DOWN, ACTION_POINTER_DOWN Condition. + */ + public Pointer(MotionEvent event) { + int pointerIndex = event.getActionIndex(); + switch(event.getActionMasked()){ + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + this.pointerId = event.getPointerId(pointerIndex); // get pointerId + event.getPointerCoords(pointerIndex, this.initialCoords);// Fill in initial coords. + event.getPointerCoords(pointerIndex, this.latestCoords);// Fill in latest coords. + //if(POINTER_VELOCITY_FACTOR != 1.0f){ + this.latestRelativeCoords.x = this.latestCoords.x; + this.latestRelativeCoords.y = this.latestCoords.y; + //} + break; + default: Log.d("error", "NativeTouchCoordHandler.Pointer must be instantiated in ACTION_DOWN & ACTION_POINTER_DOWN condition"); + } + } + public int getPointerId(){ + return this.pointerId; + } + + /** + * Update native coordinates, relative coordinates & velocity for Pointer instance + */ + private void updatePointerCoords(MotionEvent event, int pointerIndex){ + this.previousCoords.x = this.latestCoords.x; // assign x, y coords to this.previousCoords only. Other attributes can be ignored. + this.previousCoords.y = this.latestCoords.y; + event.getPointerCoords(pointerIndex, this.latestCoords); // update latestCoords from MotionEvent. + // float deltaX = this.latestCoords.x - this.previousCoords.x; + // float deltaY = this.latestCoords.y - this.previousCoords.y; + + if(ENABLE_ENHANCED_TOUCH) { + this.pointerVelocity = new float[]{this.latestCoords.x - this.previousCoords.x, this.latestCoords.y - this.previousCoords.y}; + // Log.d("Velocity","" + this.pointerVelocity[0] + " " + this.pointerVelocity[1] ); + // XY速率同比例缩放,Pointer向量方向不变 + if (POINTER_FIXED_X_VELOCITY == 0f) { + this.updateRelativeCoordsAverageXYScale(); + } + // 固定X速率模式,该模式下仍可用POINTER_VELOCITY_FACTOR调整Y的速率 + else { + this.updateRelativeCoordsFixedXVelocity(); + } + } + + if(INTIAL_ZONE_PIXELS > 0f){ + this.flattenLongPressJitter(); + } + // Log.d("INTIAL_ZONE_PIXELS", ""+INTIAL_ZONE_PIXELS); + } + + /** + * Update relative coordinates with velocity scaled by POINTER_VELOCITY_FACTOR + */ + private void updateRelativeCoordsAverageXYScale(){ + this.previousRelativeCoords.x = this.latestRelativeCoords.x; + this.previousRelativeCoords.y = this.latestRelativeCoords.y; + this.latestRelativeCoords.x = this.previousRelativeCoords.x + this.pointerVelocity[0] * POINTER_VELOCITY_FACTOR; + this.latestRelativeCoords.y = this.previousRelativeCoords.y + this.pointerVelocity[1] * POINTER_VELOCITY_FACTOR; + } + + /** + * Update relative coordinates with fixed X velocity + */ + private void updateRelativeCoordsFixedXVelocity(){ + this.previousRelativeCoords.x = this.latestRelativeCoords.x; + this.previousRelativeCoords.y = this.latestRelativeCoords.y; + this.latestRelativeCoords.x = this.previousRelativeCoords.x + Math.signum(pointerVelocity[0]) * POINTER_FIXED_X_VELOCITY; + this.latestRelativeCoords.y = this.previousRelativeCoords.y + this.pointerVelocity[1] * POINTER_VELOCITY_FACTOR; + } + + /** + * Judge whether this pointer leaves (2*INTIAL_ZONE_PIXELS)^2 square flat region + */ + public boolean doesPointerLeaveInitialZone() { + if (!this.pointerLeftInitialZone) { + // Log.d("DeltaXY to Initial Coords", "DeltaX "+deltaX+" DeltaY "+deltaY); + float deltaX = this.latestCoords.x - this.initialCoords.x; + float deltaY = this.latestCoords.y - this.initialCoords.y; + /* + if(ENABLE_ENHANCED_TOUCH){ + deltaX = (this.latestRelativeCoords.x - this.initialCoords.x); + deltaY = (this.latestRelativeCoords.y - this.initialCoords.y); + }else{ + deltaX = (this.latestCoords.x - this.initialCoords.x); + deltaY = (this.latestCoords.y - this.initialCoords.y); + }*/ + + // Note: Flat Region is scaled by POINTER_VELOCITY_FACTOR + // if (Math.abs(deltaX) > INTIAL_ZONE_PIXELS * POINTER_VELOCITY_FACTOR || Math.abs(deltaY) > INTIAL_ZONE_PIXELS * POINTER_VELOCITY_FACTOR) { + if (Math.abs(deltaX) > INTIAL_ZONE_PIXELS || Math.abs(deltaY) > INTIAL_ZONE_PIXELS) { + this.pointerLeftInitialZone = true; //Flips pointerLeftInitialZone to true when pointer moves out of flat region. + return this.pointerLeftInitialZone; + } + } + return this.pointerLeftInitialZone; + } + + /** + * Resets latest coords (both native & relative) to initial coords if pointer doesn't leave flat region. + */ + private void flattenLongPressJitter(){ + this.doesPointerLeaveInitialZone(); + // Log.d("INTIAL_ZONE_PIXELS", ""+INTIAL_ZONE_PIXELS); + if(!this.pointerLeftInitialZone){ + this.latestCoords.x = this.initialCoords.x; + this.latestCoords.y = this.initialCoords.y; + this.latestRelativeCoords.x = this.initialCoords.x; + this.latestRelativeCoords.y = this.initialCoords.y; + // Log.d("pointerLeftInitialZone", ""+pointerLeftInitialZone); + } + } + + public float getInitialX(){ + return this.initialCoords.x; + } + + public float getPointerNormalizedInitialX(){ + return this.initialCoords.x / ScreenUtils.getScreenWidth(); + } + + public float getInitialY(){ + return this.initialCoords.y; + } + + public float getPointerNormalizedInitialY(){ + return this.initialCoords.y / ScreenUtils.getScreenHeight(); + } + + public float getLatestX(){ + return this.latestCoords.x; + } + + + public float getLatestY(){ + return this.latestCoords.y; + } + public float getLatestRelativeX(){ + return this.latestRelativeCoords.x; + } + + public float getLatestRelativeY(){ + return this.latestRelativeCoords.y; + } + + + public float getPointerNormalizedLatestX(){ + return this.latestCoords.x / ScreenUtils.getScreenWidth(); + } + + public float getPointerNormalizedLatestY(){ + return this.latestCoords.y / ScreenUtils.getScreenHeight(); + } + + public void printPointerInitialCoords(){ + Log.d("Initial Coords","Pointer " + this.pointerId + " Coords: X " + this.getInitialX() + " Y " +this.getInitialY()); + } + public void printPointerLatestCoords(){ + Log.d("Latest Coords","Pointer " + this.pointerId + " Coords: X " + this.getLatestX() + " Y " +this.getLatestY()); + } + public void printPointerCoordSnapshot(){ + Log.d("Pointer " + this.pointerId, " InitialCoords:" + "[" + this.getInitialX() + ", " + this.getInitialY() + "]" + " LatestCoords:" + "[" + this.getLatestX() + ", " + this.getLatestY() + "]"); + } + + + } + + /** + * Judge whether pointer's coords should be manipulated based on its initial coords (first contact location) + * Only Supports horizontal split (left and right) for now. + */ + private static boolean isEnhancedTouchZone (float[] pointerIntialCoords) + { + // float[] normalizedCoords = new float[] {pointerIntialCoords[0]/ScreenUtils.getScreenWidth(), pointerIntialCoords[1]/ScreenUtils.getScreenHeight()}; + float normalizedX = pointerIntialCoords[0]/ScreenUtils.getScreenWidth(); + return normalizedX * ENHANCED_TOUCH_ON_RIGHT > ENHANCED_TOUCH_ZONE_DIVIDER * ENHANCED_TOUCH_ON_RIGHT; + } + + + /** + * The Game class defines an ArrayList for all instances all active pointers. + * While iterating pointer info in Game class with pointerIndex in ACTION_MOVE condition, + * this method is called to access additional pointer info from the list by finding a pointerId match, + * and decides whether the pointer's coords should be manipulated. + */ + public static float[] selectCoordsForPointer(MotionEvent event, int pointerIndex, ArrayList nativeTouchPointers){ + float selectedX = 0f; + float selectedY = 0f; + for (NativeTouchHandler.Pointer pointer : nativeTouchPointers) { + if (event.getPointerId(pointerIndex) == pointer.getPointerId()) { + if(ENABLE_ENHANCED_TOUCH) { + //to judge whether pointer located on enhanced touch zone by its initial coords. + if (isEnhancedTouchZone(new float[] {pointer.getInitialX(), pointer.getInitialY()})) { + selectedX = pointer.getLatestRelativeX(); + selectedY = pointer.getLatestRelativeY(); + } + else{ + selectedX = pointer.getLatestX(); + selectedY = pointer.getLatestY(); + } + } + else{ + selectedX = pointer.getLatestX(); + selectedY = pointer.getLatestY(); + } + break; + } + } + return new float[] {selectedX, selectedY}; + } + + /** + * Safely remove Pointer instance from a List in ACTION_POINTER_UP or ACTION_UP condition + */ + public static void safelyRemovePointerFromList(MotionEvent event, ArrayList nativeTouchPointers){ + Iterator iterator = nativeTouchPointers.iterator(); //safely remove pointer handler by iterator. + while (iterator.hasNext()){ + NativeTouchHandler.Pointer pointer = iterator.next(); + if (event.getPointerId(event.getActionIndex()) == pointer.getPointerId()) { + iterator.remove(); // immediately break when we get a pointerId match + break; + } + } + } + + /** + * Update 1 specific Pointer instance in a List in ACTION_MOVE. + */ + public static void updatePointerInList(MotionEvent event,int pointerIndex, ArrayList nativeTouchPointers) { + for (NativeTouchHandler.Pointer pointer : nativeTouchPointers) { + if (pointer.getPointerId() == event.getPointerId(pointerIndex)) { + pointer.updatePointerCoords(event, pointerIndex); + // handler.doesPointerLeaveInitialZone(); + // Log.d("NativeTouchCoordHandler", "Pointer Left Initial Zone: " + handler.doesPointerLeaveInitialZone()); + // pointer.printPointerCoordSnapshot(); + break; // immediately break when we get a pointerId match (this method update 1 pointer in the list) + } + } + } +} diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java index e0ba76e51..2d7c8717d 100644 --- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java +++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java @@ -30,6 +30,9 @@ public enum AnalogStickForScrolling { static final String FPS_PREF_STRING = "list_fps"; static final String BITRATE_PREF_STRING = "seekbar_bitrate_kbps"; private static final String BITRATE_PREF_OLD_STRING = "seekbar_bitrate"; + static final String LONG_PRESS_FLAT_REGION_PIXELS_PREF_STRING = "seekbar_flat_region_pixels"; + static final String SYNC_TOUCH_EVENT_WITH_DISPLAY_PREF_STRING = "checkbox_sync_touch_event_with_display"; + private static final String STRETCH_PREF_STRING = "checkbox_stretch_video"; private static final String SOPS_PREF_STRING = "checkbox_enable_sops"; private static final String DISABLE_TOASTS_PREF_STRING = "checkbox_disable_warnings"; @@ -61,6 +64,14 @@ public enum AnalogStickForScrolling { private static final String LATENCY_TOAST_PREF_STRING = "checkbox_enable_post_stream_toast"; private static final String FRAME_PACING_PREF_STRING = "frame_pacing"; private static final String ABSOLUTE_MOUSE_MODE_PREF_STRING = "checkbox_absolute_mouse_mode"; + + private static final String ENABLE_ENHANCED_TOUCH_PREF_STRING = "checkbox_enable_enhanced_touch"; + private static final String ENHANCED_TOUCH_ON_RIGHT_PREF_STRING = "checkbox_enhanced_touch_on_which_side"; + private static final String ENHANCED_TOUCH_ZONE_DIVIDER_PREF_STRING = "enhanced_touch_zone_divider"; + private static final String POINTER_VELOCITY_FACTOR_PREF_STRING = "pointer_velocity_factor"; + private static final String POINTER_FIXED_X_VELOCITY_PREF_STRING = "fixed_x_velocity"; + + private static final String ENABLE_AUDIO_FX_PREF_STRING = "checkbox_enable_audiofx"; private static final String REDUCE_REFRESH_RATE_PREF_STRING = "checkbox_reduce_refresh_rate"; private static final String FULL_RANGE_PREF_STRING = "checkbox_full_range"; @@ -122,6 +133,17 @@ public enum AnalogStickForScrolling { public int width, height, fps; public int bitrate; + public int longPressflatRegionPixels; //Assigned to NativeTouchHandler.INTIAL_ZONE_PIXELS + public boolean syncTouchEventWithDisplay; // if true, view.requestUnbufferedDispatch(event) will be disabled + public boolean enableEhancedTouch; //Assigned to NativeTouchHandler.ENABLE_ENHANCED_TOUCH + public boolean enhancedTouchOnWhichSide; //Assigned to NativeTouchHandler.ENHANCED_TOUCH_ON_RIGHT + public int enhanceTouchZoneDivider; //Assigned to NativeTouchHandler.ENHANCED_TOUCH_ZONE_DIVIDER + public float pointerVelocityFactor; //Assigned to NativeTouchHandler.POINTER_VELOCITY_FACTOR + public float pointerFixedXVelocity; //Assigned to NativeTouchHandler.POINTER_FIXED_X_VELOCITY + + + + public FormatOption videoFormat; public int deadzonePercentage; public int oscOpacity; @@ -545,6 +567,16 @@ else if (str.equals("4K60")) { config.bitrate = getDefaultBitrate(context); } + config.longPressflatRegionPixels = prefs.getInt(LONG_PRESS_FLAT_REGION_PIXELS_PREF_STRING, 0); + config.syncTouchEventWithDisplay = prefs.getBoolean(SYNC_TOUCH_EVENT_WITH_DISPLAY_PREF_STRING, false); + // Enhance touch settings + config.enableEhancedTouch = prefs.getBoolean(ENABLE_ENHANCED_TOUCH_PREF_STRING, false); + config.enhancedTouchOnWhichSide = prefs.getBoolean(ENHANCED_TOUCH_ON_RIGHT_PREF_STRING, true); + config.enhanceTouchZoneDivider = prefs.getInt(ENHANCED_TOUCH_ZONE_DIVIDER_PREF_STRING,50); + config.pointerVelocityFactor = prefs.getInt(POINTER_VELOCITY_FACTOR_PREF_STRING,100); + config.pointerFixedXVelocity = prefs.getInt(POINTER_FIXED_X_VELOCITY_PREF_STRING,0); + + String audioConfig = prefs.getString(AUDIO_CONFIG_PREF_STRING, DEFAULT_AUDIO_CONFIG); if (audioConfig.equals("71")) { config.audioConfiguration = MoonBridge.AUDIO_CONFIGURATION_71_SURROUND; diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c03cd575f..c37f6070f 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -123,7 +123,14 @@ 为家庭影院系统启用5.1或7.1环绕声 输入设置 将触控屏作为触控板使用 - 如果启用,则将触控屏作为触控板使用。 如果禁止,则触控屏直接控制鼠标光标。 + 如果启用,则将触控屏作为触控板使用。如果禁用,则启用多点触控模式 + + 长按抖动消除区域 + 像素值越高,抖动消除区域越大。抖动消除区域内,应用只发送触点的初始坐标 + 像素 + 触控事件与显示刷新同步 + 打开后触控事件上报率与显示刷新率同步,比如显示为60Hz,那么触控与之同步。不一定有用,习惯哪个用哪个。Moonlight原版相当于禁用该项。 + 自动检测手柄 禁用此项所有手柄将视为一个手柄 用设备震动模拟游戏震动效果 @@ -138,6 +145,25 @@ 长按开始键将手柄切换为鼠标模式 启用前进后退鼠标键 在一些支持不佳的设备上启用此项可能会使其右键失效 + + 增强型触控设置 + 打开增强型触控 + 打开增强型触控 + 反转增强型触控区 + 反转增强型触控区 (默认在右边) + 增强型触控分区位置 + 增强型触控与原生触控的分区位置,小于50%代表在屏幕左边的某个位置分区,大于50%代表分割线在右边 + 增强型触控与原生触控的分区位置,小于50%代表在屏幕左边的某个位置分区,大于50%代表分割线在右边 + % + 触点移速比例 + 设置增强型触控区内的触点移速比例。100% = 禁用,小于100%为缩小,大于100%为放大 + 增强型触控区内的触点移速比例 + % + 设置增强型触控区内触点的水平方向固定移速 + 设置增强型触控区内触点的水平方向固定移速. 0像素 = 禁用,大于0将禁用水平方向的移速比例,改为固定移速 + 触点水平方向固定移速 + 像素 + 反转技能键 为手柄和虚拟手柄调转A/B和X/Y技能键 屏幕控制按钮设置 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 82cf3222e..c80a7e018 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -196,12 +196,35 @@ Input Settings Use the touchscreen as a trackpad - If enabled, the touchscreen acts like a trackpad. If disabled, the touchscreen directly controls the mouse cursor. + If enabled, the touchscreen acts like a trackpad. If disabled, native multi-point touch will be enabled. + Flat region for long press jitter elimination + Increase for larger long-press flat region, within which the app sticks with initial contact coordinates. + pixels + Synchronize touch event with display refresh + If enabled, touch event will be synchronized with display refresh rate, like 60Hz. Remote desktop mouse mode This can make mouse acceleration behave more naturally for remote desktop usage, but it is incompatible with many games. Enable back and forward mouse buttons Enabling this option may break right clicking on some buggy devices + Enhanced Touch Settings + Enable enhanced touch + Enable enhanced touch + Reverse enhanced touch zone + Reverse enhanced touch zone to the left (default: on the right side of screen) + Enhanced touch zone divider + Defines where to divide native-touch and enhanced-touch zones, less than 50% means divide from a point on the left, more than 50% means right + Less than 50% means divide from a point on the left, more than 50% means right + % + Pointer velocity factor + Set pointer velocity factor for enhanced touch zone. Set 100% to disable + Set pointer velocity factor for enhanced touch zone. Set 100% to disable + % + Set fixed X (horizontal) velocity + Set fixed X (horizontal) velocity. Set 0 to disable fixed x velocity mode. Larger than 0 means disable horizontal velocity factor to use fixed velocity instead. + Set fixed X (horizontal) velocity in pixels. Set 0 to disable fixed x velocity. + pixels + On-screen Controls Settings Show on-screen controls Show virtual controller overlay on touchscreen diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index d68c8c577..44c6d5e72 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -35,7 +35,7 @@ android:entries="@array/video_frame_pacing_names" android:entryValues="@array/video_frame_pacing_values" android:summary="@string/summary_frame_pacing" - android:defaultValue="latency" /> + android:defaultValue="balanced" /> + android:defaultValue="false" /> + + + + + + + + + - Date: Mon, 6 May 2024 22:29:41 +0800 Subject: [PATCH 04/18] Add multi-finger tap to toggle Android on-screen keyboard --- app/src/main/java/com/limelight/Game.java | 15 +++++++++++++++ .../preferences/PreferenceConfiguration.java | 13 +++++++++++-- app/src/main/res/values-zh-rCN/strings.xml | 5 +++++ app/src/main/res/values/strings.xml | 6 ++++++ app/src/main/res/xml/preferences.xml | 18 ++++++++++++++++++ 5 files changed, 55 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 4df6f8c38..accc10958 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -1817,6 +1817,7 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: nativeTouchPointers.add(new NativeTouchHandler.Pointer(event)); //create a Pointer Instance for new touch pointer and add it to the list. + multiFingerTapToggleKeyboardNativeTouch(event); break; case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_UP: @@ -1828,6 +1829,20 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { } } + private void multiFingerTapToggleKeyboardNativeTouch (MotionEvent event) { + if (event.getPointerCount() == prefConfig.nativeTouchFingersToToggleKeyboard) { + // number of fingers to tap is defined by prefConfig.nativeTouchFingersToToggleKeyboard + + // Cancel the first and second touches to avoid + // erroneous events + for (TouchContext aTouchContext : touchContextMap) { + aTouchContext.cancelTouch(); + } + toggleKeyboard(); + + } + } + // Returns true if the event was consumed // NB: View is only present if called from a view callback private boolean handleMotionEvent(View view, MotionEvent event) { //handleMotionEvent, mark mark diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java index 2d7c8717d..f04460849 100644 --- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java +++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java @@ -32,6 +32,9 @@ public enum AnalogStickForScrolling { private static final String BITRATE_PREF_OLD_STRING = "seekbar_bitrate"; static final String LONG_PRESS_FLAT_REGION_PIXELS_PREF_STRING = "seekbar_flat_region_pixels"; static final String SYNC_TOUCH_EVENT_WITH_DISPLAY_PREF_STRING = "checkbox_sync_touch_event_with_display"; + static final String ENABLE_KEYBOARD_TOGGLE_IN_NATIVE_TOUCH = "checkbox_enable_keyboard_toggle_in_native_touch"; + static final String NATIVE_TOUCH_FINGERS_TO_TOGGLE_KEYBOARD_PREF_STRING = "seekbar_keyboard_toggle_fingers_native_touch"; + private static final String STRETCH_PREF_STRING = "checkbox_stretch_video"; private static final String SOPS_PREF_STRING = "checkbox_enable_sops"; @@ -140,7 +143,7 @@ public enum AnalogStickForScrolling { public int enhanceTouchZoneDivider; //Assigned to NativeTouchHandler.ENHANCED_TOUCH_ZONE_DIVIDER public float pointerVelocityFactor; //Assigned to NativeTouchHandler.POINTER_VELOCITY_FACTOR public float pointerFixedXVelocity; //Assigned to NativeTouchHandler.POINTER_FIXED_X_VELOCITY - + public int nativeTouchFingersToToggleKeyboard; // Number of fingers to tap to toggle local on-screen keyboard in native touch mode. @@ -569,6 +572,13 @@ else if (str.equals("4K60")) { config.longPressflatRegionPixels = prefs.getInt(LONG_PRESS_FLAT_REGION_PIXELS_PREF_STRING, 0); config.syncTouchEventWithDisplay = prefs.getBoolean(SYNC_TOUCH_EVENT_WITH_DISPLAY_PREF_STRING, false); + if(prefs.getBoolean(ENABLE_KEYBOARD_TOGGLE_IN_NATIVE_TOUCH, true)) { + config.nativeTouchFingersToToggleKeyboard = prefs.getInt(NATIVE_TOUCH_FINGERS_TO_TOGGLE_KEYBOARD_PREF_STRING, 3); + } + else{ + config.nativeTouchFingersToToggleKeyboard = -1; + } + // Enhance touch settings config.enableEhancedTouch = prefs.getBoolean(ENABLE_ENHANCED_TOUCH_PREF_STRING, false); config.enhancedTouchOnWhichSide = prefs.getBoolean(ENHANCED_TOUCH_ON_RIGHT_PREF_STRING, true); @@ -576,7 +586,6 @@ else if (str.equals("4K60")) { config.pointerVelocityFactor = prefs.getInt(POINTER_VELOCITY_FACTOR_PREF_STRING,100); config.pointerFixedXVelocity = prefs.getInt(POINTER_FIXED_X_VELOCITY_PREF_STRING,0); - String audioConfig = prefs.getString(AUDIO_CONFIG_PREF_STRING, DEFAULT_AUDIO_CONFIG); if (audioConfig.equals("71")) { config.audioConfiguration = MoonBridge.AUDIO_CONFIGURATION_71_SURROUND; diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c37f6070f..62edf4ed2 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -130,6 +130,11 @@ 像素 触控事件与显示刷新同步 打开后触控事件上报率与显示刷新率同步,比如显示为60Hz,那么触控与之同步。不一定有用,习惯哪个用哪个。Moonlight原版相当于禁用该项。 + 多点触控模式下打开本地键盘切换 + 多点触控模式下打开本地键盘切换 + 轻敲切换本地键盘的手指数量 + 轻敲手指数量 + 自动检测手柄 禁用此项所有手柄将视为一个手柄 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c80a7e018..83956fbb0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -202,6 +202,12 @@ pixels Synchronize touch event with display refresh If enabled, touch event will be synchronized with display refresh rate, like 60Hz. + Enable keyboard toggle in multi-touch mode + Enable keyboard toggle in multi-touch mode + Number of fingers to tap to toggle local on-screen keyboard in multi-touch mode + Fingers to tap + + Remote desktop mouse mode This can make mouse acceleration behave more naturally for remote desktop usage, but it is incompatible with many games. Enable back and forward mouse buttons diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 44c6d5e72..f01e3db95 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -151,6 +151,24 @@ android:title="@string/title_checkbox_sync_touch_event_with_display" android:summary="@string/summary_checkbox_sync_touch_event_with_display" android:defaultValue="false" /> + + Date: Tue, 7 May 2024 20:59:02 +0800 Subject: [PATCH 05/18] Improve multi-finger tap in native touch (invoking keyboard toggle), now keyboard toggle behaves just like trackmode --- app/src/main/java/com/limelight/Game.java | 30 +++++++++++-------- .../preferences/PreferenceConfiguration.java | 14 ++++----- app/src/main/res/values-zh-rCN/strings.xml | 16 +++++----- app/src/main/res/values/strings.xml | 23 +++++++------- app/src/main/res/xml/preferences.xml | 10 +++---- 5 files changed, 51 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index accc10958..6f5b45dab 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -99,7 +99,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, // Only 2 touches are supported private final TouchContext[] touchContextMap = new TouchContext[2]; - private long threeFingerDownTime = 0; + private long multiFingerDownTime = 0; private static final int REFERENCE_HORIZ_RES = 1280; private static final int REFERENCE_VERT_RES = 720; @@ -110,7 +110,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, private static final int STYLUS_UP_DEAD_ZONE_DELAY = 150; private static final int STYLUS_UP_DEAD_ZONE_RADIUS = 50; - private static final int THREE_FINGER_TAP_THRESHOLD = 300; + private static final int MULTI_FINGER_TAP_THRESHOLD = 300; private ControllerHandler controllerHandler; private KeyboardTranslator keyboardTranslator; @@ -1817,10 +1817,14 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: nativeTouchPointers.add(new NativeTouchHandler.Pointer(event)); //create a Pointer Instance for new touch pointer and add it to the list. - multiFingerTapToggleKeyboardNativeTouch(event); + multiFingerTapChecker(event); break; + case MotionEvent.ACTION_UP: // all fingers up + // toggle keyboard when all fingers lift up, just like how it works in trackpad mode. + if(event.getEventTime() - multiFingerDownTime < MULTI_FINGER_TAP_THRESHOLD) { + toggleKeyboard(); + } case MotionEvent.ACTION_POINTER_UP: - case MotionEvent.ACTION_UP: NativeTouchHandler.safelyRemovePointerFromList(event, nativeTouchPointers); //remove pointer from the list. break; } @@ -1829,17 +1833,16 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { } } - private void multiFingerTapToggleKeyboardNativeTouch (MotionEvent event) { + private void multiFingerTapChecker (MotionEvent event) { if (event.getPointerCount() == prefConfig.nativeTouchFingersToToggleKeyboard) { - // number of fingers to tap is defined by prefConfig.nativeTouchFingersToToggleKeyboard + // number of fingers to tap is defined by prefConfig.nativeTouchFingersToToggleKeyboard, configurable from 3 to 10, and -1(disabled) in menu. // Cancel the first and second touches to avoid // erroneous events - for (TouchContext aTouchContext : touchContextMap) { - aTouchContext.cancelTouch(); - } - toggleKeyboard(); - + // for (TouchContext aTouchContext : touchContextMap) { + // aTouchContext.cancelTouch(); + // } + multiFingerDownTime = event.getEventTime(); } } @@ -2095,7 +2098,7 @@ else if (event.getActionMasked() == MotionEvent.ACTION_UP || event.getActionMask if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN && event.getPointerCount() == 3) { // Three fingers down - threeFingerDownTime = event.getEventTime(); + multiFingerDownTime = event.getEventTime(); // Cancel the first and second touches to avoid // erroneous events @@ -2136,8 +2139,9 @@ else if (event.getActionMasked() == MotionEvent.ACTION_UP || event.getActionMask if (event.getPointerCount() == 1 && (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || (event.getFlags() & MotionEvent.FLAG_CANCELED) == 0)) { // All fingers up - if (event.getEventTime() - threeFingerDownTime < THREE_FINGER_TAP_THRESHOLD) { + if (event.getEventTime() - multiFingerDownTime < MULTI_FINGER_TAP_THRESHOLD) { // This is a 3 finger tap to bring up the keyboard + // multiFingerDownTime, previously threeFingerDowntime, is also used in native-touch for keyboard toggle. toggleKeyboard(); return true; } diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java index f04460849..98c9bac64 100644 --- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java +++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java @@ -570,20 +570,20 @@ else if (str.equals("4K60")) { config.bitrate = getDefaultBitrate(context); } - config.longPressflatRegionPixels = prefs.getInt(LONG_PRESS_FLAT_REGION_PIXELS_PREF_STRING, 0); - config.syncTouchEventWithDisplay = prefs.getBoolean(SYNC_TOUCH_EVENT_WITH_DISPLAY_PREF_STRING, false); + config.longPressflatRegionPixels = prefs.getInt(LONG_PRESS_FLAT_REGION_PIXELS_PREF_STRING, 0); // define a flat region to suppress coordinates jitter. This is a simulation of iOS behavior since it only send 1 touch event during long press, which feels better in some cases. + config.syncTouchEventWithDisplay = prefs.getBoolean(SYNC_TOUCH_EVENT_WITH_DISPLAY_PREF_STRING, false); // set true to disable "requestUnbufferedDispatch", feels better in some cases. if(prefs.getBoolean(ENABLE_KEYBOARD_TOGGLE_IN_NATIVE_TOUCH, true)) { - config.nativeTouchFingersToToggleKeyboard = prefs.getInt(NATIVE_TOUCH_FINGERS_TO_TOGGLE_KEYBOARD_PREF_STRING, 3); + config.nativeTouchFingersToToggleKeyboard = prefs.getInt(NATIVE_TOUCH_FINGERS_TO_TOGGLE_KEYBOARD_PREF_STRING, 3); // least fingers of tap to toggle local keyboard, configurable from 3 to 10 in menu. } else{ - config.nativeTouchFingersToToggleKeyboard = -1; + config.nativeTouchFingersToToggleKeyboard = -1; // completely disable keyboard toggle in multi-point touch } // Enhance touch settings config.enableEhancedTouch = prefs.getBoolean(ENABLE_ENHANCED_TOUCH_PREF_STRING, false); - config.enhancedTouchOnWhichSide = prefs.getBoolean(ENHANCED_TOUCH_ON_RIGHT_PREF_STRING, true); - config.enhanceTouchZoneDivider = prefs.getInt(ENHANCED_TOUCH_ZONE_DIVIDER_PREF_STRING,50); - config.pointerVelocityFactor = prefs.getInt(POINTER_VELOCITY_FACTOR_PREF_STRING,100); + config.enhancedTouchOnWhichSide = prefs.getBoolean(ENHANCED_TOUCH_ON_RIGHT_PREF_STRING, true); // by default, enhanced touch zone is on the right side. + config.enhanceTouchZoneDivider = prefs.getInt(ENHANCED_TOUCH_ZONE_DIVIDER_PREF_STRING,50); // decides where to divide native touch zone & enhance touch zone by a vertical line. + config.pointerVelocityFactor = prefs.getInt(POINTER_VELOCITY_FACTOR_PREF_STRING,100); // set pointer velocity faster or slower within enhance touch zone, useful in some games for tweaking view rotation sensitivity. config.pointerFixedXVelocity = prefs.getInt(POINTER_FIXED_X_VELOCITY_PREF_STRING,0); String audioConfig = prefs.getString(AUDIO_CONFIG_PREF_STRING, DEFAULT_AUDIO_CONFIG); diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 62edf4ed2..7255d210c 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -125,15 +125,17 @@ 将触控屏作为触控板使用 如果启用,则将触控屏作为触控板使用。如果禁用,则启用多点触控模式 - 长按抖动消除区域 + 多点触控长按抖动消除区域 像素值越高,抖动消除区域越大。抖动消除区域内,应用只发送触点的初始坐标 像素 + 触控事件与显示刷新同步 打开后触控事件上报率与显示刷新率同步,比如显示为60Hz,那么触控与之同步。不一定有用,习惯哪个用哪个。Moonlight原版相当于禁用该项。 + 多点触控模式下打开本地键盘切换 - 多点触控模式下打开本地键盘切换 - 轻敲切换本地键盘的手指数量 - 轻敲手指数量 + \t + 轻敲手指数量 + 轻敲切换本地键盘的最少手指数量。\n仅在多点触控模式生效,触摸板模式3指即可切换本地键盘(不受此配置影响)。 自动检测手柄 @@ -151,11 +153,11 @@ 启用前进后退鼠标键 在一些支持不佳的设备上启用此项可能会使其右键失效 - 增强型触控设置 + 增强型多点触控 打开增强型触控 - 打开增强型触控 + \t 反转增强型触控区 - 反转增强型触控区 (默认在右边) + 反转增强型触控区 (增强区默认在右边) 增强型触控分区位置 增强型触控与原生触控的分区位置,小于50%代表在屏幕左边的某个位置分区,大于50%代表分割线在右边 增强型触控与原生触控的分区位置,小于50%代表在屏幕左边的某个位置分区,大于50%代表分割线在右边 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 83956fbb0..3938b07ae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -196,16 +196,19 @@ Input Settings Use the touchscreen as a trackpad - If enabled, the touchscreen acts like a trackpad. If disabled, native multi-point touch will be enabled. - Flat region for long press jitter elimination - Increase for larger long-press flat region, within which the app sticks with initial contact coordinates. - pixels + If enabled, the touchscreen acts like a trackpad. If disabled, multi-point touch will be enabled. + Synchronize touch event with display refresh If enabled, touch event will be synchronized with display refresh rate, like 60Hz. - Enable keyboard toggle in multi-touch mode - Enable keyboard toggle in multi-touch mode - Number of fingers to tap to toggle local on-screen keyboard in multi-touch mode - Fingers to tap + + Flat region for long press jitter elimination in multi-point touch mode + Increase for larger long-press flat region, within which the app sends initial contact coordinates to server. + pixels + + Enable keyboard toggle in multi-point touch mode + \t + Fingers to tap + Least number of fingers to tap to toggle local on-screen keyboard in multi-point touch mode. \nIn trackpad mode, you always only need to tap 3 or more fingers to toggle local keyboard. Remote desktop mouse mode @@ -213,9 +216,9 @@ Enable back and forward mouse buttons Enabling this option may break right clicking on some buggy devices - Enhanced Touch Settings + Enhanced Multi-Point Touch Enable enhanced touch - Enable enhanced touch + \t Reverse enhanced touch zone Reverse enhanced touch zone to the left (default: on the right side of screen) Enhanced touch zone divider diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index f01e3db95..a9e427e90 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -134,6 +134,11 @@ android:title="@string/title_checkbox_touchscreen_trackpad" android:summary="@string/summary_checkbox_touchscreen_trackpad" android:defaultValue="false" /> + - Date: Wed, 8 May 2024 20:18:28 +0800 Subject: [PATCH 06/18] Cancel multiFingerTapChecker in ACTION_UP --- .gitignore | 3 ++- app/src/main/java/com/limelight/Game.java | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index e0ab95a51..a1cb0faa2 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,5 @@ build/ app/.externalNativeBuild/ # NDK stuff -.cxx/ \ No newline at end of file +.cxx/ +app/src/main/jni/moonlight-core/Build.txt diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 6f5b45dab..27aef6702 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -1814,7 +1814,9 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { } else { switch(event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_DOWN: // first finger down. + nativeTouchPointers.add(new NativeTouchHandler.Pointer(event)); //create a Pointer Instance for new touch pointer and add it to the list. + break; case MotionEvent.ACTION_POINTER_DOWN: nativeTouchPointers.add(new NativeTouchHandler.Pointer(event)); //create a Pointer Instance for new touch pointer and add it to the list. multiFingerTapChecker(event); From d40223fc5404e75d70ff304de33d299d35a1d89a Mon Sep 17 00:00:00 2001 From: True Zhuanjia Date: Wed, 8 May 2024 22:05:24 +0800 Subject: [PATCH 07/18] Resolve conflicts --- app/src/main/java/com/limelight/Game.java | 96 ++++++----------------- 1 file changed, 24 insertions(+), 72 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 27aef6702..655c312af 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -201,14 +201,12 @@ protected void onCreate(Bundle savedInstanceState) { // If we're going to use immersive mode, we want to have // the entire screen - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { - getWindow().getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE | - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); - } + getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); // Listen for UI visibility events getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(this); @@ -577,39 +575,19 @@ private void setPreferredOrientationForCurrentDisplay() { } if (desiredOrientation == Configuration.ORIENTATION_LANDSCAPE) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE); - } - else { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); - } + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE); } else if (desiredOrientation == Configuration.ORIENTATION_PORTRAIT) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT); - } - else { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); - } + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT); } else { // If we don't have a reason to lock to portrait or landscape, allow any orientation - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER); - } - else { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); - } + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER); } } else { // For regular displays, we always request landscape - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE); - } - else { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); - } + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE); } } @@ -937,7 +915,7 @@ else if (!isRefreshRateGoodMatch(candidate.getRefreshRate())) { displayRefreshRate = bestMode.getRefreshRate(); } // On L, we can at least tell the OS that we want a refresh rate - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + else { float bestRefreshRate = display.getRefreshRate(); for (float candidate : display.getSupportedRefreshRates()) { LimeLog.info("Examining refresh rate: "+candidate); @@ -961,19 +939,12 @@ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Apply the refresh rate change getWindow().setAttributes(windowLayoutParams); } - else { - // Otherwise, the active display refresh rate is just - // whatever is currently in use. - displayRefreshRate = display.getRefreshRate(); - } - // From 4.4 to 5.1 we can't ask for a 4K display mode, so we'll + // Until Marshmallow, we can't ask for a 4K display mode, so we'll // need to hint the OS to provide one. boolean aspectRatioMatch = false; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && - Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { - // On KitKat and later (where we can use the whole screen via immersive mode), we'll - // calculate whether we need to scale by aspect ratio or not. If not, we'll use + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + // We'll calculate whether we need to scale by aspect ratio. If not, we'll use // setFixedSize so we can handle 4K properly. The only known devices that have // >= 4K screens have exactly 4K screens, so we'll be able to hit this good path // on these devices. On Marshmallow, we can start changing to 4K manually but no @@ -1028,8 +999,8 @@ public void run() { Game.this.getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE); } - // Use immersive mode on 4.4+ or standard low profile on previous builds - else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + else { + // Use immersive mode Game.this.getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | @@ -1038,11 +1009,6 @@ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); } - else { - Game.this.getWindow().getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_FULLSCREEN | - View.SYSTEM_UI_FLAG_LOW_PROFILE); - } } }; @@ -2280,23 +2246,16 @@ public boolean onGenericMotion(View view, MotionEvent event) { @SuppressLint("ClickableViewAccessibility") @Override - public boolean onTouch(View view, MotionEvent event) { //onTouch mark mark - // Log.d("onTouchDebug","===== onTouch(View view, MotionEvent event ==========)"); - - - // 注释此段if将导致系统按显示刷新率调用onTouch()函数, 显示60Hz时,调用频率也降到60Hz。 实测发现该条件下效果反而更好, 高触控事件发送频率在60fps下对降低延迟并无帮助 - // Native Touch Passthrough的onTouch调用方式似乎仅与此处代码有关。 另一处的调用requestUnbufferedDispatch也有提到与touch相关的语句, 不能确定其实际效果 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - // Tell the OS not to buffer input events for us - // - // NB: This is still needed even when we call the newer requestUnbufferedDispatch()! - if(!prefConfig.syncTouchEventWithDisplay) { - view.requestUnbufferedDispatch(event); - } + public boolean onTouch(View view, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + // Tell the OS not to buffer input events for us + // + // NB: This is still needed even when we call the newer requestUnbufferedDispatch()! + // Add a configuration to allow view.requestUnbufferedDispatch to be disabled. + if(!prefConfig.syncTouchEventWithDisplay) { + view.requestUnbufferedDispatch(event); } } - return handleMotionEvent(view, event); //Y700平板上, onTouch的调用频率为120Hz } @@ -2741,14 +2700,7 @@ public void onSystemUiVisibilityChange(int visibility) { if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { hideSystemUi(2000); } - // This flag is only set on 4.4+ - else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && - (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) { - hideSystemUi(2000); - } - // This flag is only set before 4.4+ - else if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT && - (visibility & View.SYSTEM_UI_FLAG_LOW_PROFILE) == 0) { + else if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) { hideSystemUi(2000); } } From d065e6ebdf3d258ffff39cde1659240d9fc41e7a Mon Sep 17 00:00:00 2001 From: TrueZhuanJia <78474576+TrueZhuangJia@users.noreply.github.com> Date: Thu, 9 May 2024 12:49:09 +0800 Subject: [PATCH 08/18] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index fce2f892e..8fd7b4214 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,10 @@ And some additional features like flat region to eliminate long press jitter: ![image](https://github.com/TrueZhuangJia/moonlight-android-TZJ/assets/78474576/c91fb01e-d843-41ef-9ebf-99aafda60ea2) +Configurable local keyboard toggle: + +![image](https://github.com/TrueZhuangJia/moonlight-android-Enhanced-MultiTouch/assets/78474576/a0edaf21-a174-448e-832c-da2d171cefea) + # Moonlight Android From 1ca6d02f7846036ebf3c98fa6f8a27d4d8a9f6ce Mon Sep 17 00:00:00 2001 From: TrueZhuanJia <78474576+TrueZhuangJia@users.noreply.github.com> Date: Thu, 9 May 2024 14:02:27 +0800 Subject: [PATCH 09/18] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8fd7b4214..65eec443c 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,14 @@ Maybe useful for tweaking view rotation sensitivity in some games. ![image](https://github.com/TrueZhuangJia/moonlight-android-TZJ/assets/78474576/90a4a100-2786-4629-a5dc-89363d059be8) +Configurable local keyboard toggle: + +![image](https://github.com/TrueZhuangJia/moonlight-android-Enhanced-MultiTouch/assets/78474576/a0edaf21-a174-448e-832c-da2d171cefea) + And some additional features like flat region to eliminate long press jitter: ![image](https://github.com/TrueZhuangJia/moonlight-android-TZJ/assets/78474576/c91fb01e-d843-41ef-9ebf-99aafda60ea2) -Configurable local keyboard toggle: - -![image](https://github.com/TrueZhuangJia/moonlight-android-Enhanced-MultiTouch/assets/78474576/a0edaf21-a174-448e-832c-da2d171cefea) # Moonlight Android From af0aea43b61c1215557e3067b6e4eeb7f941edee Mon Sep 17 00:00:00 2001 From: True Zhuanjia Date: Sat, 11 May 2024 13:49:15 +0800 Subject: [PATCH 10/18] Refactor NativeTouchHandler to NativeTouchContext --- app/src/main/java/com/limelight/Game.java | 32 +++++++++---------- ...chHandler.java => NativeTouchContext.java} | 20 ++++++------ .../preferences/PreferenceConfiguration.java | 12 +++---- 3 files changed, 31 insertions(+), 33 deletions(-) rename app/src/main/java/com/limelight/binding/input/touch/{NativeTouchHandler.java => NativeTouchContext.java} (96%) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 655c312af..be4aac2fe 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -8,8 +8,8 @@ import com.limelight.binding.input.capture.InputCaptureManager; import com.limelight.binding.input.capture.InputCaptureProvider; import com.limelight.binding.input.touch.AbsoluteTouchContext; +import com.limelight.binding.input.touch.NativeTouchContext; import com.limelight.binding.input.touch.RelativeTouchContext; -import com.limelight.binding.input.touch.NativeTouchHandler; import com.limelight.binding.input.driver.UsbDriverService; import com.limelight.binding.input.evdev.EvdevListener; import com.limelight.binding.input.touch.TouchContext; @@ -24,7 +24,6 @@ import com.limelight.nvstream.http.ComputerDetails; import com.limelight.nvstream.http.NvApp; import com.limelight.nvstream.http.NvHTTP; -import com.limelight.nvstream.input.ControllerPacket; import com.limelight.nvstream.input.KeyboardPacket; import com.limelight.nvstream.input.MouseButtonPacket; import com.limelight.nvstream.jni.MoonBridge; @@ -87,7 +86,6 @@ import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; -import java.util.Iterator; import java.util.Locale; @@ -156,7 +154,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, private WifiManager.WifiLock highPerfWifiLock; private WifiManager.WifiLock lowLatencyWifiLock; - private ArrayList nativeTouchPointers = new ArrayList<>(); + private ArrayList nativeTouchPointers = new ArrayList<>(); private boolean connectedToUsbDriverService = false; private ServiceConnection usbDriverServiceConnection = new ServiceConnection() { @@ -225,16 +223,16 @@ protected void onCreate(Bundle savedInstanceState) { prefConfig = PreferenceConfiguration.readPreferences(this); tombstonePrefs = Game.this.getSharedPreferences("DecoderTombstone", 0); // Set flat region size for long press jitter elimination. - NativeTouchHandler.INTIAL_ZONE_PIXELS = prefConfig.longPressflatRegionPixels; - NativeTouchHandler.ENABLE_ENHANCED_TOUCH = prefConfig.enableEhancedTouch; + NativeTouchContext.INTIAL_ZONE_PIXELS = prefConfig.longPressflatRegionPixels; + NativeTouchContext.ENABLE_ENHANCED_TOUCH = prefConfig.enableEhancedTouch; if(prefConfig.enhancedTouchOnWhichSide){ - NativeTouchHandler.ENHANCED_TOUCH_ON_RIGHT = -1; + NativeTouchContext.ENHANCED_TOUCH_ON_RIGHT = -1; }else{ - NativeTouchHandler.ENHANCED_TOUCH_ON_RIGHT = 1; + NativeTouchContext.ENHANCED_TOUCH_ON_RIGHT = 1; } - NativeTouchHandler.ENHANCED_TOUCH_ZONE_DIVIDER = prefConfig.enhanceTouchZoneDivider * 0.01f; - NativeTouchHandler.POINTER_VELOCITY_FACTOR = prefConfig.pointerVelocityFactor * 0.01f; - NativeTouchHandler.POINTER_FIXED_X_VELOCITY = prefConfig.pointerFixedXVelocity; + NativeTouchContext.ENHANCED_TOUCH_ZONE_DIVIDER = prefConfig.enhanceTouchZoneDivider * 0.01f; + NativeTouchContext.POINTER_VELOCITY_FACTOR = prefConfig.pointerVelocityFactor * 0.01f; + NativeTouchContext.POINTER_FIXED_X_VELOCITY = prefConfig.pointerFixedXVelocity; // Enter landscape unless we're on a square screen setPreferredOrientationForCurrentDisplay(); @@ -1546,8 +1544,8 @@ private byte getLiTouchTypeFromEvent(MotionEvent event) { private float[] getStreamViewRelativeNormalizedXY(View view, MotionEvent event, int pointerIndex) { - // Coords are replaced by NativeTouchHandler here. - float targetCoords[] = NativeTouchHandler.selectCoordsForPointer(event, pointerIndex, nativeTouchPointers); + // Coords are replaced by NativeTouchContext here. + float targetCoords[] = NativeTouchContext.selectCoordsForPointer(event, pointerIndex, nativeTouchPointers); float normalizedX = targetCoords[0]; float normalizedY = targetCoords[1]; @@ -1765,7 +1763,7 @@ private boolean trySendTouchEvent(View view, MotionEvent event) { if (event.getActionMasked() == MotionEvent.ACTION_MOVE) { // Move events may impact all active pointers for (int i = 0; i < event.getPointerCount(); i++) { - NativeTouchHandler.updatePointerInList(event, i, nativeTouchPointers); + NativeTouchContext.updatePointerInList(event, i, nativeTouchPointers); if (!sendTouchEventForPointer(view, event, eventType, i)) { return false; } @@ -1781,10 +1779,10 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { else { switch(event.getActionMasked()) { case MotionEvent.ACTION_DOWN: // first finger down. - nativeTouchPointers.add(new NativeTouchHandler.Pointer(event)); //create a Pointer Instance for new touch pointer and add it to the list. + nativeTouchPointers.add(new NativeTouchContext.Pointer(event)); //create a Pointer Instance for new touch pointer and add it to the list. break; case MotionEvent.ACTION_POINTER_DOWN: - nativeTouchPointers.add(new NativeTouchHandler.Pointer(event)); //create a Pointer Instance for new touch pointer and add it to the list. + nativeTouchPointers.add(new NativeTouchContext.Pointer(event)); //create a Pointer Instance for new touch pointer and add it to the list. multiFingerTapChecker(event); break; case MotionEvent.ACTION_UP: // all fingers up @@ -1793,7 +1791,7 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { toggleKeyboard(); } case MotionEvent.ACTION_POINTER_UP: - NativeTouchHandler.safelyRemovePointerFromList(event, nativeTouchPointers); //remove pointer from the list. + NativeTouchContext.safelyRemovePointerFromList(event, nativeTouchPointers); //remove pointer from the list. break; } // Up, Down, and Hover events are specific to the action index diff --git a/app/src/main/java/com/limelight/binding/input/touch/NativeTouchHandler.java b/app/src/main/java/com/limelight/binding/input/touch/NativeTouchContext.java similarity index 96% rename from app/src/main/java/com/limelight/binding/input/touch/NativeTouchHandler.java rename to app/src/main/java/com/limelight/binding/input/touch/NativeTouchContext.java index d3474b60e..a27ae35f4 100644 --- a/app/src/main/java/com/limelight/binding/input/touch/NativeTouchHandler.java +++ b/app/src/main/java/com/limelight/binding/input/touch/NativeTouchContext.java @@ -26,10 +26,10 @@ public static float getScreenHeight() { * * * to store additional pointer info updated from Android MotionEvent object - * (stored in NativeTouchHandler.Pointer instance). + * (stored in NativeTouchContext.Pointer instance). * Provides some methods to manipulate pointer coordinates (enhanced touch) before sending to Sunshine server, */ -public class NativeTouchHandler { +public class NativeTouchContext { /** * Defines a (2*INTIAL_ZONE_PIXELS)^2 square flat region for long press jitter elimination. * Config read from prefConfig in Game class @@ -69,7 +69,7 @@ public class NativeTouchHandler { /** * Object to store, update info & manipulate coordinates for each pointer. - * An ArrayList of NativeTouchHandler.Pointer instances is created in Game Class for all active pointers. + * An ArrayList of NativeTouchContext.Pointer instances is created in Game Class for all active pointers. */ public static class Pointer{ /** @@ -98,7 +98,7 @@ public static class Pointer{ private boolean pointerLeftInitialZone = false; /** - * Constructor for NativeTouchHandler.Pointer. + * Constructor for NativeTouchContext.Pointer. * Pointer class instantiated in ACTION_DOWN, ACTION_POINTER_DOWN Condition. */ public Pointer(MotionEvent event) { @@ -284,10 +284,10 @@ private static boolean isEnhancedTouchZone (float[] pointerIntialCoords) * this method is called to access additional pointer info from the list by finding a pointerId match, * and decides whether the pointer's coords should be manipulated. */ - public static float[] selectCoordsForPointer(MotionEvent event, int pointerIndex, ArrayList nativeTouchPointers){ + public static float[] selectCoordsForPointer(MotionEvent event, int pointerIndex, ArrayList nativeTouchPointers){ float selectedX = 0f; float selectedY = 0f; - for (NativeTouchHandler.Pointer pointer : nativeTouchPointers) { + for (NativeTouchContext.Pointer pointer : nativeTouchPointers) { if (event.getPointerId(pointerIndex) == pointer.getPointerId()) { if(ENABLE_ENHANCED_TOUCH) { //to judge whether pointer located on enhanced touch zone by its initial coords. @@ -313,10 +313,10 @@ public static float[] selectCoordsForPointer(MotionEvent event, int pointerIndex /** * Safely remove Pointer instance from a List in ACTION_POINTER_UP or ACTION_UP condition */ - public static void safelyRemovePointerFromList(MotionEvent event, ArrayList nativeTouchPointers){ + public static void safelyRemovePointerFromList(MotionEvent event, ArrayList nativeTouchPointers){ Iterator iterator = nativeTouchPointers.iterator(); //safely remove pointer handler by iterator. while (iterator.hasNext()){ - NativeTouchHandler.Pointer pointer = iterator.next(); + NativeTouchContext.Pointer pointer = iterator.next(); if (event.getPointerId(event.getActionIndex()) == pointer.getPointerId()) { iterator.remove(); // immediately break when we get a pointerId match break; @@ -327,8 +327,8 @@ public static void safelyRemovePointerFromList(MotionEvent event, ArrayList nativeTouchPointers) { - for (NativeTouchHandler.Pointer pointer : nativeTouchPointers) { + public static void updatePointerInList(MotionEvent event,int pointerIndex, ArrayList nativeTouchPointers) { + for (NativeTouchContext.Pointer pointer : nativeTouchPointers) { if (pointer.getPointerId() == event.getPointerId(pointerIndex)) { pointer.updatePointerCoords(event, pointerIndex); // handler.doesPointerLeaveInitialZone(); diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java index 98c9bac64..1103f9b0c 100644 --- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java +++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java @@ -136,13 +136,13 @@ public enum AnalogStickForScrolling { public int width, height, fps; public int bitrate; - public int longPressflatRegionPixels; //Assigned to NativeTouchHandler.INTIAL_ZONE_PIXELS + public int longPressflatRegionPixels; //Assigned to NativeTouchContext.INTIAL_ZONE_PIXELS public boolean syncTouchEventWithDisplay; // if true, view.requestUnbufferedDispatch(event) will be disabled - public boolean enableEhancedTouch; //Assigned to NativeTouchHandler.ENABLE_ENHANCED_TOUCH - public boolean enhancedTouchOnWhichSide; //Assigned to NativeTouchHandler.ENHANCED_TOUCH_ON_RIGHT - public int enhanceTouchZoneDivider; //Assigned to NativeTouchHandler.ENHANCED_TOUCH_ZONE_DIVIDER - public float pointerVelocityFactor; //Assigned to NativeTouchHandler.POINTER_VELOCITY_FACTOR - public float pointerFixedXVelocity; //Assigned to NativeTouchHandler.POINTER_FIXED_X_VELOCITY + public boolean enableEhancedTouch; //Assigned to NativeTouchContext.ENABLE_ENHANCED_TOUCH + public boolean enhancedTouchOnWhichSide; //Assigned to NativeTouchContext.ENHANCED_TOUCH_ON_RIGHT + public int enhanceTouchZoneDivider; //Assigned to NativeTouchContext.ENHANCED_TOUCH_ZONE_DIVIDER + public float pointerVelocityFactor; //Assigned to NativeTouchContext.POINTER_VELOCITY_FACTOR + public float pointerFixedXVelocity; //Assigned to NativeTouchContext.POINTER_FIXED_X_VELOCITY public int nativeTouchFingersToToggleKeyboard; // Number of fingers to tap to toggle local on-screen keyboard in native touch mode. From 8ce5b1f9cd0b05fb131ffba55cc6b95764a65142 Mon Sep 17 00:00:00 2001 From: True Zhuanjia Date: Sat, 11 May 2024 19:41:25 +0800 Subject: [PATCH 11/18] Use Map instead of ArrayList to store NativeTouchContext.Pointer instances --- app/src/main/java/com/limelight/Game.java | 29 +++++----- .../input/touch/NativeTouchContext.java | 54 ++++++++++++------- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index be4aac2fe..e695ee7b7 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -61,6 +61,7 @@ import android.os.Handler; import android.os.IBinder; import android.util.Rational; +import android.util.Log; import android.view.Display; import android.view.InputDevice; import android.view.KeyCharacterMap; @@ -85,8 +86,11 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.util.ArrayList; +// import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import java.util.Locale; +import java.util.Objects; public class Game extends Activity implements SurfaceHolder.Callback, @@ -153,8 +157,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, private WifiManager.WifiLock highPerfWifiLock; private WifiManager.WifiLock lowLatencyWifiLock; - - private ArrayList nativeTouchPointers = new ArrayList<>(); + private Map nativeTouchPointerMap = new HashMap<>(); private boolean connectedToUsbDriverService = false; private ServiceConnection usbDriverServiceConnection = new ServiceConnection() { @@ -1543,13 +1546,15 @@ private byte getLiTouchTypeFromEvent(MotionEvent event) { private float[] getStreamViewRelativeNormalizedXY(View view, MotionEvent event, int pointerIndex) { - + float targetCoords[] = new float[] {0f,0f}; // Coords are replaced by NativeTouchContext here. - float targetCoords[] = NativeTouchContext.selectCoordsForPointer(event, pointerIndex, nativeTouchPointers); + NativeTouchContext.Pointer pointer = nativeTouchPointerMap.get(event.getPointerId(pointerIndex)); + if(pointer != null){ + targetCoords = pointer.XYCoordSelector(); + } float normalizedX = targetCoords[0]; float normalizedY = targetCoords[1]; - // For the containing background view, we must subtract the origin // of the StreamView to get video-relative coordinates. if (view != streamView) { @@ -1759,11 +1764,10 @@ private boolean trySendTouchEvent(View view, MotionEvent event) { if (eventType < 0) { return false; } - // Log.d("nativeTouchCoordHandlers", "Length: " + nativeTouchCoordHandlers.size()); if (event.getActionMasked() == MotionEvent.ACTION_MOVE) { // Move events may impact all active pointers for (int i = 0; i < event.getPointerCount(); i++) { - NativeTouchContext.updatePointerInList(event, i, nativeTouchPointers); + Objects.requireNonNull(nativeTouchPointerMap.get(event.getPointerId(i))).updatePointerCoords(event, i); // update pointer coords in the map. if (!sendTouchEventForPointer(view, event, eventType, i)) { return false; } @@ -1778,12 +1782,11 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { } else { switch(event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: // first finger down. - nativeTouchPointers.add(new NativeTouchContext.Pointer(event)); //create a Pointer Instance for new touch pointer and add it to the list. - break; case MotionEvent.ACTION_POINTER_DOWN: - nativeTouchPointers.add(new NativeTouchContext.Pointer(event)); //create a Pointer Instance for new touch pointer and add it to the list. multiFingerTapChecker(event); + case MotionEvent.ACTION_DOWN: // first & following finger down. + NativeTouchContext.Pointer pointer = new NativeTouchContext.Pointer(event); //create a Pointer Instance for new touch pointer, put it into the map. + nativeTouchPointerMap.put(pointer.getPointerId(), pointer); break; case MotionEvent.ACTION_UP: // all fingers up // toggle keyboard when all fingers lift up, just like how it works in trackpad mode. @@ -1791,7 +1794,7 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { toggleKeyboard(); } case MotionEvent.ACTION_POINTER_UP: - NativeTouchContext.safelyRemovePointerFromList(event, nativeTouchPointers); //remove pointer from the list. + nativeTouchPointerMap.remove(event.getPointerId(event.getActionIndex())); break; } // Up, Down, and Hover events are specific to the action index diff --git a/app/src/main/java/com/limelight/binding/input/touch/NativeTouchContext.java b/app/src/main/java/com/limelight/binding/input/touch/NativeTouchContext.java index a27ae35f4..f48459ace 100644 --- a/app/src/main/java/com/limelight/binding/input/touch/NativeTouchContext.java +++ b/app/src/main/java/com/limelight/binding/input/touch/NativeTouchContext.java @@ -124,7 +124,7 @@ public int getPointerId(){ /** * Update native coordinates, relative coordinates & velocity for Pointer instance */ - private void updatePointerCoords(MotionEvent event, int pointerIndex){ + public void updatePointerCoords(MotionEvent event, int pointerIndex){ this.previousCoords.x = this.latestCoords.x; // assign x, y coords to this.previousCoords only. Other attributes can be ignored. this.previousCoords.y = this.latestCoords.y; event.getPointerCoords(pointerIndex, this.latestCoords); // update latestCoords from MotionEvent. @@ -173,7 +173,7 @@ private void updateRelativeCoordsFixedXVelocity(){ /** * Judge whether this pointer leaves (2*INTIAL_ZONE_PIXELS)^2 square flat region */ - public boolean doesPointerLeaveInitialZone() { + private boolean doesPointerLeaveInitialZone() { if (!this.pointerLeftInitialZone) { // Log.d("DeltaXY to Initial Coords", "DeltaX "+deltaX+" DeltaY "+deltaY); float deltaX = this.latestCoords.x - this.initialCoords.x; @@ -212,6 +212,32 @@ private void flattenLongPressJitter(){ } } + /** + * Judge whether pointer's coords should be manipulated based on its initial coords (first contact location) + * Only Supports horizontal split (left and right) for now. + */ + private boolean withinEnhancedTouchZone () + { + // float[] normalizedCoords = new float[] {pointerIntialCoords[0]/ScreenUtils.getScreenWidth(), pointerIntialCoords[1]/ScreenUtils.getScreenHeight()}; + float normalizedX = this.initialCoords.x/ScreenUtils.getScreenWidth(); + return normalizedX * ENHANCED_TOUCH_ON_RIGHT > ENHANCED_TOUCH_ZONE_DIVIDER * ENHANCED_TOUCH_ON_RIGHT; + } + + public float[] XYCoordSelector(){ + if(ENABLE_ENHANCED_TOUCH) { + //to judge whether pointer located on enhanced touch zone by its initial coords. + if (this.withinEnhancedTouchZone()) { + return new float[] {this.latestRelativeCoords.x,this.latestRelativeCoords.y}; + } + else{ + return new float[] {this.latestCoords.x,this.latestCoords.y}; + } + } + else{ + return new float[] {this.latestCoords.x,this.latestCoords.y}; + } + } + public float getInitialX(){ return this.initialCoords.x; } @@ -266,16 +292,7 @@ public void printPointerCoordSnapshot(){ } - /** - * Judge whether pointer's coords should be manipulated based on its initial coords (first contact location) - * Only Supports horizontal split (left and right) for now. - */ - private static boolean isEnhancedTouchZone (float[] pointerIntialCoords) - { - // float[] normalizedCoords = new float[] {pointerIntialCoords[0]/ScreenUtils.getScreenWidth(), pointerIntialCoords[1]/ScreenUtils.getScreenHeight()}; - float normalizedX = pointerIntialCoords[0]/ScreenUtils.getScreenWidth(); - return normalizedX * ENHANCED_TOUCH_ON_RIGHT > ENHANCED_TOUCH_ZONE_DIVIDER * ENHANCED_TOUCH_ON_RIGHT; - } + /** @@ -284,7 +301,7 @@ private static boolean isEnhancedTouchZone (float[] pointerIntialCoords) * this method is called to access additional pointer info from the list by finding a pointerId match, * and decides whether the pointer's coords should be manipulated. */ - public static float[] selectCoordsForPointer(MotionEvent event, int pointerIndex, ArrayList nativeTouchPointers){ + /* public static float[] selectCoordsForPointer(MotionEvent event, int pointerIndex, ArrayList nativeTouchPointers){ float selectedX = 0f; float selectedY = 0f; for (NativeTouchContext.Pointer pointer : nativeTouchPointers) { @@ -308,12 +325,13 @@ public static float[] selectCoordsForPointer(MotionEvent event, int pointerIndex } } return new float[] {selectedX, selectedY}; - } + } */ + /** * Safely remove Pointer instance from a List in ACTION_POINTER_UP or ACTION_UP condition */ - public static void safelyRemovePointerFromList(MotionEvent event, ArrayList nativeTouchPointers){ + /* public static void safelyRemovePointerFromList(MotionEvent event, ArrayList nativeTouchPointers){ Iterator iterator = nativeTouchPointers.iterator(); //safely remove pointer handler by iterator. while (iterator.hasNext()){ NativeTouchContext.Pointer pointer = iterator.next(); @@ -322,12 +340,12 @@ public static void safelyRemovePointerFromList(MotionEvent event, ArrayList nativeTouchPointers) { + /* public static void updatePointerInList(MotionEvent event,int pointerIndex, ArrayList nativeTouchPointers) { for (NativeTouchContext.Pointer pointer : nativeTouchPointers) { if (pointer.getPointerId() == event.getPointerId(pointerIndex)) { pointer.updatePointerCoords(event, pointerIndex); @@ -337,5 +355,5 @@ public static void updatePointerInList(MotionEvent event,int pointerIndex, Array break; // immediately break when we get a pointerId match (this method update 1 pointer in the list) } } - } + } */ } From f72d5a8a7aad3ed0bcde404b6e00eb12c643f394 Mon Sep 17 00:00:00 2001 From: TrueZhuanJia <78474576+TrueZhuangJia@users.noreply.github.com> Date: Sun, 12 May 2024 09:53:15 +0800 Subject: [PATCH 12/18] Update README.md --- README.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 65eec443c..3e8ef21f1 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,24 @@ +首个实现分区触点移速调节的fork. 允许调整触点在右分屏或分屏的移速, 对调节米家游戏视角转动的灵敏度尤其有用。 This is a fork with some manipulation on native multi-touch pointer coordinaties, allows pointer to move faster or slower on specified enhanced touch zone. Maybe useful for tweaking view rotation sensitivity in some games. +
+![image](https://github.com/TrueZhuangJia/moonlight-android-Enhanced-MultiTouch/assets/78474576/3bd8efeb-89ab-477d-b501-22f25cdb8fc6) +![image](https://github.com/TrueZhuangJia/moonlight-android-Enhanced-MultiTouch/assets/78474576/0d58b391-71ef-48be-82f8-6fef1649e2eb) -![image](https://github.com/TrueZhuangJia/moonlight-android-TZJ/assets/78474576/90a4a100-2786-4629-a5dc-89363d059be8) - -Configurable local keyboard toggle: +恢复原版moonlight多指敲击屏幕唤醒本地键盘的方式, 同时允许设置敲击手指数量
+Configurable local keyboard toggle:
+![image](https://github.com/TrueZhuangJia/moonlight-android-Enhanced-MultiTouch/assets/78474576/416a2960-f0a7-4245-ac62-d8fb53ec4ca7) ![image](https://github.com/TrueZhuangJia/moonlight-android-Enhanced-MultiTouch/assets/78474576/a0edaf21-a174-448e-832c-da2d171cefea) -And some additional features like flat region to eliminate long press jitter: -![image](https://github.com/TrueZhuangJia/moonlight-android-TZJ/assets/78474576/c91fb01e-d843-41ef-9ebf-99aafda60ea2) +还有两个的功能, 使用中你可能未必能感觉到有区别:
+And some additional features like flat region to eliminate long press jitter:
+![image](https://github.com/TrueZhuangJia/moonlight-android-Enhanced-MultiTouch/assets/78474576/0594b3ef-e381-4efc-bc2b-db8f209db272) +![image](https://github.com/TrueZhuangJia/moonlight-android-Enhanced-MultiTouch/assets/78474576/98534adc-48ad-4433-8d7c-e60b88c13466) + +触控与显示同步的话,可能有助理于视角旋转时画面的流畅性。 # Moonlight Android From 0789afa64df1d7d769115c2a7c8999fefdb16aff Mon Sep 17 00:00:00 2001 From: True Zhuanjia Date: Sun, 12 May 2024 11:11:17 +0800 Subject: [PATCH 13/18] all NativeTouchContext related codes switched ON/OFF by prefConfig.enableEhancedTouch --- app/src/main/java/com/limelight/Game.java | 48 +++++++++++++------ .../preferences/PreferenceConfiguration.java | 4 +- app/src/main/res/values-zh-rCN/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- app/src/main/res/xml/preferences.xml | 25 +++++----- 5 files changed, 50 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index e695ee7b7..19cd54434 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -227,7 +227,7 @@ protected void onCreate(Bundle savedInstanceState) { tombstonePrefs = Game.this.getSharedPreferences("DecoderTombstone", 0); // Set flat region size for long press jitter elimination. NativeTouchContext.INTIAL_ZONE_PIXELS = prefConfig.longPressflatRegionPixels; - NativeTouchContext.ENABLE_ENHANCED_TOUCH = prefConfig.enableEhancedTouch; + NativeTouchContext.ENABLE_ENHANCED_TOUCH = prefConfig.enableEnhancedTouch; if(prefConfig.enhancedTouchOnWhichSide){ NativeTouchContext.ENHANCED_TOUCH_ON_RIGHT = -1; }else{ @@ -1546,14 +1546,19 @@ private byte getLiTouchTypeFromEvent(MotionEvent event) { private float[] getStreamViewRelativeNormalizedXY(View view, MotionEvent event, int pointerIndex) { - float targetCoords[] = new float[] {0f,0f}; - // Coords are replaced by NativeTouchContext here. - NativeTouchContext.Pointer pointer = nativeTouchPointerMap.get(event.getPointerId(pointerIndex)); - if(pointer != null){ - targetCoords = pointer.XYCoordSelector(); + float normalizedX = event.getX(pointerIndex); + float normalizedY = event.getY(pointerIndex); + if(prefConfig.enableEnhancedTouch){ + float targetCoords[] = new float[] {0f,0f}; + // Coords are replaced by NativeTouchContext here. + NativeTouchContext.Pointer pointer = nativeTouchPointerMap.get(event.getPointerId(pointerIndex)); + if(pointer != null){ + targetCoords = pointer.XYCoordSelector(); + } + normalizedX = targetCoords[0]; + normalizedY = targetCoords[1]; } - float normalizedX = targetCoords[0]; - float normalizedY = targetCoords[1]; + // For the containing background view, we must subtract the origin // of the StreamView to get video-relative coordinates. @@ -1766,10 +1771,19 @@ private boolean trySendTouchEvent(View view, MotionEvent event) { } if (event.getActionMasked() == MotionEvent.ACTION_MOVE) { // Move events may impact all active pointers - for (int i = 0; i < event.getPointerCount(); i++) { - Objects.requireNonNull(nativeTouchPointerMap.get(event.getPointerId(i))).updatePointerCoords(event, i); // update pointer coords in the map. - if (!sendTouchEventForPointer(view, event, eventType, i)) { - return false; + if(prefConfig.enableEnhancedTouch) { + for (int i = 0; i < event.getPointerCount(); i++) { + Objects.requireNonNull(nativeTouchPointerMap.get(event.getPointerId(i))).updatePointerCoords(event, i); // update pointer coords in the map. + if (!sendTouchEventForPointer(view, event, eventType, i)) { + return false; + } + } + } + else{ + for (int i = 0; i < event.getPointerCount(); i++) { + if (!sendTouchEventForPointer(view, event, eventType, i)) { + return false; + } } } return true; @@ -1785,8 +1799,10 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { case MotionEvent.ACTION_POINTER_DOWN: multiFingerTapChecker(event); case MotionEvent.ACTION_DOWN: // first & following finger down. - NativeTouchContext.Pointer pointer = new NativeTouchContext.Pointer(event); //create a Pointer Instance for new touch pointer, put it into the map. - nativeTouchPointerMap.put(pointer.getPointerId(), pointer); + if(prefConfig.enableEnhancedTouch) { + NativeTouchContext.Pointer pointer = new NativeTouchContext.Pointer(event); //create a Pointer Instance for new touch pointer, put it into the map. + nativeTouchPointerMap.put(pointer.getPointerId(), pointer); + } break; case MotionEvent.ACTION_UP: // all fingers up // toggle keyboard when all fingers lift up, just like how it works in trackpad mode. @@ -1794,7 +1810,9 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { toggleKeyboard(); } case MotionEvent.ACTION_POINTER_UP: - nativeTouchPointerMap.remove(event.getPointerId(event.getActionIndex())); + if(prefConfig.enableEnhancedTouch) { + nativeTouchPointerMap.remove(event.getPointerId(event.getActionIndex())); + } break; } // Up, Down, and Hover events are specific to the action index diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java index 1103f9b0c..79e58d262 100644 --- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java +++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java @@ -138,7 +138,7 @@ public enum AnalogStickForScrolling { public int bitrate; public int longPressflatRegionPixels; //Assigned to NativeTouchContext.INTIAL_ZONE_PIXELS public boolean syncTouchEventWithDisplay; // if true, view.requestUnbufferedDispatch(event) will be disabled - public boolean enableEhancedTouch; //Assigned to NativeTouchContext.ENABLE_ENHANCED_TOUCH + public boolean enableEnhancedTouch; //Assigned to NativeTouchContext.ENABLE_ENHANCED_TOUCH public boolean enhancedTouchOnWhichSide; //Assigned to NativeTouchContext.ENHANCED_TOUCH_ON_RIGHT public int enhanceTouchZoneDivider; //Assigned to NativeTouchContext.ENHANCED_TOUCH_ZONE_DIVIDER public float pointerVelocityFactor; //Assigned to NativeTouchContext.POINTER_VELOCITY_FACTOR @@ -580,7 +580,7 @@ else if (str.equals("4K60")) { } // Enhance touch settings - config.enableEhancedTouch = prefs.getBoolean(ENABLE_ENHANCED_TOUCH_PREF_STRING, false); + config.enableEnhancedTouch = prefs.getBoolean(ENABLE_ENHANCED_TOUCH_PREF_STRING, false); config.enhancedTouchOnWhichSide = prefs.getBoolean(ENHANCED_TOUCH_ON_RIGHT_PREF_STRING, true); // by default, enhanced touch zone is on the right side. config.enhanceTouchZoneDivider = prefs.getInt(ENHANCED_TOUCH_ZONE_DIVIDER_PREF_STRING,50); // decides where to divide native touch zone & enhance touch zone by a vertical line. config.pointerVelocityFactor = prefs.getInt(POINTER_VELOCITY_FACTOR_PREF_STRING,100); // set pointer velocity faster or slower within enhance touch zone, useful in some games for tweaking view rotation sensitivity. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 7255d210c..18152c8c6 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -126,7 +126,7 @@ 如果启用,则将触控屏作为触控板使用。如果禁用,则启用多点触控模式 多点触控长按抖动消除区域 - 像素值越高,抖动消除区域越大。抖动消除区域内,应用只发送触点的初始坐标 + 全屏生效。像素值越高,抖动消除区域越大。抖动消除区域内,应用只发送触点的初始坐标 像素 触控事件与显示刷新同步 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3938b07ae..0974a2574 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -202,7 +202,7 @@ If enabled, touch event will be synchronized with display refresh rate, like 60Hz. Flat region for long press jitter elimination in multi-point touch mode - Increase for larger long-press flat region, within which the app sends initial contact coordinates to server. + Works for the whole screen. Increase for larger long-press flat region, within which the app sends initial contact coordinates to server. pixels Enable keyboard toggle in multi-point touch mode diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index a9e427e90..f71200c6e 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -139,18 +139,6 @@ android:title="@string/title_checkbox_sync_touch_event_with_display" android:summary="@string/summary_checkbox_sync_touch_event_with_display" android:defaultValue="false" /> - + Date: Sun, 12 May 2024 13:18:52 +0800 Subject: [PATCH 14/18] Cancel fixed X(horizontal) velocity, since it deosn't make much sense. Minor changes on logic. --- app/src/main/java/com/limelight/Game.java | 25 +++-- .../input/touch/NativeTouchContext.java | 106 ++++++------------ .../preferences/PreferenceConfiguration.java | 6 +- app/src/main/res/xml/preferences.xml | 11 -- 4 files changed, 55 insertions(+), 93 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 19cd54434..2bfc47441 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -235,7 +235,7 @@ protected void onCreate(Bundle savedInstanceState) { } NativeTouchContext.ENHANCED_TOUCH_ZONE_DIVIDER = prefConfig.enhanceTouchZoneDivider * 0.01f; NativeTouchContext.POINTER_VELOCITY_FACTOR = prefConfig.pointerVelocityFactor * 0.01f; - NativeTouchContext.POINTER_FIXED_X_VELOCITY = prefConfig.pointerFixedXVelocity; + // NativeTouchContext.POINTER_FIXED_X_VELOCITY = prefConfig.pointerFixedXVelocity; // Enter landscape unless we're on a square screen setPreferredOrientationForCurrentDisplay(); @@ -1546,17 +1546,24 @@ private byte getLiTouchTypeFromEvent(MotionEvent event) { private float[] getStreamViewRelativeNormalizedXY(View view, MotionEvent event, int pointerIndex) { - float normalizedX = event.getX(pointerIndex); - float normalizedY = event.getY(pointerIndex); + float normalizedX; + float normalizedY; if(prefConfig.enableEnhancedTouch){ - float targetCoords[] = new float[] {0f,0f}; // Coords are replaced by NativeTouchContext here. NativeTouchContext.Pointer pointer = nativeTouchPointerMap.get(event.getPointerId(pointerIndex)); - if(pointer != null){ - targetCoords = pointer.XYCoordSelector(); + if(pointer != null) { + float targetCoords[] = pointer.XYCoordSelector(); // decides to passthrough or manipulate coords. + normalizedX = targetCoords[0]; + normalizedY = targetCoords[1]; } - normalizedX = targetCoords[0]; - normalizedY = targetCoords[1]; + else{ + normalizedX = 0f; //in this case (pointer == null), pointers are already all up. + normalizedY = 0f; + } + } + else{ + normalizedX = event.getX(pointerIndex); + normalizedY = event.getY(pointerIndex); } @@ -1797,7 +1804,7 @@ else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { else { switch(event.getActionMasked()) { case MotionEvent.ACTION_POINTER_DOWN: - multiFingerTapChecker(event); + multiFingerTapChecker(event); case MotionEvent.ACTION_DOWN: // first & following finger down. if(prefConfig.enableEnhancedTouch) { NativeTouchContext.Pointer pointer = new NativeTouchContext.Pointer(event); //create a Pointer Instance for new touch pointer, put it into the map. diff --git a/app/src/main/java/com/limelight/binding/input/touch/NativeTouchContext.java b/app/src/main/java/com/limelight/binding/input/touch/NativeTouchContext.java index f48459ace..9681b9c57 100644 --- a/app/src/main/java/com/limelight/binding/input/touch/NativeTouchContext.java +++ b/app/src/main/java/com/limelight/binding/input/touch/NativeTouchContext.java @@ -65,7 +65,7 @@ public class NativeTouchContext { * Fixed horizontal velocity (in pixels) within enhanced touch zone * Config read from prefConfig in Game class */ - public static float POINTER_FIXED_X_VELOCITY = 8f; + // public static float POINTER_FIXED_X_VELOCITY = 8f; /** * Object to store, update info & manipulate coordinates for each pointer. @@ -90,7 +90,9 @@ public static class Pointer{ /** * DeltaX & DeltaY between to 2 onTouch() callbacks. */ - private float pointerVelocity[]; + private float velocityX; + private float velocityY; + /** * Flipped to true when pointer moves out of (2*INTIAL_ZONE_PIXELS)^2 square flat region. @@ -102,20 +104,13 @@ public static class Pointer{ * Pointer class instantiated in ACTION_DOWN, ACTION_POINTER_DOWN Condition. */ public Pointer(MotionEvent event) { - int pointerIndex = event.getActionIndex(); - switch(event.getActionMasked()){ - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - this.pointerId = event.getPointerId(pointerIndex); // get pointerId - event.getPointerCoords(pointerIndex, this.initialCoords);// Fill in initial coords. - event.getPointerCoords(pointerIndex, this.latestCoords);// Fill in latest coords. - //if(POINTER_VELOCITY_FACTOR != 1.0f){ - this.latestRelativeCoords.x = this.latestCoords.x; - this.latestRelativeCoords.y = this.latestCoords.y; - //} - break; - default: Log.d("error", "NativeTouchCoordHandler.Pointer must be instantiated in ACTION_DOWN & ACTION_POINTER_DOWN condition"); - } + int pointerIndex = event.getActionIndex(); //get the pointerIndex triggers DOWN event. + this.pointerId = event.getPointerId(pointerIndex); // get pointerId + event.getPointerCoords(pointerIndex, this.initialCoords);// Fill in initial coords. + event.getPointerCoords(pointerIndex, this.latestCoords);// Fill in latest coords. + //if(POINTER_VELOCITY_FACTOR != 1.0f){ + this.latestRelativeCoords.x = this.latestCoords.x; + this.latestRelativeCoords.y = this.latestCoords.y; } public int getPointerId(){ return this.pointerId; @@ -128,80 +123,60 @@ public void updatePointerCoords(MotionEvent event, int pointerIndex){ this.previousCoords.x = this.latestCoords.x; // assign x, y coords to this.previousCoords only. Other attributes can be ignored. this.previousCoords.y = this.latestCoords.y; event.getPointerCoords(pointerIndex, this.latestCoords); // update latestCoords from MotionEvent. - // float deltaX = this.latestCoords.x - this.previousCoords.x; - // float deltaY = this.latestCoords.y - this.previousCoords.y; - - if(ENABLE_ENHANCED_TOUCH) { - this.pointerVelocity = new float[]{this.latestCoords.x - this.previousCoords.x, this.latestCoords.y - this.previousCoords.y}; - // Log.d("Velocity","" + this.pointerVelocity[0] + " " + this.pointerVelocity[1] ); - // XY速率同比例缩放,Pointer向量方向不变 - if (POINTER_FIXED_X_VELOCITY == 0f) { - this.updateRelativeCoordsAverageXYScale(); - } - // 固定X速率模式,该模式下仍可用POINTER_VELOCITY_FACTOR调整Y的速率 - else { - this.updateRelativeCoordsFixedXVelocity(); - } - } - if(INTIAL_ZONE_PIXELS > 0f){ - this.flattenLongPressJitter(); + if(POINTER_VELOCITY_FACTOR == 1.0f) { + this.latestRelativeCoords.x = this.latestCoords.x; + this.latestRelativeCoords.y = this.latestCoords.y; } + else this.updateRelativeCoords(); + + // 固定X速率模式,该模式下仍可用POINTER_VELOCITY_FACTOR调整Y的速率 + // if(POINTER_FIXED_X_VELOCITY != 0f) this.updateRelativeCoordsFixedXVelocity(); + + if(INTIAL_ZONE_PIXELS > 0f) this.flattenLongPressJitter(); // Log.d("INTIAL_ZONE_PIXELS", ""+INTIAL_ZONE_PIXELS); } /** * Update relative coordinates with velocity scaled by POINTER_VELOCITY_FACTOR */ - private void updateRelativeCoordsAverageXYScale(){ + private void updateRelativeCoords(){ + this.velocityX = this.latestCoords.x - this.previousCoords.x; + this.velocityY = this.latestCoords.y - this.previousCoords.y; this.previousRelativeCoords.x = this.latestRelativeCoords.x; this.previousRelativeCoords.y = this.latestRelativeCoords.y; - this.latestRelativeCoords.x = this.previousRelativeCoords.x + this.pointerVelocity[0] * POINTER_VELOCITY_FACTOR; - this.latestRelativeCoords.y = this.previousRelativeCoords.y + this.pointerVelocity[1] * POINTER_VELOCITY_FACTOR; + this.latestRelativeCoords.x = this.previousRelativeCoords.x + this.velocityX * POINTER_VELOCITY_FACTOR; + this.latestRelativeCoords.y = this.previousRelativeCoords.y + this.velocityY * POINTER_VELOCITY_FACTOR; } /** * Update relative coordinates with fixed X velocity */ - private void updateRelativeCoordsFixedXVelocity(){ + /* private void updateRelativeCoordsFixedXVelocity(){ + this.velocityX = this.latestCoords.x - this.previousCoords.x; + this.velocityY = this.latestCoords.y - this.previousCoords.y; this.previousRelativeCoords.x = this.latestRelativeCoords.x; this.previousRelativeCoords.y = this.latestRelativeCoords.y; - this.latestRelativeCoords.x = this.previousRelativeCoords.x + Math.signum(pointerVelocity[0]) * POINTER_FIXED_X_VELOCITY; - this.latestRelativeCoords.y = this.previousRelativeCoords.y + this.pointerVelocity[1] * POINTER_VELOCITY_FACTOR; - } + this.latestRelativeCoords.x = this.previousRelativeCoords.x + Math.signum(this.velocityX) * POINTER_FIXED_X_VELOCITY; + this.latestRelativeCoords.y = this.previousRelativeCoords.y + this.velocityY * POINTER_VELOCITY_FACTOR; + } */ /** * Judge whether this pointer leaves (2*INTIAL_ZONE_PIXELS)^2 square flat region */ - private boolean doesPointerLeaveInitialZone() { + private void checkIfPointerLeaveInitialZone() { if (!this.pointerLeftInitialZone) { - // Log.d("DeltaXY to Initial Coords", "DeltaX "+deltaX+" DeltaY "+deltaY); - float deltaX = this.latestCoords.x - this.initialCoords.x; - float deltaY = this.latestCoords.y - this.initialCoords.y; - /* - if(ENABLE_ENHANCED_TOUCH){ - deltaX = (this.latestRelativeCoords.x - this.initialCoords.x); - deltaY = (this.latestRelativeCoords.y - this.initialCoords.y); - }else{ - deltaX = (this.latestCoords.x - this.initialCoords.x); - deltaY = (this.latestCoords.y - this.initialCoords.y); - }*/ - - // Note: Flat Region is scaled by POINTER_VELOCITY_FACTOR - // if (Math.abs(deltaX) > INTIAL_ZONE_PIXELS * POINTER_VELOCITY_FACTOR || Math.abs(deltaY) > INTIAL_ZONE_PIXELS * POINTER_VELOCITY_FACTOR) { - if (Math.abs(deltaX) > INTIAL_ZONE_PIXELS || Math.abs(deltaY) > INTIAL_ZONE_PIXELS) { + if (Math.abs(this.latestCoords.x - this.initialCoords.x) > INTIAL_ZONE_PIXELS || Math.abs(this.latestCoords.y - this.initialCoords.y) > INTIAL_ZONE_PIXELS) { this.pointerLeftInitialZone = true; //Flips pointerLeftInitialZone to true when pointer moves out of flat region. - return this.pointerLeftInitialZone; } } - return this.pointerLeftInitialZone; } /** * Resets latest coords (both native & relative) to initial coords if pointer doesn't leave flat region. */ private void flattenLongPressJitter(){ - this.doesPointerLeaveInitialZone(); + this.checkIfPointerLeaveInitialZone(); // Log.d("INTIAL_ZONE_PIXELS", ""+INTIAL_ZONE_PIXELS); if(!this.pointerLeftInitialZone){ this.latestCoords.x = this.initialCoords.x; @@ -224,18 +199,9 @@ private boolean withinEnhancedTouchZone () } public float[] XYCoordSelector(){ - if(ENABLE_ENHANCED_TOUCH) { //to judge whether pointer located on enhanced touch zone by its initial coords. - if (this.withinEnhancedTouchZone()) { - return new float[] {this.latestRelativeCoords.x,this.latestRelativeCoords.y}; - } - else{ - return new float[] {this.latestCoords.x,this.latestCoords.y}; - } - } - else{ - return new float[] {this.latestCoords.x,this.latestCoords.y}; - } + if (this.withinEnhancedTouchZone()) return new float[] {this.latestRelativeCoords.x,this.latestRelativeCoords.y}; + else return new float[] {this.latestCoords.x,this.latestCoords.y}; } public float getInitialX(){ diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java index 79e58d262..7277877fc 100644 --- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java +++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java @@ -72,7 +72,7 @@ public enum AnalogStickForScrolling { private static final String ENHANCED_TOUCH_ON_RIGHT_PREF_STRING = "checkbox_enhanced_touch_on_which_side"; private static final String ENHANCED_TOUCH_ZONE_DIVIDER_PREF_STRING = "enhanced_touch_zone_divider"; private static final String POINTER_VELOCITY_FACTOR_PREF_STRING = "pointer_velocity_factor"; - private static final String POINTER_FIXED_X_VELOCITY_PREF_STRING = "fixed_x_velocity"; + // private static final String POINTER_FIXED_X_VELOCITY_PREF_STRING = "fixed_x_velocity"; private static final String ENABLE_AUDIO_FX_PREF_STRING = "checkbox_enable_audiofx"; @@ -142,7 +142,7 @@ public enum AnalogStickForScrolling { public boolean enhancedTouchOnWhichSide; //Assigned to NativeTouchContext.ENHANCED_TOUCH_ON_RIGHT public int enhanceTouchZoneDivider; //Assigned to NativeTouchContext.ENHANCED_TOUCH_ZONE_DIVIDER public float pointerVelocityFactor; //Assigned to NativeTouchContext.POINTER_VELOCITY_FACTOR - public float pointerFixedXVelocity; //Assigned to NativeTouchContext.POINTER_FIXED_X_VELOCITY + // public float pointerFixedXVelocity; //Assigned to NativeTouchContext.POINTER_FIXED_X_VELOCITY public int nativeTouchFingersToToggleKeyboard; // Number of fingers to tap to toggle local on-screen keyboard in native touch mode. @@ -584,7 +584,7 @@ else if (str.equals("4K60")) { config.enhancedTouchOnWhichSide = prefs.getBoolean(ENHANCED_TOUCH_ON_RIGHT_PREF_STRING, true); // by default, enhanced touch zone is on the right side. config.enhanceTouchZoneDivider = prefs.getInt(ENHANCED_TOUCH_ZONE_DIVIDER_PREF_STRING,50); // decides where to divide native touch zone & enhance touch zone by a vertical line. config.pointerVelocityFactor = prefs.getInt(POINTER_VELOCITY_FACTOR_PREF_STRING,100); // set pointer velocity faster or slower within enhance touch zone, useful in some games for tweaking view rotation sensitivity. - config.pointerFixedXVelocity = prefs.getInt(POINTER_FIXED_X_VELOCITY_PREF_STRING,0); + // config.pointerFixedXVelocity = prefs.getInt(POINTER_FIXED_X_VELOCITY_PREF_STRING,0); String audioConfig = prefs.getString(AUDIO_CONFIG_PREF_STRING, DEFAULT_AUDIO_CONFIG); if (audioConfig.equals("71")) { diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index f71200c6e..23c73645b 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -216,17 +216,6 @@ android:summary="@string/summary_pointer_velocity_factor" android:text="@string/suffix_pointer_velocity_factor" android:title="@string/title_pointer_velocity_factor" /> -
From 7bf05bc90395c1a20679d0a3012fc0b95808d586 Mon Sep 17 00:00:00 2001 From: True Zhuanjia Date: Tue, 14 May 2024 09:22:39 +0800 Subject: [PATCH 15/18] Set max pointer velocity factor to 500%, for better view rotation tweak in Honkai: Star Rail. --- app/src/main/res/xml/preferences.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 23c73645b..473e85409 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -211,7 +211,7 @@ android:dialogMessage="@string/dialog_title_pointer_velocity_factor" seekbar:min="0" seekbar:step="1" - android:max="200" + android:max="500" android:defaultValue="100" android:summary="@string/summary_pointer_velocity_factor" android:text="@string/suffix_pointer_velocity_factor" From bbac484ebfd8d5d1a842911b891de128d468849e Mon Sep 17 00:00:00 2001 From: TrueZhuanJia <78474576+TrueZhuangJia@users.noreply.github.com> Date: Sun, 7 Jul 2024 19:37:09 +0800 Subject: [PATCH 16/18] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e8ef21f1..148c17a6b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -首个实现分区触点移速调节的fork. 允许调整触点在右分屏或分屏的移速, 对调节米家游戏视角转动的灵敏度尤其有用。 +# 首个实现多点触控 灵敏度调节 (触点移速调节) 的 Moonlight分支.
+# The first Moonlight fork to implement multi-touch sensitivity tweak (touch point velocity tweak) + + +允许调整触点在右分屏或分屏的移速, 对调节米家游戏视角转动的灵敏度尤其有用。 This is a fork with some manipulation on native multi-touch pointer coordinaties, allows pointer to move faster or slower on specified enhanced touch zone. Maybe useful for tweaking view rotation sensitivity in some games.
From 9490776f2896053347ff92e71565e8f7af2598ee Mon Sep 17 00:00:00 2001 From: TrueZhuanJia <78474576+TrueZhuangJia@users.noreply.github.com> Date: Sun, 18 Aug 2024 13:38:43 +0800 Subject: [PATCH 17/18] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 148c17a6b..153a218bf 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # 首个实现多点触控 灵敏度调节 (触点移速调节) 的 Moonlight分支.
# The first Moonlight fork to implement multi-touch sensitivity tweak (touch point velocity tweak) +# I'm currently working on my moonlight-iOS fork, with too much deviations from the original version: +https://github.com/Moonlight-the-Fried-Fish/moonlight-ios-NativeMultiTouchPassthrough 允许调整触点在右分屏或分屏的移速, 对调节米家游戏视角转动的灵敏度尤其有用。 From 7fe0f308cfd8e7dec2e9acdcf98d7b1ea122a0fe Mon Sep 17 00:00:00 2001 From: TrueZhuanJia <78474576+TrueZhuangJia@users.noreply.github.com> Date: Sun, 18 Aug 2024 13:39:52 +0800 Subject: [PATCH 18/18] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 153a218bf..c9075e5e2 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,13 @@ https://github.com/Moonlight-the-Fried-Fish/moonlight-ios-NativeMultiTouchPassthrough +# Features of this fork: + 允许调整触点在右分屏或分屏的移速, 对调节米家游戏视角转动的灵敏度尤其有用。 This is a fork with some manipulation on native multi-touch pointer coordinaties, allows pointer to move faster or slower on specified enhanced touch zone. Maybe useful for tweaking view rotation sensitivity in some games. -
+

+ ![image](https://github.com/TrueZhuangJia/moonlight-android-Enhanced-MultiTouch/assets/78474576/3bd8efeb-89ab-477d-b501-22f25cdb8fc6) ![image](https://github.com/TrueZhuangJia/moonlight-android-Enhanced-MultiTouch/assets/78474576/0d58b391-71ef-48be-82f8-6fef1649e2eb)