Skip to content

Commit

Permalink
Introducing option to intercept system shortcuts only when pointer is…
Browse files Browse the repository at this point in the history
… also intercepted

Fixes termux#606
  • Loading branch information
twaik committed May 16, 2024
1 parent fc10156 commit ee1bd84
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 18 deletions.
1 change: 1 addition & 0 deletions app/src/main/java/com/termux/x11/LoriePreferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ void updatePreferencesLayout() {
findPreference("hideEKOnVolDown").setEnabled(p.getBoolean("showAdditionalKbd", false) && p.getBoolean("captureVolumeKeys", true));
findPreference("dexMetaKeyCapture").setEnabled(!p.getBoolean("enableAccessibilityServiceAutomatically", false));
findPreference("enableAccessibilityServiceAutomatically").setEnabled(!p.getBoolean("dexMetaKeyCapture", false));
findPreference("keyCaptureOnlyWhenPointerIntercepted").setEnabled(p.getBoolean("dexMetaKeyCapture", false) || p.getBoolean("enableAccessibilityServiceAutomatically", false));
findPreference("filterOutWinkey").setEnabled(p.getBoolean("enableAccessibilityServiceAutomatically", false));

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
Expand Down
7 changes: 5 additions & 2 deletions app/src/main/java/com/termux/x11/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public class MainActivity extends AppCompatActivity implements View.OnApplyWindo
private boolean hideEKOnVolDown = false;
private boolean toggleIMEUsingBackKey = false;
private boolean useTermuxEKBarBehaviour = false;
public boolean dexMetaKeyCapture = false;
private static final int KEY_BACK = 158;

private static boolean oldFullscreen = false;
Expand Down Expand Up @@ -522,7 +523,9 @@ void onPreferencesChanged(String key) {
if (!p.getBoolean("pointerCapture", false) && lorieView.hasPointerCapture())
lorieView.releasePointerCapture();

SamsungDexUtils.dexMetaKeyCapture(this, p.getBoolean("dexMetaKeyCapture", false));
KeyInterceptor.keyCaptureOnlyWhenPointerIntercepted = p.getBoolean("keyCaptureOnlyWhenPointerIntercepted", false);
dexMetaKeyCapture = p.getBoolean("dexMetaKeyCapture", false);
SamsungDexUtils.dexMetaKeyCapture(this, !KeyInterceptor.keyCaptureOnlyWhenPointerIntercepted && dexMetaKeyCapture);

setTerminalToolbarView();
onWindowFocusChanged(true);
Expand Down Expand Up @@ -804,7 +807,7 @@ public void onWindowFocusChanged(boolean hasFocus) {
window.setSoftInputMode((reseed ? SOFT_INPUT_ADJUST_RESIZE : SOFT_INPUT_ADJUST_PAN) | SOFT_INPUT_STATE_HIDDEN);

((FrameLayout) findViewById(android.R.id.content)).getChildAt(0).setFitsSystemWindows(!fullscreen);
SamsungDexUtils.dexMetaKeyCapture(this, hasFocus && p.getBoolean("dexMetaKeyCapture", false));
SamsungDexUtils.dexMetaKeyCapture(this, hasFocus && !KeyInterceptor.keyCaptureOnlyWhenPointerIntercepted && dexMetaKeyCapture);
}

@Override
Expand Down
9 changes: 8 additions & 1 deletion app/src/main/java/com/termux/x11/input/InputEventSender.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
import android.view.MotionEvent;
import android.view.View;

import com.termux.x11.MainActivity;
import com.termux.x11.utils.KeyInterceptor;
import com.termux.x11.utils.SamsungDexUtils;

import java.util.List;
import java.util.TreeSet;

Expand Down Expand Up @@ -204,8 +208,11 @@ else if (e.getUnicodeChar() != 0)
if (e.getRepeatCount() > 0)
return true;

if (pointerCapture && keyCode == KEYCODE_ESCAPE && !pressed)
if (pointerCapture && keyCode == KEYCODE_ESCAPE && !pressed) {
v.releasePointerCapture();
if (KeyInterceptor.keyCaptureOnlyWhenPointerIntercepted && MainActivity.getInstance().dexMetaKeyCapture)
SamsungDexUtils.dexMetaKeyCapture(MainActivity.getInstance(), false);
}

// We try to send all other key codes to the host directly.
return mInjector.sendKeyEvent(scancode, keyCode, pressed);
Expand Down
33 changes: 20 additions & 13 deletions app/src/main/java/com/termux/x11/input/TouchInputHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
import androidx.annotation.IntDef;
import androidx.core.math.MathUtils;

import com.termux.x11.MainActivity;
import com.termux.x11.utils.KeyInterceptor;
import com.termux.x11.utils.SamsungDexUtils;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

Expand Down Expand Up @@ -66,7 +70,7 @@ public class TouchInputHandler {

private InputStrategyInterface mInputStrategy;
private final InputEventSender mInjector;
private final Context mContext;
private final MainActivity mActivity;

/**
* Used for tracking swipe gestures. Only the Y-direction is needed for responding to swipe-up
Expand Down Expand Up @@ -100,43 +104,43 @@ public class TouchInputHandler {

@CapturedPointerTransformation int capturedPointerTransformation = CapturedPointerTransformation.NONE;

private TouchInputHandler(Context ctx, RenderData renderData, RenderStub renderStub,
private TouchInputHandler(MainActivity activity, RenderData renderData, RenderStub renderStub,
final InputEventSender injector, boolean isTouchpad) {
if (renderStub == null || injector == null)
throw new NullPointerException();

mRenderStub = renderStub;
mRenderData = renderData != null ? renderData :new RenderData();
mInjector = injector;
mContext = ctx;
mActivity = activity;

GestureListener listener = new GestureListener();
mScroller = new GestureDetector(/*desktop*/ ctx, listener, null, false);
mScroller = new GestureDetector(/*desktop*/ activity, listener, null, false);

// If long-press is enabled, the gesture-detector will not emit any further onScroll
// notifications after the onLongPress notification. Since onScroll is being used for
// moving the cursor, it means that the cursor would become stuck if the finger were held
// down too long.
mScroller.setIsLongpressEnabled(false);

mTapDetector = new TapGestureDetector(/*desktop*/ ctx, listener);
mSwipePinchDetector = new SwipeDetector(/*desktop*/ ctx);
mTapDetector = new TapGestureDetector(/*desktop*/ activity, listener);
mSwipePinchDetector = new SwipeDetector(/*desktop*/ activity);

// The threshold needs to be bigger than the ScaledTouchSlop used by the gesture-detectors,
// so that a gesture cannot be both a tap and a swipe. It also needs to be small enough so
// that intentional swipes are usually detected.
float density = /*desktop*/ ctx.getResources().getDisplayMetrics().density;
float density = /*desktop*/ activity.getResources().getDisplayMetrics().density;
mSwipeThreshold = 40 * density;

// mEdgeSlopInPx = ViewConfiguration.get(/*desktop*/ ctx).getScaledEdgeSlop();

setInputMode(InputMode.TRACKPAD);
mDexListener = new DexListener(ctx);
mTouchpadHandler = isTouchpad ? null : new TouchInputHandler(ctx, mRenderData, renderStub, injector, true);
mDexListener = new DexListener(activity);
mTouchpadHandler = isTouchpad ? null : new TouchInputHandler(activity, mRenderData, renderStub, injector, true);
}

public TouchInputHandler(Context ctx, RenderStub renderStub, final InputEventSender injector) {
this(ctx, null, renderStub, injector, false);
public TouchInputHandler(MainActivity activity, RenderStub renderStub, final InputEventSender injector) {
this(activity, null, renderStub, injector, false);
}

boolean isDexEvent(MotionEvent event) {
Expand All @@ -163,8 +167,11 @@ public boolean handleTouchEvent(View view0, View view, MotionEvent event) {
if (!view.isFocused() && event.getAction() == MotionEvent.ACTION_DOWN)
view.requestFocus();

if (mInjector.pointerCapture && !view.hasPointerCapture() && event.getAction() == MotionEvent.ACTION_UP)
if (mInjector.pointerCapture && !view.hasPointerCapture() && event.getAction() == MotionEvent.ACTION_UP) {
view.requestPointerCapture();
if (KeyInterceptor.keyCaptureOnlyWhenPointerIntercepted && mActivity.dexMetaKeyCapture)
SamsungDexUtils.dexMetaKeyCapture(mActivity, true);
}

if (event.getToolType(event.getActionIndex()) == MotionEvent.TOOL_TYPE_STYLUS)
return mStylusListener.onTouch(event);
Expand Down Expand Up @@ -261,7 +268,7 @@ public void setInputMode(@InputMode int inputMode) {
if (inputMode == InputMode.TOUCH)
mInputStrategy = new InputStrategyInterface.NullInputStrategy();
else if (inputMode == InputMode.SIMULATED_TOUCH)
mInputStrategy = new InputStrategyInterface.SimulatedTouchInputStrategy(mRenderData, mInjector, mContext);
mInputStrategy = new InputStrategyInterface.SimulatedTouchInputStrategy(mRenderData, mInjector, mActivity);
else
mInputStrategy = new InputStrategyInterface.TrackpadInputStrategy(mInjector);
}
Expand Down
6 changes: 4 additions & 2 deletions app/src/main/java/com/termux/x11/utils/KeyInterceptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
public class KeyInterceptor extends AccessibilityService {
LinkedHashSet<Integer> pressedKeys = new LinkedHashSet<>();

public static boolean keyCaptureOnlyWhenPointerIntercepted = false;
private static KeyInterceptor self;

public KeyInterceptor() {
Expand All @@ -39,6 +40,9 @@ public boolean onKeyEvent(KeyEvent event) {
&& (instance.findViewById(R.id.terminal_toolbar_text_input) == null
|| !instance.findViewById(R.id.terminal_toolbar_text_input).isFocused());

if (intercept && keyCaptureOnlyWhenPointerIntercepted && !instance.getWindow().getDecorView().hasPointerCapture())
intercept = false;

if (intercept || (event.getAction() == KeyEvent.ACTION_UP && pressedKeys.contains(event.getKeyCode())))
ret = instance.handleKey(event);

Expand All @@ -50,8 +54,6 @@ public boolean onKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP)
pressedKeys.remove(event.getKeyCode());

Log.d("KeyInterceptor", "" + (event.getUnicodeChar() != 0 ? (char) event.getUnicodeChar() : "") + " " + (event.getCharacters() != null ? event.getCharacters() : "") + " " + (ret ? " " : " not ") + "intercepted event " + event);

return ret;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.termux.x11.utils;

import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
Expand Down Expand Up @@ -76,6 +78,8 @@ public Object instantiateItem(@NonNull ViewGroup collection, int position) {

editText.setOnCapturedPointerListener((v2, e2) -> {
v2.releasePointerCapture();
if (KeyInterceptor.keyCaptureOnlyWhenPointerIntercepted && mActivity.dexMetaKeyCapture)
SamsungDexUtils.dexMetaKeyCapture(mActivity, false);
return false;
});

Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/xml/preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@
android:defaultValue="false"
android:key="enableAccessibilityServiceAutomatically" />

<SwitchPreferenceCompat
android:title="Intercept system shortcuts only when pointer is also intercepted"
android:defaultValue="false"
android:key="keyCaptureOnlyWhenPointerIntercepted" />

<SwitchPreferenceCompat
android:title="Filter out intercepted Win (Meta/Mod4) key."
android:summary="Allows you to use Dex shortcuts while intercepting."
Expand Down

0 comments on commit ee1bd84

Please sign in to comment.