Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb5e619636 | ||
|
|
42641d2737 | ||
|
|
3c0fc8f54f | ||
|
|
1b73eff3c9 |
59
README.md
59
README.md
@@ -301,7 +301,7 @@ ssh -CN -L5037:localhost:5037 -L27183:localhost:27183 your_remote_computer
|
|||||||
From another terminal:
|
From another terminal:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
scrcpy --force-adb-forwrad
|
scrcpy --force-adb-forward
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -550,46 +550,43 @@ scrcpy --push-target /sdcard/foo/bar/
|
|||||||
|
|
||||||
### Audio forwarding
|
### Audio forwarding
|
||||||
|
|
||||||
Audio is not forwarded by _scrcpy_. Use [USBaudio] (Linux-only).
|
Audio is not forwarded by _scrcpy_. Use [sndcpy].
|
||||||
|
|
||||||
Also see [issue #14].
|
Also see [issue #14].
|
||||||
|
|
||||||
[USBaudio]: https://github.com/rom1v/usbaudio
|
[sndcpy]: https://github.com/rom1v/sndcpy
|
||||||
[issue #14]: https://github.com/Genymobile/scrcpy/issues/14
|
[issue #14]: https://github.com/Genymobile/scrcpy/issues/14
|
||||||
|
|
||||||
|
|
||||||
## Shortcuts
|
## Shortcuts
|
||||||
|
|
||||||
_`Meta` is typically the `Windows` key on the keyboard, or `Cmd` on macOS._
|
| Action | Shortcut | Shortcut (macOS)
|
||||||
|
| ------------------------------------------- |:----------------------------- |:-----------------------------
|
||||||
| Action | Shortcut
|
| Switch fullscreen mode | `Ctrl`+`f` | `Cmd`+`f`
|
||||||
| ---------------------------------------------------- |:-----------------------------
|
| Rotate display left | `Ctrl`+`←` _(left)_ | `Cmd`+`←` _(left)_
|
||||||
| Switch fullscreen mode | `Meta`+`f`
|
| Rotate display right | `Ctrl`+`→` _(right)_ | `Cmd`+`→` _(right)_
|
||||||
| Rotate display left | `Meta`+`←` _(left)_
|
| Resize window to 1:1 (pixel-perfect) | `Ctrl`+`g` | `Cmd`+`g`
|
||||||
| Rotate display right | `Meta`+`→` _(right)_
|
| Resize window to remove black borders | `Ctrl`+`x` \| _Double-click¹_ | `Cmd`+`x` \| _Double-click¹_
|
||||||
| Resize window to 1:1 (pixel-perfect) | `Meta`+`g`
|
| Click on `HOME` | `Ctrl`+`h` \| _Middle-click_ | `Ctrl`+`h` \| _Middle-click_
|
||||||
| Resize window to remove black borders | `Meta`+`w` \| _Double-click¹_
|
| Click on `BACK` | `Ctrl`+`b` \| _Right-click²_ | `Cmd`+`b` \| _Right-click²_
|
||||||
| Click on `HOME` | `Meta`+`h` \| _Middle-click_
|
| Click on `APP_SWITCH` | `Ctrl`+`s` | `Cmd`+`s`
|
||||||
| Click on `BACK` | `Meta`+`b` \| _Right-click²_
|
| Click on `MENU` | `Ctrl`+`m` | `Ctrl`+`m`
|
||||||
| Click on `APP_SWITCH` | `Meta`+`s`
|
| Click on `VOLUME_UP` | `Ctrl`+`↑` _(up)_ | `Cmd`+`↑` _(up)_
|
||||||
| Click on `MENU` | `Meta`+`m`
|
| Click on `VOLUME_DOWN` | `Ctrl`+`↓` _(down)_ | `Cmd`+`↓` _(down)_
|
||||||
| Click on `VOLUME_UP` | `Meta`+`↑` _(up)_
|
| Click on `POWER` | `Ctrl`+`p` | `Cmd`+`p`
|
||||||
| Click on `VOLUME_DOWN` | `Meta`+`↓` _(down)_
|
| Power on | _Right-click²_ | _Right-click²_
|
||||||
| Click on `POWER` | `Meta`+`p`
|
| Turn device screen off (keep mirroring) | `Ctrl`+`o` | `Cmd`+`o`
|
||||||
| Power on | _Right-click²_
|
| Turn device screen on | `Ctrl`+`Shift`+`o` | `Cmd`+`Shift`+`o`
|
||||||
| Turn device screen off (keep mirroring) | `Meta`+`o`
|
| Rotate device screen | `Ctrl`+`r` | `Cmd`+`r`
|
||||||
| Turn device screen on | `Meta`+`Shift`+`o`
|
| Expand notification panel | `Ctrl`+`n` | `Cmd`+`n`
|
||||||
| Rotate device screen | `Meta`+`r`
|
| Collapse notification panel | `Ctrl`+`Shift`+`n` | `Cmd`+`Shift`+`n`
|
||||||
| Expand notification panel | `Meta`+`n`
|
| Copy device clipboard to computer | `Ctrl`+`c` | `Cmd`+`c`
|
||||||
| Collapse notification panel | `Meta`+`Shift`+`n`
|
| Paste computer clipboard to device | `Ctrl`+`v` | `Cmd`+`v`
|
||||||
| Press COPY³, then Copy device clipboard to computer | `Meta`+`c`
|
| Copy computer clipboard to device and paste | `Ctrl`+`Shift`+`v` | `Cmd`+`Shift`+`v`
|
||||||
| Press CUT³ | `Meta`+`x`
|
| Enable/disable FPS counter (on stdout) | `Ctrl`+`i` | `Cmd`+`i`
|
||||||
| Paste computer clipboard to device | `Meta`+`v`
|
|
||||||
| Enable/disable FPS counter (on stdout) | `Meta`+`i`
|
|
||||||
|
|
||||||
_¹Double-click on black borders to remove them._
|
_¹Double-click on black borders to remove them._
|
||||||
_²Right-click turns the screen on if it was off, presses BACK otherwise._
|
_²Right-click turns the screen on if it was off, presses BACK otherwise._
|
||||||
_³Only if the device runs Android >= 7._
|
|
||||||
|
|
||||||
|
|
||||||
## Custom paths
|
## Custom paths
|
||||||
|
|||||||
50
app/scrcpy.1
50
app/scrcpy.1
@@ -204,51 +204,51 @@ Default is 0 (automatic).\n
|
|||||||
.SH SHORTCUTS
|
.SH SHORTCUTS
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+f
|
.B Ctrl+f
|
||||||
Switch fullscreen mode
|
Switch fullscreen mode
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+Left
|
.B Ctrl+Left
|
||||||
Rotate display left
|
Rotate display left
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+Right
|
.B Ctrl+Right
|
||||||
Rotate display right
|
Rotate display right
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+g
|
.B Ctrl+g
|
||||||
Resize window to 1:1 (pixel\-perfect)
|
Resize window to 1:1 (pixel\-perfect)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+w, Double\-click on black borders
|
.B Ctrl+x, Double\-click on black borders
|
||||||
Resize window to remove black borders
|
Resize window to remove black borders
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+h, Home, Middle\-click
|
.B Ctrl+h, Home, Middle\-click
|
||||||
Click on HOME
|
Click on HOME
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+b, Meta+Backspace, Right\-click (when screen is on)
|
.B Ctrl+b, Ctrl+Backspace, Right\-click (when screen is on)
|
||||||
Click on BACK
|
Click on BACK
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+s
|
.B Ctrl+s
|
||||||
Click on APP_SWITCH
|
Click on APP_SWITCH
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+m
|
.B Ctrl+m
|
||||||
Click on MENU
|
Click on MENU
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+Up
|
.B Ctrl+Up
|
||||||
Click on VOLUME_UP
|
Click on VOLUME_UP
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+Down
|
.B Ctrl+Down
|
||||||
Click on VOLUME_DOWN
|
Click on VOLUME_DOWN
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+p
|
.B Ctrl+p
|
||||||
Click on POWER (turn screen on/off)
|
Click on POWER (turn screen on/off)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
@@ -256,39 +256,39 @@ Click on POWER (turn screen on/off)
|
|||||||
Turn screen on
|
Turn screen on
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+o
|
.B Ctrl+o
|
||||||
Turn device screen off (keep mirroring)
|
Turn device screen off (keep mirroring)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+Shift+o
|
.B Ctrl+Shift+o
|
||||||
Turn device screen on
|
Turn device screen on
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+r
|
.B Ctrl+r
|
||||||
Rotate device screen
|
Rotate device screen
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+n
|
.B Ctrl+n
|
||||||
Expand notification panel
|
Expand notification panel
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+Shift+n
|
.B Ctrl+Shift+n
|
||||||
Collapse notification panel
|
Collapse notification panel
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+c
|
.B Ctrl+c
|
||||||
Press COPY (Android >= 7), then copy device clipboard to computer
|
Copy device clipboard to computer
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+x
|
.B Ctrl+v
|
||||||
Press CUT (Android >= 7)
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B Meta+v
|
|
||||||
Paste computer clipboard to device
|
Paste computer clipboard to device
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Meta+i
|
.B Ctrl+Shift+v
|
||||||
|
Copy computer clipboard to device (and paste if the device runs Android >= 7)
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B Ctrl+i
|
||||||
Enable/disable FPS counter (print frames/second in logs)
|
Enable/disable FPS counter (print frames/second in logs)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
void
|
void
|
||||||
scrcpy_print_usage(const char *arg0) {
|
scrcpy_print_usage(const char *arg0) {
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
# define MOD "Cmd"
|
# define CTRL_OR_CMD "Cmd"
|
||||||
#else
|
#else
|
||||||
# define MOD "Meta"
|
# define CTRL_OR_CMD "Ctrl"
|
||||||
#endif
|
#endif
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage: %s [options]\n"
|
"Usage: %s [options]\n"
|
||||||
@@ -186,19 +186,19 @@ scrcpy_print_usage(const char *arg0) {
|
|||||||
"\n"
|
"\n"
|
||||||
"Shortcuts:\n"
|
"Shortcuts:\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+f\n"
|
" " CTRL_OR_CMD "+f\n"
|
||||||
" Switch fullscreen mode\n"
|
" Switch fullscreen mode\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+Left\n"
|
" " CTRL_OR_CMD "+Left\n"
|
||||||
" Rotate display left\n"
|
" Rotate display left\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+Right\n"
|
" " CTRL_OR_CMD "+Right\n"
|
||||||
" Rotate display right\n"
|
" Rotate display right\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+g\n"
|
" " CTRL_OR_CMD "+g\n"
|
||||||
" Resize window to 1:1 (pixel-perfect)\n"
|
" Resize window to 1:1 (pixel-perfect)\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+w\n"
|
" " CTRL_OR_CMD "+x\n"
|
||||||
" Double-click on black borders\n"
|
" Double-click on black borders\n"
|
||||||
" Resize window to remove black borders\n"
|
" Resize window to remove black borders\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -206,55 +206,55 @@ scrcpy_print_usage(const char *arg0) {
|
|||||||
" Middle-click\n"
|
" Middle-click\n"
|
||||||
" Click on HOME\n"
|
" Click on HOME\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+b\n"
|
" " CTRL_OR_CMD "+b\n"
|
||||||
" " MOD "+Backspace\n"
|
" " CTRL_OR_CMD "+Backspace\n"
|
||||||
" Right-click (when screen is on)\n"
|
" Right-click (when screen is on)\n"
|
||||||
" Click on BACK\n"
|
" Click on BACK\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+s\n"
|
" " CTRL_OR_CMD "+s\n"
|
||||||
" Click on APP_SWITCH\n"
|
" Click on APP_SWITCH\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Ctrl+m\n"
|
" Ctrl+m\n"
|
||||||
" Click on MENU\n"
|
" Click on MENU\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+Up\n"
|
" " CTRL_OR_CMD "+Up\n"
|
||||||
" Click on VOLUME_UP\n"
|
" Click on VOLUME_UP\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+Down\n"
|
" " CTRL_OR_CMD "+Down\n"
|
||||||
" Click on VOLUME_DOWN\n"
|
" Click on VOLUME_DOWN\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+p\n"
|
" " CTRL_OR_CMD "+p\n"
|
||||||
" Click on POWER (turn screen on/off)\n"
|
" Click on POWER (turn screen on/off)\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Right-click (when screen is off)\n"
|
" Right-click (when screen is off)\n"
|
||||||
" Power on\n"
|
" Power on\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+o\n"
|
" " CTRL_OR_CMD "+o\n"
|
||||||
" Turn device screen off (keep mirroring)\n"
|
" Turn device screen off (keep mirroring)\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+Shift+o\n"
|
" " CTRL_OR_CMD "+Shift+o\n"
|
||||||
" Turn device screen on\n"
|
" Turn device screen on\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+r\n"
|
" " CTRL_OR_CMD "+r\n"
|
||||||
" Rotate device screen\n"
|
" Rotate device screen\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+n\n"
|
" " CTRL_OR_CMD "+n\n"
|
||||||
" Expand notification panel\n"
|
" Expand notification panel\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+Shift+n\n"
|
" " CTRL_OR_CMD "+Shift+n\n"
|
||||||
" Collapse notification panel\n"
|
" Collapse notification panel\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+c\n"
|
" " CTRL_OR_CMD "+c\n"
|
||||||
" Press COPY (Android >= 7), then copy device clipboard to\n"
|
" Copy device clipboard to computer\n"
|
||||||
" computer\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+x\n"
|
" " CTRL_OR_CMD "+v\n"
|
||||||
" Press CUT (Android >= 7)\n"
|
|
||||||
"\n"
|
|
||||||
" " MOD "+v\n"
|
|
||||||
" Paste computer clipboard to device\n"
|
" Paste computer clipboard to device\n"
|
||||||
"\n"
|
"\n"
|
||||||
" " MOD "+i\n"
|
" " CTRL_OR_CMD "+Shift+v\n"
|
||||||
|
" Copy computer clipboard to device (and paste if the device\n"
|
||||||
|
" runs Android >= 7)\n"
|
||||||
|
"\n"
|
||||||
|
" " CTRL_OR_CMD "+i\n"
|
||||||
" Enable/disable FPS counter (print frames/second in logs)\n"
|
" Enable/disable FPS counter (print frames/second in logs)\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Drag & drop APK file\n"
|
" Drag & drop APK file\n"
|
||||||
@@ -265,7 +265,6 @@ scrcpy_print_usage(const char *arg0) {
|
|||||||
DEFAULT_LOCK_VIDEO_ORIENTATION, DEFAULT_LOCK_VIDEO_ORIENTATION >= 0 ? "" : " (unlocked)",
|
DEFAULT_LOCK_VIDEO_ORIENTATION, DEFAULT_LOCK_VIDEO_ORIENTATION >= 0 ? "" : " (unlocked)",
|
||||||
DEFAULT_MAX_SIZE, DEFAULT_MAX_SIZE ? "" : " (unlimited)",
|
DEFAULT_MAX_SIZE, DEFAULT_MAX_SIZE ? "" : " (unlimited)",
|
||||||
DEFAULT_LOCAL_PORT_RANGE_FIRST, DEFAULT_LOCAL_PORT_RANGE_LAST);
|
DEFAULT_LOCAL_PORT_RANGE_FIRST, DEFAULT_LOCAL_PORT_RANGE_LAST);
|
||||||
#undef MOD
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|||||||
@@ -66,9 +66,6 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
|
|||||||
buffer_write32be(&buf[17],
|
buffer_write32be(&buf[17],
|
||||||
(uint32_t) msg->inject_scroll_event.vscroll);
|
(uint32_t) msg->inject_scroll_event.vscroll);
|
||||||
return 21;
|
return 21;
|
||||||
case CONTROL_MSG_TYPE_GET_CLIPBOARD:
|
|
||||||
buf[1] = msg->get_clipboard.copy;
|
|
||||||
return 2;
|
|
||||||
case CONTROL_MSG_TYPE_SET_CLIPBOARD: {
|
case CONTROL_MSG_TYPE_SET_CLIPBOARD: {
|
||||||
buf[1] = !!msg->set_clipboard.paste;
|
buf[1] = !!msg->set_clipboard.paste;
|
||||||
size_t len = write_string(msg->set_clipboard.text,
|
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_BACK_OR_SCREEN_ON:
|
||||||
case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
|
case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||||
case CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL:
|
case CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL:
|
||||||
|
case CONTROL_MSG_TYPE_GET_CLIPBOARD:
|
||||||
case CONTROL_MSG_TYPE_ROTATE_DEVICE:
|
case CONTROL_MSG_TYPE_ROTATE_DEVICE:
|
||||||
// no additional data
|
// no additional data
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -60,9 +60,6 @@ struct control_msg {
|
|||||||
int32_t hscroll;
|
int32_t hscroll;
|
||||||
int32_t vscroll;
|
int32_t vscroll;
|
||||||
} inject_scroll_event;
|
} inject_scroll_event;
|
||||||
struct {
|
|
||||||
bool copy;
|
|
||||||
} get_clipboard;
|
|
||||||
struct {
|
struct {
|
||||||
char *text; // owned, to be freed by SDL_free()
|
char *text; // owned, to be freed by SDL_free()
|
||||||
bool paste;
|
bool paste;
|
||||||
|
|||||||
@@ -92,10 +92,6 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod,
|
|||||||
MAP(SDLK_LEFT, AKEYCODE_DPAD_LEFT);
|
MAP(SDLK_LEFT, AKEYCODE_DPAD_LEFT);
|
||||||
MAP(SDLK_DOWN, AKEYCODE_DPAD_DOWN);
|
MAP(SDLK_DOWN, AKEYCODE_DPAD_DOWN);
|
||||||
MAP(SDLK_UP, AKEYCODE_DPAD_UP);
|
MAP(SDLK_UP, AKEYCODE_DPAD_UP);
|
||||||
MAP(SDLK_LCTRL, AKEYCODE_CTRL_LEFT);
|
|
||||||
MAP(SDLK_RCTRL, AKEYCODE_CTRL_RIGHT);
|
|
||||||
MAP(SDLK_LSHIFT, AKEYCODE_SHIFT_LEFT);
|
|
||||||
MAP(SDLK_RSHIFT, AKEYCODE_SHIFT_RIGHT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(mod & (KMOD_NUM | KMOD_SHIFT))) {
|
if (!(mod & (KMOD_NUM | KMOD_SHIFT))) {
|
||||||
|
|||||||
@@ -70,11 +70,6 @@ action_menu(struct controller *controller, int actions) {
|
|||||||
send_keycode(controller, AKEYCODE_MENU, actions, "MENU");
|
send_keycode(controller, AKEYCODE_MENU, actions, "MENU");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
|
||||||
action_cut(struct controller *controller, int actions) {
|
|
||||||
send_keycode(controller, AKEYCODE_CUT, actions, "CUT");
|
|
||||||
}
|
|
||||||
|
|
||||||
// turn the screen on if it was off, press BACK otherwise
|
// turn the screen on if it was off, press BACK otherwise
|
||||||
static void
|
static void
|
||||||
press_back_or_turn_screen_on(struct controller *controller) {
|
press_back_or_turn_screen_on(struct controller *controller) {
|
||||||
@@ -107,10 +102,9 @@ collapse_notification_panel(struct controller *controller) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
request_device_clipboard(struct controller *controller, bool copy) {
|
request_device_clipboard(struct controller *controller) {
|
||||||
struct control_msg msg;
|
struct control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_GET_CLIPBOARD;
|
msg.type = CONTROL_MSG_TYPE_GET_CLIPBOARD;
|
||||||
msg.get_clipboard.copy = copy;
|
|
||||||
|
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request device clipboard");
|
LOGW("Could not request device clipboard");
|
||||||
@@ -268,56 +262,66 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
bool ctrl = event->keysym.mod & (KMOD_LCTRL | KMOD_RCTRL);
|
bool ctrl = event->keysym.mod & (KMOD_LCTRL | KMOD_RCTRL);
|
||||||
bool alt = event->keysym.mod & (KMOD_LALT | KMOD_RALT);
|
bool alt = event->keysym.mod & (KMOD_LALT | KMOD_RALT);
|
||||||
bool meta = event->keysym.mod & (KMOD_LGUI | KMOD_RGUI);
|
bool meta = event->keysym.mod & (KMOD_LGUI | KMOD_RGUI);
|
||||||
bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT);
|
|
||||||
|
// use Cmd on macOS, Ctrl on other platforms
|
||||||
|
#ifdef __APPLE__
|
||||||
|
bool cmd = !ctrl && meta;
|
||||||
|
#else
|
||||||
|
if (meta) {
|
||||||
|
// no shortcuts involve Meta on platforms other than macOS, and it must
|
||||||
|
// not be forwarded to the device
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool cmd = ctrl; // && !meta, already guaranteed
|
||||||
|
#endif
|
||||||
|
|
||||||
if (alt) {
|
if (alt) {
|
||||||
// No shortcuts involve Alt, and it is not forwarded to the device
|
// no shortcuts involve Alt, and it must not be forwarded to the device
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct controller *controller = im->controller;
|
struct controller *controller = im->controller;
|
||||||
|
|
||||||
SDL_Keycode keycode = event->keysym.sym;
|
// capture all Ctrl events
|
||||||
bool down = event->type == SDL_KEYDOWN;
|
if (ctrl || cmd) {
|
||||||
|
SDL_Keycode keycode = event->keysym.sym;
|
||||||
// Capture all Meta events
|
bool down = event->type == SDL_KEYDOWN;
|
||||||
if (meta) {
|
|
||||||
if (ctrl) {
|
|
||||||
// No shortcuts involve Ctrl+Meta
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int action = down ? ACTION_DOWN : ACTION_UP;
|
int action = down ? ACTION_DOWN : ACTION_UP;
|
||||||
bool repeat = event->repeat;
|
bool repeat = event->repeat;
|
||||||
|
bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT);
|
||||||
switch (keycode) {
|
switch (keycode) {
|
||||||
case SDLK_h:
|
case SDLK_h:
|
||||||
if (control && !shift && !repeat) {
|
// Ctrl+h on all platform, since Cmd+h is already captured by
|
||||||
|
// the system on macOS to hide the window
|
||||||
|
if (control && ctrl && !meta && !shift && !repeat) {
|
||||||
action_home(controller, action);
|
action_home(controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_b: // fall-through
|
case SDLK_b: // fall-through
|
||||||
case SDLK_BACKSPACE:
|
case SDLK_BACKSPACE:
|
||||||
if (control && !shift && !repeat) {
|
if (control && cmd && !shift && !repeat) {
|
||||||
action_back(controller, action);
|
action_back(controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_s:
|
case SDLK_s:
|
||||||
if (control && !shift && !repeat) {
|
if (control && cmd && !shift && !repeat) {
|
||||||
action_app_switch(controller, action);
|
action_app_switch(controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_m:
|
case SDLK_m:
|
||||||
if (control && !shift && !repeat) {
|
// Ctrl+m on all platform, since Cmd+m is already captured by
|
||||||
|
// the system on macOS to minimize the window
|
||||||
|
if (control && ctrl && !meta && !shift && !repeat) {
|
||||||
action_menu(controller, action);
|
action_menu(controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_p:
|
case SDLK_p:
|
||||||
if (control && !shift && !repeat) {
|
if (control && cmd && !shift && !repeat) {
|
||||||
action_power(controller, action);
|
action_power(controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_o:
|
case SDLK_o:
|
||||||
if (control && !repeat && down) {
|
if (control && cmd && down) {
|
||||||
enum screen_power_mode mode = shift
|
enum screen_power_mode mode = shift
|
||||||
? SCREEN_POWER_MODE_NORMAL
|
? SCREEN_POWER_MODE_NORMAL
|
||||||
: SCREEN_POWER_MODE_OFF;
|
: SCREEN_POWER_MODE_OFF;
|
||||||
@@ -325,71 +329,67 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_DOWN:
|
case SDLK_DOWN:
|
||||||
if (control && !shift) {
|
if (control && cmd && !shift) {
|
||||||
// forward repeated events
|
// forward repeated events
|
||||||
action_volume_down(controller, action);
|
action_volume_down(controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_UP:
|
case SDLK_UP:
|
||||||
if (control && !shift) {
|
if (control && cmd && !shift) {
|
||||||
// forward repeated events
|
// forward repeated events
|
||||||
action_volume_up(controller, action);
|
action_volume_up(controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_LEFT:
|
case SDLK_LEFT:
|
||||||
if (!shift && !repeat && down) {
|
if (cmd && !shift && down) {
|
||||||
rotate_client_left(im->screen);
|
rotate_client_left(im->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_RIGHT:
|
case SDLK_RIGHT:
|
||||||
if (!shift && !repeat && down) {
|
if (cmd && !shift && down) {
|
||||||
rotate_client_right(im->screen);
|
rotate_client_right(im->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_c:
|
case SDLK_c:
|
||||||
if (control && !shift && !repeat && down) {
|
if (control && cmd && !shift && !repeat && down) {
|
||||||
// Press COPY, then get the clipboard content
|
request_device_clipboard(controller);
|
||||||
request_device_clipboard(controller, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case SDLK_x:
|
|
||||||
if (control && !shift && !repeat && down) {
|
|
||||||
// For convenience (especially on macOS), bind Meta+x to
|
|
||||||
// CUT (even if it is already accessible by pressing Ctrl+x
|
|
||||||
// on the device)
|
|
||||||
action_cut(controller, action);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_v:
|
case SDLK_v:
|
||||||
if (control && !shift && !repeat && down) {
|
if (control && cmd && !repeat && down) {
|
||||||
// Inject the text as input events
|
if (shift) {
|
||||||
clipboard_paste(controller);
|
// store the text in the device clipboard and paste
|
||||||
|
set_device_clipboard(controller, true);
|
||||||
|
} else {
|
||||||
|
// inject the text as input events
|
||||||
|
clipboard_paste(controller);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_f:
|
case SDLK_f:
|
||||||
if (!shift && !repeat && down) {
|
if (!shift && cmd && !repeat && down) {
|
||||||
screen_switch_fullscreen(im->screen);
|
screen_switch_fullscreen(im->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_w:
|
case SDLK_x:
|
||||||
if (!shift && !repeat && down) {
|
if (!shift && cmd && !repeat && down) {
|
||||||
screen_resize_to_fit(im->screen);
|
screen_resize_to_fit(im->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_g:
|
case SDLK_g:
|
||||||
if (!shift && !repeat && down) {
|
if (!shift && cmd && !repeat && down) {
|
||||||
screen_resize_to_pixel_perfect(im->screen);
|
screen_resize_to_pixel_perfect(im->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_i:
|
case SDLK_i:
|
||||||
if (!shift && !repeat && down) {
|
if (!shift && cmd && !repeat && down) {
|
||||||
struct fps_counter *fps_counter =
|
struct fps_counter *fps_counter =
|
||||||
im->video_buffer->fps_counter;
|
im->video_buffer->fps_counter;
|
||||||
switch_fps_counter_state(fps_counter);
|
switch_fps_counter_state(fps_counter);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_n:
|
case SDLK_n:
|
||||||
if (control && !repeat && down) {
|
if (control && cmd && !repeat && down) {
|
||||||
if (shift) {
|
if (shift) {
|
||||||
collapse_notification_panel(controller);
|
collapse_notification_panel(controller);
|
||||||
} else {
|
} else {
|
||||||
@@ -398,7 +398,7 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_r:
|
case SDLK_r:
|
||||||
if (control && !shift && !repeat && down) {
|
if (control && cmd && !shift && !repeat && down) {
|
||||||
rotate_device(controller);
|
rotate_device(controller);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -411,14 +411,6 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!meta);
|
|
||||||
|
|
||||||
if (ctrl && !shift && keycode == SDLK_v && down) {
|
|
||||||
// Synchronize the computer clipboard to the device clipboard before
|
|
||||||
// sending Ctrl+v
|
|
||||||
set_device_clipboard(controller, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct control_msg msg;
|
struct control_msg msg;
|
||||||
if (convert_input_key(event, &msg, im->prefer_text)) {
|
if (convert_input_key(event, &msg, im->prefer_text)) {
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!controller_push_msg(controller, &msg)) {
|
||||||
@@ -435,7 +427,7 @@ convert_mouse_motion(const SDL_MouseMotionEvent *from, struct screen *screen,
|
|||||||
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
|
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
|
||||||
to->inject_touch_event.position.screen_size = screen->frame_size;
|
to->inject_touch_event.position.screen_size = screen->frame_size;
|
||||||
to->inject_touch_event.position.point =
|
to->inject_touch_event.position.point =
|
||||||
screen_convert_to_frame_coords(screen, from->x, from->y);
|
screen_convert_window_to_frame_coords(screen, from->x, from->y);
|
||||||
to->inject_touch_event.pressure = 1.f;
|
to->inject_touch_event.pressure = 1.f;
|
||||||
to->inject_touch_event.buttons = convert_mouse_buttons(from->state);
|
to->inject_touch_event.buttons = convert_mouse_buttons(from->state);
|
||||||
|
|
||||||
@@ -473,15 +465,15 @@ convert_touch(const SDL_TouchFingerEvent *from, struct screen *screen,
|
|||||||
to->inject_touch_event.pointer_id = from->fingerId;
|
to->inject_touch_event.pointer_id = from->fingerId;
|
||||||
to->inject_touch_event.position.screen_size = screen->frame_size;
|
to->inject_touch_event.position.screen_size = screen->frame_size;
|
||||||
|
|
||||||
int ww;
|
int dw;
|
||||||
int wh;
|
int dh;
|
||||||
SDL_GL_GetDrawableSize(screen->window, &ww, &wh);
|
SDL_GL_GetDrawableSize(screen->window, &dw, &dh);
|
||||||
|
|
||||||
// SDL touch event coordinates are normalized in the range [0; 1]
|
// SDL touch event coordinates are normalized in the range [0; 1]
|
||||||
int32_t x = from->x * ww;
|
int32_t x = from->x * dw;
|
||||||
int32_t y = from->y * wh;
|
int32_t y = from->y * dh;
|
||||||
to->inject_touch_event.position.point =
|
to->inject_touch_event.position.point =
|
||||||
screen_convert_to_frame_coords(screen, x, y);
|
screen_convert_drawable_to_frame_coords(screen, x, y);
|
||||||
|
|
||||||
to->inject_touch_event.pressure = from->pressure;
|
to->inject_touch_event.pressure = from->pressure;
|
||||||
to->inject_touch_event.buttons = 0;
|
to->inject_touch_event.buttons = 0;
|
||||||
@@ -511,7 +503,7 @@ convert_mouse_button(const SDL_MouseButtonEvent *from, struct screen *screen,
|
|||||||
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
|
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
|
||||||
to->inject_touch_event.position.screen_size = screen->frame_size;
|
to->inject_touch_event.position.screen_size = screen->frame_size;
|
||||||
to->inject_touch_event.position.point =
|
to->inject_touch_event.position.point =
|
||||||
screen_convert_to_frame_coords(screen, from->x, from->y);
|
screen_convert_window_to_frame_coords(screen, from->x, from->y);
|
||||||
to->inject_touch_event.pressure = 1.f;
|
to->inject_touch_event.pressure = 1.f;
|
||||||
to->inject_touch_event.buttons =
|
to->inject_touch_event.buttons =
|
||||||
convert_mouse_buttons(SDL_BUTTON(from->button));
|
convert_mouse_buttons(SDL_BUTTON(from->button));
|
||||||
@@ -576,7 +568,8 @@ convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct screen *screen,
|
|||||||
|
|
||||||
struct position position = {
|
struct position position = {
|
||||||
.screen_size = screen->frame_size,
|
.screen_size = screen->frame_size,
|
||||||
.point = screen_convert_to_frame_coords(screen, mouse_x, mouse_y),
|
.point = screen_convert_window_to_frame_coords(screen,
|
||||||
|
mouse_x, mouse_y),
|
||||||
};
|
};
|
||||||
|
|
||||||
to->type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT;
|
to->type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT;
|
||||||
|
|||||||
@@ -579,14 +579,14 @@ screen_handle_window_event(struct screen *screen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct point
|
struct point
|
||||||
screen_convert_to_frame_coords(struct screen *screen, int32_t x, int32_t y) {
|
screen_convert_drawable_to_frame_coords(struct screen *screen,
|
||||||
|
int32_t x, int32_t y) {
|
||||||
unsigned rotation = screen->rotation;
|
unsigned rotation = screen->rotation;
|
||||||
assert(rotation < 4);
|
assert(rotation < 4);
|
||||||
|
|
||||||
int32_t w = screen->content_size.width;
|
int32_t w = screen->content_size.width;
|
||||||
int32_t h = screen->content_size.height;
|
int32_t h = screen->content_size.height;
|
||||||
|
|
||||||
screen_hidpi_scale_coords(screen, &x, &y);
|
|
||||||
|
|
||||||
x = (int64_t) (x - screen->rect.x) * w / screen->rect.w;
|
x = (int64_t) (x - screen->rect.x) * w / screen->rect.w;
|
||||||
y = (int64_t) (y - screen->rect.y) * h / screen->rect.h;
|
y = (int64_t) (y - screen->rect.y) * h / screen->rect.h;
|
||||||
@@ -615,6 +615,13 @@ screen_convert_to_frame_coords(struct screen *screen, int32_t x, int32_t y) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct point
|
||||||
|
screen_convert_window_to_frame_coords(struct screen *screen,
|
||||||
|
int32_t x, int32_t y) {
|
||||||
|
screen_hidpi_scale_coords(screen, &x, &y);
|
||||||
|
return screen_convert_drawable_to_frame_coords(screen, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_hidpi_scale_coords(struct screen *screen, int32_t *x, int32_t *y) {
|
screen_hidpi_scale_coords(struct screen *screen, int32_t *x, int32_t *y) {
|
||||||
// take the HiDPI scaling (dw/ww and dh/wh) into account
|
// take the HiDPI scaling (dw/ww and dh/wh) into account
|
||||||
|
|||||||
@@ -126,7 +126,14 @@ screen_handle_window_event(struct screen *screen, const SDL_WindowEvent *event);
|
|||||||
// convert point from window coordinates to frame coordinates
|
// convert point from window coordinates to frame coordinates
|
||||||
// x and y are expressed in pixels
|
// x and y are expressed in pixels
|
||||||
struct point
|
struct point
|
||||||
screen_convert_to_frame_coords(struct screen *screen, int32_t x, int32_t y);
|
screen_convert_window_to_frame_coords(struct screen *screen,
|
||||||
|
int32_t x, int32_t y);
|
||||||
|
|
||||||
|
// convert point from drawable coordinates to frame coordinates
|
||||||
|
// x and y are expressed in pixels
|
||||||
|
struct point
|
||||||
|
screen_convert_drawable_to_frame_coords(struct screen *screen,
|
||||||
|
int32_t x, int32_t y);
|
||||||
|
|
||||||
// Convert coordinates from window to drawable.
|
// Convert coordinates from window to drawable.
|
||||||
// Events are expressed in window coordinates, but content is expressed in
|
// Events are expressed in window coordinates, but content is expressed in
|
||||||
|
|||||||
@@ -185,18 +185,14 @@ static void test_serialize_collapse_notification_panel(void) {
|
|||||||
static void test_serialize_get_clipboard(void) {
|
static void test_serialize_get_clipboard(void) {
|
||||||
struct control_msg msg = {
|
struct control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
.type = CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
||||||
.get_clipboard = {
|
|
||||||
.copy = true,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
|
||||||
int size = control_msg_serialize(&msg, buf);
|
int size = control_msg_serialize(&msg, buf);
|
||||||
assert(size == 2);
|
assert(size == 1);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
||||||
1, // copy
|
|
||||||
};
|
};
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ echo "Generating java from aidl..."
|
|||||||
cd "$SERVER_DIR/src/main/aidl"
|
cd "$SERVER_DIR/src/main/aidl"
|
||||||
"$ANDROID_HOME/build-tools/$BUILD_TOOLS/aidl" -o"$CLASSES_DIR" \
|
"$ANDROID_HOME/build-tools/$BUILD_TOOLS/aidl" -o"$CLASSES_DIR" \
|
||||||
android/view/IRotationWatcher.aidl
|
android/view/IRotationWatcher.aidl
|
||||||
|
"$ANDROID_HOME/build-tools/$BUILD_TOOLS/aidl" -o"$CLASSES_DIR" \
|
||||||
|
android/content/IOnPrimaryClipChangedListener.aidl
|
||||||
|
|
||||||
echo "Compiling java sources..."
|
echo "Compiling java sources..."
|
||||||
cd ../java
|
cd ../java
|
||||||
@@ -55,6 +57,7 @@ cd "$CLASSES_DIR"
|
|||||||
"$ANDROID_HOME/build-tools/$BUILD_TOOLS/dx" --dex \
|
"$ANDROID_HOME/build-tools/$BUILD_TOOLS/dx" --dex \
|
||||||
--output "$BUILD_DIR/classes.dex" \
|
--output "$BUILD_DIR/classes.dex" \
|
||||||
android/view/*.class \
|
android/view/*.class \
|
||||||
|
android/content/*.class \
|
||||||
com/genymobile/scrcpy/*.class \
|
com/genymobile/scrcpy/*.class \
|
||||||
com/genymobile/scrcpy/wrappers/*.class
|
com/genymobile/scrcpy/wrappers/*.class
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ public final class ControlMessage {
|
|||||||
public static final int TYPE_SET_SCREEN_POWER_MODE = 9;
|
public static final int TYPE_SET_SCREEN_POWER_MODE = 9;
|
||||||
public static final int TYPE_ROTATE_DEVICE = 10;
|
public static final int TYPE_ROTATE_DEVICE = 10;
|
||||||
|
|
||||||
|
public static final int FLAGS_PASTE = 1;
|
||||||
|
|
||||||
private int type;
|
private int type;
|
||||||
private String text;
|
private String text;
|
||||||
private int metaState; // KeyEvent.META_*
|
private int metaState; // KeyEvent.META_*
|
||||||
@@ -28,7 +30,7 @@ public final class ControlMessage {
|
|||||||
private Position position;
|
private Position position;
|
||||||
private int hScroll;
|
private int hScroll;
|
||||||
private int vScroll;
|
private int vScroll;
|
||||||
private boolean pressCopyOrPaste;
|
private int flags;
|
||||||
|
|
||||||
private ControlMessage() {
|
private ControlMessage() {
|
||||||
}
|
}
|
||||||
@@ -69,18 +71,13 @@ public final class ControlMessage {
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ControlMessage createGetClipboard(boolean copy) {
|
|
||||||
ControlMessage msg = new ControlMessage();
|
|
||||||
msg.type = TYPE_GET_CLIPBOARD;
|
|
||||||
msg.pressCopyOrPaste = copy;
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ControlMessage createSetClipboard(String text, boolean paste) {
|
public static ControlMessage createSetClipboard(String text, boolean paste) {
|
||||||
ControlMessage msg = new ControlMessage();
|
ControlMessage msg = new ControlMessage();
|
||||||
msg.type = TYPE_SET_CLIPBOARD;
|
msg.type = TYPE_SET_CLIPBOARD;
|
||||||
msg.text = text;
|
msg.text = text;
|
||||||
msg.pressCopyOrPaste = paste;
|
if (paste) {
|
||||||
|
msg.flags = FLAGS_PASTE;
|
||||||
|
}
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +141,7 @@ public final class ControlMessage {
|
|||||||
return vScroll;
|
return vScroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getPressCopyOrPaste() {
|
public int getFlags() {
|
||||||
return pressCopyOrPaste;
|
return flags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ public class ControlMessageReader {
|
|||||||
static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 27;
|
static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 27;
|
||||||
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20;
|
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20;
|
||||||
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
|
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;
|
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)
|
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:
|
case ControlMessage.TYPE_INJECT_SCROLL_EVENT:
|
||||||
msg = parseInjectScrollEvent();
|
msg = parseInjectScrollEvent();
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_GET_CLIPBOARD:
|
|
||||||
msg = parseGetClipboard();
|
|
||||||
break;
|
|
||||||
case ControlMessage.TYPE_SET_CLIPBOARD:
|
case ControlMessage.TYPE_SET_CLIPBOARD:
|
||||||
msg = parseSetClipboard();
|
msg = parseSetClipboard();
|
||||||
break;
|
break;
|
||||||
@@ -80,6 +76,7 @@ public class ControlMessageReader {
|
|||||||
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
|
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
|
||||||
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
|
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||||
case ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL:
|
case ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL:
|
||||||
|
case ControlMessage.TYPE_GET_CLIPBOARD:
|
||||||
case ControlMessage.TYPE_ROTATE_DEVICE:
|
case ControlMessage.TYPE_ROTATE_DEVICE:
|
||||||
msg = ControlMessage.createEmpty(type);
|
msg = ControlMessage.createEmpty(type);
|
||||||
break;
|
break;
|
||||||
@@ -151,14 +148,6 @@ public class ControlMessageReader {
|
|||||||
return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll);
|
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() {
|
private ControlMessage parseSetClipboard() {
|
||||||
if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) {
|
if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -104,10 +104,14 @@ public class Controller {
|
|||||||
device.collapsePanels();
|
device.collapsePanels();
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_GET_CLIPBOARD:
|
case ControlMessage.TYPE_GET_CLIPBOARD:
|
||||||
getClipboard(msg.getPressCopyOrPaste());
|
String clipboardText = device.getClipboardText();
|
||||||
|
if (clipboardText != null) {
|
||||||
|
sender.pushClipboardText(clipboardText);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_SET_CLIPBOARD:
|
case ControlMessage.TYPE_SET_CLIPBOARD:
|
||||||
setClipboard(msg.getText(), msg.getPressCopyOrPaste());
|
boolean paste = (msg.getFlags() & ControlMessage.FLAGS_PASTE) != 0;
|
||||||
|
setClipboard(msg.getText(), paste);
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
|
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
|
||||||
if (device.supportsInputEvents()) {
|
if (device.supportsInputEvents()) {
|
||||||
@@ -225,23 +229,6 @@ public class Controller {
|
|||||||
return device.injectKeycode(keycode);
|
return device.injectKeycode(keycode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean 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()) {
|
|
||||||
// If there is something to copy, the clipboard will be automatically sent to the computer clipboard via the ClipboardListener
|
|
||||||
return device.injectKeycode(KeyEvent.KEYCODE_COPY);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can't press COPY, so only synchronize the current clipboard
|
|
||||||
String clipboardText = device.getClipboardText();
|
|
||||||
if (clipboardText != null) {
|
|
||||||
sender.pushClipboardText(clipboardText);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean setClipboard(String text, boolean paste) {
|
private boolean setClipboard(String text, boolean paste) {
|
||||||
boolean ok = device.setClipboardText(text);
|
boolean ok = device.setClipboardText(text);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
|
|||||||
@@ -200,7 +200,6 @@ public class ControlMessageReaderTest {
|
|||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
DataOutputStream dos = new DataOutputStream(bos);
|
DataOutputStream dos = new DataOutputStream(bos);
|
||||||
dos.writeByte(ControlMessage.TYPE_GET_CLIPBOARD);
|
dos.writeByte(ControlMessage.TYPE_GET_CLIPBOARD);
|
||||||
dos.writeByte(1); // copy
|
|
||||||
|
|
||||||
byte[] packet = bos.toByteArray();
|
byte[] packet = bos.toByteArray();
|
||||||
|
|
||||||
@@ -208,7 +207,6 @@ public class ControlMessageReaderTest {
|
|||||||
ControlMessage event = reader.next();
|
ControlMessage event = reader.next();
|
||||||
|
|
||||||
Assert.assertEquals(ControlMessage.TYPE_GET_CLIPBOARD, event.getType());
|
Assert.assertEquals(ControlMessage.TYPE_GET_CLIPBOARD, event.getType());
|
||||||
Assert.assertTrue(event.getPressCopyOrPaste());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -230,7 +228,9 @@ public class ControlMessageReaderTest {
|
|||||||
|
|
||||||
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
|
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
|
||||||
Assert.assertEquals("testé", event.getText());
|
Assert.assertEquals("testé", event.getText());
|
||||||
Assert.assertTrue(event.getPressCopyOrPaste());
|
|
||||||
|
boolean parse = (event.getFlags() & ControlMessage.FLAGS_PASTE) != 0;
|
||||||
|
Assert.assertTrue(parse);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -256,7 +256,9 @@ public class ControlMessageReaderTest {
|
|||||||
|
|
||||||
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
|
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
|
||||||
Assert.assertEquals(text, event.getText());
|
Assert.assertEquals(text, event.getText());
|
||||||
Assert.assertTrue(event.getPressCopyOrPaste());
|
|
||||||
|
boolean parse = (event.getFlags() & ControlMessage.FLAGS_PASTE) != 0;
|
||||||
|
Assert.assertTrue(parse);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user