forked from moonlight-stream/moonlight-android
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Custom Resolution - Absolute Touch (Tablet Mode) - Game Menu - And a few custom send special keys command
- Loading branch information
1 parent
f54f8c8
commit 0ec169c
Showing
18 changed files
with
670 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
|
||
package com.limelight; | ||
|
||
import android.app.AlertDialog; | ||
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; | ||
|
||
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, 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; | ||
private final NvConnection conn; | ||
private final GameInputDevice device; | ||
|
||
public GameMenu(Game game, NvConnection conn, GameInputDevice device) { | ||
this.game = game; | ||
this.conn = conn; | ||
this.device = device; | ||
|
||
showMenu(); | ||
} | ||
|
||
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, 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 | ||
modifier[0] |= getModifier(key); | ||
} | ||
|
||
new Handler().postDelayed((() -> { | ||
|
||
for (int pos = keys.length - 1; pos >= 0; pos--) { | ||
short key = keys[pos]; | ||
|
||
// Remove the keys modifier before releasing the key | ||
modifier[0] &= ~getModifier(key); | ||
|
||
conn.sendKeyboardInput(key, KeyboardPacket.KEY_UP, modifier[0], (byte) 0); | ||
} | ||
}), 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); | ||
|
||
final ArrayAdapter<String> actions = | ||
new ArrayAdapter<String>(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; | ||
} | ||
|
||
run(option); | ||
|
||
break; | ||
} | ||
}); | ||
|
||
builder.show(); | ||
} | ||
|
||
private void showSpecialKeysMenu() { | ||
showMenuDialog(getString(R.string.game_menu_send_keys), new MenuOption[]{ | ||
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_f11_alt), | ||
() -> sendKeys(new short[]{KeyboardTranslator.VK_MENU, KeyboardTranslator.VK_RETURN})), | ||
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_send_keys_insert), | ||
() -> sendKeys(new short[]{KeyboardTranslator.VK_INSERT})), | ||
new MenuOption(getString(R.string.game_menu_send_move_window), | ||
() -> sendKeys(new short[]{KeyboardTranslator.VK_LSHIFT, KeyboardTranslator.VK_LWIN, KeyboardTranslator.VK_RIGHT})), | ||
new MenuOption(getString(R.string.game_menu_cancel), null), | ||
}); | ||
} | ||
|
||
private void showMenu() { | ||
List<MenuOption> options = new ArrayList<>(); | ||
|
||
options.add(new MenuOption(getString(R.string.game_menu_toggle_keyboard), true, | ||
() -> game.toggleKeyboard())); | ||
if (device != null) { | ||
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)); | ||
|
||
showMenuDialog("Game Menu", options.toArray(new MenuOption[options.size()])); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
app/src/main/java/com/limelight/binding/input/GameInputDevice.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<GameMenu.MenuOption> getGameMenuOptions(); | ||
} |
Oops, something went wrong.