mirror of
https://github.com/Genymobile/scrcpy
synced 2024-11-11 01:10:32 +00:00
Add mouse secondary bindings
Add secondary bindings (Shift+click) for mouse buttons. In addition to: --mouse-bind=xxxx It is now possible to pass a sequence of secondary bindings: --mouse-bind=xxxx:xxxx <--> <--> primary secondary bindings bindings If the second sequence is omitted, then it is the same as the first one. By default, for SDK mouse, primary bindings trigger shortcuts and secondary bindings forward all clicks. For AOA and UHID, the default bindings are reversed: all clicks are forwarded by default, whereas pressing Shift+click trigger shortcuts. --mouse-bind=bhsn:++++ # default for SDK --mouse-bind=++++:bhsn # default for AOA and UHID Refs035d60cf5d
Refsf5e6b8092a
Fixes #5055 <https://github.com/Genymobile/scrcpy/issues/5055> PR #5076 <https://github.com/Genymobile/scrcpy/pull/5076>
This commit is contained in:
parent
6baea57987
commit
9989668226
10
app/scrcpy.1
10
app/scrcpy.1
@ -258,10 +258,14 @@ LAlt, LSuper or RSuper toggle the capture mode, to give control of the mouse bac
|
|||||||
Also see \fB\-\-keyboard\fR.
|
Also see \fB\-\-keyboard\fR.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "\-\-mouse\-bind " xxxx
|
.BI "\-\-mouse\-bind " xxxx[:xxxx]
|
||||||
Configure bindings of secondary clicks.
|
Configure bindings of secondary clicks.
|
||||||
|
|
||||||
The argument must be exactly 4 characters, one for each secondary click (in order: right click, middle click, 4th click, 5th click).
|
The argument must be one or two sequences (separated by ':') of exactly 4 characters, one for each secondary click (in order: right click, middle click, 4th click, 5th click).
|
||||||
|
|
||||||
|
The first sequence defines the primary bindings, used when a mouse button is pressed alone. The second sequence defines the secondary bindings, used when a mouse button is pressed while the Shift key is held.
|
||||||
|
|
||||||
|
If the second sequence of bindings is omitted, then it is the same as the first one.
|
||||||
|
|
||||||
Each character must be one of the following:
|
Each character must be one of the following:
|
||||||
|
|
||||||
@ -272,7 +276,7 @@ Each character must be one of the following:
|
|||||||
- 's': trigger shortcut APP_SWITCH
|
- 's': trigger shortcut APP_SWITCH
|
||||||
- 'n': trigger shortcut "expand notification panel"
|
- 'n': trigger shortcut "expand notification panel"
|
||||||
|
|
||||||
Default is 'bhsn' for SDK mouse, and '++++' for AOA and UHID.
|
Default is 'bhsn:++++' for SDK mouse, and '++++:bhsn' for AOA and UHID.
|
||||||
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
|
119
app/src/cli.c
119
app/src/cli.c
@ -493,11 +493,17 @@ static const struct sc_option options[] = {
|
|||||||
{
|
{
|
||||||
.longopt_id = OPT_MOUSE_BIND,
|
.longopt_id = OPT_MOUSE_BIND,
|
||||||
.longopt = "mouse-bind",
|
.longopt = "mouse-bind",
|
||||||
.argdesc = "xxxx",
|
.argdesc = "xxxx[:xxxx]",
|
||||||
.text = "Configure bindings of secondary clicks.\n"
|
.text = "Configure bindings of secondary clicks.\n"
|
||||||
"The argument must be exactly 4 characters, one for each "
|
"The argument must be one or two sequences (separated by ':') "
|
||||||
"secondary click (in order: right click, middle click, 4th "
|
"of exactly 4 characters, one for each secondary click (in "
|
||||||
"click, 5th click).\n"
|
"order: right click, middle click, 4th click, 5th click).\n"
|
||||||
|
"The first sequence defines the primary bindings, used when a "
|
||||||
|
"mouse button is pressed alone. The second sequence defines "
|
||||||
|
"the secondary bindings, used when a mouse button is pressed "
|
||||||
|
"while the Shift key is held.\n"
|
||||||
|
"If the second sequence of bindings is omitted, then it is the "
|
||||||
|
"same as the first one.\n"
|
||||||
"Each character must be one of the following:\n"
|
"Each character must be one of the following:\n"
|
||||||
" '+': forward the click to the device\n"
|
" '+': forward the click to the device\n"
|
||||||
" '-': ignore the click\n"
|
" '-': ignore the click\n"
|
||||||
@ -505,7 +511,8 @@ static const struct sc_option options[] = {
|
|||||||
" 'h': trigger shortcut HOME\n"
|
" 'h': trigger shortcut HOME\n"
|
||||||
" 's': trigger shortcut APP_SWITCH\n"
|
" 's': trigger shortcut APP_SWITCH\n"
|
||||||
" 'n': trigger shortcut \"expand notification panel\"\n"
|
" 'n': trigger shortcut \"expand notification panel\"\n"
|
||||||
"Default is 'bhsn' for SDK mouse, and '++++' for AOA and UHID.",
|
"Default is 'bhsn:++++' for SDK mouse, and '++++:bhsn' for AOA "
|
||||||
|
"and UHID.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.shortopt = 'n',
|
.shortopt = 'n',
|
||||||
@ -2095,24 +2102,46 @@ parse_mouse_binding(char c, enum sc_mouse_binding *b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
parse_mouse_bindings(const char *s, struct sc_mouse_bindings *mb) {
|
parse_mouse_binding_set(const char *s, struct sc_mouse_binding_set *mbs) {
|
||||||
if (strlen(s) != 4) {
|
assert(strlen(s) >= 4);
|
||||||
LOGE("Invalid mouse bindings: '%s' (expected exactly 4 characters from "
|
|
||||||
"{'+', '-', 'b', 'h', 's', 'n'})", s);
|
if (!parse_mouse_binding(s[0], &mbs->right_click)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!parse_mouse_binding(s[1], &mbs->middle_click)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!parse_mouse_binding(s[2], &mbs->click4)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!parse_mouse_binding(s[3], &mbs->click5)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parse_mouse_binding(s[0], &mb->right_click)) {
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
parse_mouse_bindings(const char *s, struct sc_mouse_bindings *mb) {
|
||||||
|
size_t len = strlen(s);
|
||||||
|
// either "xxxx" or "xxxx:xxxx"
|
||||||
|
if (len != 4 && (len != 9 || s[4] != ':')) {
|
||||||
|
LOGE("Invalid mouse bindings: '%s' (expected 'xxxx' or 'xxxx:xxxx', "
|
||||||
|
"with each 'x' being in {'+', '-', 'b', 'h', 's', 'n'})", s);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!parse_mouse_binding(s[1], &mb->middle_click)) {
|
|
||||||
|
if (!parse_mouse_binding_set(s, &mb->pri)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!parse_mouse_binding(s[2], &mb->click4)) {
|
|
||||||
return false;
|
if (len == 9) {
|
||||||
}
|
if (!parse_mouse_binding_set(s + 5, &mb->sec)) {
|
||||||
if (!parse_mouse_binding(s[3], &mb->click5)) {
|
return false;
|
||||||
return false;
|
}
|
||||||
|
} else {
|
||||||
|
// use the same bindings for Shift+click
|
||||||
|
mb->sec = mb->pri;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -2408,10 +2437,18 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
LOGW("--forward-all-clicks is deprecated, "
|
LOGW("--forward-all-clicks is deprecated, "
|
||||||
"use --mouse-bind=++++ instead.");
|
"use --mouse-bind=++++ instead.");
|
||||||
opts->mouse_bindings = (struct sc_mouse_bindings) {
|
opts->mouse_bindings = (struct sc_mouse_bindings) {
|
||||||
.right_click = SC_MOUSE_BINDING_CLICK,
|
.pri = {
|
||||||
.middle_click = SC_MOUSE_BINDING_CLICK,
|
.right_click = SC_MOUSE_BINDING_CLICK,
|
||||||
.click4 = SC_MOUSE_BINDING_CLICK,
|
.middle_click = SC_MOUSE_BINDING_CLICK,
|
||||||
.click5 = SC_MOUSE_BINDING_CLICK,
|
.click4 = SC_MOUSE_BINDING_CLICK,
|
||||||
|
.click5 = SC_MOUSE_BINDING_CLICK,
|
||||||
|
},
|
||||||
|
.sec = {
|
||||||
|
.right_click = SC_MOUSE_BINDING_CLICK,
|
||||||
|
.middle_click = SC_MOUSE_BINDING_CLICK,
|
||||||
|
.click4 = SC_MOUSE_BINDING_CLICK,
|
||||||
|
.click5 = SC_MOUSE_BINDING_CLICK,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case OPT_LEGACY_PASTE:
|
case OPT_LEGACY_PASTE:
|
||||||
@ -2701,26 +2738,36 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If mouse bindings are not explictly set, configure default bindings
|
// If mouse bindings are not explictly set, configure default bindings
|
||||||
if (opts->mouse_bindings.right_click == SC_MOUSE_BINDING_AUTO) {
|
if (opts->mouse_bindings.pri.right_click == SC_MOUSE_BINDING_AUTO) {
|
||||||
assert(opts->mouse_bindings.middle_click == SC_MOUSE_BINDING_AUTO);
|
assert(opts->mouse_bindings.pri.middle_click == SC_MOUSE_BINDING_AUTO);
|
||||||
assert(opts->mouse_bindings.click4 == SC_MOUSE_BINDING_AUTO);
|
assert(opts->mouse_bindings.pri.click4 == SC_MOUSE_BINDING_AUTO);
|
||||||
assert(opts->mouse_bindings.click5 == SC_MOUSE_BINDING_AUTO);
|
assert(opts->mouse_bindings.pri.click5 == SC_MOUSE_BINDING_AUTO);
|
||||||
|
assert(opts->mouse_bindings.sec.right_click == SC_MOUSE_BINDING_AUTO);
|
||||||
|
assert(opts->mouse_bindings.sec.middle_click == SC_MOUSE_BINDING_AUTO);
|
||||||
|
assert(opts->mouse_bindings.sec.click4 == SC_MOUSE_BINDING_AUTO);
|
||||||
|
assert(opts->mouse_bindings.sec.click5 == SC_MOUSE_BINDING_AUTO);
|
||||||
|
|
||||||
|
static struct sc_mouse_binding_set default_shortcuts = {
|
||||||
|
.right_click = SC_MOUSE_BINDING_BACK,
|
||||||
|
.middle_click = SC_MOUSE_BINDING_HOME,
|
||||||
|
.click4 = SC_MOUSE_BINDING_APP_SWITCH,
|
||||||
|
.click5 = SC_MOUSE_BINDING_EXPAND_NOTIFICATION_PANEL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sc_mouse_binding_set forward = {
|
||||||
|
.right_click = SC_MOUSE_BINDING_CLICK,
|
||||||
|
.middle_click = SC_MOUSE_BINDING_CLICK,
|
||||||
|
.click4 = SC_MOUSE_BINDING_CLICK,
|
||||||
|
.click5 = SC_MOUSE_BINDING_CLICK,
|
||||||
|
};
|
||||||
|
|
||||||
// By default, forward all clicks only for UHID and AOA
|
// By default, forward all clicks only for UHID and AOA
|
||||||
if (opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_SDK) {
|
if (opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_SDK) {
|
||||||
opts->mouse_bindings = (struct sc_mouse_bindings) {
|
opts->mouse_bindings.pri = default_shortcuts;
|
||||||
.right_click = SC_MOUSE_BINDING_BACK,
|
opts->mouse_bindings.sec = forward;
|
||||||
.middle_click = SC_MOUSE_BINDING_HOME,
|
|
||||||
.click4 = SC_MOUSE_BINDING_APP_SWITCH,
|
|
||||||
.click5 = SC_MOUSE_BINDING_EXPAND_NOTIFICATION_PANEL,
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
opts->mouse_bindings = (struct sc_mouse_bindings) {
|
opts->mouse_bindings.pri = forward;
|
||||||
.right_click = SC_MOUSE_BINDING_CLICK,
|
opts->mouse_bindings.sec = default_shortcuts;
|
||||||
.middle_click = SC_MOUSE_BINDING_CLICK,
|
|
||||||
.click4 = SC_MOUSE_BINDING_CLICK,
|
|
||||||
.click5 = SC_MOUSE_BINDING_CLICK,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -708,7 +708,7 @@ sc_input_manager_process_touch(struct sc_input_manager *im,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static enum sc_mouse_binding
|
static enum sc_mouse_binding
|
||||||
sc_input_manager_get_binding(const struct sc_mouse_bindings *bindings,
|
sc_input_manager_get_binding(const struct sc_mouse_binding_set *bindings,
|
||||||
uint8_t sdl_button) {
|
uint8_t sdl_button) {
|
||||||
switch (sdl_button) {
|
switch (sdl_button) {
|
||||||
case SDL_BUTTON_LEFT:
|
case SDL_BUTTON_LEFT:
|
||||||
@ -744,11 +744,18 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im,
|
|||||||
im->mouse_buttons_state &= ~button;
|
im->mouse_buttons_state &= ~button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_Keymod keymod = SDL_GetModState();
|
||||||
|
bool ctrl_pressed = keymod & KMOD_CTRL;
|
||||||
|
bool shift_pressed = keymod & KMOD_SHIFT;
|
||||||
|
|
||||||
if (control && !paused) {
|
if (control && !paused) {
|
||||||
enum sc_action action = down ? SC_ACTION_DOWN : SC_ACTION_UP;
|
enum sc_action action = down ? SC_ACTION_DOWN : SC_ACTION_UP;
|
||||||
|
|
||||||
|
struct sc_mouse_binding_set *bindings = !shift_pressed
|
||||||
|
? &im->mouse_bindings.pri
|
||||||
|
: &im->mouse_bindings.sec;
|
||||||
enum sc_mouse_binding binding =
|
enum sc_mouse_binding binding =
|
||||||
sc_input_manager_get_binding(&im->mouse_bindings, event->button);
|
sc_input_manager_get_binding(bindings, event->button);
|
||||||
assert(binding != SC_MOUSE_BINDING_AUTO);
|
assert(binding != SC_MOUSE_BINDING_AUTO);
|
||||||
switch (binding) {
|
switch (binding) {
|
||||||
case SC_MOUSE_BINDING_DISABLED:
|
case SC_MOUSE_BINDING_DISABLED:
|
||||||
@ -812,9 +819,6 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im,
|
|||||||
im->mouse_buttons_state |= button;
|
im->mouse_buttons_state |= button;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Keymod keymod = SDL_GetModState();
|
|
||||||
bool ctrl_pressed = keymod & KMOD_CTRL;
|
|
||||||
bool shift_pressed = keymod & KMOD_SHIFT;
|
|
||||||
bool change_vfinger = event->button == SDL_BUTTON_LEFT &&
|
bool change_vfinger = event->button == SDL_BUTTON_LEFT &&
|
||||||
((down && !im->vfinger_down && (ctrl_pressed ^ shift_pressed)) ||
|
((down && !im->vfinger_down && (ctrl_pressed ^ shift_pressed)) ||
|
||||||
(!down && im->vfinger_down));
|
(!down && im->vfinger_down));
|
||||||
|
@ -24,10 +24,18 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||||||
.keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_AUTO,
|
.keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_AUTO,
|
||||||
.mouse_input_mode = SC_MOUSE_INPUT_MODE_AUTO,
|
.mouse_input_mode = SC_MOUSE_INPUT_MODE_AUTO,
|
||||||
.mouse_bindings = {
|
.mouse_bindings = {
|
||||||
.right_click = SC_MOUSE_BINDING_AUTO,
|
.pri = {
|
||||||
.middle_click = SC_MOUSE_BINDING_AUTO,
|
.right_click = SC_MOUSE_BINDING_AUTO,
|
||||||
.click4 = SC_MOUSE_BINDING_AUTO,
|
.middle_click = SC_MOUSE_BINDING_AUTO,
|
||||||
.click5 = SC_MOUSE_BINDING_AUTO,
|
.click4 = SC_MOUSE_BINDING_AUTO,
|
||||||
|
.click5 = SC_MOUSE_BINDING_AUTO,
|
||||||
|
},
|
||||||
|
.sec = {
|
||||||
|
.right_click = SC_MOUSE_BINDING_AUTO,
|
||||||
|
.middle_click = SC_MOUSE_BINDING_AUTO,
|
||||||
|
.click4 = SC_MOUSE_BINDING_AUTO,
|
||||||
|
.click5 = SC_MOUSE_BINDING_AUTO,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
.camera_facing = SC_CAMERA_FACING_ANY,
|
.camera_facing = SC_CAMERA_FACING_ANY,
|
||||||
.port_range = {
|
.port_range = {
|
||||||
|
@ -165,13 +165,18 @@ enum sc_mouse_binding {
|
|||||||
SC_MOUSE_BINDING_EXPAND_NOTIFICATION_PANEL,
|
SC_MOUSE_BINDING_EXPAND_NOTIFICATION_PANEL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sc_mouse_bindings {
|
struct sc_mouse_binding_set {
|
||||||
enum sc_mouse_binding right_click;
|
enum sc_mouse_binding right_click;
|
||||||
enum sc_mouse_binding middle_click;
|
enum sc_mouse_binding middle_click;
|
||||||
enum sc_mouse_binding click4;
|
enum sc_mouse_binding click4;
|
||||||
enum sc_mouse_binding click5;
|
enum sc_mouse_binding click5;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sc_mouse_bindings {
|
||||||
|
struct sc_mouse_binding_set pri;
|
||||||
|
struct sc_mouse_binding_set sec; // When Shift is pressed
|
||||||
|
};
|
||||||
|
|
||||||
enum sc_key_inject_mode {
|
enum sc_key_inject_mode {
|
||||||
// Inject special keys, letters and space as key events.
|
// Inject special keys, letters and space as key events.
|
||||||
// Inject numbers and punctuation as text events.
|
// Inject numbers and punctuation as text events.
|
||||||
|
52
doc/mouse.md
52
doc/mouse.md
@ -80,21 +80,37 @@ process like the _adb daemon_).
|
|||||||
|
|
||||||
## Mouse bindings
|
## Mouse bindings
|
||||||
|
|
||||||
By default, with SDK mouse, right-click triggers BACK (or POWER on) and
|
By default, with SDK mouse:
|
||||||
middle-click triggers HOME. In addition, the 4th click triggers APP_SWITCH and
|
- right-click triggers BACK (or POWER on)
|
||||||
the 5th click expands the notification panel.
|
- middle-click triggers HOME
|
||||||
|
- the 4th click triggers APP_SWITCH
|
||||||
|
- the 5th click expands the notification panel
|
||||||
|
|
||||||
In AOA and UHID mouse modes, all clicks are forwarded by default.
|
The secondary clicks may be forwarded to the device instead by pressing the
|
||||||
|
<kbd>Shift</kbd> key (e.g. <kbd>Shift</kbd>+right-click injects a right click to
|
||||||
|
the device).
|
||||||
|
|
||||||
The shortcuts can be configured using `--mouse-bind=xxxx` for any mouse mode.
|
In AOA and UHID mouse modes, the default bindings are reversed: all clicks are
|
||||||
The argument must be exactly 4 characters, one for each secondary click:
|
forwarded by default, and pressing <kbd>Shift</kbd> gives access to the
|
||||||
|
shortcuts (since the cursor is handled on the device side, it makes more sense
|
||||||
|
to forward all mouse buttons by default in these modes).
|
||||||
|
|
||||||
|
The shortcuts can be configured using `--mouse-bind=xxxx:xxxx` for any mouse
|
||||||
|
mode. The argument must be one or two sequences (separated by `:`) of exactly 4
|
||||||
|
characters, one for each secondary click:
|
||||||
|
|
||||||
```
|
```
|
||||||
--mouse-bind=xxxx
|
.---- Shift + right click
|
||||||
|
SECONDARY |.--- Shift + middle click
|
||||||
|
BINDINGS ||.-- Shift + 4th click
|
||||||
|
|||.- Shift + 5th click
|
||||||
|
||||
|
||||||
|
vvvv
|
||||||
|
--mouse-bind=xxxx:xxxx
|
||||||
^^^^
|
^^^^
|
||||||
||||
|
||||
|
||||||
||| `- 5th click
|
PRIMARY ||| `- 5th click
|
||||||
|| `-- 4th click
|
BINDINGS || `-- 4th click
|
||||||
| `--- middle click
|
| `--- middle click
|
||||||
`---- right click
|
`---- right click
|
||||||
```
|
```
|
||||||
@ -111,8 +127,18 @@ Each character must be one of the following:
|
|||||||
For example:
|
For example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
scrcpy --mouse-bind=bhsn # the default mode with SDK mouse
|
scrcpy --mouse-bind=bhsn:++++ # the default mode for SDK mouse
|
||||||
scrcpy --mouse-bind=++++ # forward all clicks (default for AOA/UHID)
|
scrcpy --mouse-bind=++++:bhsn # the default mode for AOA and UHID
|
||||||
scrcpy --mouse-bind=++bh # forward right and middle clicks,
|
scrcpy --mouse-bind=++bh:++sn # forward right and middle clicks,
|
||||||
# use 4th and 5th for BACK and HOME
|
# use 4th and 5th for BACK and HOME,
|
||||||
|
# use Shift+4th and Shift+5th for APP_SWITCH
|
||||||
|
# and expand notification panel
|
||||||
|
```
|
||||||
|
|
||||||
|
The second sequence of bindings may be omitted. In that case, it is the same as
|
||||||
|
the first one:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --mouse-bind=bhsn
|
||||||
|
scrcpy --mouse-bind=bhsn:bhsn # equivalent
|
||||||
```
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user