diff --git a/app/src/cli.c b/app/src/cli.c index 9c791fbf..64d1a2c9 100644 --- a/app/src/cli.c +++ b/app/src/cli.c @@ -651,6 +651,7 @@ guess_record_format(const char *filename) { #define OPT_DISABLE_SCREENSAVER 1020 #define OPT_SHORTCUT_MOD 1021 #define OPT_NO_KEY_REPEAT 1022 +#define OPT_USE_ADB_KEYBOARD 1026 bool scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) { @@ -688,6 +689,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) { {"show-touches", no_argument, NULL, 't'}, {"stay-awake", no_argument, NULL, 'w'}, {"turn-screen-off", no_argument, NULL, 'S'}, + {"use-adb-keyboard", no_argument, NULL, OPT_USE_ADB_KEYBOARD}, {"verbosity", required_argument, NULL, 'V'}, {"version", no_argument, NULL, 'v'}, {"window-title", required_argument, NULL, OPT_WINDOW_TITLE}, @@ -773,6 +775,9 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) { case 'S': opts->turn_screen_off = true; break; + case OPT_USE_ADB_KEYBOARD: + opts->use_adb_keyboard = true; + break; case 't': opts->show_touches = true; break; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 45068cbb..d5279871 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -319,6 +319,7 @@ scrcpy(const struct scrcpy_options *options) { .stay_awake = options->stay_awake, .codec_options = options->codec_options, .force_adb_forward = options->force_adb_forward, + .use_adb_keyboard = options->use_adb_keyboard, }; if (!server_start(&server, options->serial, ¶ms)) { return false; diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index 86a2b57b..5c5fedef 100644 --- a/app/src/scrcpy.h +++ b/app/src/scrcpy.h @@ -79,6 +79,7 @@ struct scrcpy_options { bool force_adb_forward; bool disable_screensaver; bool forward_key_repeat; + bool use_adb_keyboard; }; #define SCRCPY_OPTIONS_DEFAULT { \ @@ -123,6 +124,7 @@ struct scrcpy_options { .force_adb_forward = false, \ .disable_screensaver = false, \ .forward_key_repeat = true, \ + .use_adb_keyboard = false, \ } bool diff --git a/app/src/server.c b/app/src/server.c index 05b2cf91..3d21234e 100644 --- a/app/src/server.c +++ b/app/src/server.c @@ -294,6 +294,7 @@ execute_server(struct server *server, const struct server_params *params) { params->show_touches ? "true" : "false", params->stay_awake ? "true" : "false", params->codec_options ? params->codec_options : "-", + params->use_adb_keyboard ? "true" : "false", }; #ifdef SERVER_DEBUGGER LOGI("Server debugger waiting for a client on device port " diff --git a/app/src/server.h b/app/src/server.h index 254afe30..22ef76fe 100644 --- a/app/src/server.h +++ b/app/src/server.h @@ -58,6 +58,7 @@ struct server_params { bool show_touches; bool stay_awake; bool force_adb_forward; + bool use_adb_keyboard; }; // init default values diff --git a/server/src/main/java/com/genymobile/scrcpy/Controller.java b/server/src/main/java/com/genymobile/scrcpy/Controller.java index 9100a9db..fc96358e 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/Controller.java @@ -20,6 +20,7 @@ public class Controller { private final Device device; private final DesktopConnection connection; + private final Options options; private final DeviceMessageSender sender; private final KeyCharacterMap charMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); @@ -31,9 +32,10 @@ public class Controller { private boolean keepPowerModeOff; - public Controller(Device device, DesktopConnection connection) { + public Controller(Device device, DesktopConnection connection, Options options) { this.device = device; this.connection = connection; + this.options = options; initPointers(); sender = new DeviceMessageSender(connection); } @@ -145,18 +147,28 @@ public class Controller { } private boolean injectChar(char c) { - String decomposed = KeyComposition.decompose(c); - char[] chars = decomposed != null ? decomposed.toCharArray() : new char[]{c}; - KeyEvent[] events = charMap.getEvents(chars); - if (events == null) { - return false; - } - for (KeyEvent event : events) { - if (!device.injectEvent(event)) { + if (options.useADBKeyboard()) { + // Process latin keys the same way in order to provide same reaction speed. + try { + Process process = Runtime.getRuntime().exec("am broadcast -a ADB_INPUT_CHARS --eia chars " + String.valueOf((int) c)); + return process.waitFor() == 0; + } catch (Throwable throwable) { return false; } + } else { + String decomposed = KeyComposition.decompose(c); + char[] chars = decomposed != null ? decomposed.toCharArray() : new char[]{c}; + KeyEvent[] events = charMap.getEvents(chars); + if (events == null) { + return false; + } + for (KeyEvent event : events) { + if (!device.injectEvent(event)) { + return false; + } + } + return true; } - return true; } private int injectText(String text) { diff --git a/server/src/main/java/com/genymobile/scrcpy/Options.java b/server/src/main/java/com/genymobile/scrcpy/Options.java index 06312a37..bdeccd30 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Options.java +++ b/server/src/main/java/com/genymobile/scrcpy/Options.java @@ -16,6 +16,7 @@ public class Options { private boolean showTouches; private boolean stayAwake; private String codecOptions; + private boolean useADBKeyboard; public Ln.Level getLogLevel() { return logLevel; @@ -120,4 +121,12 @@ public class Options { public void setCodecOptions(String codecOptions) { this.codecOptions = codecOptions; } + + public boolean useADBKeyboard() { + return useADBKeyboard; + } + + public void setUseADBKeyboard(boolean useADBKeyboard) { + this.useADBKeyboard = useADBKeyboard; + } } diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index d257e319..c95565ba 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -57,7 +57,7 @@ public final class Server { ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions); if (options.getControl()) { - final Controller controller = new Controller(device, connection); + final Controller controller = new Controller(device, connection, options); // asynchronous startController(controller); @@ -120,7 +120,7 @@ public final class Server { "The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")"); } - final int expectedParameters = 14; + final int expectedParameters = 15; if (args.length != expectedParameters) { throw new IllegalArgumentException("Expecting " + expectedParameters + " parameters"); } @@ -167,6 +167,9 @@ public final class Server { String codecOptions = args[13]; options.setCodecOptions(codecOptions); + boolean useADBKeyboard = Boolean.parseBoolean(args[14]); + options.setUseADBKeyboard(useADBKeyboard); + return options; }