mirror of https://github.com/Genymobile/scrcpy
Simplify shortcut modifiers
Restrict shortcut modifiers to be composed of only one item each. Before, it was possible to select a list of multiple combinations of modifier keys, like --shortcut-mod='lctrl+lalt,rctrl+rsuper', meaning that shortcuts would be triggered either by LCtrl+LAlt+key or RCtrl+RSuper+key. This was overly generic, probably not used very much, and it prevents to solve inconsistencies between UP and DOWN events of modifier keys sent to the device. Refs #4732 <https://github.com/Genymobile/scrcpy/issues/4732> PR #4741 <https://github.com/Genymobile/scrcpy/pull/4741>
This commit is contained in:
parent
592ca0b59b
commit
24bcc3fa2b
|
@ -424,9 +424,9 @@ Turn the device screen off immediately.
|
|||
.BI "\-\-shortcut\-mod " key\fR[+...]][,...]
|
||||
Specify the modifiers to use for scrcpy shortcuts. Possible keys are "lctrl", "rctrl", "lalt", "ralt", "lsuper" and "rsuper".
|
||||
|
||||
A shortcut can consist in several keys, separated by '+'. Several shortcuts can be specified, separated by ','.
|
||||
Several shortcut modifiers can be specified, separated by ','.
|
||||
|
||||
For example, to use either LCtrl+LAlt or LSuper for scrcpy shortcuts, pass "lctrl+lalt,lsuper".
|
||||
For example, to use either LCtrl or LSuper for scrcpy shortcuts, pass "lctrl,lsuper".
|
||||
|
||||
Default is "lalt,lsuper" (left-Alt or left-Super).
|
||||
|
||||
|
|
100
app/src/cli.c
100
app/src/cli.c
|
@ -716,10 +716,10 @@ static const struct sc_option options[] = {
|
|||
.text = "Specify the modifiers to use for scrcpy shortcuts.\n"
|
||||
"Possible keys are \"lctrl\", \"rctrl\", \"lalt\", \"ralt\", "
|
||||
"\"lsuper\" and \"rsuper\".\n"
|
||||
"A shortcut can consist in several keys, separated by '+'. "
|
||||
"Several shortcuts can be specified, separated by ','.\n"
|
||||
"For example, to use either LCtrl+LAlt or LSuper for scrcpy "
|
||||
"shortcuts, pass \"lctrl+lalt,lsuper\".\n"
|
||||
"Several shortcut modifiers can be specified, separated by "
|
||||
"','.\n"
|
||||
"For example, to use either LCtrl or LSuper for scrcpy "
|
||||
"shortcuts, pass \"lctrl,lsuper\".\n"
|
||||
"Default is \"lalt,lsuper\" (left-Alt or left-Super).",
|
||||
},
|
||||
{
|
||||
|
@ -1687,82 +1687,62 @@ parse_log_level(const char *s, enum sc_log_level *log_level) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// item is a list of mod keys separated by '+' (e.g. "lctrl+lalt")
|
||||
// returns a bitwise-or of SC_SHORTCUT_MOD_* constants (or 0 on error)
|
||||
static unsigned
|
||||
static enum sc_shortcut_mod
|
||||
parse_shortcut_mods_item(const char *item, size_t len) {
|
||||
unsigned mod = 0;
|
||||
|
||||
for (;;) {
|
||||
char *plus = strchr(item, '+');
|
||||
// strchr() does not consider the "len" parameter, to it could find an
|
||||
// occurrence too far in the string (there is no strnchr())
|
||||
bool has_plus = plus && plus < item + len;
|
||||
|
||||
assert(!has_plus || plus > item);
|
||||
size_t key_len = has_plus ? (size_t) (plus - item) : len;
|
||||
|
||||
#define STREQ(literal, s, len) \
|
||||
((sizeof(literal)-1 == len) && !memcmp(literal, s, len))
|
||||
|
||||
if (STREQ("lctrl", item, key_len)) {
|
||||
mod |= SC_SHORTCUT_MOD_LCTRL;
|
||||
} else if (STREQ("rctrl", item, key_len)) {
|
||||
mod |= SC_SHORTCUT_MOD_RCTRL;
|
||||
} else if (STREQ("lalt", item, key_len)) {
|
||||
mod |= SC_SHORTCUT_MOD_LALT;
|
||||
} else if (STREQ("ralt", item, key_len)) {
|
||||
mod |= SC_SHORTCUT_MOD_RALT;
|
||||
} else if (STREQ("lsuper", item, key_len)) {
|
||||
mod |= SC_SHORTCUT_MOD_LSUPER;
|
||||
} else if (STREQ("rsuper", item, key_len)) {
|
||||
mod |= SC_SHORTCUT_MOD_RSUPER;
|
||||
} else {
|
||||
LOGE("Unknown modifier key: %.*s "
|
||||
"(must be one of: lctrl, rctrl, lalt, ralt, lsuper, rsuper)",
|
||||
(int) key_len, item);
|
||||
return 0;
|
||||
}
|
||||
if (STREQ("lctrl", item, len)) {
|
||||
return SC_SHORTCUT_MOD_LCTRL;
|
||||
}
|
||||
if (STREQ("rctrl", item, len)) {
|
||||
return SC_SHORTCUT_MOD_RCTRL;
|
||||
}
|
||||
if (STREQ("lalt", item, len)) {
|
||||
return SC_SHORTCUT_MOD_LALT;
|
||||
}
|
||||
if (STREQ("ralt", item, len)) {
|
||||
return SC_SHORTCUT_MOD_RALT;
|
||||
}
|
||||
if (STREQ("lsuper", item, len)) {
|
||||
return SC_SHORTCUT_MOD_LSUPER;
|
||||
}
|
||||
if (STREQ("rsuper", item, len)) {
|
||||
return SC_SHORTCUT_MOD_RSUPER;
|
||||
}
|
||||
#undef STREQ
|
||||
|
||||
if (!has_plus) {
|
||||
break;
|
||||
}
|
||||
|
||||
item = plus + 1;
|
||||
assert(len >= key_len + 1);
|
||||
len -= key_len + 1;
|
||||
bool has_plus = strchr(item, '+');
|
||||
if (has_plus) {
|
||||
LOGE("Shortcut mod combination with '+' is not supported anymore: "
|
||||
"'%.*s' (see #4741)", (int) len, item);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mod;
|
||||
LOGE("Unknown modifier key: %.*s "
|
||||
"(must be one of: lctrl, rctrl, lalt, ralt, lsuper, rsuper)",
|
||||
(int) len, item);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_shortcut_mods(const char *s, struct sc_shortcut_mods *mods) {
|
||||
unsigned count = 0;
|
||||
unsigned current = 0;
|
||||
parse_shortcut_mods(const char *s, uint8_t *shortcut_mods) {
|
||||
uint8_t mods = 0;
|
||||
|
||||
// LCtrl+LAlt or RCtrl or LCtrl+RSuper: "lctrl+lalt,rctrl,lctrl+rsuper"
|
||||
// A list of shortcut modifiers, for example "lctrl,rctrl,rsuper"
|
||||
|
||||
for (;;) {
|
||||
char *comma = strchr(s, ',');
|
||||
if (comma && count == SC_MAX_SHORTCUT_MODS - 1) {
|
||||
assert(count < SC_MAX_SHORTCUT_MODS);
|
||||
LOGW("Too many shortcut modifiers alternatives");
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(!comma || comma > s);
|
||||
size_t limit = comma ? (size_t) (comma - s) : strlen(s);
|
||||
|
||||
unsigned mod = parse_shortcut_mods_item(s, limit);
|
||||
enum sc_shortcut_mod mod = parse_shortcut_mods_item(s, limit);
|
||||
if (!mod) {
|
||||
LOGE("Invalid modifier keys: %.*s", (int) limit, s);
|
||||
return false;
|
||||
}
|
||||
|
||||
mods->data[current++] = mod;
|
||||
++count;
|
||||
mods |= mod;
|
||||
|
||||
if (!comma) {
|
||||
break;
|
||||
|
@ -1771,7 +1751,7 @@ parse_shortcut_mods(const char *s, struct sc_shortcut_mods *mods) {
|
|||
s = comma + 1;
|
||||
}
|
||||
|
||||
mods->count = count;
|
||||
*shortcut_mods = mods;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1779,7 +1759,7 @@ parse_shortcut_mods(const char *s, struct sc_shortcut_mods *mods) {
|
|||
#ifdef SC_TEST
|
||||
// expose the function to unit-tests
|
||||
bool
|
||||
sc_parse_shortcut_mods(const char *s, struct sc_shortcut_mods *mods) {
|
||||
sc_parse_shortcut_mods(const char *s, uint8_t *mods) {
|
||||
return parse_shortcut_mods(s, mods);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -28,7 +28,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]);
|
|||
|
||||
#ifdef SC_TEST
|
||||
bool
|
||||
sc_parse_shortcut_mods(const char *s, struct sc_shortcut_mods *mods);
|
||||
sc_parse_shortcut_mods(const char *s, uint8_t *shortcut_mods);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#define SC_SDL_SHORTCUT_MODS_MASK (KMOD_CTRL | KMOD_ALT | KMOD_GUI)
|
||||
|
||||
static inline uint16_t
|
||||
to_sdl_mod(unsigned shortcut_mod) {
|
||||
to_sdl_mod(uint8_t shortcut_mod) {
|
||||
uint16_t sdl_mod = 0;
|
||||
if (shortcut_mod & SC_SHORTCUT_MOD_LCTRL) {
|
||||
sdl_mod |= KMOD_LCTRL;
|
||||
|
@ -38,15 +38,8 @@ is_shortcut_mod(struct sc_input_manager *im, uint16_t sdl_mod) {
|
|||
// keep only the relevant modifier keys
|
||||
sdl_mod &= SC_SDL_SHORTCUT_MODS_MASK;
|
||||
|
||||
assert(im->sdl_shortcut_mods.count);
|
||||
assert(im->sdl_shortcut_mods.count < SC_MAX_SHORTCUT_MODS);
|
||||
for (unsigned i = 0; i < im->sdl_shortcut_mods.count; ++i) {
|
||||
if (im->sdl_shortcut_mods.data[i] == sdl_mod) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
// at least one shortcut mod pressed?
|
||||
return sdl_mod & im->sdl_shortcut_mods;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -68,15 +61,7 @@ sc_input_manager_init(struct sc_input_manager *im,
|
|||
im->legacy_paste = params->legacy_paste;
|
||||
im->clipboard_autosync = params->clipboard_autosync;
|
||||
|
||||
const struct sc_shortcut_mods *shortcut_mods = params->shortcut_mods;
|
||||
assert(shortcut_mods->count);
|
||||
assert(shortcut_mods->count < SC_MAX_SHORTCUT_MODS);
|
||||
for (unsigned i = 0; i < shortcut_mods->count; ++i) {
|
||||
uint16_t sdl_mod = to_sdl_mod(shortcut_mods->data[i]);
|
||||
assert(sdl_mod);
|
||||
im->sdl_shortcut_mods.data[i] = sdl_mod;
|
||||
}
|
||||
im->sdl_shortcut_mods.count = shortcut_mods->count;
|
||||
im->sdl_shortcut_mods = to_sdl_mod(params->shortcut_mods);
|
||||
|
||||
im->vfinger_down = false;
|
||||
im->vfinger_invert_x = false;
|
||||
|
|
|
@ -26,10 +26,7 @@ struct sc_input_manager {
|
|||
bool legacy_paste;
|
||||
bool clipboard_autosync;
|
||||
|
||||
struct {
|
||||
unsigned data[SC_MAX_SHORTCUT_MODS];
|
||||
unsigned count;
|
||||
} sdl_shortcut_mods;
|
||||
uint16_t sdl_shortcut_mods;
|
||||
|
||||
bool vfinger_down;
|
||||
bool vfinger_invert_x;
|
||||
|
@ -55,7 +52,7 @@ struct sc_input_manager_params {
|
|||
bool forward_all_clicks;
|
||||
bool legacy_paste;
|
||||
bool clipboard_autosync;
|
||||
const struct sc_shortcut_mods *shortcut_mods;
|
||||
uint8_t shortcut_mods; // OR of enum sc_shortcut_mod values
|
||||
};
|
||||
|
||||
void
|
||||
|
|
|
@ -30,10 +30,7 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||
},
|
||||
.tunnel_host = 0,
|
||||
.tunnel_port = 0,
|
||||
.shortcut_mods = {
|
||||
.data = {SC_SHORTCUT_MOD_LALT, SC_SHORTCUT_MOD_LSUPER},
|
||||
.count = 2,
|
||||
},
|
||||
.shortcut_mods = SC_SHORTCUT_MOD_LALT | SC_SHORTCUT_MOD_LSUPER,
|
||||
.max_size = 0,
|
||||
.video_bit_rate = 0,
|
||||
.audio_bit_rate = 0,
|
||||
|
|
|
@ -169,8 +169,6 @@ enum sc_key_inject_mode {
|
|||
SC_KEY_INJECT_MODE_RAW,
|
||||
};
|
||||
|
||||
#define SC_MAX_SHORTCUT_MODS 8
|
||||
|
||||
enum sc_shortcut_mod {
|
||||
SC_SHORTCUT_MOD_LCTRL = 1 << 0,
|
||||
SC_SHORTCUT_MOD_RCTRL = 1 << 1,
|
||||
|
@ -180,11 +178,6 @@ enum sc_shortcut_mod {
|
|||
SC_SHORTCUT_MOD_RSUPER = 1 << 5,
|
||||
};
|
||||
|
||||
struct sc_shortcut_mods {
|
||||
unsigned data[SC_MAX_SHORTCUT_MODS];
|
||||
unsigned count;
|
||||
};
|
||||
|
||||
struct sc_port_range {
|
||||
uint16_t first;
|
||||
uint16_t last;
|
||||
|
@ -219,7 +212,7 @@ struct scrcpy_options {
|
|||
struct sc_port_range port_range;
|
||||
uint32_t tunnel_host;
|
||||
uint16_t tunnel_port;
|
||||
struct sc_shortcut_mods shortcut_mods;
|
||||
uint8_t shortcut_mods; // OR of enum sc_shortcut_mod values
|
||||
uint16_t max_size;
|
||||
uint32_t video_bit_rate;
|
||||
uint32_t audio_bit_rate;
|
||||
|
|
|
@ -715,7 +715,7 @@ scrcpy(struct scrcpy_options *options) {
|
|||
.forward_all_clicks = options->forward_all_clicks,
|
||||
.legacy_paste = options->legacy_paste,
|
||||
.clipboard_autosync = options->clipboard_autosync,
|
||||
.shortcut_mods = &options->shortcut_mods,
|
||||
.shortcut_mods = options->shortcut_mods,
|
||||
.window_title = window_title,
|
||||
.always_on_top = options->always_on_top,
|
||||
.window_x = options->window_x,
|
||||
|
|
|
@ -82,7 +82,7 @@ struct sc_screen_params {
|
|||
bool forward_all_clicks;
|
||||
bool legacy_paste;
|
||||
bool clipboard_autosync;
|
||||
const struct sc_shortcut_mods *shortcut_mods;
|
||||
uint8_t shortcut_mods; // OR of enum sc_shortcut_mod values
|
||||
|
||||
const char *window_title;
|
||||
bool always_on_top;
|
||||
|
|
|
@ -124,32 +124,22 @@ static void test_options2(void) {
|
|||
}
|
||||
|
||||
static void test_parse_shortcut_mods(void) {
|
||||
struct sc_shortcut_mods mods;
|
||||
uint8_t mods;
|
||||
bool ok;
|
||||
|
||||
ok = sc_parse_shortcut_mods("lctrl", &mods);
|
||||
assert(ok);
|
||||
assert(mods.count == 1);
|
||||
assert(mods.data[0] == SC_SHORTCUT_MOD_LCTRL);
|
||||
|
||||
ok = sc_parse_shortcut_mods("lctrl+lalt", &mods);
|
||||
assert(ok);
|
||||
assert(mods.count == 1);
|
||||
assert(mods.data[0] == (SC_SHORTCUT_MOD_LCTRL | SC_SHORTCUT_MOD_LALT));
|
||||
assert(mods == SC_SHORTCUT_MOD_LCTRL);
|
||||
|
||||
ok = sc_parse_shortcut_mods("rctrl,lalt", &mods);
|
||||
assert(ok);
|
||||
assert(mods.count == 2);
|
||||
assert(mods.data[0] == SC_SHORTCUT_MOD_RCTRL);
|
||||
assert(mods.data[1] == SC_SHORTCUT_MOD_LALT);
|
||||
assert(mods == (SC_SHORTCUT_MOD_RCTRL | SC_SHORTCUT_MOD_LALT));
|
||||
|
||||
ok = sc_parse_shortcut_mods("lsuper,rsuper+lalt,lctrl+rctrl+ralt", &mods);
|
||||
ok = sc_parse_shortcut_mods("lsuper,rsuper,lctrl", &mods);
|
||||
assert(ok);
|
||||
assert(mods.count == 3);
|
||||
assert(mods.data[0] == SC_SHORTCUT_MOD_LSUPER);
|
||||
assert(mods.data[1] == (SC_SHORTCUT_MOD_RSUPER | SC_SHORTCUT_MOD_LALT));
|
||||
assert(mods.data[2] == (SC_SHORTCUT_MOD_LCTRL | SC_SHORTCUT_MOD_RCTRL |
|
||||
SC_SHORTCUT_MOD_RALT));
|
||||
assert(mods == (SC_SHORTCUT_MOD_LSUPER
|
||||
| SC_SHORTCUT_MOD_RSUPER
|
||||
| SC_SHORTCUT_MOD_LCTRL));
|
||||
|
||||
ok = sc_parse_shortcut_mods("", &mods);
|
||||
assert(!ok);
|
||||
|
|
|
@ -13,8 +13,8 @@ It can be changed using `--shortcut-mod`. Possible keys are `lctrl`, `rctrl`,
|
|||
# use RCtrl for shortcuts
|
||||
scrcpy --shortcut-mod=rctrl
|
||||
|
||||
# use either LCtrl+LAlt or LSuper for shortcuts
|
||||
scrcpy --shortcut-mod=lctrl+lalt,lsuper
|
||||
# use either LCtrl or LSuper for shortcuts
|
||||
scrcpy --shortcut-mod=lctrl,lsuper
|
||||
```
|
||||
|
||||
_<kbd>[Super]</kbd> is typically the <kbd>Windows</kbd> or <kbd>Cmd</kbd> key._
|
||||
|
|
Loading…
Reference in New Issue