Compare commits

..

3 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
12 changed files with 158 additions and 200 deletions

View File

@@ -560,36 +560,36 @@ Also see [issue #14].
## Shortcuts ## Shortcuts
_`Meta` is typically the `Windows` key on the keyboard, or `Cmd` on macOS._ `LCtrl` is the left `Ctrl` key (the right `Ctrl` key is forwarded to the
device).
| Action | Shortcut | Action | Shortcut | Shortcut (macOS)
| ---------------------------------------------------- |:----------------------------- | ------------------------------------------- |:----------------------------- |:-----------------------------
| Switch fullscreen mode | `Meta`+`f` | Switch fullscreen mode | `LCtrl`+`f` | `Cmd`+`f`
| Rotate display left | `Meta`+`←` _(left)_ | Rotate display left | `LCtrl`+`←` _(left)_ | `Cmd`+`←` _(left)_
| Rotate display right | `Meta`+`→` _(right)_ | Rotate display right | `LCtrl`+`→` _(right)_ | `Cmd`+`→` _(right)_
| Resize window to 1:1 (pixel-perfect) | `Meta`+`g` | Resize window to 1:1 (pixel-perfect) | `LCtrl`+`g` | `Cmd`+`g`
| Resize window to remove black borders | `Meta`+`w` \| _Double-click¹_ | Resize window to remove black borders | `LCtrl`+`x` \| _Double-click¹_ | `Cmd`+`x` \| _Double-click¹_
| Click on `HOME` | `Meta`+`h` \| _Middle-click_ | Click on `HOME` | `LCtrl`+`h` \| _Middle-click_ | `Ctrl`+`h` \| _Middle-click_
| Click on `BACK` | `Meta`+`b` \| _Right-click²_ | Click on `BACK` | `LCtrl`+`b` \| _Right-click²_ | `Cmd`+`b` \| _Right-click²_
| Click on `APP_SWITCH` | `Meta`+`s` | Click on `APP_SWITCH` | `LCtrl`+`s` | `Cmd`+`s`
| Click on `MENU` | `Meta`+`m` | Click on `MENU` | `LCtrl`+`m` | `Ctrl`+`m`
| Click on `VOLUME_UP` | `Meta`+`↑` _(up)_ | Click on `VOLUME_UP` | `LCtrl`+`↑` _(up)_ | `Cmd`+`↑` _(up)_
| Click on `VOLUME_DOWN` | `Meta`+`↓` _(down)_ | Click on `VOLUME_DOWN` | `LCtrl`+`↓` _(down)_ | `Cmd`+`↓` _(down)_
| Click on `POWER` | `Meta`+`p` | Click on `POWER` | `LCtrl`+`p` | `Cmd`+`p`
| Power on | _Right-click²_ | Power on | _Right-click²_ | _Right-click²_
| Turn device screen off (keep mirroring) | `Meta`+`o` | Turn device screen off (keep mirroring) | `LCtrl`+`o` | `Cmd`+`o`
| Turn device screen on | `Meta`+`Shift`+`o` | Turn device screen on | `LCtrl`+`Shift`+`o` | `Cmd`+`Shift`+`o`
| Rotate device screen | `Meta`+`r` | Rotate device screen | `LCtrl`+`r` | `Cmd`+`r`
| Expand notification panel | `Meta`+`n` | Expand notification panel | `LCtrl`+`n` | `Cmd`+`n`
| Collapse notification panel | `Meta`+`Shift`+`n` | Collapse notification panel | `LCtrl`+`Shift`+`n` | `Cmd`+`Shift`+`n`
| Press COPY³, then Copy device clipboard to computer | `Meta`+`c` | Copy device clipboard to computer | `LCtrl`+`c` | `Cmd`+`c`
| Press CUT³ | `Meta`+`x` | Paste computer clipboard to device | `LCtrl`+`v` | `Cmd`+`v`
| Paste computer clipboard to device | `Meta`+`v` | Copy computer clipboard to device and paste | `LCtrl`+`Shift`+`v` | `Cmd`+`Shift`+`v`
| Enable/disable FPS counter (on stdout) | `Meta`+`i` | Enable/disable FPS counter (on stdout) | `LCtrl`+`i` | `Cmd`+`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

View File

@@ -203,52 +203,54 @@ Default is 0 (automatic).\n
.SH SHORTCUTS .SH SHORTCUTS
\fBLCtrl\fR is the left Ctrl key (the right Ctrl key is forwarded to the device).
.TP .TP
.B Meta+f .B LCtrl+f
Switch fullscreen mode Switch fullscreen mode
.TP .TP
.B Meta+Left .B LCtrl+Left
Rotate display left Rotate display left
.TP .TP
.B Meta+Right .B LCtrl+Right
Rotate display right Rotate display right
.TP .TP
.B Meta+g .B LCtrl+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 LCtrl+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 LCtrl+h, Home, Middle\-click
Click on HOME Click on HOME
.TP .TP
.B Meta+b, Meta+Backspace, Right\-click (when screen is on) .B LCtrl+b, Ctrl+Backspace, Right\-click (when screen is on)
Click on BACK Click on BACK
.TP .TP
.B Meta+s .B LCtrl+s
Click on APP_SWITCH Click on APP_SWITCH
.TP .TP
.B Meta+m .B LCtrl+m
Click on MENU Click on MENU
.TP .TP
.B Meta+Up .B LCtrl+Up
Click on VOLUME_UP Click on VOLUME_UP
.TP .TP
.B Meta+Down .B LCtrl+Down
Click on VOLUME_DOWN Click on VOLUME_DOWN
.TP .TP
.B Meta+p .B LCtrl+p
Click on POWER (turn screen on/off) Click on POWER (turn screen on/off)
.TP .TP
@@ -256,39 +258,39 @@ Click on POWER (turn screen on/off)
Turn screen on Turn screen on
.TP .TP
.B Meta+o .B LCtrl+o
Turn device screen off (keep mirroring) Turn device screen off (keep mirroring)
.TP .TP
.B Meta+Shift+o .B LCtrl+Shift+o
Turn device screen on Turn device screen on
.TP .TP
.B Meta+r .B LCtrl+r
Rotate device screen Rotate device screen
.TP .TP
.B Meta+n .B LCtrl+n
Expand notification panel Expand notification panel
.TP .TP
.B Meta+Shift+n .B LCtrl+Shift+n
Collapse notification panel Collapse notification panel
.TP .TP
.B Meta+c .B LCtrl+c
Press COPY (Android >= 7), then copy device clipboard to computer Copy device clipboard to computer
.TP .TP
.B Meta+x .B LCtrl+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 LCtrl+Shift+v
Copy computer clipboard to device (and paste if the device runs Android >= 7)
.TP
.B LCtrl+i
Enable/disable FPS counter (print frames/second in logs) Enable/disable FPS counter (print frames/second in logs)
.TP .TP

View File

@@ -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 "LCtrl"
#endif #endif
fprintf(stderr, fprintf(stderr,
"Usage: %s [options]\n" "Usage: %s [options]\n"
@@ -186,75 +186,78 @@ scrcpy_print_usage(const char *arg0) {
"\n" "\n"
"Shortcuts:\n" "Shortcuts:\n"
"\n" "\n"
" " MOD "+f\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" " 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"
" Ctrl+h\n" " LCtrl+h\n"
" 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" " LCtrl+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 +268,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

View File

@@ -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;

View File

@@ -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;

View File

@@ -92,10 +92,11 @@ 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_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);
MAP(SDLK_LALT, AKEYCODE_ALT_LEFT);
MAP(SDLK_RALT, AKEYCODE_ALT_RIGHT);
} }
if (!(mod & (KMOD_NUM | KMOD_SHIFT))) { if (!(mod & (KMOD_NUM | KMOD_SHIFT))) {

View File

@@ -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");
@@ -265,59 +259,64 @@ 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 ctrl = event->keysym.mod & (KMOD_LCTRL | KMOD_RCTRL); // Only capture Left-Ctrl, Right-Ctrl is forwarded to the device
bool alt = event->keysym.mod & (KMOD_LALT | KMOD_RALT); bool ctrl = event->keysym.mod & KMOD_LCTRL;
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);
if (alt) { // use Cmd on macOS, Ctrl on other platforms
// No shortcuts involve Alt, and it is not forwarded to the device #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; return;
} }
bool cmd = ctrl; // && !meta, already guaranteed
#endif
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 +324,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 +393,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 +406,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)) {

View File

@@ -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)));
} }

View File

@@ -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;
} }
} }

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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