Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e31b13b0b2 | ||
|
2a7f3d70d7 | ||
|
94269ccaad |
20
README.md
20
README.md
@ -440,8 +440,12 @@ scrcpy -S
|
|||||||
|
|
||||||
Or by pressing <kbd>MOD</kbd>+<kbd>o</kbd> at any time.
|
Or by pressing <kbd>MOD</kbd>+<kbd>o</kbd> at any time.
|
||||||
|
|
||||||
To turn it back on, press <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd> (or
|
To turn it back on, press <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>.
|
||||||
`POWER`, <kbd>MOD</kbd>+<kbd>p</kbd>).
|
|
||||||
|
On Android, the `POWER` button always turns the screen on. For convenience, if
|
||||||
|
`POWER` is sent via scrcpy (via right-click or <kbd>Ctrl</kbd>+<kbd>p</kbd>), it
|
||||||
|
will force to turn the screen off after a small delay (on a best effort basis).
|
||||||
|
The physical `POWER` button will still cause the screen to be turned on.
|
||||||
|
|
||||||
It can be useful to also prevent the device to sleep:
|
It can be useful to also prevent the device to sleep:
|
||||||
|
|
||||||
@ -558,6 +562,18 @@ scrcpy --prefer-text
|
|||||||
[prefertext]: https://github.com/Genymobile/scrcpy/issues/650#issuecomment-512945343
|
[prefertext]: https://github.com/Genymobile/scrcpy/issues/650#issuecomment-512945343
|
||||||
|
|
||||||
|
|
||||||
|
#### Key repeat
|
||||||
|
|
||||||
|
By default, holding a key down generates repeated key events. This can cause
|
||||||
|
performance problems in some games, where these events are useless anyway.
|
||||||
|
|
||||||
|
To avoid forwarding repeated key events:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --no-key-repeat
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### File drop
|
### File drop
|
||||||
|
|
||||||
#### Install APK
|
#### Install APK
|
||||||
|
@ -96,6 +96,10 @@ Do not display device (only when screen recording is enabled).
|
|||||||
.B \-\-no\-mipmaps
|
.B \-\-no\-mipmaps
|
||||||
If the renderer is OpenGL 3.0+ or OpenGL ES 2.0+, then mipmaps are automatically generated to improve downscaling quality. This option disables the generation of mipmaps.
|
If the renderer is OpenGL 3.0+ or OpenGL ES 2.0+, then mipmaps are automatically generated to improve downscaling quality. This option disables the generation of mipmaps.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B \-\-no\-key\-repeat
|
||||||
|
Do not forward repeated key events when a key is held down.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "\-p, \-\-port " port[:port]
|
.BI "\-p, \-\-port " port[:port]
|
||||||
Set the TCP port (range) used by the client to listen.
|
Set the TCP port (range) used by the client to listen.
|
||||||
|
@ -92,6 +92,9 @@ scrcpy_print_usage(const char *arg0) {
|
|||||||
" mipmaps are automatically generated to improve downscaling\n"
|
" mipmaps are automatically generated to improve downscaling\n"
|
||||||
" quality. This option disables the generation of mipmaps.\n"
|
" quality. This option disables the generation of mipmaps.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" --no-key-repeat\n"
|
||||||
|
" Do not forward repeated key events when a key is held down.\n"
|
||||||
|
"\n"
|
||||||
" -p, --port port[:port]\n"
|
" -p, --port port[:port]\n"
|
||||||
" Set the TCP port (range) used by the client to listen.\n"
|
" Set the TCP port (range) used by the client to listen.\n"
|
||||||
" Default is %d:%d.\n"
|
" Default is %d:%d.\n"
|
||||||
@ -642,6 +645,7 @@ guess_record_format(const char *filename) {
|
|||||||
#define OPT_FORCE_ADB_FORWARD 1019
|
#define OPT_FORCE_ADB_FORWARD 1019
|
||||||
#define OPT_DISABLE_SCREENSAVER 1020
|
#define OPT_DISABLE_SCREENSAVER 1020
|
||||||
#define OPT_SHORTCUT_MOD 1021
|
#define OPT_SHORTCUT_MOD 1021
|
||||||
|
#define OPT_NO_KEY_REPEAT 1022
|
||||||
|
|
||||||
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[]) {
|
||||||
@ -664,6 +668,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||||||
{"no-control", no_argument, NULL, 'n'},
|
{"no-control", no_argument, NULL, 'n'},
|
||||||
{"no-display", no_argument, NULL, 'N'},
|
{"no-display", no_argument, NULL, 'N'},
|
||||||
{"no-mipmaps", no_argument, NULL, OPT_NO_MIPMAPS},
|
{"no-mipmaps", no_argument, NULL, OPT_NO_MIPMAPS},
|
||||||
|
{"no-key-repeat", no_argument, NULL, OPT_NO_KEY_REPEAT},
|
||||||
{"port", required_argument, NULL, 'p'},
|
{"port", required_argument, NULL, 'p'},
|
||||||
{"prefer-text", no_argument, NULL, OPT_PREFER_TEXT},
|
{"prefer-text", no_argument, NULL, OPT_PREFER_TEXT},
|
||||||
{"push-target", required_argument, NULL, OPT_PUSH_TARGET},
|
{"push-target", required_argument, NULL, OPT_PUSH_TARGET},
|
||||||
@ -829,6 +834,9 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||||||
case OPT_NO_MIPMAPS:
|
case OPT_NO_MIPMAPS:
|
||||||
opts->mipmaps = false;
|
opts->mipmaps = false;
|
||||||
break;
|
break;
|
||||||
|
case OPT_NO_KEY_REPEAT:
|
||||||
|
opts->forward_key_repeat = false;
|
||||||
|
break;
|
||||||
case OPT_CODEC_OPTIONS:
|
case OPT_CODEC_OPTIONS:
|
||||||
opts->codec_options = optarg;
|
opts->codec_options = optarg;
|
||||||
break;
|
break;
|
||||||
|
@ -58,6 +58,7 @@ input_manager_init(struct input_manager *im,
|
|||||||
const struct scrcpy_options *options)
|
const struct scrcpy_options *options)
|
||||||
{
|
{
|
||||||
im->control = options->control;
|
im->control = options->control;
|
||||||
|
im->forward_key_repeat = options->forward_key_repeat;
|
||||||
im->prefer_text = options->prefer_text;
|
im->prefer_text = options->prefer_text;
|
||||||
|
|
||||||
const struct sc_shortcut_mods *shortcut_mods = &options->shortcut_mods;
|
const struct sc_shortcut_mods *shortcut_mods = &options->shortcut_mods;
|
||||||
@ -461,6 +462,9 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event->repeat) {
|
if (event->repeat) {
|
||||||
|
if (!im->forward_key_repeat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
++im->repeat;
|
++im->repeat;
|
||||||
} else {
|
} else {
|
||||||
im->repeat = 0;
|
im->repeat = 0;
|
||||||
|
@ -23,6 +23,7 @@ struct input_manager {
|
|||||||
unsigned repeat;
|
unsigned repeat;
|
||||||
|
|
||||||
bool control;
|
bool control;
|
||||||
|
bool forward_key_repeat;
|
||||||
bool prefer_text;
|
bool prefer_text;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -78,6 +78,7 @@ struct scrcpy_options {
|
|||||||
bool stay_awake;
|
bool stay_awake;
|
||||||
bool force_adb_forward;
|
bool force_adb_forward;
|
||||||
bool disable_screensaver;
|
bool disable_screensaver;
|
||||||
|
bool forward_key_repeat;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SCRCPY_OPTIONS_DEFAULT { \
|
#define SCRCPY_OPTIONS_DEFAULT { \
|
||||||
@ -121,6 +122,7 @@ struct scrcpy_options {
|
|||||||
.stay_awake = false, \
|
.stay_awake = false, \
|
||||||
.force_adb_forward = false, \
|
.force_adb_forward = false, \
|
||||||
.disable_screensaver = false, \
|
.disable_screensaver = false, \
|
||||||
|
.forward_key_repeat = true, \
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -8,11 +8,16 @@ import android.view.KeyEvent;
|
|||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class Controller {
|
public class Controller {
|
||||||
|
|
||||||
private static final int DEVICE_ID_VIRTUAL = -1;
|
private static final int DEVICE_ID_VIRTUAL = -1;
|
||||||
|
|
||||||
|
private static final ScheduledExecutorService EXECUTOR = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
|
||||||
private final Device device;
|
private final Device device;
|
||||||
private final DesktopConnection connection;
|
private final DesktopConnection connection;
|
||||||
private final DeviceMessageSender sender;
|
private final DeviceMessageSender sender;
|
||||||
@ -24,6 +29,8 @@ public class Controller {
|
|||||||
private final MotionEvent.PointerProperties[] pointerProperties = new MotionEvent.PointerProperties[PointersState.MAX_POINTERS];
|
private final MotionEvent.PointerProperties[] pointerProperties = new MotionEvent.PointerProperties[PointersState.MAX_POINTERS];
|
||||||
private final MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[PointersState.MAX_POINTERS];
|
private final MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[PointersState.MAX_POINTERS];
|
||||||
|
|
||||||
|
private boolean screenStayOff;
|
||||||
|
|
||||||
public Controller(Device device, DesktopConnection connection) {
|
public Controller(Device device, DesktopConnection connection) {
|
||||||
this.device = device;
|
this.device = device;
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
@ -117,6 +124,7 @@ public class Controller {
|
|||||||
int mode = msg.getAction();
|
int mode = msg.getAction();
|
||||||
boolean setPowerModeOk = Device.setScreenPowerMode(mode);
|
boolean setPowerModeOk = Device.setScreenPowerMode(mode);
|
||||||
if (setPowerModeOk) {
|
if (setPowerModeOk) {
|
||||||
|
screenStayOff = mode == Device.POWER_MODE_OFF;
|
||||||
Ln.i("Device screen turned " + (mode == Device.POWER_MODE_OFF ? "off" : "on"));
|
Ln.i("Device screen turned " + (mode == Device.POWER_MODE_OFF ? "off" : "on"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,6 +138,9 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean injectKeycode(int action, int keycode, int repeat, int metaState) {
|
private boolean injectKeycode(int action, int keycode, int repeat, int metaState) {
|
||||||
|
if (screenStayOff && action == KeyEvent.ACTION_UP && (keycode == KeyEvent.KEYCODE_POWER || keycode == KeyEvent.KEYCODE_WAKEUP)) {
|
||||||
|
scheduleScreenOff();
|
||||||
|
}
|
||||||
return device.injectKeyEvent(action, keycode, repeat, metaState);
|
return device.injectKeyEvent(action, keycode, repeat, metaState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,8 +234,24 @@ public class Controller {
|
|||||||
return device.injectEvent(event);
|
return device.injectEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule a call to turn the screen off after a small delay.
|
||||||
|
*/
|
||||||
|
private static void scheduleScreenOff() {
|
||||||
|
EXECUTOR.schedule(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Ln.i("Forcing screen off");
|
||||||
|
Device.setScreenPowerMode(Device.POWER_MODE_OFF);
|
||||||
|
}
|
||||||
|
}, 200, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean pressBackOrTurnScreenOn() {
|
private boolean pressBackOrTurnScreenOn() {
|
||||||
int keycode = device.isScreenOn() ? KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_WAKEUP;
|
int keycode = device.isScreenOn() ? KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_WAKEUP;
|
||||||
|
if (screenStayOff && keycode == KeyEvent.KEYCODE_WAKEUP) {
|
||||||
|
scheduleScreenOff();
|
||||||
|
}
|
||||||
return device.injectKeycode(keycode);
|
return device.injectKeycode(keycode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user