diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java
index 5d214508a3..501a7a6729 100644
--- a/app/src/main/java/com/limelight/Game.java
+++ b/app/src/main/java/com/limelight/Game.java
@@ -76,6 +76,7 @@
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.view.inputmethod.InputMethodManager;
+import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
@@ -96,7 +97,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 keyboardToggleDownTime = 0;
private static final int REFERENCE_HORIZ_RES = 1280;
private static final int REFERENCE_VERT_RES = 720;
@@ -107,7 +108,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 KEYBOARD_TOGGLE_TAP_THRESHOLD = 300;
private ControllerHandler controllerHandler;
private KeyboardTranslator keyboardTranslator;
@@ -146,6 +147,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
private TextView notificationOverlayView;
private int requestedNotificationOverlayVisibility = View.GONE;
private TextView performanceOverlayView;
+ private ImageButton keyboardToggleButtonView;
private MediaCodecDecoderRenderer decoderRenderer;
private boolean reportedCrash;
@@ -272,6 +274,17 @@ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
performanceOverlayView = findViewById(R.id.performanceOverlay);
+ keyboardToggleButtonView = findViewById(R.id.keyboardToggleButton);
+ keyboardToggleButtonView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ toggleKeyboard();
+ }
+ });
+ if (prefConfig.showKeyboardToggleButton) {
+ keyboardToggleButtonView.setVisibility(View.VISIBLE);
+ }
+
inputCaptureProvider = InputCaptureManager.getInputCaptureProvider(this, this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -597,6 +610,7 @@ public void onConfigurationChanged(Configuration newConfig) {
performanceOverlayView.setVisibility(View.GONE);
notificationOverlayView.setVisibility(View.GONE);
+ keyboardToggleButtonView.setVisibility(View.GONE);
// Disable sensors while in PiP mode
controllerHandler.disableSensors();
@@ -619,6 +633,10 @@ public void onConfigurationChanged(Configuration newConfig) {
notificationOverlayView.setVisibility(requestedNotificationOverlayVisibility);
+ if (prefConfig.showKeyboardToggleButton) {
+ keyboardToggleButtonView.setVisibility(View.VISIBLE);
+ }
+
// Enable sensors again after exiting PiP
controllerHandler.enableSensors();
@@ -1998,11 +2016,12 @@ else if (event.getActionMasked() == MotionEvent.ACTION_UP || event.getActionMask
int eventX = (int)(event.getX(actionIndex) + xOffset);
int eventY = (int)(event.getY(actionIndex) + yOffset);
- // Special handling for 3 finger gesture
- if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN &&
- event.getPointerCount() == 3) {
- // Three fingers down
- threeFingerDownTime = event.getEventTime();
+ // Special handling for the configurable keyboard-toggle tap gesture
+ if (prefConfig.keyboardToggleFingers != 0 &&
+ event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN &&
+ event.getPointerCount() == prefConfig.keyboardToggleFingers) {
+ // All configured fingers down
+ keyboardToggleDownTime = event.getEventTime();
// Cancel the first and second touches to avoid
// erroneous events
@@ -2041,8 +2060,8 @@ 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) {
- // This is a 3 finger tap to bring up the keyboard
+ if (event.getEventTime() - keyboardToggleDownTime < KEYBOARD_TOGGLE_TAP_THRESHOLD) {
+ // This is a tap with the configured finger count to bring up the keyboard
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 8ed01e3610..0368fdbf50 100644
--- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java
+++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java
@@ -59,6 +59,8 @@ public enum AnalogStickForScrolling {
private static final String VIBRATE_FALLBACK_STRENGTH_PREF_STRING = "seekbar_vibrate_fallback_strength";
private static final String FLIP_FACE_BUTTONS_PREF_STRING = "checkbox_flip_face_buttons";
private static final String TOUCHSCREEN_TRACKPAD_PREF_STRING = "checkbox_touchscreen_trackpad";
+ private static final String KEYBOARD_TOGGLE_FINGERS_PREF_STRING = "list_keyboard_toggle_fingers";
+ private static final String SHOW_KEYBOARD_BUTTON_PREF_STRING = "checkbox_show_keyboard_button";
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";
@@ -98,6 +100,8 @@ public enum AnalogStickForScrolling {
private static final int DEFAULT_VIBRATE_FALLBACK_STRENGTH = 100;
private static final boolean DEFAULT_FLIP_FACE_BUTTONS = false;
private static final boolean DEFAULT_TOUCHSCREEN_TRACKPAD = true;
+ private static final String DEFAULT_KEYBOARD_TOGGLE_FINGERS = "3";
+ private static final boolean DEFAULT_SHOW_KEYBOARD_BUTTON = false;
private static final String DEFAULT_AUDIO_CONFIG = "2"; // Stereo
private static final boolean DEFAULT_LATENCY_TOAST = false;
private static final String DEFAULT_FRAME_PACING = "latency";
@@ -146,6 +150,8 @@ public enum AnalogStickForScrolling {
public boolean vibrateFallbackToDevice;
public int vibrateFallbackToDeviceStrength;
public boolean touchscreenTrackpad;
+ public int keyboardToggleFingers;
+ public boolean showKeyboardToggleButton;
public MoonBridge.AudioConfiguration audioConfiguration;
public int framePacing;
public boolean absoluteMouseMode;
@@ -593,6 +599,8 @@ else if (audioConfig.equals("51")) {
config.vibrateFallbackToDeviceStrength = prefs.getInt(VIBRATE_FALLBACK_STRENGTH_PREF_STRING, DEFAULT_VIBRATE_FALLBACK_STRENGTH);
config.flipFaceButtons = prefs.getBoolean(FLIP_FACE_BUTTONS_PREF_STRING, DEFAULT_FLIP_FACE_BUTTONS);
config.touchscreenTrackpad = prefs.getBoolean(TOUCHSCREEN_TRACKPAD_PREF_STRING, DEFAULT_TOUCHSCREEN_TRACKPAD);
+ config.keyboardToggleFingers = Integer.parseInt(prefs.getString(KEYBOARD_TOGGLE_FINGERS_PREF_STRING, DEFAULT_KEYBOARD_TOGGLE_FINGERS));
+ config.showKeyboardToggleButton = prefs.getBoolean(SHOW_KEYBOARD_BUTTON_PREF_STRING, DEFAULT_SHOW_KEYBOARD_BUTTON);
config.enableLatencyToast = prefs.getBoolean(LATENCY_TOAST_PREF_STRING, DEFAULT_LATENCY_TOAST);
config.absoluteMouseMode = prefs.getBoolean(ABSOLUTE_MOUSE_MODE_PREF_STRING, DEFAULT_ABSOLUTE_MOUSE_MODE);
config.enableAudioFx = prefs.getBoolean(ENABLE_AUDIO_FX_PREF_STRING, DEFAULT_ENABLE_AUDIO_FX);
diff --git a/app/src/main/res/drawable/bg_keyboard_toggle_button.xml b/app/src/main/res/drawable/bg_keyboard_toggle_button.xml
new file mode 100644
index 0000000000..35321c9e04
--- /dev/null
+++ b/app/src/main/res/drawable/bg_keyboard_toggle_button.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_keyboard.xml b/app/src/main/res/drawable/ic_keyboard.xml
new file mode 100644
index 0000000000..bf6193a6cd
--- /dev/null
+++ b/app/src/main/res/drawable/ic_keyboard.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_game.xml b/app/src/main/res/layout/activity_game.xml
index 85a960d963..2409cb53cc 100644
--- a/app/src/main/res/layout/activity_game.xml
+++ b/app/src/main/res/layout/activity_game.xml
@@ -50,4 +50,19 @@
android:preferKeepClear="true"
android:visibility="gone" />
+
+
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 9bdeb036b7..a6aec7cbdb 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -131,4 +131,15 @@
- right
- left
+
+
+ - @string/keyboard_toggle_fingers_disabled
+ - @string/keyboard_toggle_fingers_3
+ - @string/keyboard_toggle_fingers_4
+
+
+ - 0
+ - 3
+ - 4
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 9cc2215aaa..f75891d526 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -201,6 +201,13 @@
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
+ On-screen keyboard gesture
+ Number of fingers to tap with to show/hide the on-screen keyboard. Change this if your device intercepts the default gesture for a system action, or disable it entirely.
+ Disabled
+ 3 fingers
+ 4 fingers
+ Show on-screen keyboard button
+ Shows a small button over the stream to show/hide the on-screen keyboard. Useful if your device doesn\'t support the tap gesture above.
On-screen Controls Settings
Show on-screen controls
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 5b09082b35..dafbd05915 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -144,6 +144,18 @@
android:title="@string/title_checkbox_absolute_mouse_mode"
android:summary="@string/summary_checkbox_absolute_mouse_mode"
android:defaultValue="false" />
+
+