From e78a64892abe2502f7e4216c87c9691b3c1e06e9 Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Sat, 14 Jan 2023 16:56:18 +0100 Subject: [PATCH 01/13] feat: add in game stream menu Add back menu to send sepcial keys. E.g. close fullscreen while using yuzu. --- app/src/main/java/com/limelight/Game.java | 19 ++- .../main/java/com/limelight/GameBackMenu.java | 122 ++++++++++++++++++ app/src/main/res/values/strings.xml | 11 ++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/limelight/GameBackMenu.java diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 3f58bb19b..731a6a27c 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -39,10 +39,12 @@ import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; +import android.app.AlertDialog; import android.app.PictureInPictureParams; import android.app.Service; import android.content.ComponentName; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; @@ -64,7 +66,10 @@ import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.Menu; import android.view.MotionEvent; +import android.view.SubMenu; import android.view.Surface; import android.view.SurfaceHolder; import android.view.View; @@ -73,12 +78,15 @@ import android.view.View.OnTouchListener; import android.view.Window; import android.view.WindowManager; +import android.widget.ArrayAdapter; import android.widget.FrameLayout; import android.view.inputmethod.InputMethodManager; +import android.widget.PopupMenu; import android.widget.TextView; import android.widget.Toast; import java.io.ByteArrayInputStream; +import java.io.PipedOutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.cert.CertificateException; @@ -2298,7 +2306,16 @@ public void onUsbPermissionPromptCompleted() { public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { switch (keyEvent.getAction()) { case KeyEvent.ACTION_DOWN: - return handleKeyDown(keyEvent); + boolean handled = handleKeyDown(keyEvent); + if (handled) + return true; + + // Intercept back key event before android handles it + // Always handle the request, the user has to select "Disconnect" within the back menu to actually disconnect + if (keyCode == keyEvent.KEYCODE_BACK) { + new GameBackMenu(this, conn); + return true; + } case KeyEvent.ACTION_UP: return handleKeyUp(keyEvent); case KeyEvent.ACTION_MULTIPLE: diff --git a/app/src/main/java/com/limelight/GameBackMenu.java b/app/src/main/java/com/limelight/GameBackMenu.java new file mode 100644 index 000000000..9daa206ae --- /dev/null +++ b/app/src/main/java/com/limelight/GameBackMenu.java @@ -0,0 +1,122 @@ +package com.limelight; + +import android.app.AlertDialog; +import android.widget.ArrayAdapter; + +import com.limelight.nvstream.NvConnection; +import com.limelight.nvstream.input.KeyboardPacket; + +public class GameBackMenu { + + private final String ACTION_SEND_SPECIAL_KEYS; + private final String ACTION_DISCONNECT; + private final String ACTION_CANCEL; + + private final String ACTION_SEND_SPECIAL_KEYS_ESC; + private final String ACTION_SEND_SPECIAL_KEYS_F11; + private final String ACTION_SEND_SPECIAL_KEYS_WIN; + private final String ACTION_SEND_SPECIAL_KEYS_WIN_D; + private final String ACTION_SEND_SPECIAL_KEYS_WIN_G; + + private static class MenuOption { + private final String label; + private final Runnable runnable; + + MenuOption(String label, Runnable runnable) { + this.label = label; + this.runnable = runnable; + } + } + + + private final Game game; + private final NvConnection conn; + + public GameBackMenu(Game game, NvConnection conn) { + this.game = game; + this.conn = conn; + + this.ACTION_SEND_SPECIAL_KEYS = getString(R.string.back_menu_send_keys); + this.ACTION_DISCONNECT = getString(R.string.back_menu_disconnect); + this.ACTION_CANCEL = getString(R.string.back_menu_cancel); + + this.ACTION_SEND_SPECIAL_KEYS_ESC = getString(R.string.back_menu_send_keys_esc); + this.ACTION_SEND_SPECIAL_KEYS_F11 = getString(R.string.back_menu_send_keys_f11); + this.ACTION_SEND_SPECIAL_KEYS_WIN = getString(R.string.back_menu_send_keys_win); + this.ACTION_SEND_SPECIAL_KEYS_WIN_D = getString(R.string.back_menu_send_keys_win_d); + this.ACTION_SEND_SPECIAL_KEYS_WIN_G = getString(R.string.back_menu_send_keys_win_g); + + showBackMenu(); + } + + private String getString(int id) { + return game.getResources().getString(id); + } + + private void sendKeySequence(byte modifier, short[] keys) { + for (short key : keys) + conn.sendKeyboardInput(key, KeyboardPacket.KEY_DOWN, + (byte) (modifier | KeyboardPacket.KEY_DOWN)); + + for (int pos = keys.length - 1; pos >= 0; pos--) + conn.sendKeyboardInput(keys[pos], KeyboardPacket.KEY_UP, + (byte) (modifier | KeyboardPacket.KEY_UP)); + } + + private void showMenuDialog(String title, MenuOption[] options) { + AlertDialog.Builder builder = new AlertDialog.Builder(game); + builder.setTitle(title); + + final ArrayAdapter actions = + new ArrayAdapter(game, android.R.layout.simple_list_item_1); + + for (MenuOption option : options) { + actions.add(option.label); + } + + builder.setAdapter(actions, (dialog, which) -> { + String label = actions.getItem(which); + for (MenuOption option : options) { + if (!label.equals(option.label)) { + continue; + } + + if (option.runnable != null) { + option.runnable.run(); + } + break; + } + }); + + builder.show(); + } + + private void showSpecialKeysMenu() { + showMenuDialog(ACTION_SEND_SPECIAL_KEYS, new MenuOption[]{ + new MenuOption(ACTION_SEND_SPECIAL_KEYS_ESC, () -> sendKeySequence( + (byte) 0, new short[]{0x18})), + new MenuOption(ACTION_SEND_SPECIAL_KEYS_F11, () -> sendKeySequence( + (byte) 0, new short[]{0x7a})), + new MenuOption(ACTION_SEND_SPECIAL_KEYS_WIN, () -> sendKeySequence( + (byte) 0, new short[]{0x5B})), + new MenuOption(ACTION_SEND_SPECIAL_KEYS_WIN_D, () -> sendKeySequence( + (byte) 0, new short[]{0x5B, 0x44})), + new MenuOption(ACTION_SEND_SPECIAL_KEYS_WIN_G, () -> sendKeySequence( + (byte) 0, new short[]{0x5B, 0x47})), + /* + TODO: Currently not working + new MenuDialogOption(ACTION_SEND_SPECIAL_KEYS_SHIFT_TAB, () -> sendKeySequence( + (byte) 0, new short[]{0xA0, 0x09})), + */ + new MenuOption(ACTION_CANCEL, null), + }); + } + + private void showBackMenu() { + showMenuDialog("Back Menu", new MenuOption[]{ + new MenuOption(ACTION_SEND_SPECIAL_KEYS, () -> showSpecialKeysMenu()), + new MenuOption(ACTION_DISCONNECT, () -> game.onBackPressed()), + new MenuOption(ACTION_CANCEL, null), + }); + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 074ca4913..616ff0c61 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -132,6 +132,17 @@ Are you sure you want to quit the running app? All unsaved data will be lost. App ID: + + Disconnect + Cancel + Send special key(s) + Send ESC (Menu) + Send F11 (Exit full screen) + Send WIN (Open Start Menu) + Send WIN + D (Switch to Desktop) + Send WIN + G (Open Xbox Game Bar) + Send SHIFT + TAB (Open Steam Overlay) + Add PC Manually Connecting to the PC… From 104f6f8f54186aa16b1250bc111ab53c0d0710bc Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Sat, 21 Jan 2023 10:04:38 +0100 Subject: [PATCH 02/13] game menu: refactor back menu to game menu --- app/src/main/java/com/limelight/Game.java | 12 ++---------- .../{GameBackMenu.java => GameMenu.java} | 15 ++++++++++----- 2 files changed, 12 insertions(+), 15 deletions(-) rename app/src/main/java/com/limelight/{GameBackMenu.java => GameMenu.java} (94%) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 731a6a27c..f339cd61b 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -39,12 +39,10 @@ import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; -import android.app.AlertDialog; import android.app.PictureInPictureParams; import android.app.Service; import android.content.ComponentName; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; @@ -66,10 +64,7 @@ import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; import android.view.MotionEvent; -import android.view.SubMenu; import android.view.Surface; import android.view.SurfaceHolder; import android.view.View; @@ -78,15 +73,12 @@ import android.view.View.OnTouchListener; import android.view.Window; import android.view.WindowManager; -import android.widget.ArrayAdapter; import android.widget.FrameLayout; import android.view.inputmethod.InputMethodManager; -import android.widget.PopupMenu; import android.widget.TextView; import android.widget.Toast; import java.io.ByteArrayInputStream; -import java.io.PipedOutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.cert.CertificateException; @@ -2311,9 +2303,9 @@ public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { return true; // Intercept back key event before android handles it - // Always handle the request, the user has to select "Disconnect" within the back menu to actually disconnect + // Always handle the request, the user has to select "Disconnect" within the game menu to actually disconnect if (keyCode == keyEvent.KEYCODE_BACK) { - new GameBackMenu(this, conn); + new GameMenu(this, conn); return true; } case KeyEvent.ACTION_UP: diff --git a/app/src/main/java/com/limelight/GameBackMenu.java b/app/src/main/java/com/limelight/GameMenu.java similarity index 94% rename from app/src/main/java/com/limelight/GameBackMenu.java rename to app/src/main/java/com/limelight/GameMenu.java index 9daa206ae..b6b0b629d 100644 --- a/app/src/main/java/com/limelight/GameBackMenu.java +++ b/app/src/main/java/com/limelight/GameMenu.java @@ -6,7 +6,12 @@ import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.input.KeyboardPacket; -public class GameBackMenu { +/** + * Provide options for ongoing Game Stream. + * + * Shown on back action in game activity. + */ +public class GameMenu { private final String ACTION_SEND_SPECIAL_KEYS; private final String ACTION_DISCONNECT; @@ -32,7 +37,7 @@ private static class MenuOption { private final Game game; private final NvConnection conn; - public GameBackMenu(Game game, NvConnection conn) { + public GameMenu(Game game, NvConnection conn) { this.game = game; this.conn = conn; @@ -46,7 +51,7 @@ public GameBackMenu(Game game, NvConnection conn) { this.ACTION_SEND_SPECIAL_KEYS_WIN_D = getString(R.string.back_menu_send_keys_win_d); this.ACTION_SEND_SPECIAL_KEYS_WIN_G = getString(R.string.back_menu_send_keys_win_g); - showBackMenu(); + showMenu(); } private String getString(int id) { @@ -112,8 +117,8 @@ private void showSpecialKeysMenu() { }); } - private void showBackMenu() { - showMenuDialog("Back Menu", new MenuOption[]{ + private void showMenu() { + showMenuDialog("Game Menu", new MenuOption[]{ new MenuOption(ACTION_SEND_SPECIAL_KEYS, () -> showSpecialKeysMenu()), new MenuOption(ACTION_DISCONNECT, () -> game.onBackPressed()), new MenuOption(ACTION_CANCEL, null), From ace2b3e0b00188ed2b17cffbabf2bde33816ce83 Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Sat, 21 Jan 2023 10:14:08 +0100 Subject: [PATCH 03/13] game menu: use string refs directly --- app/src/main/java/com/limelight/GameMenu.java | 45 +++++-------------- app/src/main/res/values/strings.xml | 20 ++++----- 2 files changed, 22 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/limelight/GameMenu.java b/app/src/main/java/com/limelight/GameMenu.java index b6b0b629d..544018446 100644 --- a/app/src/main/java/com/limelight/GameMenu.java +++ b/app/src/main/java/com/limelight/GameMenu.java @@ -13,16 +13,6 @@ */ public class GameMenu { - private final String ACTION_SEND_SPECIAL_KEYS; - private final String ACTION_DISCONNECT; - private final String ACTION_CANCEL; - - private final String ACTION_SEND_SPECIAL_KEYS_ESC; - private final String ACTION_SEND_SPECIAL_KEYS_F11; - private final String ACTION_SEND_SPECIAL_KEYS_WIN; - private final String ACTION_SEND_SPECIAL_KEYS_WIN_D; - private final String ACTION_SEND_SPECIAL_KEYS_WIN_G; - private static class MenuOption { private final String label; private final Runnable runnable; @@ -33,7 +23,6 @@ private static class MenuOption { } } - private final Game game; private final NvConnection conn; @@ -41,16 +30,6 @@ public GameMenu(Game game, NvConnection conn) { this.game = game; this.conn = conn; - this.ACTION_SEND_SPECIAL_KEYS = getString(R.string.back_menu_send_keys); - this.ACTION_DISCONNECT = getString(R.string.back_menu_disconnect); - this.ACTION_CANCEL = getString(R.string.back_menu_cancel); - - this.ACTION_SEND_SPECIAL_KEYS_ESC = getString(R.string.back_menu_send_keys_esc); - this.ACTION_SEND_SPECIAL_KEYS_F11 = getString(R.string.back_menu_send_keys_f11); - this.ACTION_SEND_SPECIAL_KEYS_WIN = getString(R.string.back_menu_send_keys_win); - this.ACTION_SEND_SPECIAL_KEYS_WIN_D = getString(R.string.back_menu_send_keys_win_d); - this.ACTION_SEND_SPECIAL_KEYS_WIN_G = getString(R.string.back_menu_send_keys_win_g); - showMenu(); } @@ -97,31 +76,31 @@ private void showMenuDialog(String title, MenuOption[] options) { } private void showSpecialKeysMenu() { - showMenuDialog(ACTION_SEND_SPECIAL_KEYS, new MenuOption[]{ - new MenuOption(ACTION_SEND_SPECIAL_KEYS_ESC, () -> sendKeySequence( + showMenuDialog(getString(R.string.game_menu_send_keys), new MenuOption[]{ + new MenuOption(getString(R.string.game_menu_send_keys_esc), () -> sendKeySequence( (byte) 0, new short[]{0x18})), - new MenuOption(ACTION_SEND_SPECIAL_KEYS_F11, () -> sendKeySequence( + new MenuOption(getString(R.string.game_menu_send_keys_f11), () -> sendKeySequence( (byte) 0, new short[]{0x7a})), - new MenuOption(ACTION_SEND_SPECIAL_KEYS_WIN, () -> sendKeySequence( + new MenuOption(getString(R.string.game_menu_send_keys_win), () -> sendKeySequence( (byte) 0, new short[]{0x5B})), - new MenuOption(ACTION_SEND_SPECIAL_KEYS_WIN_D, () -> sendKeySequence( + new MenuOption(getString(R.string.game_menu_send_keys_win_d), () -> sendKeySequence( (byte) 0, new short[]{0x5B, 0x44})), - new MenuOption(ACTION_SEND_SPECIAL_KEYS_WIN_G, () -> sendKeySequence( + new MenuOption(getString(R.string.game_menu_send_keys_win_g), () -> sendKeySequence( (byte) 0, new short[]{0x5B, 0x47})), /* - TODO: Currently not working - new MenuDialogOption(ACTION_SEND_SPECIAL_KEYS_SHIFT_TAB, () -> sendKeySequence( + // TODO: Currently not working + new MenuDialogOption(getString(R.string.game_menu_send_keys_shift_tab), () -> sendKeySequence( (byte) 0, new short[]{0xA0, 0x09})), */ - new MenuOption(ACTION_CANCEL, null), + new MenuOption(getString(R.string.game_menu_cancel), null), }); } private void showMenu() { showMenuDialog("Game Menu", new MenuOption[]{ - new MenuOption(ACTION_SEND_SPECIAL_KEYS, () -> showSpecialKeysMenu()), - new MenuOption(ACTION_DISCONNECT, () -> game.onBackPressed()), - new MenuOption(ACTION_CANCEL, null), + new MenuOption(getString(R.string.game_menu_send_keys), () -> showSpecialKeysMenu()), + new MenuOption(getString(R.string.game_menu_disconnect), () -> game.onBackPressed()), + new MenuOption(getString(R.string.game_menu_cancel), null), }); } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 616ff0c61..1d0962659 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -132,16 +132,16 @@ Are you sure you want to quit the running app? All unsaved data will be lost. App ID: - - Disconnect - Cancel - Send special key(s) - Send ESC (Menu) - Send F11 (Exit full screen) - Send WIN (Open Start Menu) - Send WIN + D (Switch to Desktop) - Send WIN + G (Open Xbox Game Bar) - Send SHIFT + TAB (Open Steam Overlay) + + Disconnect + Cancel + Send special key(s) + Send ESC (Menu) + Send F11 (Toggle full screen) + Send WIN (Toggle Windows start menu) + Send WIN + D (Switch to Desktop) + Send WIN + G (Open Xbox Game Bar) + Send SHIFT + TAB (Open Steam Overlay) Add PC Manually From f3ff170dbb0e419e0c900adcb4cc114244c33493 Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Sat, 21 Jan 2023 11:56:03 +0100 Subject: [PATCH 04/13] game menu: cleanup + fix steam overlay --- app/src/main/java/com/limelight/GameMenu.java | 52 +++++++++++-------- .../binding/input/KeyboardTranslator.java | 9 +++- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/limelight/GameMenu.java b/app/src/main/java/com/limelight/GameMenu.java index 544018446..c637d2756 100644 --- a/app/src/main/java/com/limelight/GameMenu.java +++ b/app/src/main/java/com/limelight/GameMenu.java @@ -1,18 +1,22 @@ package com.limelight; import android.app.AlertDialog; +import android.os.Handler; import android.widget.ArrayAdapter; +import com.limelight.binding.input.KeyboardTranslator; import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.input.KeyboardPacket; /** * Provide options for ongoing Game Stream. - * + *

* Shown on back action in game activity. */ public class GameMenu { + private static final long KEY_UP_DELAY = 25; + private static class MenuOption { private final String label; private final Runnable runnable; @@ -37,14 +41,19 @@ private String getString(int id) { return game.getResources().getString(id); } - private void sendKeySequence(byte modifier, short[] keys) { - for (short key : keys) - conn.sendKeyboardInput(key, KeyboardPacket.KEY_DOWN, - (byte) (modifier | KeyboardPacket.KEY_DOWN)); + private void sendKeys(short[] keys) { + for (short key : keys) { + conn.sendKeyboardInput(key, KeyboardPacket.KEY_DOWN, (byte) 0); + } + + new Handler().postDelayed((() -> { - for (int pos = keys.length - 1; pos >= 0; pos--) - conn.sendKeyboardInput(keys[pos], KeyboardPacket.KEY_UP, - (byte) (modifier | KeyboardPacket.KEY_UP)); + for (int pos = keys.length - 1; pos >= 0; pos--) { + short key = keys[pos]; + + conn.sendKeyboardInput(key, KeyboardPacket.KEY_UP, (byte) 0); + } + }), KEY_UP_DELAY); } private void showMenuDialog(String title, MenuOption[] options) { @@ -77,21 +86,18 @@ private void showMenuDialog(String title, MenuOption[] options) { private void showSpecialKeysMenu() { showMenuDialog(getString(R.string.game_menu_send_keys), new MenuOption[]{ - new MenuOption(getString(R.string.game_menu_send_keys_esc), () -> sendKeySequence( - (byte) 0, new short[]{0x18})), - new MenuOption(getString(R.string.game_menu_send_keys_f11), () -> sendKeySequence( - (byte) 0, new short[]{0x7a})), - new MenuOption(getString(R.string.game_menu_send_keys_win), () -> sendKeySequence( - (byte) 0, new short[]{0x5B})), - new MenuOption(getString(R.string.game_menu_send_keys_win_d), () -> sendKeySequence( - (byte) 0, new short[]{0x5B, 0x44})), - new MenuOption(getString(R.string.game_menu_send_keys_win_g), () -> sendKeySequence( - (byte) 0, new short[]{0x5B, 0x47})), - /* - // TODO: Currently not working - new MenuDialogOption(getString(R.string.game_menu_send_keys_shift_tab), () -> sendKeySequence( - (byte) 0, new short[]{0xA0, 0x09})), - */ + new MenuOption(getString(R.string.game_menu_send_keys_esc), + () -> sendKeys(new short[]{KeyboardTranslator.VK_ESCAPE})), + new MenuOption(getString(R.string.game_menu_send_keys_f11), + () -> sendKeys(new short[]{KeyboardTranslator.VK_F11})), + new MenuOption(getString(R.string.game_menu_send_keys_win), + () -> sendKeys(new short[]{KeyboardTranslator.VK_LWIN})), + new MenuOption(getString(R.string.game_menu_send_keys_win_d), + () -> sendKeys(new short[]{KeyboardTranslator.VK_LWIN, KeyboardTranslator.VK_D})), + new MenuOption(getString(R.string.game_menu_send_keys_win_g), + () -> sendKeys(new short[]{KeyboardTranslator.VK_LWIN, KeyboardTranslator.VK_G})), + new MenuOption(getString(R.string.game_menu_send_keys_shift_tab), + () -> sendKeys(new short[]{KeyboardTranslator.VK_LSHIFT, KeyboardTranslator.VK_TAB})), new MenuOption(getString(R.string.game_menu_cancel), null), }); } diff --git a/app/src/main/java/com/limelight/binding/input/KeyboardTranslator.java b/app/src/main/java/com/limelight/binding/input/KeyboardTranslator.java index b9d47f098..2ca92830e 100644 --- a/app/src/main/java/com/limelight/binding/input/KeyboardTranslator.java +++ b/app/src/main/java/com/limelight/binding/input/KeyboardTranslator.java @@ -24,6 +24,8 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener { public static final int VK_0 = 48; public static final int VK_9 = 57; public static final int VK_A = 65; + public static final int VK_D = 68; + public static final int VK_G = 71; public static final int VK_Z = 90; public static final int VK_NUMPAD0 = 96; public static final int VK_BACK_SLASH = 92; @@ -34,6 +36,7 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener { public static final int VK_EQUALS = 61; public static final int VK_ESCAPE = 27; public static final int VK_F1 = 112; + public static final int VK_F11 = 122; public static final int VK_END = 35; public static final int VK_HOME = 36; public static final int VK_NUM_LOCK = 144; @@ -54,6 +57,8 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener { public static final int VK_BACK_QUOTE = 192; public static final int VK_QUOTE = 222; public static final int VK_PAUSE = 19; + public static final int VK_LWIN = 91; + public static final int VK_LSHIFT = 160; private static class KeyboardMapping { private final InputDevice device; @@ -225,7 +230,7 @@ else if (keycode >= KeyEvent.KEYCODE_F1 && break; case KeyEvent.KEYCODE_META_LEFT: - translated = 0x5b; + translated = VK_LWIN; break; case KeyEvent.KEYCODE_META_RIGHT: @@ -273,7 +278,7 @@ else if (keycode >= KeyEvent.KEYCODE_F1 && break; case KeyEvent.KEYCODE_SHIFT_LEFT: - translated = 0xA0; + translated = VK_LSHIFT; break; case KeyEvent.KEYCODE_SHIFT_RIGHT: From 6331160750bf57b954cc259cbabf51e0f11f842c Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Sat, 21 Jan 2023 12:49:51 +0100 Subject: [PATCH 05/13] game menu: add ctrl + v (paste) --- app/src/main/java/com/limelight/GameMenu.java | 2 ++ .../java/com/limelight/binding/input/KeyboardTranslator.java | 5 ++++- app/src/main/res/values/strings.xml | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/limelight/GameMenu.java b/app/src/main/java/com/limelight/GameMenu.java index c637d2756..dee433178 100644 --- a/app/src/main/java/com/limelight/GameMenu.java +++ b/app/src/main/java/com/limelight/GameMenu.java @@ -90,6 +90,8 @@ private void showSpecialKeysMenu() { () -> sendKeys(new short[]{KeyboardTranslator.VK_ESCAPE})), new MenuOption(getString(R.string.game_menu_send_keys_f11), () -> sendKeys(new short[]{KeyboardTranslator.VK_F11})), + new MenuOption(getString(R.string.game_menu_send_keys_ctrl_v), + () -> sendKeys(new short[]{KeyboardTranslator.VK_LCONTROL, KeyboardTranslator.VK_V})), new MenuOption(getString(R.string.game_menu_send_keys_win), () -> sendKeys(new short[]{KeyboardTranslator.VK_LWIN})), new MenuOption(getString(R.string.game_menu_send_keys_win_d), diff --git a/app/src/main/java/com/limelight/binding/input/KeyboardTranslator.java b/app/src/main/java/com/limelight/binding/input/KeyboardTranslator.java index 2ca92830e..a08aa7371 100644 --- a/app/src/main/java/com/limelight/binding/input/KeyboardTranslator.java +++ b/app/src/main/java/com/limelight/binding/input/KeyboardTranslator.java @@ -24,8 +24,10 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener { public static final int VK_0 = 48; public static final int VK_9 = 57; public static final int VK_A = 65; + public static final int VK_C = 67; public static final int VK_D = 68; public static final int VK_G = 71; + public static final int VK_V = 86; public static final int VK_Z = 90; public static final int VK_NUMPAD0 = 96; public static final int VK_BACK_SLASH = 92; @@ -59,6 +61,7 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener { public static final int VK_PAUSE = 19; public static final int VK_LWIN = 91; public static final int VK_LSHIFT = 160; + public static final int VK_LCONTROL = 162; private static class KeyboardMapping { private final InputDevice device; @@ -193,7 +196,7 @@ else if (keycode >= KeyEvent.KEYCODE_F1 && break; case KeyEvent.KEYCODE_CTRL_LEFT: - translated = 0xA2; + translated = VK_LCONTROL; break; case KeyEvent.KEYCODE_CTRL_RIGHT: diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1d0962659..273ee8226 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -138,6 +138,7 @@ Send special key(s) Send ESC (Menu) Send F11 (Toggle full screen) + Send CTRL + V (Paste clipboard) Send WIN (Toggle Windows start menu) Send WIN + D (Switch to Desktop) Send WIN + G (Open Xbox Game Bar) From d8c0908a92b0abdcb295389435868ca080e09ed0 Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Sun, 22 Jan 2023 08:20:05 +0100 Subject: [PATCH 06/13] game menu: use modifier for send keys --- app/src/main/java/com/limelight/GameMenu.java | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/limelight/GameMenu.java b/app/src/main/java/com/limelight/GameMenu.java index dee433178..474669835 100644 --- a/app/src/main/java/com/limelight/GameMenu.java +++ b/app/src/main/java/com/limelight/GameMenu.java @@ -41,9 +41,29 @@ private String getString(int id) { return game.getResources().getString(id); } + private static byte getModifier(short key) { + switch (key) { + case KeyboardTranslator.VK_LSHIFT: + return KeyboardPacket.MODIFIER_SHIFT; + case KeyboardTranslator.VK_LCONTROL: + return KeyboardPacket.MODIFIER_CTRL; + case KeyboardTranslator.VK_LWIN: + return KeyboardPacket.MODIFIER_META; + + default: + return 0; + } + } + private void sendKeys(short[] keys) { + final byte[] modifier = {(byte) 0}; + for (short key : keys) { - conn.sendKeyboardInput(key, KeyboardPacket.KEY_DOWN, (byte) 0); + conn.sendKeyboardInput(key, KeyboardPacket.KEY_DOWN, modifier[0]); + + // Apply the modifier of the pressed key, e.g. CTRL first issues a CTRL event (without + // modifier) and then sends the following keys with the CTRL modifier applied + modifier[0] |= getModifier(key); } new Handler().postDelayed((() -> { @@ -51,7 +71,10 @@ private void sendKeys(short[] keys) { for (int pos = keys.length - 1; pos >= 0; pos--) { short key = keys[pos]; - conn.sendKeyboardInput(key, KeyboardPacket.KEY_UP, (byte) 0); + // Remove the keys modifier before releasing the key + modifier[0] &= ~getModifier(key); + + conn.sendKeyboardInput(key, KeyboardPacket.KEY_UP, modifier[0]); } }), KEY_UP_DELAY); } From 7f9baa779cdfe6790bf11086541543a80a13260e Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Wed, 15 Feb 2023 07:27:36 +0100 Subject: [PATCH 07/13] game menu: add toggle keyboard and toggle mouse Changes: * Include toggle keyboard action in game menu * Add generic game input device abstraction (which can be implemented by all kind of input devices) * Show input device game menu options * Implement for controller to provide mouse emulation selection --- app/src/main/java/com/limelight/Game.java | 8 ++++- app/src/main/java/com/limelight/GameMenu.java | 31 ++++++++++++++----- .../binding/input/ControllerHandler.java | 18 +++++++++-- .../binding/input/GameInputDevice.java | 16 ++++++++++ .../java/com/limelight/ui/GameGestures.java | 4 +++ app/src/main/res/values/strings.xml | 11 ++++--- 6 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/com/limelight/binding/input/GameInputDevice.java diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index f339cd61b..420fa185a 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -4,6 +4,7 @@ import com.limelight.binding.PlatformBinding; import com.limelight.binding.audio.AndroidAudioRenderer; import com.limelight.binding.input.ControllerHandler; +import com.limelight.binding.input.GameInputDevice; import com.limelight.binding.input.KeyboardTranslator; import com.limelight.binding.input.capture.InputCaptureManager; import com.limelight.binding.input.capture.InputCaptureProvider; @@ -2294,6 +2295,11 @@ public void onUsbPermissionPromptCompleted() { updatePipAutoEnter(); } + @Override + public void showGameMenu(GameInputDevice device) { + new GameMenu(this, conn, device); + } + @Override public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { switch (keyEvent.getAction()) { @@ -2305,7 +2311,7 @@ public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { // Intercept back key event before android handles it // Always handle the request, the user has to select "Disconnect" within the game menu to actually disconnect if (keyCode == keyEvent.KEYCODE_BACK) { - new GameMenu(this, conn); + showGameMenu(null); return true; } case KeyEvent.ACTION_UP: diff --git a/app/src/main/java/com/limelight/GameMenu.java b/app/src/main/java/com/limelight/GameMenu.java index 474669835..e2da27643 100644 --- a/app/src/main/java/com/limelight/GameMenu.java +++ b/app/src/main/java/com/limelight/GameMenu.java @@ -4,10 +4,14 @@ import android.os.Handler; import android.widget.ArrayAdapter; +import com.limelight.binding.input.GameInputDevice; import com.limelight.binding.input.KeyboardTranslator; import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.input.KeyboardPacket; +import java.util.ArrayList; +import java.util.List; + /** * Provide options for ongoing Game Stream. *

@@ -17,11 +21,11 @@ public class GameMenu { private static final long KEY_UP_DELAY = 25; - private static class MenuOption { + public static class MenuOption { private final String label; private final Runnable runnable; - MenuOption(String label, Runnable runnable) { + public MenuOption(String label, Runnable runnable) { this.label = label; this.runnable = runnable; } @@ -29,10 +33,12 @@ private static class MenuOption { private final Game game; private final NvConnection conn; + private final GameInputDevice device; - public GameMenu(Game game, NvConnection conn) { + public GameMenu(Game game, NvConnection conn, GameInputDevice device) { this.game = game; this.conn = conn; + this.device = device; showMenu(); } @@ -128,10 +134,19 @@ private void showSpecialKeysMenu() { } private void showMenu() { - showMenuDialog("Game Menu", new MenuOption[]{ - new MenuOption(getString(R.string.game_menu_send_keys), () -> showSpecialKeysMenu()), - new MenuOption(getString(R.string.game_menu_disconnect), () -> game.onBackPressed()), - new MenuOption(getString(R.string.game_menu_cancel), null), - }); + List options = new ArrayList<>(); + + options.add(new MenuOption(getString(R.string.game_menu_toggle_keyboard), + () -> game.toggleKeyboard())); + + if (device != null) { + options.addAll(device.getGameMenuOptions()); + } + + options.add(new MenuOption(getString(R.string.game_menu_send_keys), () -> showSpecialKeysMenu())); + options.add(new MenuOption(getString(R.string.game_menu_disconnect), () -> game.onBackPressed())); + options.add(new MenuOption(getString(R.string.game_menu_cancel), null)); + + showMenuDialog("Game Menu", options.toArray(new MenuOption[options.size()])); } } diff --git a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java index be0f2b6c6..47e6ae1fc 100644 --- a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java +++ b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java @@ -22,7 +22,9 @@ import android.view.MotionEvent; import android.widget.Toast; +import com.limelight.GameMenu; import com.limelight.LimeLog; +import com.limelight.R; import com.limelight.binding.input.driver.AbstractController; import com.limelight.binding.input.driver.UsbDriverListener; import com.limelight.binding.input.driver.UsbDriverService; @@ -36,6 +38,8 @@ import org.cgutman.shieldcontrollerextensions.SceManager; import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; public class ControllerHandler implements InputManager.InputDeviceListener, UsbDriverListener { @@ -1521,7 +1525,7 @@ public boolean handleButtonUp(KeyEvent event) { if ((context.inputMap & ControllerPacket.PLAY_FLAG) != 0 && event.getEventTime() - context.startDownTime > ControllerHandler.START_DOWN_TIME_MOUSE_MODE_MS && prefConfig.mouseEmulation) { - context.toggleMouseEmulation(); + gestures.showGameMenu(context); } context.inputMap &= ~ControllerPacket.PLAY_FLAG; break; @@ -1868,7 +1872,7 @@ public void deviceAdded(AbstractController controller) { usbDeviceContexts.put(controller.getControllerId(), context); } - class GenericControllerContext { + class GenericControllerContext implements GameInputDevice { public int id; public boolean external; @@ -1911,6 +1915,16 @@ public void run() { } }; + @Override + public List getGameMenuOptions() { + List options = new ArrayList<>(); + options.add(new GameMenu.MenuOption(activityContext.getString(mouseEmulationActive ? + R.string.game_menu_toggle_mouse_off : R.string.game_menu_toggle_mouse_on), + () -> toggleMouseEmulation())); + + return options; + } + public void toggleMouseEmulation() { handler.removeCallbacks(mouseEmulationRunnable); mouseEmulationActive = !mouseEmulationActive; diff --git a/app/src/main/java/com/limelight/binding/input/GameInputDevice.java b/app/src/main/java/com/limelight/binding/input/GameInputDevice.java new file mode 100644 index 000000000..96df3ada0 --- /dev/null +++ b/app/src/main/java/com/limelight/binding/input/GameInputDevice.java @@ -0,0 +1,16 @@ +package com.limelight.binding.input; + +import com.limelight.GameMenu; + +import java.util.List; + +/** + * Generic Input Device + */ +public interface GameInputDevice { + + /** + * @return list of device specific game menu options, e.g. configure a controller's mouse mode + */ + List getGameMenuOptions(); +} diff --git a/app/src/main/java/com/limelight/ui/GameGestures.java b/app/src/main/java/com/limelight/ui/GameGestures.java index 74dd7b056..a4197b29b 100644 --- a/app/src/main/java/com/limelight/ui/GameGestures.java +++ b/app/src/main/java/com/limelight/ui/GameGestures.java @@ -1,5 +1,9 @@ package com.limelight.ui; +import com.limelight.binding.input.GameInputDevice; + public interface GameGestures { void toggleKeyboard(); + + void showGameMenu(GameInputDevice device); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 273ee8226..1145895e0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -133,13 +133,16 @@ App ID: + Toggle On-screen Keyboard + Enable Controller Mouse Emulation + Disable Controller Mouse Emulation Disconnect Cancel - Send special key(s) + Send special Key(s) Send ESC (Menu) - Send F11 (Toggle full screen) - Send CTRL + V (Paste clipboard) - Send WIN (Toggle Windows start menu) + Send F11 (Toggle Full Screen) + Send CTRL + V (Paste Clipboard) + Send WIN (Toggle Windows Start Menu) Send WIN + D (Switch to Desktop) Send WIN + G (Open Xbox Game Bar) Send SHIFT + TAB (Open Steam Overlay) From 96a38f5cc27fdf9c519259c4d77e20c5475d13e7 Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Wed, 15 Feb 2023 08:56:38 +0100 Subject: [PATCH 08/13] game menu: clean-up open on back navigation --- app/src/main/java/com/limelight/Game.java | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 420fa185a..7482a837a 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -1268,8 +1268,16 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { @Override public boolean handleKeyDown(KeyEvent event) { - // Pass-through virtual navigation keys + // Handle (virtual) Navigation Keys if ((event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) { + // Show Game Menu on back action instead of finishing the activity, the user has to + // select "Disconnect" within the game menu to actually disconnect + if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { + showGameMenu(null); + return true; + } + + // Pass-through other navigation keys return false; } @@ -2304,16 +2312,7 @@ public void showGameMenu(GameInputDevice device) { public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { switch (keyEvent.getAction()) { case KeyEvent.ACTION_DOWN: - boolean handled = handleKeyDown(keyEvent); - if (handled) - return true; - - // Intercept back key event before android handles it - // Always handle the request, the user has to select "Disconnect" within the game menu to actually disconnect - if (keyCode == keyEvent.KEYCODE_BACK) { - showGameMenu(null); - return true; - } + return handleKeyDown(keyEvent); case KeyEvent.ACTION_UP: return handleKeyUp(keyEvent); case KeyEvent.ACTION_MULTIPLE: From d30bc0aecc38ba0842a3d2fa6ad61e2f31293d16 Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Sun, 26 Feb 2023 19:16:25 +0100 Subject: [PATCH 09/13] game menu: fix closing on-screen keyboard --- app/src/main/java/com/limelight/Game.java | 26 ++++++++++++------- app/src/main/java/com/limelight/GameMenu.java | 2 +- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 7482a837a..c13b44696 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -1268,16 +1268,8 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { @Override public boolean handleKeyDown(KeyEvent event) { - // Handle (virtual) Navigation Keys + // Pass-through navigation keys if ((event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) { - // Show Game Menu on back action instead of finishing the activity, the user has to - // select "Disconnect" within the game menu to actually disconnect - if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { - showGameMenu(null); - return true; - } - - // Pass-through other navigation keys return false; } @@ -2321,4 +2313,20 @@ public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { return false; } } + + public void disconnect() { + super.onBackPressed(); + } + + @Override + public void onBackPressed() { + // Instead of "closing" the game activity open the game menu. The user has to select + // "Disconnect" within the game menu to actually disconnect from the remote host. + // + // Use the onBackPressed instead of the onKey function, since the onKey function + // also captures events while having the on-screen keyboard open. Using onBackPressed + // ensures that Android properly handles the back key when needed and only open the game + // menu when the activity would be closed. + showGameMenu(null); + } } diff --git a/app/src/main/java/com/limelight/GameMenu.java b/app/src/main/java/com/limelight/GameMenu.java index e2da27643..fc6640b36 100644 --- a/app/src/main/java/com/limelight/GameMenu.java +++ b/app/src/main/java/com/limelight/GameMenu.java @@ -144,7 +144,7 @@ private void showMenu() { } options.add(new MenuOption(getString(R.string.game_menu_send_keys), () -> showSpecialKeysMenu())); - options.add(new MenuOption(getString(R.string.game_menu_disconnect), () -> game.onBackPressed())); + options.add(new MenuOption(getString(R.string.game_menu_disconnect), () -> game.disconnect())); options.add(new MenuOption(getString(R.string.game_menu_cancel), null)); showMenuDialog("Game Menu", options.toArray(new MenuOption[options.size()])); From b5d055031d7129939b8d43857bcbdd6ad5e21872 Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Sun, 26 Feb 2023 19:58:42 +0100 Subject: [PATCH 10/13] game menu: add send key flags --- app/src/main/java/com/limelight/GameMenu.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/limelight/GameMenu.java b/app/src/main/java/com/limelight/GameMenu.java index fc6640b36..3374e626e 100644 --- a/app/src/main/java/com/limelight/GameMenu.java +++ b/app/src/main/java/com/limelight/GameMenu.java @@ -65,7 +65,7 @@ private void sendKeys(short[] keys) { final byte[] modifier = {(byte) 0}; for (short key : keys) { - conn.sendKeyboardInput(key, KeyboardPacket.KEY_DOWN, modifier[0]); + conn.sendKeyboardInput(key, KeyboardPacket.KEY_DOWN, modifier[0], (byte) 0); // Apply the modifier of the pressed key, e.g. CTRL first issues a CTRL event (without // modifier) and then sends the following keys with the CTRL modifier applied @@ -80,7 +80,7 @@ private void sendKeys(short[] keys) { // Remove the keys modifier before releasing the key modifier[0] &= ~getModifier(key); - conn.sendKeyboardInput(key, KeyboardPacket.KEY_UP, modifier[0]); + conn.sendKeyboardInput(key, KeyboardPacket.KEY_UP, modifier[0], (byte) 0); } }), KEY_UP_DELAY); } From 25db6aaa744dbb46524f405aa2d88db744232839 Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Tue, 28 Mar 2023 16:20:39 +0200 Subject: [PATCH 11/13] game menu: use finish to end game activity --- app/src/main/java/com/limelight/Game.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index c13b44696..b68caab79 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -2315,7 +2315,7 @@ public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { } public void disconnect() { - super.onBackPressed(); + finish(); } @Override From 84dc8341ef071c8601d1257ecd300e3080101bfc Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Tue, 28 Mar 2023 21:57:41 +0200 Subject: [PATCH 12/13] game menu: add option to run with game focus Changes: * Add withGameFocus option to game menu option to run the given runnable after alert dialog has been closed and the game has focus again. * use game focus option for on screen keyboard and toogle mouse --- app/src/main/java/com/limelight/GameMenu.java | 41 ++++++++++++++++--- .../binding/input/ControllerHandler.java | 2 +- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/limelight/GameMenu.java b/app/src/main/java/com/limelight/GameMenu.java index 3374e626e..0eeea6ffa 100644 --- a/app/src/main/java/com/limelight/GameMenu.java +++ b/app/src/main/java/com/limelight/GameMenu.java @@ -19,16 +19,23 @@ */ public class GameMenu { + private static final long TEST_GAME_FOCUS_DELAY = 10; private static final long KEY_UP_DELAY = 25; public static class MenuOption { private final String label; + private final boolean withGameFocus; private final Runnable runnable; - public MenuOption(String label, Runnable runnable) { + public MenuOption(String label, boolean withGameFocus, Runnable runnable) { this.label = label; + this.withGameFocus = withGameFocus; this.runnable = runnable; } + + public MenuOption(String label, Runnable runnable) { + this(label, false, runnable); + } } private final Game game; @@ -85,6 +92,32 @@ private void sendKeys(short[] keys) { }), KEY_UP_DELAY); } + private void runWithGameFocus(Runnable runnable) { + // Ensure that the Game activity is still active (not finished) + if (game.isFinishing()) { + return; + } + // Check if the game window has focus again, if not try again after delay + if (!game.hasWindowFocus()) { + new Handler().postDelayed(() -> runWithGameFocus(runnable), TEST_GAME_FOCUS_DELAY); + return; + } + // Game Activity has focus, run runnable + runnable.run(); + } + + private void run(MenuOption option) { + if (option.runnable == null) { + return; + } + + if (option.withGameFocus) { + runWithGameFocus(option.runnable); + } else { + option.runnable.run(); + } + } + private void showMenuDialog(String title, MenuOption[] options) { AlertDialog.Builder builder = new AlertDialog.Builder(game); builder.setTitle(title); @@ -103,9 +136,7 @@ private void showMenuDialog(String title, MenuOption[] options) { continue; } - if (option.runnable != null) { - option.runnable.run(); - } + run(option); break; } }); @@ -136,7 +167,7 @@ private void showSpecialKeysMenu() { private void showMenu() { List options = new ArrayList<>(); - options.add(new MenuOption(getString(R.string.game_menu_toggle_keyboard), + options.add(new MenuOption(getString(R.string.game_menu_toggle_keyboard), true, () -> game.toggleKeyboard())); if (device != null) { diff --git a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java index 47e6ae1fc..d933f1b30 100644 --- a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java +++ b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java @@ -1920,7 +1920,7 @@ public List getGameMenuOptions() { List options = new ArrayList<>(); options.add(new GameMenu.MenuOption(activityContext.getString(mouseEmulationActive ? R.string.game_menu_toggle_mouse_off : R.string.game_menu_toggle_mouse_on), - () -> toggleMouseEmulation())); + true, () -> toggleMouseEmulation())); return options; } From e3e438c80fa5ec12fa4df2c911caeed40d4168e6 Mon Sep 17 00:00:00 2001 From: Timothy Lusk Date: Thu, 8 Jun 2023 14:31:56 -0400 Subject: [PATCH 13/13] Allow toggling performance overlay while streaming This adds an option into the GameMenu allowing us to turn the performance overlay on/off without needing to exit and go into the settings. --- app/src/main/java/com/limelight/Game.java | 25 ++++++++++++------- app/src/main/java/com/limelight/GameMenu.java | 1 + .../video/MediaCodecDecoderRenderer.java | 2 +- .../binding/video/PerfOverlayListener.java | 1 + .../preferences/PreferenceConfiguration.java | 4 --- app/src/main/res/values-cs/strings.xml | 2 -- app/src/main/res/values-de/strings.xml | 2 -- app/src/main/res/values-el/strings.xml | 2 -- app/src/main/res/values-es/strings.xml | 2 -- app/src/main/res/values-fr/strings.xml | 2 -- app/src/main/res/values-hu/strings.xml | 2 -- app/src/main/res/values-it/strings.xml | 2 -- app/src/main/res/values-ko/strings.xml | 2 -- app/src/main/res/values-nb-rNO/strings.xml | 2 -- app/src/main/res/values-nl/strings.xml | 2 -- app/src/main/res/values-pt-rBR/strings.xml | 2 -- app/src/main/res/values-pt/strings.xml | 2 -- app/src/main/res/values-ro/strings.xml | 2 -- app/src/main/res/values-ru/strings.xml | 2 -- app/src/main/res/values-uk/strings.xml | 2 -- app/src/main/res/values-vi/strings.xml | 2 -- app/src/main/res/values-zh-rCN/strings.xml | 2 -- app/src/main/res/values-zh-rTW/strings.xml | 2 -- app/src/main/res/values/strings.xml | 3 +-- app/src/main/res/xml/preferences.xml | 5 ---- 25 files changed, 20 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index b68caab79..1d4497ecc 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -143,6 +143,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, private TextView notificationOverlayView; private int requestedNotificationOverlayVisibility = View.GONE; private TextView performanceOverlayView; + private int requestedPerformanceOverlayVisibility = View.GONE; private ShortcutHelper shortcutHelper; @@ -379,11 +380,6 @@ public boolean onCapturedPointer(View view, MotionEvent motionEvent) { } } - // Check if the user has enabled performance stats overlay - if (prefConfig.enablePerfOverlay) { - performanceOverlayView.setVisibility(View.VISIBLE); - } - decoderRenderer = new MediaCodecDecoderRenderer( this, prefConfig, @@ -631,10 +627,7 @@ public void onConfigurationChanged(Configuration newConfig) { virtualController.show(); } - if (prefConfig.enablePerfOverlay) { - performanceOverlayView.setVisibility(View.VISIBLE); - } - + performanceOverlayView.setVisibility(requestedPerformanceOverlayVisibility); notificationOverlayView.setVisibility(requestedNotificationOverlayVisibility); // Update GameManager state to indicate we're out of PiP (gaming, non-interruptible) @@ -2281,6 +2274,11 @@ public void run() { }); } + @Override + public boolean isPerfOverlayVisible() { + return requestedPerformanceOverlayVisibility == View.VISIBLE; + } + @Override public void onUsbPermissionPromptStarting() { // Disable PiP auto-enter while the USB permission prompt is on-screen. This prevents @@ -2329,4 +2327,13 @@ public void onBackPressed() { // menu when the activity would be closed. showGameMenu(null); } + + public void togglePerformanceOverlay() { + if (requestedPerformanceOverlayVisibility == View.VISIBLE) { + requestedPerformanceOverlayVisibility = View.GONE; + } else { + requestedPerformanceOverlayVisibility = View.VISIBLE; + } + performanceOverlayView.setVisibility(requestedPerformanceOverlayVisibility); + } } diff --git a/app/src/main/java/com/limelight/GameMenu.java b/app/src/main/java/com/limelight/GameMenu.java index 0eeea6ffa..6d5019912 100644 --- a/app/src/main/java/com/limelight/GameMenu.java +++ b/app/src/main/java/com/limelight/GameMenu.java @@ -174,6 +174,7 @@ private void showMenu() { options.addAll(device.getGameMenuOptions()); } + options.add(new MenuOption(getString(R.string.game_menu_toggle_performance_overlay), () -> game.togglePerformanceOverlay())); options.add(new MenuOption(getString(R.string.game_menu_send_keys), () -> showSpecialKeysMenu())); options.add(new MenuOption(getString(R.string.game_menu_disconnect), () -> game.disconnect())); options.add(new MenuOption(getString(R.string.game_menu_cancel), null)); diff --git a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java index 74e47f509..d363a50a0 100644 --- a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java +++ b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java @@ -1305,7 +1305,7 @@ public int submitDecodeUnit(byte[] decodeUnitData, int decodeUnitLength, int dec // Flip stats windows roughly every second if (SystemClock.uptimeMillis() >= activeWindowVideoStats.measurementStartTimestamp + 1000) { - if (prefs.enablePerfOverlay) { + if (perfListener.isPerfOverlayVisible()) { VideoStats lastTwo = new VideoStats(); lastTwo.add(lastWindowVideoStats); lastTwo.add(activeWindowVideoStats); diff --git a/app/src/main/java/com/limelight/binding/video/PerfOverlayListener.java b/app/src/main/java/com/limelight/binding/video/PerfOverlayListener.java index 281f95a04..c4ae6d953 100644 --- a/app/src/main/java/com/limelight/binding/video/PerfOverlayListener.java +++ b/app/src/main/java/com/limelight/binding/video/PerfOverlayListener.java @@ -2,4 +2,5 @@ public interface PerfOverlayListener { void onPerfUpdate(final String text); + boolean isPerfOverlayVisible(); } diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java index 36c26483b..bfe37ebdf 100644 --- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java +++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java @@ -34,7 +34,6 @@ public class PreferenceConfiguration { private static final String LEGACY_DISABLE_FRAME_DROP_PREF_STRING = "checkbox_disable_frame_drop"; private static final String ENABLE_HDR_PREF_STRING = "checkbox_enable_hdr"; private static final String ENABLE_PIP_PREF_STRING = "checkbox_enable_pip"; - private static final String ENABLE_PERF_OVERLAY_STRING = "checkbox_enable_perf_overlay"; private static final String BIND_ALL_USB_STRING = "checkbox_usb_bind_all"; private static final String MOUSE_EMULATION_STRING = "checkbox_mouse_emulation"; private static final String MOUSE_NAV_BUTTONS_STRING = "checkbox_mouse_nav_buttons"; @@ -66,7 +65,6 @@ public class PreferenceConfiguration { private static final boolean ONLY_L3_R3_DEFAULT = false; private static final boolean DEFAULT_ENABLE_HDR = false; private static final boolean DEFAULT_ENABLE_PIP = false; - private static final boolean DEFAULT_ENABLE_PERF_OVERLAY = false; private static final boolean DEFAULT_BIND_ALL_USB = false; private static final boolean DEFAULT_MOUSE_EMULATION = true; private static final boolean DEFAULT_MOUSE_NAV_BUTTONS = false; @@ -112,7 +110,6 @@ public class PreferenceConfiguration { public boolean onlyL3R3; public boolean enableHdr; public boolean enablePip; - public boolean enablePerfOverlay; public boolean enableLatencyToast; public boolean bindAllUsb; public boolean mouseEmulation; @@ -496,7 +493,6 @@ else if (audioConfig.equals("51")) { config.onlyL3R3 = prefs.getBoolean(ONLY_L3_R3_PREF_STRING, ONLY_L3_R3_DEFAULT); config.enableHdr = prefs.getBoolean(ENABLE_HDR_PREF_STRING, DEFAULT_ENABLE_HDR) && !isShieldAtvFirmwareWithBrokenHdr(); config.enablePip = prefs.getBoolean(ENABLE_PIP_PREF_STRING, DEFAULT_ENABLE_PIP); - config.enablePerfOverlay = prefs.getBoolean(ENABLE_PERF_OVERLAY_STRING, DEFAULT_ENABLE_PERF_OVERLAY); config.bindAllUsb = prefs.getBoolean(BIND_ALL_USB_STRING, DEFAULT_BIND_ALL_USB); config.mouseEmulation = prefs.getBoolean(MOUSE_EMULATION_STRING, DEFAULT_MOUSE_EMULATION); config.mouseNavButtons = prefs.getBoolean(MOUSE_NAV_BUTTONS_STRING, DEFAULT_MOUSE_NAV_BUTTONS); diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 354685fc6..be77603f3 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -90,8 +90,6 @@ Nápověda Zakáže varování o pomalém připojení během streamování Nezahazovat snímky - Zobrazit během streamování informace o výkonu - Zobrazit realtime informace o výkonu streamu během streamování 4K 30 FPS Průvodce řešením problémů diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 290377c24..8eae34faa 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -195,8 +195,6 @@ HEVC verringert die Video-Bandbreitenanforderung, funktioniert allerdings nur auf sehr neuen Geräten HDR aktivieren (experimentell) HDR-Streaming sofern dies von der Host-GPU unterstützt wird. HDR erfordert eine GPU der GTX 1000 Serie oder neuer. - Performance Overlay aktivieren - Leistungsmerkmale während des Streamens in Echtzeit einblenden Zeige Latenz-Informationen nach dem Streaming Anzeige einer Informationsmeldung über die Latenz nach dem Ende des Streams Nativ diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 1629869db..fe0dd890a 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -44,7 +44,6 @@ Αποτυχία διακοπής Είστε σίγουροι ότι θέλετε να τερματίσετε την τρέχουσα εφαρμογή; Όλα τα μη αποθηκευμένα δεδομένα θα χαθούν. Είστε βέβαιοι ότι θέλετε να διαγράψετε την αποθηκευμένη διάταξη στοιχείων ελέγχου στην οθόνη; - Εμφάνιση στατιστικών στοιχείων απόδοσης κατά τη ροή Η συσκευή δεν είχε συζευξηθεί Ο υπολογιστής είναι εκτός σύνδεσης Αποτυχία επίλυσης ονόματος κεντρικού υπολογιστή @@ -130,7 +129,6 @@ Μπορεί να μειώσει το micro-stuttering σε ορισμένες συσκευές, αλλά μπορεί να αυξήσει την καθυστέρηση Ενεργοποίηση HDR (πειραματικό) Μεταδώστε HDR όταν το παιχνίδι και η GPU του υπολογιστή το υποστηρίζουν. Το HDR απαιτεί GPU της σειράς GTX 1000 ή νεότερη. - Εμφάνιση πληροφοριών απόδοσης ροής σε πραγματικό χρόνο κατά τη ροή Εμφάνιση ενός μηνύματος πληροφοριών καθυστέρησης μετά το τέλος της ροής Ο υπολογιστής διαγράφηκε Ο υπολογιστής δεν βρέθηκε diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 11e8a27c6..5b80099c9 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -209,7 +209,6 @@ Activar los botones atrás y adelante del ratón Desbloquear todas las opciones de tasa de cuadros disponibles Transmitir a 90 o 120 FPS puede reducir latencia en dispositivos de gama alta pero puede causar retrasos en dispositivos que no lo soporten - Mostrar estadísticas de rendimiento mientras la transmisión está activa Mostrar un mensaje sobre la información de latencia cuando la transmisión termine Ayuda ¿Estás seguro de eliminar este PC\? @@ -243,7 +242,6 @@ Puede reducir micro-tartamudeos (Stuttering) en algunos dispositivos , pero puede incrementar latencia Activar HDR (Alto Rango Dinámico / Experimental) Transmite en HDR cuando el juego y la GPU del PC lo admitan. HDR requiere una GPU compatible con la codificación HEVC Main 10. - Mostrar en tiempo real la información del desempeño de la transmisión mientras está activa la misma Mostrar mensajes sobre latencia mientras se transmite Ayuda Guía para la Configuración diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 440d2f78b..6dc1843b7 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -189,8 +189,6 @@ HEVC réduit les besoins en bande passante vidéo mais nécessite un périphérique très récent Activer le HDR (expérimental) Diffuser du HDR lorsque le jeu et le processeur graphique du PC le prennent en charge. HDR nécessite un GPU série GTX 1000 ou une version ultérieure. - Activer la superposition de performance - Afficher une superposition à l\'écran avec des informations de performance en temps réel pendant la lecture en continu Afficher le message de latence après la diffusion en continu Afficher un message d’informations de latence après la fin du flux Aucune vidéo reçue depuis l\'hôte. diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 2db34e5e6..4126b2a00 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -2,8 +2,6 @@ Késleltetési információs üzenet megjelenítése az adatfolyam vége után A késleltetési üzenet megjelenítése streaming után - Valós idejű adatfolyam-adat megjelenítése streaming közben - Teljesítmény statisztikák megjelenítése közvetítés közben Streaming HDR, amikor a játék és a PC GPU támogatja. A HDR-hez GTX 1000 sorozatú vagy újabb verzió szükséges. HDR engedélyezése (kísérleti) A HEVC csökkenti a video sávszélesség követelményeit, de újabb eszközt igényel diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 529b2c6df..519e4a21a 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -213,7 +213,6 @@ Non usare mai HEVC Bilanciamento frame video Specifica come bilanciare il ritardo video e la fluidità - Mostra informazioni real time sulla trasmissione Sembra che l\'attuale connessione di rete del tuo dispositivo stia bloccando Moonlight. Trasmettere via Internet potrebbe non funzionare mentre sei connesso a questa rete. \n \nQueste porte di rete sono bloccate: @@ -222,7 +221,6 @@ Il tuo launcher non permette la creazione di scorciatoie appuntate. Il decoder video non è riuscito ad inizializzarsi. Il tuo dispositivo potrebbe non supportare la risoluzione o il frame rate selezionati. Controlla il tuo firewall e le regole di inoltro delle seguenti porte: - Mostra le statistiche delle performance durante la trasmissione Mostra un messaggio sulla latenza dopo la trasmissione La tua connessione di rete non sta funzionando bene. Riduci il bitrate video o prova ad usare una connessione più veloce. Qualcosa è andato storto sul PC sorgente mentre la trasmissione veniva avviata. diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 25893f874..11cbfdc2d 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -188,8 +188,6 @@ 앱을 사용할 수 없음 스트림 종료 후 지연시간 정보 표시 스트리밍 후 지연시간 정보 표시 - 스트리밍 중 성능 정보 표시 - 스트리밍하는 동안 실시간 스트림 성능 정보 표시 게임 및 PC의 GPU가 HDR을 지원하는 경우 HDR을 활성화합니다. HDR에는 GTX 1000 시리즈 또는 그 이상의 GPU가 필요합니다. HDR활성화 (실험용) 일부 장치에서 미세한 끊김 현상을 줄일 수 있지만 지연 시간이 늘어날 수 있습니다. diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 730c4ee42..c8f736911 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -143,8 +143,6 @@ \nFølgende nettverksporter ble blokkert: \n Nettverkstesten kunne ikke utføres fordi ingen av Moonlight sine tilkoblingstesttjenere kunne nås. Sjekk din tilkobling til Internett og prøv igjen senere. - Viser ytelsesinfo i sanntid under strømming - Vis ytelsesstatistikk under strømming Strøm HDR når spillet og PC-ens skjermkort støtter det. HDR krever GTX 1000-eller nyere. Tillater strømmen å vises (men ikke kontrolleres) under fleroppgaveløsning Skru på bilde-i-bilde-observatørmodus diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index cb8060864..409159cbd 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -174,7 +174,6 @@ Kan micro-stotteren op sommige toestellen verminderen, maar kan vertraging verhogen HDR Inschakelen (Experimenteel) Stream HDR als het spel en de GPU van de PC dit ondersteund. HDR vereist een GTX 1000-reeks GPU of later. - Prestatiestatistieken tonen tijdens het streamen Details Bent u zeker dat u deze PC wilt verwijderen\? Oorspronkelijk Volledig Scherm @@ -201,7 +200,6 @@ Wanneer ingeschakeld functioneert het touchscreen als een trackpad. Wanneer uitgeschakeld bedient het touchscreen rechtstreeks de muiscursor. Gebruik Moonlight\'s USB driver voor alle ondersteunde gamepads, zelfs als een standaard Xbox controller aanwezig is Bent u zeker dat u uw opgeslagen on-screen controle-elementen wilt verwijderen\? - Real-time prestatie-informatie tonen tijdens het streamen Simuleer rumble-ondersteuning met trillingen Deze optie inschakelen kan problemen veroorzaken met rechts-klikken op sommige buggy apparaten Laat uw apparaat trillen om gerommel te simuleren als uw gamepad dit niet ondersteund diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 3cfabff84..04e602849 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -226,8 +226,6 @@ Talvez reduza o micro-stuttering em alguns dispositivos, mas pode aumentar a latência Habilitar HDR (Experimental) Mostrar aviso de latência após terminar a transmissão - Exibe informações de performance em tempo real durante a transmissão - Mostrar status de performance durante a transmissão Ajuda Guia de solução de problemas Guia de configuração diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index ab115d724..78e930678 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -117,7 +117,6 @@ Ativar HDR (Experimental) Isso causará perda de detalhes em áreas claras e escuras se o seu aparelho não exibir corretamente todo o conteúdo de vídeo em cores. Nunca dropar quadros - Exibe informações de performance em tempo real durante a transmissão Mostrar aviso de latência após terminar a transmissão Guia de solução de problemas Veja dicas para diagnosticar e corrigir problemas comuns de streaming @@ -209,7 +208,6 @@ Desativar mensagens de alerta Mudar configurações do HEVC Transmita HDR quando o jogo e a GPU do PC suportarem. O HDR requer uma GPU da série GTX 1000 ou posterior. - Mostrar status de performance durante a transmissão Teste de Internet Completo O teste de rede não pôde ser executado porque nenhum dos servidores de teste de conexão do Moonlight estava acessível. Verifique a sua conexão com a Internet ou tente novamente mais tarde. A parear… diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 398d63063..16e90e76e 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -188,8 +188,6 @@ HEVC funcționează cu o conexiune mai slaba, dar necesită un dispozitiv recent, performant Activează HDR (Experimental) Folosește HDR daca aplicația si placa video suportă. Necesită o placa video seria GTX 1000 sau mai nouă. - Activează statisticile de performanță - Afișează în timp real statisticile de performanță ale conexiunii. Stereo diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index f091faa58..3e81c0ce0 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -162,7 +162,6 @@ Детали Слабое соединение с PC Детали - Включить отображение статистики Разблокировать все возможные частоты обновления ID приложения: Эмуляция виброотдачи @@ -174,7 +173,6 @@ Включить кнопки вперед и назад для мыши Медленное подключение к PC\nУменьшите битрейт Трансляция со скоростью 90 или 120 кадров в секунду может уменьшить задержку на устройствах высокого класса, но может вызвать задержки или сбой на устройствах без поддержки этого функционала - Отображение оверлея на экране с информацией о производительности во время трансляции в режиме реального времени Декодер: %1$s Входящая частота кадров из сети: %1$.2f FPS Частота кадров при рендеринге: %1$.2f FPS diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index b06d44de7..42954cfdd 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -146,7 +146,6 @@ Деталі Слабке з\'єднання з пристроєм Деталі - Увімкнути відображення статистики Розблокувати всі можливі частоти кадрів ID застосунку: Емуляція вібровіддачі @@ -161,7 +160,6 @@ Повільне підключення \nЗменшіть швидкість потоку Трансляція зі швидкістю 90 або 120 кадрів на секунду може зменшити затримку на швидких пристроях але, може викликати затримки або збої на слабших - Відображає статистику продуктивності під час трансляції, в режимі реального часу Розцифрувач: %1$s Вхідна частота кадрів з мережі: %1$.2f FPS Частота кадрів при відтворенні: %1$.2f FPS diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 8461aaf44..23390e61f 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -2,8 +2,6 @@ Hiển thị một thông báo thông tin độ trễ sau khi kết thúc stream Hiện thông báo độ trễ sau khi stream - Hiển thị thông tin hiệu năng stream theo thời gian thực trong khi stream - Hiện thống kê hiệu năng trong khi stream Stream HDR khi trò chơi và GPU của PC hỗ trợ nó. HDR yêu cầu GPU GTX series 1000 hoặc mới hơn. Bật HDR (Thử nghiệm) HEVC làm giảm yêu cầu băng thông video nhưng yêu cầu một thiết bị mới hơn diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 5e535f6fd..e0500b784 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -169,8 +169,6 @@ HEVC能降低视频带宽需求,但需要较新的设备才能支持 启用 HDR (实验性) 当游戏和显卡支持时以HDR模式串流。 HDR需要显卡支持 HEVC Main 10 编码。 - 启用性能信息 - 在串流中显示实时性能信息 串流完毕显示延迟信息 串流结束后显示延迟信息 更改屏幕按钮透明度 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index d341a5811..a5ad4ff16 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -170,8 +170,6 @@ HEVC 能降低視訊頻寬需求,但需要較新的裝置才能支援 啟用 HDR (實驗性) 在遊戲和 GPU 支援時以 HDR 模式串流,HDR 模式需要支援 HEVC Main 10 編碼的 GPU。 - 串流時顯示效能資訊 - 在串流中顯示即時效能資訊 串流後顯示延時資訊 串流結束後顯示延時資訊 變更螢幕控制按鈕透明度 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1145895e0..a97930648 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -134,6 +134,7 @@ Toggle On-screen Keyboard + Toggle Performance Overlay Enable Controller Mouse Emulation Disable Controller Mouse Emulation Disconnect @@ -248,8 +249,6 @@ Stream HDR when the game and PC GPU support it. HDR requires a GPU with HEVC Main 10 encoding support. Force full range video (Experimental) This will cause loss of detail in light and dark areas if your device doesn\'t properly display full range video content. - Show performance stats while streaming - Display real-time stream performance information while streaming Show latency message after streaming Display a latency information message after the stream ends diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 7c1becf86..d540e9a45 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -216,11 +216,6 @@ android:title="@string/title_full_range" android:summary="@string/summary_full_range" android:defaultValue="false" /> -