Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8da10eb4af | ||
|
|
b330ba448b | ||
|
|
a98b74df3d | ||
|
|
567c5a7da7 | ||
|
|
9badd2bdf0 | ||
|
|
31cee2c49f | ||
|
|
51d969b20c | ||
|
|
149de2f788 | ||
|
|
26cadf1022 | ||
|
|
f650b0195f |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,8 +1,5 @@
|
|||||||
build/
|
build/
|
||||||
/dist/
|
/dist/
|
||||||
/build-*/
|
|
||||||
/build_*/
|
|
||||||
/release-*/
|
|
||||||
.idea/
|
.idea/
|
||||||
.gradle/
|
.gradle/
|
||||||
/x/
|
/x/
|
||||||
|
|||||||
83
README.md
83
README.md
@@ -354,7 +354,7 @@ scrcpy --fullscreen
|
|||||||
scrcpy -f # short version
|
scrcpy -f # short version
|
||||||
```
|
```
|
||||||
|
|
||||||
Fullscreen can then be toggled dynamically with `RCtrl`+`f`.
|
Fullscreen can then be toggled dynamically with `Ctrl`+`f`.
|
||||||
|
|
||||||
#### Rotation
|
#### Rotation
|
||||||
|
|
||||||
@@ -370,18 +370,18 @@ Possibles values are:
|
|||||||
- `2`: 180 degrees
|
- `2`: 180 degrees
|
||||||
- `3`: 90 degrees clockwise
|
- `3`: 90 degrees clockwise
|
||||||
|
|
||||||
The rotation can also be changed dynamically with `RCtrl`+`←` _(left)_ and
|
The rotation can also be changed dynamically with `Ctrl`+`←` _(left)_ and
|
||||||
`RCtrl`+`→` _(right)_.
|
`Ctrl`+`→` _(right)_.
|
||||||
|
|
||||||
Note that _scrcpy_ manages 3 different rotations:
|
Note that _scrcpy_ manages 3 different rotations:
|
||||||
- `RCtrl`+`r` requests the device to switch between portrait and landscape (the
|
- `Ctrl`+`r` requests the device to switch between portrait and landscape (the
|
||||||
current running app may refuse, if it does support the requested
|
current running app may refuse, if it does support the requested
|
||||||
orientation).
|
orientation).
|
||||||
- `--lock-video-orientation` changes the mirroring orientation (the orientation
|
- `--lock-video-orientation` changes the mirroring orientation (the orientation
|
||||||
of the video sent from the device to the computer). This affects the
|
of the video sent from the device to the computer). This affects the
|
||||||
recording.
|
recording.
|
||||||
- `--rotation` (or `RCtrl`+`←`/`RCtrl`+`→`) rotates only the window content.
|
- `--rotation` (or `Ctrl`+`←`/`Ctrl`+`→`) rotates only the window content. This
|
||||||
This affects only the display, not the recording.
|
affects only the display, not the recording.
|
||||||
|
|
||||||
|
|
||||||
### Other mirroring options
|
### Other mirroring options
|
||||||
@@ -437,9 +437,9 @@ scrcpy --turn-screen-off
|
|||||||
scrcpy -S
|
scrcpy -S
|
||||||
```
|
```
|
||||||
|
|
||||||
Or by pressing `RCtrl`+`o` at any time.
|
Or by pressing `Ctrl`+`o` at any time.
|
||||||
|
|
||||||
To turn it back on, press `RCtrl`+`Shift`+`o` (or `POWER`, `RCtrl`+`p`).
|
To turn it back on, press `Ctrl`+`Shift`+`o` (or `POWER`, `Ctrl`+`p`).
|
||||||
|
|
||||||
It can be useful to also prevent the device to sleep:
|
It can be useful to also prevent the device to sleep:
|
||||||
|
|
||||||
@@ -483,22 +483,24 @@ Note that it only shows _physical_ touches (with the finger on the device).
|
|||||||
|
|
||||||
#### Rotate device screen
|
#### Rotate device screen
|
||||||
|
|
||||||
Press `RCtrl`+`r` to switch between portrait and landscape modes.
|
Press `Ctrl`+`r` to switch between portrait and landscape modes.
|
||||||
|
|
||||||
Note that it rotates only if the application in foreground supports the
|
Note that it rotates only if the application in foreground supports the
|
||||||
requested orientation.
|
requested orientation.
|
||||||
|
|
||||||
#### Copy-paste
|
#### Copy-paste
|
||||||
|
|
||||||
Any time the Android clipboard changes, it is automatically synchronized to the
|
It is possible to synchronize clipboards between the computer and the device, in
|
||||||
computer clipboard.
|
both directions:
|
||||||
|
|
||||||
`Ctrl`+`c` (copy), `Ctrl`+`x` (cut) and `LCtrl`+`v` (paste) work as you expect.
|
- `Ctrl`+`c` copies the device clipboard to the computer clipboard;
|
||||||
|
- `Ctrl`+`Shift`+`v` copies the computer clipboard to the device clipboard (and
|
||||||
In addition, `RCtrl`+`v` allows to inject the computer clipboard content as a
|
pastes if the device runs Android >= 7);
|
||||||
sequence of text event. Even if it can break non-ASCII content, this is
|
- `Ctrl`+`v` _pastes_ the computer clipboard as a sequence of text events (but
|
||||||
sometimes necessary when pasting directly is not possible.
|
breaks non-ASCII characters).
|
||||||
|
|
||||||
|
Moreover, any time the Android clipboard changes, it is automatically
|
||||||
|
synchronized to the computer clipboard.
|
||||||
|
|
||||||
#### Text injection preference
|
#### Text injection preference
|
||||||
|
|
||||||
@@ -558,37 +560,36 @@ Also see [issue #14].
|
|||||||
|
|
||||||
## Shortcuts
|
## Shortcuts
|
||||||
|
|
||||||
`RCtrl` is the right `Ctrl` key (the left `Ctrl` key is forwarded to the
|
_`Meta` is typically the `Windows` key on the keyboard, or `Cmd` on macOS._
|
||||||
device).
|
|
||||||
|
|
||||||
On macOS, `Cmd` also works (for shortcuts which are not already captured by the
|
|
||||||
system).
|
|
||||||
|
|
||||||
| Action | Shortcut
|
| Action | Shortcut
|
||||||
| ------------------------------------------- |:-----------------------------
|
| ---------------------------------------------------- |:-----------------------------
|
||||||
| Switch fullscreen mode | `RCtrl`+`f`
|
| Switch fullscreen mode | `Meta`+`f`
|
||||||
| Rotate display left | `RCtrl`+`←`
|
| Rotate display left | `Meta`+`←` _(left)_
|
||||||
| Rotate display right | `RCtrl`+`→`
|
| Rotate display right | `Meta`+`→` _(right)_
|
||||||
| Resize window to 1:1 (pixel-perfect) | `RCtrl`+`g`
|
| Resize window to 1:1 (pixel-perfect) | `Meta`+`g`
|
||||||
| Resize window to remove black borders | `RCtrl`+`w` \| _Double-click¹_
|
| Resize window to remove black borders | `Meta`+`w` \| _Double-click¹_
|
||||||
| Click on `HOME` | `RCtrl`+`h` \| _Middle-click_
|
| Click on `HOME` | `Meta`+`h` \| _Middle-click_
|
||||||
| Click on `BACK` | `RCtrl`+`b` \| _Right-click²_
|
| Click on `BACK` | `Meta`+`b` \| _Right-click²_
|
||||||
| Click on `APP_SWITCH` | `RCtrl`+`s`
|
| Click on `APP_SWITCH` | `Meta`+`s`
|
||||||
| Click on `MENU` | `RCtrl`+`m`
|
| Click on `MENU` | `Meta`+`m`
|
||||||
| Click on `VOLUME_UP` | `RCtrl`+`↑` _(up)_
|
| Click on `VOLUME_UP` | `Meta`+`↑` _(up)_
|
||||||
| Click on `VOLUME_DOWN` | `RCtrl`+`↓` _(down)_
|
| Click on `VOLUME_DOWN` | `Meta`+`↓` _(down)_
|
||||||
| Click on `POWER` | `RCtrl`+`p`
|
| Click on `POWER` | `Meta`+`p`
|
||||||
| Power on | _Right-click²_
|
| Power on | _Right-click²_
|
||||||
| Turn device screen off (keep mirroring) | `RCtrl`+`o`
|
| Turn device screen off (keep mirroring) | `Meta`+`o`
|
||||||
| Turn device screen on | `RCtrl`+`Shift`+`o`
|
| Turn device screen on | `Meta`+`Shift`+`o`
|
||||||
| Rotate device screen | `RCtrl`+`r`
|
| Rotate device screen | `Meta`+`r`
|
||||||
| Expand notification panel | `RCtrl`+`n`
|
| Expand notification panel | `Meta`+`n`
|
||||||
| Collapse notification panel | `RCtrl`+`Shift`+`n`
|
| Collapse notification panel | `Meta`+`Shift`+`n`
|
||||||
| Inject computer clipboard text | `RCtrl`+`v`
|
| Press COPY³, then Copy device clipboard to computer | `Meta`+`c`
|
||||||
| Enable/disable FPS counter (on stdout) | `RCtrl`+`i`
|
| Press CUT³ | `Meta`+`x`
|
||||||
|
| 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
@@ -203,54 +203,52 @@ Default is 0 (automatic).\n
|
|||||||
|
|
||||||
.SH SHORTCUTS
|
.SH SHORTCUTS
|
||||||
|
|
||||||
RCtrl is the right Ctrl key (the left Ctrl key is forwarded to the device).
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+f
|
.B Meta+f
|
||||||
Switch fullscreen mode
|
Switch fullscreen mode
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+Left
|
.B Meta+Left
|
||||||
Rotate display left
|
Rotate display left
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+Right
|
.B Meta+Right
|
||||||
Rotate display right
|
Rotate display right
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+g
|
.B Meta+g
|
||||||
Resize window to 1:1 (pixel\-perfect)
|
Resize window to 1:1 (pixel\-perfect)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+w, Double\-click on black borders
|
.B Meta+w, Double\-click on black borders
|
||||||
Resize window to remove black borders
|
Resize window to remove black borders
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+h, Home, Middle\-click
|
.B Meta+h, Home, Middle\-click
|
||||||
Click on HOME
|
Click on HOME
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+b, RCtrl+Backspace, Right\-click (when screen is on)
|
.B Meta+b, Meta+Backspace, Right\-click (when screen is on)
|
||||||
Click on BACK
|
Click on BACK
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+s
|
.B Meta+s
|
||||||
Click on APP_SWITCH
|
Click on APP_SWITCH
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+m
|
.B Meta+m
|
||||||
Click on MENU
|
Click on MENU
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+Up
|
.B Meta+Up
|
||||||
Click on VOLUME_UP
|
Click on VOLUME_UP
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+Down
|
.B Meta+Down
|
||||||
Click on VOLUME_DOWN
|
Click on VOLUME_DOWN
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+p
|
.B Meta+p
|
||||||
Click on POWER (turn screen on/off)
|
Click on POWER (turn screen on/off)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
@@ -258,31 +256,39 @@ Click on POWER (turn screen on/off)
|
|||||||
Turn screen on
|
Turn screen on
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+o
|
.B Meta+o
|
||||||
Turn device screen off (keep mirroring)
|
Turn device screen off (keep mirroring)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+Shift+o
|
.B Meta+Shift+o
|
||||||
Turn device screen on
|
Turn device screen on
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+r
|
.B Meta+r
|
||||||
Rotate device screen
|
Rotate device screen
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+n
|
.B Meta+n
|
||||||
Expand notification panel
|
Expand notification panel
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+Shift+n
|
.B Meta+Shift+n
|
||||||
Collapse notification panel
|
Collapse notification panel
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+v
|
.B Meta+c
|
||||||
Inject computer clipboard text
|
Press COPY (Android >= 7), then copy device clipboard to computer
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B RCtrl+i
|
.B Meta+x
|
||||||
|
Press CUT (Android >= 7)
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B Meta+v
|
||||||
|
Paste computer clipboard to device
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B Meta+i
|
||||||
Enable/disable FPS counter (print frames/second in logs)
|
Enable/disable FPS counter (print frames/second in logs)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -12,6 +12,11 @@
|
|||||||
|
|
||||||
void
|
void
|
||||||
scrcpy_print_usage(const char *arg0) {
|
scrcpy_print_usage(const char *arg0) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
# define MOD "Cmd"
|
||||||
|
#else
|
||||||
|
# define MOD "Meta"
|
||||||
|
#endif
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage: %s [options]\n"
|
"Usage: %s [options]\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -181,71 +186,75 @@ scrcpy_print_usage(const char *arg0) {
|
|||||||
"\n"
|
"\n"
|
||||||
"Shortcuts:\n"
|
"Shortcuts:\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl is the right Ctrl key (the left Ctrl key is forwarded to\n"
|
" " MOD "+f\n"
|
||||||
" the device.\n"
|
|
||||||
"\n"
|
|
||||||
" RCtrl+f\n"
|
|
||||||
" Switch fullscreen mode\n"
|
" Switch fullscreen mode\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+Left\n"
|
" " MOD "+Left\n"
|
||||||
" Rotate display left\n"
|
" Rotate display left\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+Right\n"
|
" " MOD "+Right\n"
|
||||||
" Rotate display right\n"
|
" Rotate display right\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+g\n"
|
" " MOD "+g\n"
|
||||||
" Resize window to 1:1 (pixel-perfect)\n"
|
" Resize window to 1:1 (pixel-perfect)\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+w\n"
|
" " MOD "+w\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"
|
||||||
" RCtrl+h\n"
|
" Ctrl+h\n"
|
||||||
" Middle-click\n"
|
" Middle-click\n"
|
||||||
" Click on HOME\n"
|
" Click on HOME\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+b\n"
|
" " MOD "+b\n"
|
||||||
" RCtrl+Backspace\n"
|
" " MOD "+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"
|
||||||
" RCtrl+s\n"
|
" " MOD "+s\n"
|
||||||
" Click on APP_SWITCH\n"
|
" Click on APP_SWITCH\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+m\n"
|
" Ctrl+m\n"
|
||||||
" Click on MENU\n"
|
" Click on MENU\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+Up\n"
|
" " MOD "+Up\n"
|
||||||
" Click on VOLUME_UP\n"
|
" Click on VOLUME_UP\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+Down\n"
|
" " MOD "+Down\n"
|
||||||
" Click on VOLUME_DOWN\n"
|
" Click on VOLUME_DOWN\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+p\n"
|
" " MOD "+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"
|
||||||
" RCtrl+o\n"
|
" " MOD "+o\n"
|
||||||
" Turn device screen off (keep mirroring)\n"
|
" Turn device screen off (keep mirroring)\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+Shift+o\n"
|
" " MOD "+Shift+o\n"
|
||||||
" Turn device screen on\n"
|
" Turn device screen on\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+r\n"
|
" " MOD "+r\n"
|
||||||
" Rotate device screen\n"
|
" Rotate device screen\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+n\n"
|
" " MOD "+n\n"
|
||||||
" Expand notification panel\n"
|
" Expand notification panel\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+Shift+n\n"
|
" " MOD "+Shift+n\n"
|
||||||
" Collapse notification panel\n"
|
" Collapse notification panel\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+v\n"
|
" " MOD "+c\n"
|
||||||
" Inject computer clipboard text\n"
|
" Press COPY (Android >= 7), then copy device clipboard to\n"
|
||||||
|
" computer\n"
|
||||||
"\n"
|
"\n"
|
||||||
" RCtrl+i\n"
|
" " MOD "+x\n"
|
||||||
|
" Press CUT (Android >= 7)\n"
|
||||||
|
"\n"
|
||||||
|
" " MOD "+v\n"
|
||||||
|
" Paste computer clipboard to device\n"
|
||||||
|
"\n"
|
||||||
|
" " MOD "+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"
|
||||||
@@ -256,6 +265,7 @@ 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,6 +66,9 @@ 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,
|
||||||
@@ -79,7 +82,6 @@ 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,6 +60,9 @@ 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;
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod,
|
|||||||
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_LCTRL, AKEYCODE_CTRL_LEFT);
|
||||||
|
MAP(SDLK_RCTRL, AKEYCODE_CTRL_RIGHT);
|
||||||
MAP(SDLK_LSHIFT, AKEYCODE_SHIFT_LEFT);
|
MAP(SDLK_LSHIFT, AKEYCODE_SHIFT_LEFT);
|
||||||
MAP(SDLK_RSHIFT, AKEYCODE_SHIFT_RIGHT);
|
MAP(SDLK_RSHIFT, AKEYCODE_SHIFT_RIGHT);
|
||||||
}
|
}
|
||||||
@@ -114,7 +115,7 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefer_text && !(mod & KMOD_LCTRL)) {
|
if (prefer_text) {
|
||||||
// do not forward alpha and space key events
|
// do not forward alpha and space key events
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,11 @@ 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) {
|
||||||
@@ -101,6 +106,17 @@ collapse_notification_panel(struct controller *controller) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
request_device_clipboard(struct controller *controller, bool copy) {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_device_clipboard(struct controller *controller, bool paste) {
|
set_device_clipboard(struct controller *controller, bool paste) {
|
||||||
char *text = SDL_GetClipboardText();
|
char *text = SDL_GetClipboardText();
|
||||||
@@ -242,25 +258,6 @@ convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
inject_as_ctrl(struct input_manager *im, const SDL_KeyboardEvent *event) {
|
|
||||||
struct control_msg msg;
|
|
||||||
|
|
||||||
if (!convert_input_key(event, &msg, false)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable RCtrl and Meta
|
|
||||||
msg.inject_keycode.metastate &=
|
|
||||||
~(AMETA_CTRL_RIGHT_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
|
|
||||||
// Enable LCtrl
|
|
||||||
msg.inject_keycode.metastate |= AMETA_CTRL_LEFT_ON;
|
|
||||||
|
|
||||||
if (!controller_push_msg(im->controller, &msg)) {
|
|
||||||
LOGW("Could not request 'inject keycode'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
input_manager_process_key(struct input_manager *im,
|
input_manager_process_key(struct input_manager *im,
|
||||||
const SDL_KeyboardEvent *event,
|
const SDL_KeyboardEvent *event,
|
||||||
@@ -268,22 +265,11 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
// control: indicates the state of the command-line option --no-control
|
// control: indicates the state of the command-line option --no-control
|
||||||
// ctrl: the Ctrl key
|
// ctrl: the Ctrl key
|
||||||
|
|
||||||
bool lctrl = event->keysym.mod & KMOD_LCTRL;
|
bool ctrl = event->keysym.mod & (KMOD_LCTRL | KMOD_RCTRL);
|
||||||
bool rctrl = event->keysym.mod & 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);
|
bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT);
|
||||||
|
|
||||||
bool shortcut_key = rctrl;
|
|
||||||
#ifdef __APPLE__
|
|
||||||
shortcut_key |= meta;
|
|
||||||
#else
|
|
||||||
if (meta) {
|
|
||||||
// No shortcut involve Meta, and it is not forwarded to the device
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (alt) {
|
if (alt) {
|
||||||
// No shortcuts involve Alt, and it is not forwarded to the device
|
// No shortcuts involve Alt, and it is not forwarded to the device
|
||||||
return;
|
return;
|
||||||
@@ -294,14 +280,17 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
SDL_Keycode keycode = event->keysym.sym;
|
SDL_Keycode keycode = event->keysym.sym;
|
||||||
bool down = event->type == SDL_KEYDOWN;
|
bool down = event->type == SDL_KEYDOWN;
|
||||||
|
|
||||||
// Capture all RCtrl events
|
// Capture all Meta events
|
||||||
if (shortcut_key) {
|
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;
|
||||||
switch (keycode) {
|
switch (keycode) {
|
||||||
case SDLK_h:
|
case SDLK_h:
|
||||||
// Ctrl+h on all platform, since Cmd+h is already captured by
|
|
||||||
// the system on macOS to hide the window
|
|
||||||
if (control && !shift && !repeat) {
|
if (control && !shift && !repeat) {
|
||||||
action_home(controller, action);
|
action_home(controller, action);
|
||||||
}
|
}
|
||||||
@@ -318,8 +307,6 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_m:
|
case SDLK_m:
|
||||||
// Ctrl+m on all platform, since Cmd+m is already captured by
|
|
||||||
// the system on macOS to minimize the window
|
|
||||||
if (control && !shift && !repeat) {
|
if (control && !shift && !repeat) {
|
||||||
action_menu(controller, action);
|
action_menu(controller, action);
|
||||||
}
|
}
|
||||||
@@ -359,6 +346,20 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
rotate_client_right(im->screen);
|
rotate_client_right(im->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
case SDLK_c:
|
||||||
|
if (control && !shift && !repeat && down) {
|
||||||
|
// Press COPY, then get the clipboard content
|
||||||
|
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;
|
||||||
case SDLK_v:
|
case SDLK_v:
|
||||||
if (control && !shift && !repeat && down) {
|
if (control && !shift && !repeat && down) {
|
||||||
// Inject the text as input events
|
// Inject the text as input events
|
||||||
@@ -401,15 +402,6 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
rotate_device(controller);
|
rotate_device(controller);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_c:
|
|
||||||
case SDLK_x:
|
|
||||||
if (control && !shift) {
|
|
||||||
// For convenience, forward shortcut_key+c and
|
|
||||||
// shortcut_key+x as Ctrl+c and Ctrl+x (typically "copy" and
|
|
||||||
// "cut", but not always) to the device
|
|
||||||
inject_as_ctrl(im, event);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -419,9 +411,11 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lctrl && !shift && keycode == SDLK_v && down) {
|
assert(!meta);
|
||||||
|
|
||||||
|
if (ctrl && !shift && keycode == SDLK_v && down) {
|
||||||
// Synchronize the computer clipboard to the device clipboard before
|
// Synchronize the computer clipboard to the device clipboard before
|
||||||
// sending Ctrl+V, to allow seamless copy-paste.
|
// sending Ctrl+v
|
||||||
set_device_clipboard(controller, false);
|
set_device_clipboard(controller, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ convert_log_level_to_sdl(enum sc_log_level level) {
|
|||||||
return SDL_LOG_PRIORITY_ERROR;
|
return SDL_LOG_PRIORITY_ERROR;
|
||||||
default:
|
default:
|
||||||
assert(!"unexpected log level");
|
assert(!"unexpected log level");
|
||||||
return SDL_LOG_PRIORITY_INFO;
|
return SC_LOG_LEVEL_INFO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SDL_LogPriority sdl_log = convert_log_level_to_sdl(args.opts.log_level);
|
SDL_LogPriority sdl_log = convert_log_level_to_sdl(args.opts.log_level);
|
||||||
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, sdl_log);
|
SDL_LogSetAllPriority(sdl_log);
|
||||||
|
|
||||||
if (args.help) {
|
if (args.help) {
|
||||||
scrcpy_print_usage(argv[0]);
|
scrcpy_print_usage(argv[0]);
|
||||||
|
|||||||
@@ -185,14 +185,18 @@ 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 == 1);
|
assert(size == 2);
|
||||||
|
|
||||||
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)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,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 paste;
|
private boolean pressCopyOrPaste;
|
||||||
|
|
||||||
private ControlMessage() {
|
private ControlMessage() {
|
||||||
}
|
}
|
||||||
@@ -69,11 +69,18 @@ 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.paste = paste;
|
msg.pressCopyOrPaste = paste;
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +144,7 @@ public final class ControlMessage {
|
|||||||
return vScroll;
|
return vScroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getPaste() {
|
public boolean getPressCopyOrPaste() {
|
||||||
return paste;
|
return pressCopyOrPaste;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ 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)
|
||||||
@@ -21,6 +22,7 @@ public class ControlMessageReader {
|
|||||||
|
|
||||||
private final byte[] rawBuffer = new byte[RAW_BUFFER_SIZE];
|
private final byte[] rawBuffer = new byte[RAW_BUFFER_SIZE];
|
||||||
private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer);
|
private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer);
|
||||||
|
private final byte[] textBuffer = new byte[CLIPBOARD_TEXT_MAX_LENGTH];
|
||||||
|
|
||||||
public ControlMessageReader() {
|
public ControlMessageReader() {
|
||||||
// invariant: the buffer is always in "get" mode
|
// invariant: the buffer is always in "get" mode
|
||||||
@@ -66,6 +68,9 @@ 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;
|
||||||
@@ -75,7 +80,6 @@ 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;
|
||||||
@@ -110,10 +114,8 @@ public class ControlMessageReader {
|
|||||||
if (buffer.remaining() < len) {
|
if (buffer.remaining() < len) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int position = buffer.position();
|
buffer.get(textBuffer, 0, len);
|
||||||
// Move the buffer position to consume the text
|
return new String(textBuffer, 0, len, StandardCharsets.UTF_8);
|
||||||
buffer.position(position + len);
|
|
||||||
return new String(rawBuffer, position, len, StandardCharsets.UTF_8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ControlMessage parseInjectText() {
|
private ControlMessage parseInjectText() {
|
||||||
@@ -149,6 +151,14 @@ 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,13 +104,10 @@ public class Controller {
|
|||||||
device.collapsePanels();
|
device.collapsePanels();
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_GET_CLIPBOARD:
|
case ControlMessage.TYPE_GET_CLIPBOARD:
|
||||||
String clipboardText = device.getClipboardText();
|
getClipboard(msg.getPressCopyOrPaste());
|
||||||
if (clipboardText != null) {
|
|
||||||
sender.pushClipboardText(clipboardText);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_SET_CLIPBOARD:
|
case ControlMessage.TYPE_SET_CLIPBOARD:
|
||||||
setClipboard(msg.getText(), msg.getPaste());
|
setClipboard(msg.getText(), msg.getPressCopyOrPaste());
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
|
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
|
||||||
if (device.supportsInputEvents()) {
|
if (device.supportsInputEvents()) {
|
||||||
@@ -228,6 +225,23 @@ 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) {
|
||||||
|
|||||||
@@ -207,14 +207,6 @@ public final class Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean setClipboardText(String text) {
|
public boolean setClipboardText(String text) {
|
||||||
String currentClipboard = getClipboardText();
|
|
||||||
if (currentClipboard == null || currentClipboard.equals(text)) {
|
|
||||||
// The clipboard already contains the requested text.
|
|
||||||
// Since pasting text from the computer involves setting the device clipboard, it could be set twice on a copy-paste. This would cause
|
|
||||||
// the clipboard listeners to be notified twice, and that would flood the Android keyboard clipboard history. To workaround this
|
|
||||||
// problem, do not explicitly set the clipboard text if it already contains the expected content.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
isSettingClipboard.set(true);
|
isSettingClipboard.set(true);
|
||||||
boolean ok = serviceManager.getClipboardManager().setText(text);
|
boolean ok = serviceManager.getClipboardManager().setText(text);
|
||||||
isSettingClipboard.set(false);
|
isSettingClipboard.set(false);
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ 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();
|
||||||
|
|
||||||
@@ -207,6 +208,7 @@ 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
|
||||||
@@ -228,7 +230,7 @@ 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.getPaste());
|
Assert.assertTrue(event.getPressCopyOrPaste());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -254,7 +256,7 @@ 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.getPaste());
|
Assert.assertTrue(event.getPressCopyOrPaste());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user