Compare commits

..

4 Commits

Author SHA1 Message Date
Romain Vimont
d95a52f277 Forward Alt to the device
There is no reason not to forward it.
2020-05-29 01:08:03 +02:00
Romain Vimont
ad78ca9cfb Forward Shift to the device
This allows to select text with Shift + arrow keys.

Fixes #942 <https://github.com/Genymobile/scrcpy/issues/942>.
2020-05-29 01:07:42 +02:00
Romain Vimont
3bdc45925f Forward Right-Ctrl to the device
Only capture Left-Ctrl for scrcpy shortcuts, so that Right-Ctrl can be
forwarded to the device.

Fixes #555 <https://github.com/Genymobile/scrcpy/issues/555>
2020-05-29 01:07:25 +02:00
Romain Vimont
0e4a6f462b Mention stay awake limitation
The "stay awake" feature only works when the device is plugged in.

Refs #1445 <https://github.com/Genymobile/scrcpy/issues/1445>
2020-05-28 23:07:28 +02:00
13 changed files with 76 additions and 134 deletions

View File

@@ -417,7 +417,7 @@ The secondary display may only be controlled if the device runs at least Android
#### Stay awake
To prevent the device to sleep after some delay:
To prevent the device to sleep after some delay when the device is plugged in:
```bash
scrcpy --stay-awake
@@ -560,30 +560,33 @@ Also see [issue #14].
## Shortcuts
`LCtrl` is the left `Ctrl` key (the right `Ctrl` key is forwarded to the
device).
| Action | Shortcut | Shortcut (macOS)
| ------------------------------------------- |:----------------------------- |:-----------------------------
| Switch fullscreen mode | `Ctrl`+`f` | `Cmd`+`f`
| Rotate display left | `Ctrl`+`←` _(left)_ | `Cmd`+`←` _(left)_
| Rotate display right | `Ctrl`+`→` _(right)_ | `Cmd`+`→` _(right)_
| Resize window to 1:1 (pixel-perfect) | `Ctrl`+`g` | `Cmd`+`g`
| Resize window to remove black borders | `Ctrl`+`x` \| _Double-click¹_ | `Cmd`+`x` \| _Double-click¹_
| Click on `HOME` | `Ctrl`+`h` \| _Middle-click_ | `Ctrl`+`h` \| _Middle-click_
| Click on `BACK` | `Ctrl`+`b` \| _Right-click²_ | `Cmd`+`b` \| _Right-click²_
| Click on `APP_SWITCH` | `Ctrl`+`s` | `Cmd`+`s`
| Click on `MENU` | `Ctrl`+`m` | `Ctrl`+`m`
| Click on `VOLUME_UP` | `Ctrl`+`↑` _(up)_ | `Cmd`+`↑` _(up)_
| Click on `VOLUME_DOWN` | `Ctrl`+`↓` _(down)_ | `Cmd`+`↓` _(down)_
| Click on `POWER` | `Ctrl`+`p` | `Cmd`+`p`
| Power on | _Right-click²_ | _Right-click²_
| Turn device screen off (keep mirroring) | `Ctrl`+`o` | `Cmd`+`o`
| Turn device screen on | `Ctrl`+`Shift`+`o` | `Cmd`+`Shift`+`o`
| Rotate device screen | `Ctrl`+`r` | `Cmd`+`r`
| Expand notification panel | `Ctrl`+`n` | `Cmd`+`n`
| Collapse notification panel | `Ctrl`+`Shift`+`n` | `Cmd`+`Shift`+`n`
| Copy device clipboard to computer | `Ctrl`+`c` | `Cmd`+`c`
| Paste computer clipboard to device | `Ctrl`+`v` | `Cmd`+`v`
| Copy computer clipboard to device and paste | `Ctrl`+`Shift`+`v` | `Cmd`+`Shift`+`v`
| Enable/disable FPS counter (on stdout) | `Ctrl`+`i` | `Cmd`+`i`
| Switch fullscreen mode | `LCtrl`+`f` | `Cmd`+`f`
| Rotate display left | `LCtrl`+`←` _(left)_ | `Cmd`+`←` _(left)_
| Rotate display right | `LCtrl`+`→` _(right)_ | `Cmd`+`→` _(right)_
| Resize window to 1:1 (pixel-perfect) | `LCtrl`+`g` | `Cmd`+`g`
| Resize window to remove black borders | `LCtrl`+`x` \| _Double-click¹_ | `Cmd`+`x` \| _Double-click¹_
| Click on `HOME` | `LCtrl`+`h` \| _Middle-click_ | `Ctrl`+`h` \| _Middle-click_
| Click on `BACK` | `LCtrl`+`b` \| _Right-click²_ | `Cmd`+`b` \| _Right-click²_
| Click on `APP_SWITCH` | `LCtrl`+`s` | `Cmd`+`s`
| Click on `MENU` | `LCtrl`+`m` | `Ctrl`+`m`
| Click on `VOLUME_UP` | `LCtrl`+`↑` _(up)_ | `Cmd`+`↑` _(up)_
| Click on `VOLUME_DOWN` | `LCtrl`+`↓` _(down)_ | `Cmd`+`↓` _(down)_
| Click on `POWER` | `LCtrl`+`p` | `Cmd`+`p`
| Power on | _Right-click²_ | _Right-click²_
| Turn device screen off (keep mirroring) | `LCtrl`+`o` | `Cmd`+`o`
| Turn device screen on | `LCtrl`+`Shift`+`o` | `Cmd`+`Shift`+`o`
| Rotate device screen | `LCtrl`+`r` | `Cmd`+`r`
| Expand notification panel | `LCtrl`+`n` | `Cmd`+`n`
| Collapse notification panel | `LCtrl`+`Shift`+`n` | `Cmd`+`Shift`+`n`
| Copy device clipboard to computer | `LCtrl`+`c` | `Cmd`+`c`
| Paste computer clipboard to device | `LCtrl`+`v` | `Cmd`+`v`
| Copy computer clipboard to device and paste | `LCtrl`+`Shift`+`v` | `Cmd`+`Shift`+`v`
| Enable/disable FPS counter (on stdout) | `LCtrl`+`i` | `Cmd`+`i`
_¹Double-click on black borders to remove them._
_²Right-click turns the screen on if it was off, presses BACK otherwise._

View File

@@ -167,7 +167,7 @@ Default is "info" for release builds, "debug" for debug builds.
.TP
.B \-w, \-\-stay-awake
Keep the device on while scrcpy is running.
Keep the device on while scrcpy is running, when the device is plugged in.
.TP
.B \-\-window\-borderless
@@ -203,52 +203,54 @@ Default is 0 (automatic).\n
.SH SHORTCUTS
\fBLCtrl\fR is the left Ctrl key (the right Ctrl key is forwarded to the device).
.TP
.B Ctrl+f
.B LCtrl+f
Switch fullscreen mode
.TP
.B Ctrl+Left
.B LCtrl+Left
Rotate display left
.TP
.B Ctrl+Right
.B LCtrl+Right
Rotate display right
.TP
.B Ctrl+g
.B LCtrl+g
Resize window to 1:1 (pixel\-perfect)
.TP
.B Ctrl+x, Double\-click on black borders
.B LCtrl+x, Double\-click on black borders
Resize window to remove black borders
.TP
.B Ctrl+h, Home, Middle\-click
.B LCtrl+h, Home, Middle\-click
Click on HOME
.TP
.B Ctrl+b, Ctrl+Backspace, Right\-click (when screen is on)
.B LCtrl+b, Ctrl+Backspace, Right\-click (when screen is on)
Click on BACK
.TP
.B Ctrl+s
.B LCtrl+s
Click on APP_SWITCH
.TP
.B Ctrl+m
.B LCtrl+m
Click on MENU
.TP
.B Ctrl+Up
.B LCtrl+Up
Click on VOLUME_UP
.TP
.B Ctrl+Down
.B LCtrl+Down
Click on VOLUME_DOWN
.TP
.B Ctrl+p
.B LCtrl+p
Click on POWER (turn screen on/off)
.TP
@@ -256,39 +258,39 @@ Click on POWER (turn screen on/off)
Turn screen on
.TP
.B Ctrl+o
.B LCtrl+o
Turn device screen off (keep mirroring)
.TP
.B Ctrl+Shift+o
.B LCtrl+Shift+o
Turn device screen on
.TP
.B Ctrl+r
.B LCtrl+r
Rotate device screen
.TP
.B Ctrl+n
.B LCtrl+n
Expand notification panel
.TP
.B Ctrl+Shift+n
.B LCtrl+Shift+n
Collapse notification panel
.TP
.B Ctrl+c
.B LCtrl+c
Copy device clipboard to computer
.TP
.B Ctrl+v
.B LCtrl+v
Paste computer clipboard to device
.TP
.B Ctrl+Shift+v
.B LCtrl+Shift+v
Copy computer clipboard to device (and paste if the device runs Android >= 7)
.TP
.B Ctrl+i
.B LCtrl+i
Enable/disable FPS counter (print frames/second in logs)
.TP

View File

@@ -15,7 +15,7 @@ scrcpy_print_usage(const char *arg0) {
#ifdef __APPLE__
# define CTRL_OR_CMD "Cmd"
#else
# define CTRL_OR_CMD "Ctrl"
# define CTRL_OR_CMD "LCtrl"
#endif
fprintf(stderr,
"Usage: %s [options]\n"
@@ -159,7 +159,8 @@ scrcpy_print_usage(const char *arg0) {
#endif
"\n"
" -w, --stay-awake\n"
" Keep the device on while scrcpy is running.\n"
" Keep the device on while scrcpy is running, when the device\n"
" is plugged in.\n"
"\n"
" --window-borderless\n"
" Disable window decorations (display borderless window).\n"
@@ -185,6 +186,9 @@ scrcpy_print_usage(const char *arg0) {
"\n"
"Shortcuts:\n"
"\n"
" LCtrl is the left Ctrl key (the right Ctrl key is forwarded to\n"
" the device).\n"
"\n"
" " CTRL_OR_CMD "+f\n"
" Switch fullscreen mode\n"
"\n"
@@ -201,7 +205,7 @@ scrcpy_print_usage(const char *arg0) {
" Double-click on black borders\n"
" Resize window to remove black borders\n"
"\n"
" Ctrl+h\n"
" LCtrl+h\n"
" Middle-click\n"
" Click on HOME\n"
"\n"
@@ -213,7 +217,7 @@ scrcpy_print_usage(const char *arg0) {
" " CTRL_OR_CMD "+s\n"
" Click on APP_SWITCH\n"
"\n"
" Ctrl+m\n"
" LCtrl+m\n"
" Click on MENU\n"
"\n"
" " CTRL_OR_CMD "+Up\n"

View File

@@ -66,9 +66,6 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
buffer_write32be(&buf[17],
(uint32_t) msg->inject_scroll_event.vscroll);
return 21;
case CONTROL_MSG_TYPE_GET_CLIPBOARD:
buf[1] = msg->get_clipboard.copy;
return 2;
case CONTROL_MSG_TYPE_SET_CLIPBOARD: {
buf[1] = !!msg->set_clipboard.paste;
size_t len = write_string(msg->set_clipboard.text,
@@ -82,6 +79,7 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
case CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL:
case CONTROL_MSG_TYPE_GET_CLIPBOARD:
case CONTROL_MSG_TYPE_ROTATE_DEVICE:
// no additional data
return 1;

View File

@@ -60,9 +60,6 @@ struct control_msg {
int32_t hscroll;
int32_t vscroll;
} inject_scroll_event;
struct {
bool copy;
} get_clipboard;
struct {
char *text; // owned, to be freed by SDL_free()
bool paste;

View File

@@ -92,8 +92,11 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod,
MAP(SDLK_LEFT, AKEYCODE_DPAD_LEFT);
MAP(SDLK_DOWN, AKEYCODE_DPAD_DOWN);
MAP(SDLK_UP, AKEYCODE_DPAD_UP);
MAP(SDLK_RCTRL, AKEYCODE_CTRL_RIGHT);
MAP(SDLK_LSHIFT, AKEYCODE_SHIFT_LEFT);
MAP(SDLK_RSHIFT, AKEYCODE_SHIFT_RIGHT);
MAP(SDLK_LALT, AKEYCODE_ALT_LEFT);
MAP(SDLK_RALT, AKEYCODE_ALT_RIGHT);
}
if (!(mod & (KMOD_NUM | KMOD_SHIFT))) {

View File

@@ -102,10 +102,9 @@ collapse_notification_panel(struct controller *controller) {
}
static void
request_device_clipboard(struct controller *controller, bool copy) {
request_device_clipboard(struct controller *controller) {
struct control_msg msg;
msg.type = CONTROL_MSG_TYPE_GET_CLIPBOARD;
msg.get_clipboard.copy = copy;
if (!controller_push_msg(controller, &msg)) {
LOGW("Could not request device clipboard");
@@ -260,8 +259,8 @@ input_manager_process_key(struct input_manager *im,
// control: indicates the state of the command-line option --no-control
// ctrl: the Ctrl key
bool ctrl = event->keysym.mod & (KMOD_LCTRL | KMOD_RCTRL);
bool alt = event->keysym.mod & (KMOD_LALT | KMOD_RALT);
// Only capture Left-Ctrl, Right-Ctrl is forwarded to the device
bool ctrl = event->keysym.mod & KMOD_LCTRL;
bool meta = event->keysym.mod & (KMOD_LGUI | KMOD_RGUI);
// use Cmd on macOS, Ctrl on other platforms
@@ -276,11 +275,6 @@ input_manager_process_key(struct input_manager *im,
bool cmd = ctrl; // && !meta, already guaranteed
#endif
if (alt) {
// no shortcuts involve Alt, and it must not be forwarded to the device
return;
}
struct controller *controller = im->controller;
// capture all Ctrl events
@@ -353,8 +347,7 @@ input_manager_process_key(struct input_manager *im,
return;
case SDLK_c:
if (control && cmd && !shift && !repeat && down) {
// press COPY and get the clipboard content
request_device_clipboard(controller, true);
request_device_clipboard(controller);
}
return;
case SDLK_v:

View File

@@ -185,18 +185,14 @@ static void test_serialize_collapse_notification_panel(void) {
static void test_serialize_get_clipboard(void) {
struct control_msg msg = {
.type = CONTROL_MSG_TYPE_GET_CLIPBOARD,
.get_clipboard = {
.copy = true,
},
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 2);
assert(size == 1);
const unsigned char expected[] = {
CONTROL_MSG_TYPE_GET_CLIPBOARD,
1, // copy
};
assert(!memcmp(buf, expected, sizeof(expected)));
}

View File

@@ -18,7 +18,6 @@ public final class ControlMessage {
public static final int TYPE_ROTATE_DEVICE = 10;
public static final int FLAGS_PASTE = 1;
public static final int FLAGS_COPY = 2;
private int type;
private String text;
@@ -82,15 +81,6 @@ public final class ControlMessage {
return msg;
}
public static ControlMessage createGetClipboard(boolean copy) {
ControlMessage msg = new ControlMessage();
msg.type = TYPE_GET_CLIPBOARD;
if (copy) {
msg.flags = FLAGS_COPY;
}
return msg;
}
/**
* @param mode one of the {@code Device.SCREEN_POWER_MODE_*} constants
*/

View File

@@ -12,7 +12,6 @@ public class ControlMessageReader {
static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 27;
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20;
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
static final int GET_CLIPBOARD_PAYLOAD_LENGTH = 1;
static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 1;
public static final int CLIPBOARD_TEXT_MAX_LENGTH = 4092; // 4096 - 1 (type) - 1 (parse flag) - 2 (length)
@@ -68,9 +67,6 @@ public class ControlMessageReader {
case ControlMessage.TYPE_INJECT_SCROLL_EVENT:
msg = parseInjectScrollEvent();
break;
case ControlMessage.TYPE_GET_CLIPBOARD:
msg = parseGetClipboard();
break;
case ControlMessage.TYPE_SET_CLIPBOARD:
msg = parseSetClipboard();
break;
@@ -80,6 +76,7 @@ public class ControlMessageReader {
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
case ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL:
case ControlMessage.TYPE_GET_CLIPBOARD:
case ControlMessage.TYPE_ROTATE_DEVICE:
msg = ControlMessage.createEmpty(type);
break;
@@ -151,14 +148,6 @@ public class ControlMessageReader {
return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll);
}
private ControlMessage parseGetClipboard() {
if (buffer.remaining() < GET_CLIPBOARD_PAYLOAD_LENGTH) {
return null;
}
boolean copy = buffer.get() != 0;
return ControlMessage.createGetClipboard(copy);
}
private ControlMessage parseSetClipboard() {
if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) {
return null;

View File

@@ -104,8 +104,10 @@ public class Controller {
device.collapsePanels();
break;
case ControlMessage.TYPE_GET_CLIPBOARD:
boolean copy = (msg.getFlags() & ControlMessage.FLAGS_COPY) != 0;
getClipboard(copy);
String clipboardText = device.getClipboardText();
if (clipboardText != null) {
sender.pushClipboardText(clipboardText);
}
break;
case ControlMessage.TYPE_SET_CLIPBOARD:
boolean paste = (msg.getFlags() & ControlMessage.FLAGS_PASTE) != 0;
@@ -227,19 +229,6 @@ public class Controller {
return device.injectKeycode(keycode);
}
private void getClipboard(boolean copy) {
// On Android >= 7, also press the COPY key if requested
if (copy && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && device.supportsInputEvents()) {
// Must wait until the COPY has been executed
device.injectCopyKeycode();
}
String clipboardText = device.getClipboardText();
if (clipboardText != null) {
sender.pushClipboardText(clipboardText);
}
}
private boolean setClipboard(String text, boolean paste) {
boolean ok = device.setClipboardText(text);
if (ok) {
@@ -248,7 +237,7 @@ public class Controller {
// On Android >= 7, also press the PASTE key if requested
if (paste && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && device.supportsInputEvents()) {
device.injectPasteKeycode();
device.injectKeycode(KeyEvent.KEYCODE_PASTE);
}
return ok;

View File

@@ -167,35 +167,15 @@ public final class Device {
return injectEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
public boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState, int mode) {
public boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState) {
long now = SystemClock.uptimeMillis();
KeyEvent event = new KeyEvent(now, now, action, keyCode, repeat, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0,
InputDevice.SOURCE_KEYBOARD);
return injectEvent(event, mode);
}
public boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState) {
return injectKeyEvent(action, keyCode, repeat, metaState, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
public boolean injectKeycode(int keyCode, int mode) {
return injectKeyEvent(KeyEvent.ACTION_DOWN, keyCode, 0, 0) && injectKeyEvent(KeyEvent.ACTION_UP, keyCode, 0, 0, mode);
return injectEvent(event);
}
public boolean injectKeycode(int keyCode) {
return injectKeycode(keyCode, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
public boolean injectCopyKeycode() {
isSettingClipboard.set(true);
// Must wait until the COPY has been executed
boolean ret = injectKeycode(KeyEvent.KEYCODE_COPY, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
isSettingClipboard.set(false);
return ret;
}
public boolean injectPasteKeycode() {
return injectKeycode(KeyEvent.KEYCODE_PASTE);
return injectKeyEvent(KeyEvent.ACTION_DOWN, keyCode, 0, 0) && injectKeyEvent(KeyEvent.ACTION_UP, keyCode, 0, 0);
}
public boolean isScreenOn() {

View File

@@ -200,7 +200,6 @@ public class ControlMessageReaderTest {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_GET_CLIPBOARD);
dos.writeByte(1); // copy
byte[] packet = bos.toByteArray();
@@ -208,7 +207,6 @@ public class ControlMessageReaderTest {
ControlMessage event = reader.next();
Assert.assertEquals(ControlMessage.TYPE_GET_CLIPBOARD, event.getType());
Assert.assertEquals(1, (event.getFlags() & ControlMessage.FLAGS_COPY));
}
@Test