Compare commits
3 Commits
custom-ffm
...
adbkeyboar
Author | SHA1 | Date | |
---|---|---|---|
cd860bff81 | |||
160ae02b93 | |||
e970b4bda3 |
@ -668,6 +668,7 @@ guess_record_format(const char *filename) {
|
|||||||
#define OPT_FORWARD_ALL_CLICKS 1023
|
#define OPT_FORWARD_ALL_CLICKS 1023
|
||||||
#define OPT_LEGACY_PASTE 1024
|
#define OPT_LEGACY_PASTE 1024
|
||||||
#define OPT_ENCODER_NAME 1025
|
#define OPT_ENCODER_NAME 1025
|
||||||
|
#define OPT_USE_ADB_KEYBOARD 1026
|
||||||
|
|
||||||
bool
|
bool
|
||||||
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
||||||
@ -709,6 +710,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||||||
{"show-touches", no_argument, NULL, 't'},
|
{"show-touches", no_argument, NULL, 't'},
|
||||||
{"stay-awake", no_argument, NULL, 'w'},
|
{"stay-awake", no_argument, NULL, 'w'},
|
||||||
{"turn-screen-off", no_argument, NULL, 'S'},
|
{"turn-screen-off", no_argument, NULL, 'S'},
|
||||||
|
{"use-adb-keyboard", no_argument, NULL, OPT_USE_ADB_KEYBOARD},
|
||||||
{"verbosity", required_argument, NULL, 'V'},
|
{"verbosity", required_argument, NULL, 'V'},
|
||||||
{"version", no_argument, NULL, 'v'},
|
{"version", no_argument, NULL, 'v'},
|
||||||
{"window-title", required_argument, NULL, OPT_WINDOW_TITLE},
|
{"window-title", required_argument, NULL, OPT_WINDOW_TITLE},
|
||||||
@ -794,6 +796,9 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||||||
case 'S':
|
case 'S':
|
||||||
opts->turn_screen_off = true;
|
opts->turn_screen_off = true;
|
||||||
break;
|
break;
|
||||||
|
case OPT_USE_ADB_KEYBOARD:
|
||||||
|
opts->use_adb_keyboard = true;
|
||||||
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
opts->show_touches = true;
|
opts->show_touches = true;
|
||||||
break;
|
break;
|
||||||
|
@ -320,6 +320,7 @@ scrcpy(const struct scrcpy_options *options) {
|
|||||||
.codec_options = options->codec_options,
|
.codec_options = options->codec_options,
|
||||||
.encoder_name = options->encoder_name,
|
.encoder_name = options->encoder_name,
|
||||||
.force_adb_forward = options->force_adb_forward,
|
.force_adb_forward = options->force_adb_forward,
|
||||||
|
.use_adb_keyboard = options->use_adb_keyboard,
|
||||||
};
|
};
|
||||||
if (!server_start(&server, options->serial, ¶ms)) {
|
if (!server_start(&server, options->serial, ¶ms)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -82,6 +82,7 @@ struct scrcpy_options {
|
|||||||
bool forward_key_repeat;
|
bool forward_key_repeat;
|
||||||
bool forward_all_clicks;
|
bool forward_all_clicks;
|
||||||
bool legacy_paste;
|
bool legacy_paste;
|
||||||
|
bool use_adb_keyboard;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SCRCPY_OPTIONS_DEFAULT { \
|
#define SCRCPY_OPTIONS_DEFAULT { \
|
||||||
@ -129,6 +130,7 @@ struct scrcpy_options {
|
|||||||
.forward_key_repeat = true, \
|
.forward_key_repeat = true, \
|
||||||
.forward_all_clicks = false, \
|
.forward_all_clicks = false, \
|
||||||
.legacy_paste = false, \
|
.legacy_paste = false, \
|
||||||
|
.use_adb_keyboard = false, \
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -295,6 +295,7 @@ execute_server(struct server *server, const struct server_params *params) {
|
|||||||
params->stay_awake ? "true" : "false",
|
params->stay_awake ? "true" : "false",
|
||||||
params->codec_options ? params->codec_options : "-",
|
params->codec_options ? params->codec_options : "-",
|
||||||
params->encoder_name ? params->encoder_name : "-",
|
params->encoder_name ? params->encoder_name : "-",
|
||||||
|
params->use_adb_keyboard ? "true" : "false",
|
||||||
};
|
};
|
||||||
#ifdef SERVER_DEBUGGER
|
#ifdef SERVER_DEBUGGER
|
||||||
LOGI("Server debugger waiting for a client on device port "
|
LOGI("Server debugger waiting for a client on device port "
|
||||||
|
@ -59,6 +59,7 @@ struct server_params {
|
|||||||
bool show_touches;
|
bool show_touches;
|
||||||
bool stay_awake;
|
bool stay_awake;
|
||||||
bool force_adb_forward;
|
bool force_adb_forward;
|
||||||
|
bool use_adb_keyboard;
|
||||||
};
|
};
|
||||||
|
|
||||||
// init default values
|
// init default values
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.genymobile.scrcpy;
|
package com.genymobile.scrcpy;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
@ -20,6 +21,7 @@ public class Controller {
|
|||||||
|
|
||||||
private final Device device;
|
private final Device device;
|
||||||
private final DesktopConnection connection;
|
private final DesktopConnection connection;
|
||||||
|
private final Options options;
|
||||||
private final DeviceMessageSender sender;
|
private final DeviceMessageSender sender;
|
||||||
|
|
||||||
private final KeyCharacterMap charMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
|
private final KeyCharacterMap charMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
|
||||||
@ -31,9 +33,10 @@ public class Controller {
|
|||||||
|
|
||||||
private boolean keepPowerModeOff;
|
private boolean keepPowerModeOff;
|
||||||
|
|
||||||
public Controller(Device device, DesktopConnection connection) {
|
public Controller(Device device, DesktopConnection connection, Options options) {
|
||||||
this.device = device;
|
this.device = device;
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
|
this.options = options;
|
||||||
initPointers();
|
initPointers();
|
||||||
sender = new DeviceMessageSender(connection);
|
sender = new DeviceMessageSender(connection);
|
||||||
}
|
}
|
||||||
@ -160,8 +163,20 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int injectText(String text) {
|
private int injectText(String text) {
|
||||||
|
char[] chars = text.toCharArray();
|
||||||
|
if (options.useADBKeyboard()) {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setAction("ADB_INPUT_CHARS");
|
||||||
|
int[] intChars = new int[chars.length];
|
||||||
|
for (int i = 0; i < chars.length; ++i) {
|
||||||
|
intChars[i] = chars[i];
|
||||||
|
}
|
||||||
|
intent.putExtra("chars", intChars);
|
||||||
|
device.sendBroadcast(intent);
|
||||||
|
return chars.length;
|
||||||
|
}
|
||||||
int successCount = 0;
|
int successCount = 0;
|
||||||
for (char c : text.toCharArray()) {
|
for (char c : chars) {
|
||||||
if (!injectChar(c)) {
|
if (!injectChar(c)) {
|
||||||
Ln.w("Could not inject char u+" + String.format("%04x", (int) c));
|
Ln.w("Could not inject char u+" + String.format("%04x", (int) c));
|
||||||
continue;
|
continue;
|
||||||
|
@ -8,6 +8,7 @@ import com.genymobile.scrcpy.wrappers.SurfaceControl;
|
|||||||
import com.genymobile.scrcpy.wrappers.WindowManager;
|
import com.genymobile.scrcpy.wrappers.WindowManager;
|
||||||
|
|
||||||
import android.content.IOnPrimaryClipChangedListener;
|
import android.content.IOnPrimaryClipChangedListener;
|
||||||
|
import android.content.Intent;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
@ -273,4 +274,8 @@ public final class Device {
|
|||||||
public static ContentProvider createSettingsProvider() {
|
public static ContentProvider createSettingsProvider() {
|
||||||
return SERVICE_MANAGER.getActivityManager().createSettingsProvider();
|
return SERVICE_MANAGER.getActivityManager().createSettingsProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendBroadcast(Intent intent) {
|
||||||
|
SERVICE_MANAGER.getActivityManager().sendBroadcast(intent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ public class Options {
|
|||||||
private boolean stayAwake;
|
private boolean stayAwake;
|
||||||
private String codecOptions;
|
private String codecOptions;
|
||||||
private String encoderName;
|
private String encoderName;
|
||||||
|
private boolean useADBKeyboard;
|
||||||
|
|
||||||
public Ln.Level getLogLevel() {
|
public Ln.Level getLogLevel() {
|
||||||
return logLevel;
|
return logLevel;
|
||||||
@ -129,4 +130,12 @@ public class Options {
|
|||||||
public void setEncoderName(String encoderName) {
|
public void setEncoderName(String encoderName) {
|
||||||
this.encoderName = encoderName;
|
this.encoderName = encoderName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean useADBKeyboard() {
|
||||||
|
return useADBKeyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseADBKeyboard(boolean useADBKeyboard) {
|
||||||
|
this.useADBKeyboard = useADBKeyboard;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ public final class Server {
|
|||||||
options.getEncoderName());
|
options.getEncoderName());
|
||||||
|
|
||||||
if (options.getControl()) {
|
if (options.getControl()) {
|
||||||
final Controller controller = new Controller(device, connection);
|
final Controller controller = new Controller(device, connection, options);
|
||||||
|
|
||||||
// asynchronous
|
// asynchronous
|
||||||
startController(controller);
|
startController(controller);
|
||||||
@ -122,7 +122,7 @@ public final class Server {
|
|||||||
"The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")");
|
"The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
final int expectedParameters = 15;
|
final int expectedParameters = 16;
|
||||||
if (args.length != expectedParameters) {
|
if (args.length != expectedParameters) {
|
||||||
throw new IllegalArgumentException("Expecting " + expectedParameters + " parameters");
|
throw new IllegalArgumentException("Expecting " + expectedParameters + " parameters");
|
||||||
}
|
}
|
||||||
@ -172,6 +172,9 @@ public final class Server {
|
|||||||
String encoderName = "-".equals(args[14]) ? null : args[14];
|
String encoderName = "-".equals(args[14]) ? null : args[14];
|
||||||
options.setEncoderName(encoderName);
|
options.setEncoderName(encoderName);
|
||||||
|
|
||||||
|
boolean useADBKeyboard = Boolean.parseBoolean(args[15]);
|
||||||
|
options.setUseADBKeyboard(useADBKeyboard);
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,9 @@ package com.genymobile.scrcpy.wrappers;
|
|||||||
|
|
||||||
import com.genymobile.scrcpy.Ln;
|
import com.genymobile.scrcpy.Ln;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.IInterface;
|
import android.os.IInterface;
|
||||||
|
|
||||||
@ -16,6 +18,7 @@ public class ActivityManager {
|
|||||||
private Method getContentProviderExternalMethod;
|
private Method getContentProviderExternalMethod;
|
||||||
private boolean getContentProviderExternalMethodLegacy;
|
private boolean getContentProviderExternalMethodLegacy;
|
||||||
private Method removeContentProviderExternalMethod;
|
private Method removeContentProviderExternalMethod;
|
||||||
|
private Method broadcastIntentMethod;
|
||||||
|
|
||||||
public ActivityManager(IInterface manager) {
|
public ActivityManager(IInterface manager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
@ -42,6 +45,22 @@ public class ActivityManager {
|
|||||||
return removeContentProviderExternalMethod;
|
return removeContentProviderExternalMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Method getBroadcastIntentMethod() throws NoSuchMethodException {
|
||||||
|
if (broadcastIntentMethod == null) {
|
||||||
|
try {
|
||||||
|
Class<?> iApplicationThreadClass = Class.forName("android.app.IApplicationThread");
|
||||||
|
Class<?> iIntentReceiverClass = Class.forName("android.content.IIntentReceiver");
|
||||||
|
broadcastIntentMethod = manager.getClass()
|
||||||
|
.getMethod("broadcastIntent", iApplicationThreadClass, Intent.class, String.class, iIntentReceiverClass, int.class,
|
||||||
|
String.class, Bundle.class, String[].class, int.class, Bundle.class, boolean.class, boolean.class, int.class);
|
||||||
|
return broadcastIntentMethod;
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return broadcastIntentMethod;
|
||||||
|
}
|
||||||
|
|
||||||
private ContentProvider getContentProviderExternal(String name, IBinder token) {
|
private ContentProvider getContentProviderExternal(String name, IBinder token) {
|
||||||
try {
|
try {
|
||||||
Method method = getGetContentProviderExternalMethod();
|
Method method = getGetContentProviderExternalMethod();
|
||||||
@ -84,4 +103,13 @@ public class ActivityManager {
|
|||||||
public ContentProvider createSettingsProvider() {
|
public ContentProvider createSettingsProvider() {
|
||||||
return getContentProviderExternal("settings", new Binder());
|
return getContentProviderExternal("settings", new Binder());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendBroadcast(Intent intent) {
|
||||||
|
try {
|
||||||
|
Method method = getBroadcastIntentMethod();
|
||||||
|
method.invoke(manager, null, intent, null, null, 0, null, null, null, -1, null, true, false, ServiceManager.USER_ID);
|
||||||
|
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||||
|
Ln.e("Could not invoke method", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user