Compare commits
15 Commits
display_ma
...
uhid.1
Author | SHA1 | Date | |
---|---|---|---|
24efeace4b | |||
2ad93d1fc0 | |||
d067a11478 | |||
cd4056d0f3 | |||
6a58891e13 | |||
ec41896c85 | |||
4cd61b5a90 | |||
d2ed4510a7 | |||
604dfd7c6b | |||
af69689ec1 | |||
cbce42336d | |||
c9a4d2b38f | |||
1beec99f82 | |||
5ce8672ebc | |||
3001f8a2d5 |
@ -27,8 +27,8 @@ _scrcpy() {
|
|||||||
--force-adb-forward
|
--force-adb-forward
|
||||||
--forward-all-clicks
|
--forward-all-clicks
|
||||||
-h --help
|
-h --help
|
||||||
|
--keyboard-input-mode=
|
||||||
--kill-adb-on-close
|
--kill-adb-on-close
|
||||||
-K --hid-keyboard
|
|
||||||
--legacy-paste
|
--legacy-paste
|
||||||
--list-camera-sizes
|
--list-camera-sizes
|
||||||
--list-cameras
|
--list-cameras
|
||||||
@ -115,13 +115,16 @@ _scrcpy() {
|
|||||||
COMPREPLY=($(compgen -W 'front back external' -- "$cur"))
|
COMPREPLY=($(compgen -W 'front back external' -- "$cur"))
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
--orientation
|
--keyboard-input-mode)
|
||||||
--display-orientation)
|
COMPREPLY=($(compgen -W 'inject aoa' -- "$cur"))
|
||||||
COMPREPLY=($(compgen -> '0 90 180 270 flip0 flip90 flip180 flip270' -- "$cur"))
|
return
|
||||||
|
;;
|
||||||
|
--orientation|--display-orientation)
|
||||||
|
COMPREPLY=($(compgen -W '0 90 180 270 flip0 flip90 flip180 flip270' -- "$cur"))
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
--record-orientation)
|
--record-orientation)
|
||||||
COMPREPLY=($(compgen -> '0 90 180 270' -- "$cur"))
|
COMPREPLY=($(compgen -W '0 90 180 270' -- "$cur"))
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
--lock-video-orientation)
|
--lock-video-orientation)
|
||||||
|
@ -34,8 +34,8 @@ arguments=(
|
|||||||
'--force-adb-forward[Do not attempt to use \"adb reverse\" to connect to the device]'
|
'--force-adb-forward[Do not attempt to use \"adb reverse\" to connect to the device]'
|
||||||
'--forward-all-clicks[Forward clicks to device]'
|
'--forward-all-clicks[Forward clicks to device]'
|
||||||
{-h,--help}'[Print the help]'
|
{-h,--help}'[Print the help]'
|
||||||
|
'--keyboard-input-mode=[Set the keyboard input mode]:mode:(inject aoa)'
|
||||||
'--kill-adb-on-close[Kill adb when scrcpy terminates]'
|
'--kill-adb-on-close[Kill adb when scrcpy terminates]'
|
||||||
{-K,--hid-keyboard}'[Simulate a physical keyboard by using HID over AOAv2]'
|
|
||||||
'--legacy-paste[Inject computer clipboard text as a sequence of key events on Ctrl+v]'
|
'--legacy-paste[Inject computer clipboard text as a sequence of key events on Ctrl+v]'
|
||||||
'--list-camera-sizes[List the valid camera capture sizes]'
|
'--list-camera-sizes[List the valid camera capture sizes]'
|
||||||
'--list-cameras[List cameras available on the device]'
|
'--list-cameras[List cameras available on the device]'
|
||||||
|
@ -124,7 +124,7 @@ Use USB device (if there is exactly one, like adb -d).
|
|||||||
Also see \fB\-e\fR (\fB\-\-select\-tcpip\fR).
|
Also see \fB\-e\fR (\fB\-\-select\-tcpip\fR).
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "\-\-disable-screensaver"
|
.BI "\-\-disable\-screensaver"
|
||||||
Disable screensaver while scrcpy is running.
|
Disable screensaver while scrcpy is running.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
@ -642,7 +642,11 @@ Enable/disable FPS counter (print frames/second in logs)
|
|||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Ctrl+click-and-move
|
.B Ctrl+click-and-move
|
||||||
Pinch-to-zoom from the center of the screen
|
Pinch-to-zoom and rotate from the center of the screen
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B Shift+click-and-move
|
||||||
|
Tilt (slide vertically with two fingers)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Drag & drop APK file
|
.B Drag & drop APK file
|
||||||
|
@ -4,16 +4,16 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "trait/frame_sink.h"
|
|
||||||
#include <util/audiobuf.h>
|
|
||||||
#include <util/average.h>
|
|
||||||
#include <util/thread.h>
|
|
||||||
#include <util/tick.h>
|
|
||||||
|
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
#include <libswresample/swresample.h>
|
#include <libswresample/swresample.h>
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
#include "trait/frame_sink.h"
|
||||||
|
#include "util/audiobuf.h"
|
||||||
|
#include "util/average.h"
|
||||||
|
#include "util/thread.h"
|
||||||
|
#include "util/tick.h"
|
||||||
|
|
||||||
struct sc_audio_player {
|
struct sc_audio_player {
|
||||||
struct sc_frame_sink frame_sink;
|
struct sc_frame_sink frame_sink;
|
||||||
|
|
||||||
|
165
app/src/cli.c
165
app/src/cli.c
@ -93,6 +93,8 @@ enum {
|
|||||||
OPT_DISPLAY_ORIENTATION,
|
OPT_DISPLAY_ORIENTATION,
|
||||||
OPT_RECORD_ORIENTATION,
|
OPT_RECORD_ORIENTATION,
|
||||||
OPT_ORIENTATION,
|
OPT_ORIENTATION,
|
||||||
|
OPT_KEYBOARD_INPUT_MODE,
|
||||||
|
OPT_MOUSE_INPUT_MODE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sc_option {
|
struct sc_option {
|
||||||
@ -359,14 +361,19 @@ static const struct sc_option options[] = {
|
|||||||
.text = "Print this help.",
|
.text = "Print this help.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.longopt_id = OPT_KILL_ADB_ON_CLOSE,
|
.longopt_id = OPT_KEYBOARD_INPUT_MODE,
|
||||||
.longopt = "kill-adb-on-close",
|
.longopt = "keyboard-input-mode",
|
||||||
.text = "Kill adb when scrcpy terminates.",
|
.argdesc = "value",
|
||||||
},
|
.text = "Select how to send keyboard inputs to the device.\n"
|
||||||
{
|
"Possible values are \"disable\", \"inject\" and \"aoa\".\n"
|
||||||
.shortopt = 'K',
|
"\n"
|
||||||
.longopt = "hid-keyboard",
|
"\"disable\" does not send keyboard inputs to the device.\n"
|
||||||
.text = "Simulate a physical keyboard by using HID over AOAv2.\n"
|
"\n"
|
||||||
|
"\"inject\" uses the Android system API to deliver keyboard\n"
|
||||||
|
"events to applications.\n"
|
||||||
|
"\n"
|
||||||
|
"\"aoa\" simulates a physical keyboard using the AOAv2\n"
|
||||||
|
"protocol. It may only work over USB.\n"
|
||||||
"It provides a better experience for IME users, and allows to "
|
"It provides a better experience for IME users, and allows to "
|
||||||
"generate non-ASCII characters, contrary to the default "
|
"generate non-ASCII characters, contrary to the default "
|
||||||
"injection method.\n"
|
"injection method.\n"
|
||||||
@ -378,7 +385,19 @@ static const struct sc_option options[] = {
|
|||||||
"android.settings.HARD_KEYBOARD_SETTINGS`.\n"
|
"android.settings.HARD_KEYBOARD_SETTINGS`.\n"
|
||||||
"However, the option is only available when the HID keyboard "
|
"However, the option is only available when the HID keyboard "
|
||||||
"is enabled (or a physical keyboard is connected).\n"
|
"is enabled (or a physical keyboard is connected).\n"
|
||||||
"Also see --hid-mouse.",
|
"Also see --mouse-input-mode and --otg."
|
||||||
|
"\n"
|
||||||
|
"Default is \"inject\" (or \"aoa\" if --otg is set).",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.longopt_id = OPT_KILL_ADB_ON_CLOSE,
|
||||||
|
.longopt = "kill-adb-on-close",
|
||||||
|
.text = "Kill adb when scrcpy terminates.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// deprecated
|
||||||
|
.shortopt = 'K',
|
||||||
|
.longopt = "hid-keyboard",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.longopt_id = OPT_LEGACY_PASTE,
|
.longopt_id = OPT_LEGACY_PASTE,
|
||||||
@ -440,7 +459,7 @@ static const struct sc_option options[] = {
|
|||||||
"LAlt, LSuper or RSuper toggle the capture mode, to give "
|
"LAlt, LSuper or RSuper toggle the capture mode, to give "
|
||||||
"control of the mouse back to the computer.\n"
|
"control of the mouse back to the computer.\n"
|
||||||
"It may only work over USB.\n"
|
"It may only work over USB.\n"
|
||||||
"Also see --hid-keyboard.",
|
"Also see --keyboard-input-mode and --otg.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.longopt_id = OPT_MAX_FPS,
|
.longopt_id = OPT_MAX_FPS,
|
||||||
@ -449,6 +468,26 @@ static const struct sc_option options[] = {
|
|||||||
.text = "Limit the frame rate of screen capture (officially supported "
|
.text = "Limit the frame rate of screen capture (officially supported "
|
||||||
"since Android 10, but may work on earlier versions).",
|
"since Android 10, but may work on earlier versions).",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.longopt_id = OPT_MOUSE_INPUT_MODE,
|
||||||
|
.longopt = "mouse-input-mode",
|
||||||
|
.argdesc = "value",
|
||||||
|
.text = "Select how to send mouse inputs to the device.\n"
|
||||||
|
"Possible values are \"disable\", \"inject\" and \"aoa\".\n"
|
||||||
|
"\n"
|
||||||
|
"\"disable\" does not send mouse inputs to the device.\n"
|
||||||
|
"\n"
|
||||||
|
"\"inject\" uses the Android system API to deliver mouse\n"
|
||||||
|
"events to applications.\n"
|
||||||
|
"\n"
|
||||||
|
"\"aoa\" simulates a physical mouse using the AOAv2\n"
|
||||||
|
"protocol. It may only work over USB.\n"
|
||||||
|
"In this mode, the computer mouse is captured to control the "
|
||||||
|
"device directly (relative mouse mode).\n"
|
||||||
|
"LAlt, LSuper or RSuper toggle the capture mode, to give "
|
||||||
|
"control of the mouse back to the computer.\n"
|
||||||
|
"Also see --keyboard-input-mode and --otg.",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.shortopt = 'n',
|
.shortopt = 'n',
|
||||||
.longopt = "no-control",
|
.longopt = "no-control",
|
||||||
@ -543,10 +582,11 @@ static const struct sc_option options[] = {
|
|||||||
"mirroring is disabled.\n"
|
"mirroring is disabled.\n"
|
||||||
"LAlt, LSuper or RSuper toggle the mouse capture mode, to give "
|
"LAlt, LSuper or RSuper toggle the mouse capture mode, to give "
|
||||||
"control of the mouse back to the computer.\n"
|
"control of the mouse back to the computer.\n"
|
||||||
"If any of --hid-keyboard or --hid-mouse is set, only enable "
|
"Keyboard and mouse may be disabled separately using\n"
|
||||||
"keyboard or mouse respectively, otherwise enable both.\n"
|
"--keyboard-input-mode=disable and\n"
|
||||||
|
"--mouse-input-mode=disable.\n"
|
||||||
"It may only work over USB.\n"
|
"It may only work over USB.\n"
|
||||||
"See --hid-keyboard and --hid-mouse.",
|
"See --keyboard-input-mode and --mouse-input-mode.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.shortopt = 'p',
|
.shortopt = 'p',
|
||||||
@ -947,7 +987,11 @@ static const struct sc_shortcut shortcuts[] = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.shortcuts = { "Ctrl+click-and-move" },
|
.shortcuts = { "Ctrl+click-and-move" },
|
||||||
.text = "Pinch-to-zoom from the center of the screen",
|
.text = "Pinch-to-zoom and rotate from the center of the screen",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.shortcuts = { "Shift+click-and-move" },
|
||||||
|
.text = "Tilt (slide vertically with two fingers)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.shortcuts = { "Drag & drop APK file" },
|
.shortcuts = { "Drag & drop APK file" },
|
||||||
@ -1898,6 +1942,61 @@ parse_camera_fps(const char *s, uint16_t *camera_fps) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
parse_keyboard_input_mode(const char *optarg,
|
||||||
|
enum sc_keyboard_input_mode *mode) {
|
||||||
|
if (!strcmp(optarg, "disable")) {
|
||||||
|
*mode = SC_KEYBOARD_INPUT_MODE_DISABLED;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(optarg, "inject")) {
|
||||||
|
*mode = SC_KEYBOARD_INPUT_MODE_INJECT;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(optarg, "aoa")) {
|
||||||
|
#ifdef HAVE_USB
|
||||||
|
*mode = SC_KEYBOARD_INPUT_MODE_AOA;
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
LOGE("--keyboard-input-mode=aoa is disabled.");
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGE("Unsupported keyboard input mode: %s (expected disable, inject, aoa)",
|
||||||
|
optarg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
parse_mouse_input_mode(const char *optarg, enum sc_mouse_input_mode *mode) {
|
||||||
|
if (!strcmp(optarg, "disable")) {
|
||||||
|
*mode = SC_MOUSE_INPUT_MODE_DISABLED;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(optarg, "inject")) {
|
||||||
|
*mode = SC_MOUSE_INPUT_MODE_INJECT;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(optarg, "aoa")) {
|
||||||
|
#ifdef HAVE_USB
|
||||||
|
*mode = SC_MOUSE_INPUT_MODE_AOA;
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
LOGE("--mouse-input-mode=aoa is disabled.");
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGE("Unsupported mouse input mode: %s (expected disable, inject, aoa)",
|
||||||
|
optarg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
parse_time_limit(const char *s, sc_tick *tick) {
|
parse_time_limit(const char *s, sc_tick *tick) {
|
||||||
long value;
|
long value;
|
||||||
@ -1987,12 +2086,20 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
break;
|
break;
|
||||||
case 'K':
|
case 'K':
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_USB
|
||||||
opts->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_HID;
|
LOGW("-K/--hid-keyboard is deprecated, use "
|
||||||
|
"--keyboard-input-mode=aoa instead.");
|
||||||
|
opts->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_AOA;
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
LOGE("HID over AOA (-K/--hid-keyboard) is disabled.");
|
LOGE("HID over AOA (-K/--hid-keyboard) is disabled.");
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
case OPT_KEYBOARD_INPUT_MODE:
|
||||||
|
if (!parse_keyboard_input_mode(optarg,
|
||||||
|
&opts->keyboard_input_mode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case OPT_MAX_FPS:
|
case OPT_MAX_FPS:
|
||||||
if (!parse_max_fps(optarg, &opts->max_fps)) {
|
if (!parse_max_fps(optarg, &opts->max_fps)) {
|
||||||
return false;
|
return false;
|
||||||
@ -2005,12 +2112,19 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
break;
|
break;
|
||||||
case 'M':
|
case 'M':
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_USB
|
||||||
opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_HID;
|
LOGW("-M/--hid-mouse is deprecated, use --mouse-input-mode=aoa "
|
||||||
|
"instead.");
|
||||||
|
opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_AOA;
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
LOGE("HID over AOA (-M/--hid-mouse) is disabled.");
|
LOGE("HID over AOA (-M/--hid-mouse) is disabled.");
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
case OPT_MOUSE_INPUT_MODE:
|
||||||
|
if (!parse_mouse_input_mode(optarg, &opts->mouse_input_mode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case OPT_LOCK_VIDEO_ORIENTATION:
|
case OPT_LOCK_VIDEO_ORIENTATION:
|
||||||
if (!parse_lock_video_orientation(optarg,
|
if (!parse_lock_video_orientation(optarg,
|
||||||
&opts->lock_video_orientation)) {
|
&opts->lock_video_orientation)) {
|
||||||
@ -2394,6 +2508,8 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
|
|
||||||
if (!opts->video) {
|
if (!opts->video) {
|
||||||
opts->video_playback = false;
|
opts->video_playback = false;
|
||||||
|
// Do not power on the device on start if video capture is disabled
|
||||||
|
opts->power_on = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opts->audio) {
|
if (!opts->audio) {
|
||||||
@ -2455,6 +2571,15 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (opts->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_AUTO) {
|
||||||
|
opts->keyboard_input_mode = otg ? SC_KEYBOARD_INPUT_MODE_AOA
|
||||||
|
: SC_KEYBOARD_INPUT_MODE_INJECT;
|
||||||
|
}
|
||||||
|
if (opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_AUTO) {
|
||||||
|
opts->mouse_input_mode = otg ? SC_MOUSE_INPUT_MODE_AOA
|
||||||
|
: SC_MOUSE_INPUT_MODE_INJECT;
|
||||||
|
}
|
||||||
|
|
||||||
if ((opts->tunnel_host || opts->tunnel_port) && !opts->force_adb_forward) {
|
if ((opts->tunnel_host || opts->tunnel_port) && !opts->force_adb_forward) {
|
||||||
LOGI("Tunnel host/port is set, "
|
LOGI("Tunnel host/port is set, "
|
||||||
"--force-adb-forward automatically enabled.");
|
"--force-adb-forward automatically enabled.");
|
||||||
@ -2615,12 +2740,12 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ifdef _WIN32
|
# ifdef _WIN32
|
||||||
if (!otg && (opts->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID
|
if (!otg && (opts->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_AOA
|
||||||
|| opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_HID)) {
|
|| opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_AOA)) {
|
||||||
LOGE("On Windows, it is not possible to open a USB device already open "
|
LOGE("On Windows, it is not possible to open a USB device already open "
|
||||||
"by another process (like adb).");
|
"by another process (like adb).");
|
||||||
LOGE("Therefore, -K/--hid-keyboard and -M/--hid-mouse may only work in "
|
LOGE("Therefore, --keyboard-input-mode=aoa and --mouse-input-mode=aoa "
|
||||||
"OTG mode (--otg).");
|
"may only work in OTG mode (--otg).");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
@ -76,6 +76,8 @@ sc_input_manager_init(struct sc_input_manager *im,
|
|||||||
im->sdl_shortcut_mods.count = shortcut_mods->count;
|
im->sdl_shortcut_mods.count = shortcut_mods->count;
|
||||||
|
|
||||||
im->vfinger_down = false;
|
im->vfinger_down = false;
|
||||||
|
im->vfinger_invert_x = false;
|
||||||
|
im->vfinger_invert_y = false;
|
||||||
|
|
||||||
im->last_keycode = SDLK_UNKNOWN;
|
im->last_keycode = SDLK_UNKNOWN;
|
||||||
im->last_mod = 0;
|
im->last_mod = 0;
|
||||||
@ -347,9 +349,14 @@ simulate_virtual_finger(struct sc_input_manager *im,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct sc_point
|
static struct sc_point
|
||||||
inverse_point(struct sc_point point, struct sc_size size) {
|
inverse_point(struct sc_point point, struct sc_size size,
|
||||||
point.x = size.width - point.x;
|
bool invert_x, bool invert_y) {
|
||||||
point.y = size.height - point.y;
|
if (invert_x) {
|
||||||
|
point.x = size.width - point.x;
|
||||||
|
}
|
||||||
|
if (invert_y) {
|
||||||
|
point.y = size.height - point.y;
|
||||||
|
}
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,7 +612,9 @@ sc_input_manager_process_mouse_motion(struct sc_input_manager *im,
|
|||||||
struct sc_point mouse =
|
struct sc_point mouse =
|
||||||
sc_screen_convert_window_to_frame_coords(im->screen, event->x,
|
sc_screen_convert_window_to_frame_coords(im->screen, event->x,
|
||||||
event->y);
|
event->y);
|
||||||
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size);
|
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size,
|
||||||
|
im->vfinger_invert_x,
|
||||||
|
im->vfinger_invert_y);
|
||||||
simulate_virtual_finger(im, AMOTION_EVENT_ACTION_MOVE, vfinger);
|
simulate_virtual_finger(im, AMOTION_EVENT_ACTION_MOVE, vfinger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -726,7 +735,7 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pinch-to-zoom simulation.
|
// Pinch-to-zoom, rotate and tilt simulation.
|
||||||
//
|
//
|
||||||
// If Ctrl is hold when the left-click button is pressed, then
|
// If Ctrl is hold when the left-click button is pressed, then
|
||||||
// pinch-to-zoom mode is enabled: on every mouse event until the left-click
|
// pinch-to-zoom mode is enabled: on every mouse event until the left-click
|
||||||
@ -735,14 +744,29 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im,
|
|||||||
//
|
//
|
||||||
// In other words, the center of the rotation/scaling is the center of the
|
// In other words, the center of the rotation/scaling is the center of the
|
||||||
// screen.
|
// screen.
|
||||||
#define CTRL_PRESSED (SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL))
|
//
|
||||||
|
// To simulate a tilt gesture (a vertical slide with two fingers), Shift
|
||||||
|
// can be used instead of Ctrl. The "virtual finger" has a position
|
||||||
|
// inverted with respect to the vertical axis of symmetry in the middle of
|
||||||
|
// the screen.
|
||||||
|
const SDL_Keymod keymod = SDL_GetModState();
|
||||||
|
const bool ctrl_pressed = keymod & KMOD_CTRL;
|
||||||
|
const bool shift_pressed = keymod & KMOD_SHIFT;
|
||||||
if (event->button == SDL_BUTTON_LEFT &&
|
if (event->button == SDL_BUTTON_LEFT &&
|
||||||
((down && !im->vfinger_down && CTRL_PRESSED) ||
|
((down && !im->vfinger_down &&
|
||||||
|
((ctrl_pressed && !shift_pressed) ||
|
||||||
|
(!ctrl_pressed && shift_pressed))) ||
|
||||||
(!down && im->vfinger_down))) {
|
(!down && im->vfinger_down))) {
|
||||||
struct sc_point mouse =
|
struct sc_point mouse =
|
||||||
sc_screen_convert_window_to_frame_coords(im->screen, event->x,
|
sc_screen_convert_window_to_frame_coords(im->screen, event->x,
|
||||||
event->y);
|
event->y);
|
||||||
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size);
|
if (down) {
|
||||||
|
im->vfinger_invert_x = ctrl_pressed || shift_pressed;
|
||||||
|
im->vfinger_invert_y = ctrl_pressed;
|
||||||
|
}
|
||||||
|
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size,
|
||||||
|
im->vfinger_invert_x,
|
||||||
|
im->vfinger_invert_y);
|
||||||
enum android_motionevent_action action = down
|
enum android_motionevent_action action = down
|
||||||
? AMOTION_EVENT_ACTION_DOWN
|
? AMOTION_EVENT_ACTION_DOWN
|
||||||
: AMOTION_EVENT_ACTION_UP;
|
: AMOTION_EVENT_ACTION_UP;
|
||||||
|
@ -32,6 +32,8 @@ struct sc_input_manager {
|
|||||||
} sdl_shortcut_mods;
|
} sdl_shortcut_mods;
|
||||||
|
|
||||||
bool vfinger_down;
|
bool vfinger_down;
|
||||||
|
bool vfinger_invert_x;
|
||||||
|
bool vfinger_invert_y;
|
||||||
|
|
||||||
// Tracks the number of identical consecutive shortcut key down events.
|
// Tracks the number of identical consecutive shortcut key down events.
|
||||||
// Not to be confused with event->repeat, which counts the number of
|
// Not to be confused with event->repeat, which counts the number of
|
||||||
|
@ -21,8 +21,8 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||||||
.video_source = SC_VIDEO_SOURCE_DISPLAY,
|
.video_source = SC_VIDEO_SOURCE_DISPLAY,
|
||||||
.audio_source = SC_AUDIO_SOURCE_AUTO,
|
.audio_source = SC_AUDIO_SOURCE_AUTO,
|
||||||
.record_format = SC_RECORD_FORMAT_AUTO,
|
.record_format = SC_RECORD_FORMAT_AUTO,
|
||||||
.keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_INJECT,
|
.keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_AUTO,
|
||||||
.mouse_input_mode = SC_MOUSE_INPUT_MODE_INJECT,
|
.mouse_input_mode = SC_MOUSE_INPUT_MODE_AUTO,
|
||||||
.camera_facing = SC_CAMERA_FACING_ANY,
|
.camera_facing = SC_CAMERA_FACING_ANY,
|
||||||
.port_range = {
|
.port_range = {
|
||||||
.first = DEFAULT_LOCAL_PORT_RANGE_FIRST,
|
.first = DEFAULT_LOCAL_PORT_RANGE_FIRST,
|
||||||
|
@ -140,13 +140,17 @@ enum sc_lock_video_orientation {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum sc_keyboard_input_mode {
|
enum sc_keyboard_input_mode {
|
||||||
|
SC_KEYBOARD_INPUT_MODE_AUTO,
|
||||||
|
SC_KEYBOARD_INPUT_MODE_DISABLED,
|
||||||
SC_KEYBOARD_INPUT_MODE_INJECT,
|
SC_KEYBOARD_INPUT_MODE_INJECT,
|
||||||
SC_KEYBOARD_INPUT_MODE_HID,
|
SC_KEYBOARD_INPUT_MODE_AOA,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sc_mouse_input_mode {
|
enum sc_mouse_input_mode {
|
||||||
|
SC_MOUSE_INPUT_MODE_AUTO,
|
||||||
|
SC_MOUSE_INPUT_MODE_DISABLED,
|
||||||
SC_MOUSE_INPUT_MODE_INJECT,
|
SC_MOUSE_INPUT_MODE_INJECT,
|
||||||
SC_MOUSE_INPUT_MODE_HID,
|
SC_MOUSE_INPUT_MODE_AOA,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sc_key_inject_mode {
|
enum sc_key_inject_mode {
|
||||||
|
@ -543,11 +543,11 @@ scrcpy(struct scrcpy_options *options) {
|
|||||||
|
|
||||||
if (options->control) {
|
if (options->control) {
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_USB
|
||||||
bool use_hid_keyboard =
|
bool use_aoa_keyboard =
|
||||||
options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID;
|
options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_AOA;
|
||||||
bool use_hid_mouse =
|
bool use_aoa_mouse =
|
||||||
options->mouse_input_mode == SC_MOUSE_INPUT_MODE_HID;
|
options->mouse_input_mode == SC_MOUSE_INPUT_MODE_AOA;
|
||||||
if (use_hid_keyboard || use_hid_mouse) {
|
if (use_aoa_keyboard || use_aoa_mouse) {
|
||||||
bool ok = sc_acksync_init(&s->acksync);
|
bool ok = sc_acksync_init(&s->acksync);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
goto end;
|
goto end;
|
||||||
@ -590,7 +590,7 @@ scrcpy(struct scrcpy_options *options) {
|
|||||||
goto aoa_hid_end;
|
goto aoa_hid_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_hid_keyboard) {
|
if (use_aoa_keyboard) {
|
||||||
if (sc_hid_keyboard_init(&s->keyboard_hid, &s->aoa)) {
|
if (sc_hid_keyboard_init(&s->keyboard_hid, &s->aoa)) {
|
||||||
hid_keyboard_initialized = true;
|
hid_keyboard_initialized = true;
|
||||||
kp = &s->keyboard_hid.key_processor;
|
kp = &s->keyboard_hid.key_processor;
|
||||||
@ -599,7 +599,7 @@ scrcpy(struct scrcpy_options *options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_hid_mouse) {
|
if (use_aoa_mouse) {
|
||||||
if (sc_hid_mouse_init(&s->mouse_hid, &s->aoa)) {
|
if (sc_hid_mouse_init(&s->mouse_hid, &s->aoa)) {
|
||||||
hid_mouse_initialized = true;
|
hid_mouse_initialized = true;
|
||||||
mp = &s->mouse_hid.mouse_processor;
|
mp = &s->mouse_hid.mouse_processor;
|
||||||
@ -636,19 +636,19 @@ aoa_hid_end:
|
|||||||
|
|
||||||
if (use_hid_keyboard && !hid_keyboard_initialized) {
|
if (use_hid_keyboard && !hid_keyboard_initialized) {
|
||||||
LOGE("Fallback to default keyboard injection method "
|
LOGE("Fallback to default keyboard injection method "
|
||||||
"(-K/--hid-keyboard ignored)");
|
"(--keyboard-input-mode=aoa ignored)");
|
||||||
options->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_INJECT;
|
options->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_INJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_hid_mouse && !hid_mouse_initialized) {
|
if (use_hid_mouse && !hid_mouse_initialized) {
|
||||||
LOGE("Fallback to default mouse injection method "
|
LOGE("Fallback to default mouse injection method "
|
||||||
"(-M/--hid-mouse ignored)");
|
"(--mouse-input-mode=aoa ignored)");
|
||||||
options->mouse_input_mode = SC_MOUSE_INPUT_MODE_INJECT;
|
options->mouse_input_mode = SC_MOUSE_INPUT_MODE_INJECT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
assert(options->keyboard_input_mode != SC_KEYBOARD_INPUT_MODE_HID);
|
assert(options->keyboard_input_mode != SC_KEYBOARD_INPUT_MODE_AOA);
|
||||||
assert(options->mouse_input_mode != SC_MOUSE_INPUT_MODE_HID);
|
assert(options->mouse_input_mode != SC_MOUSE_INPUT_MODE_AOA);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// keyboard_input_mode may have been reset if HID mode failed
|
// keyboard_input_mode may have been reset if HID mode failed
|
||||||
|
@ -53,6 +53,25 @@ scrcpy_otg(struct scrcpy_options *options) {
|
|||||||
static struct scrcpy_otg scrcpy_otg;
|
static struct scrcpy_otg scrcpy_otg;
|
||||||
struct scrcpy_otg *s = &scrcpy_otg;
|
struct scrcpy_otg *s = &scrcpy_otg;
|
||||||
|
|
||||||
|
bool enable_keyboard;
|
||||||
|
assert(options->keyboard_input_mode != SC_KEYBOARD_INPUT_MODE_AUTO);
|
||||||
|
switch (options->keyboard_input_mode) {
|
||||||
|
case SC_KEYBOARD_INPUT_MODE_AOA:
|
||||||
|
enable_keyboard = true;
|
||||||
|
break;
|
||||||
|
case SC_KEYBOARD_INPUT_MODE_DISABLED:
|
||||||
|
enable_keyboard = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGE("In --otg mode, --keyboard-input-mode must be either aoa or "
|
||||||
|
"disable");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (options->keyboard_input_mode != SC_KEYBOARD_INPUT_MODE_AOA
|
||||||
|
&& options->keyboard_input_mode != SC_KEYBOARD_INPUT_MODE_DISABLED) {
|
||||||
|
return SCRCPY_EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
const char *serial = options->serial;
|
const char *serial = options->serial;
|
||||||
|
|
||||||
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
|
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
|
||||||
@ -62,7 +81,7 @@ scrcpy_otg(struct scrcpy_options *options) {
|
|||||||
// Minimal SDL initialization
|
// Minimal SDL initialization
|
||||||
if (SDL_Init(SDL_INIT_EVENTS)) {
|
if (SDL_Init(SDL_INIT_EVENTS)) {
|
||||||
LOGE("Could not initialize SDL: %s", SDL_GetError());
|
LOGE("Could not initialize SDL: %s", SDL_GetError());
|
||||||
return false;
|
return SCRCPY_EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
atexit(SDL_Quit);
|
atexit(SDL_Quit);
|
||||||
@ -118,9 +137,9 @@ scrcpy_otg(struct scrcpy_options *options) {
|
|||||||
aoa_initialized = true;
|
aoa_initialized = true;
|
||||||
|
|
||||||
bool enable_keyboard =
|
bool enable_keyboard =
|
||||||
options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID;
|
options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_AOA;
|
||||||
bool enable_mouse =
|
bool enable_mouse =
|
||||||
options->mouse_input_mode == SC_MOUSE_INPUT_MODE_HID;
|
options->mouse_input_mode == SC_MOUSE_INPUT_MODE_AOA;
|
||||||
|
|
||||||
// If neither --hid-keyboard or --hid-mouse is passed, enable both
|
// If neither --hid-keyboard or --hid-mouse is passed, enable both
|
||||||
if (!enable_keyboard && !enable_mouse) {
|
if (!enable_keyboard && !enable_mouse) {
|
||||||
|
@ -85,7 +85,7 @@ way as <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>).
|
|||||||
To disable automatic clipboard synchronization, use
|
To disable automatic clipboard synchronization, use
|
||||||
`--no-clipboard-autosync`.
|
`--no-clipboard-autosync`.
|
||||||
|
|
||||||
## Pinch-to-zoom
|
## Pinch-to-zoom, rotate and tilt simulation
|
||||||
|
|
||||||
To simulate "pinch-to-zoom": <kbd>Ctrl</kbd>+_click-and-move_.
|
To simulate "pinch-to-zoom": <kbd>Ctrl</kbd>+_click-and-move_.
|
||||||
|
|
||||||
@ -93,8 +93,12 @@ More precisely, hold down <kbd>Ctrl</kbd> while pressing the left-click button.
|
|||||||
Until the left-click button is released, all mouse movements scale and rotate
|
Until the left-click button is released, all mouse movements scale and rotate
|
||||||
the content (if supported by the app) relative to the center of the screen.
|
the content (if supported by the app) relative to the center of the screen.
|
||||||
|
|
||||||
|
To simulate a tilt gesture: <kbd>Shift</kbd>+_click-and-move-up-or-down_.
|
||||||
|
|
||||||
Technically, _scrcpy_ generates additional touch events from a "virtual finger"
|
Technically, _scrcpy_ generates additional touch events from a "virtual finger"
|
||||||
at a location inverted through the center of the screen.
|
at a location inverted through the center of the screen. When pressing
|
||||||
|
<kbd>Ctrl</kbd> the x and y coordinates are inverted. Using <kbd>Shift</kbd>
|
||||||
|
only inverts x.
|
||||||
|
|
||||||
|
|
||||||
## Key repeat
|
## Key repeat
|
||||||
|
@ -49,7 +49,8 @@ _<kbd>[Super]</kbd> is typically the <kbd>Windows</kbd> or <kbd>Cmd</kbd> key._
|
|||||||
| Synchronize clipboards and paste⁵ | <kbd>MOD</kbd>+<kbd>v</kbd>
|
| Synchronize clipboards and paste⁵ | <kbd>MOD</kbd>+<kbd>v</kbd>
|
||||||
| Inject computer clipboard text | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>
|
| Inject computer clipboard text | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>
|
||||||
| Enable/disable FPS counter (on stdout) | <kbd>MOD</kbd>+<kbd>i</kbd>
|
| Enable/disable FPS counter (on stdout) | <kbd>MOD</kbd>+<kbd>i</kbd>
|
||||||
| Pinch-to-zoom | <kbd>Ctrl</kbd>+_click-and-move_
|
| Pinch-to-zoom/rotate | <kbd>Ctrl</kbd>+_click-and-move_
|
||||||
|
| Tilt (slide vertically with 2 fingers) | <kbd>Shift</kbd>+_click-and-move_
|
||||||
| Drag & drop APK file | Install APK from computer
|
| Drag & drop APK file | Install APK from computer
|
||||||
| Drag & drop non-APK file | [Push file to device](control.md#push-file-to-device)
|
| Drag & drop non-APK file | [Push file to device](control.md#push-file-to-device)
|
||||||
|
|
||||||
|
@ -153,13 +153,14 @@ public final class AudioCapture {
|
|||||||
previousRecorderTimestamp = timestamp.nanoTime;
|
previousRecorderTimestamp = timestamp.nanoTime;
|
||||||
} else {
|
} else {
|
||||||
if (nextPts == 0) {
|
if (nextPts == 0) {
|
||||||
Ln.w("Could not get any audio timestamp");
|
Ln.w("Could not get initial audio timestamp");
|
||||||
|
nextPts = System.nanoTime() / 1000;
|
||||||
}
|
}
|
||||||
// compute from previous timestamp and packet size
|
// compute from previous timestamp and packet size
|
||||||
pts = nextPts;
|
pts = nextPts;
|
||||||
}
|
}
|
||||||
|
|
||||||
long durationUs = r * 1000000 / (CHANNELS * BYTES_PER_SAMPLE * SAMPLE_RATE);
|
long durationUs = r * 1000000L / (CHANNELS * BYTES_PER_SAMPLE * SAMPLE_RATE);
|
||||||
nextPts = pts + durationUs;
|
nextPts = pts + durationUs;
|
||||||
|
|
||||||
if (previousPts != 0 && pts < previousPts + ONE_SAMPLE_US) {
|
if (previousPts != 0 && pts < previousPts + ONE_SAMPLE_US) {
|
||||||
|
@ -187,5 +187,7 @@ public final class CleanUp {
|
|||||||
Device.setScreenPowerMode(Device.POWER_MODE_NORMAL);
|
Device.setScreenPowerMode(Device.POWER_MODE_NORMAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,11 +45,11 @@ public final class Device {
|
|||||||
void onClipboardTextChanged(String text);
|
void onClipboardTextChanged(String text);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Size deviceSize;
|
|
||||||
private final Rect crop;
|
private final Rect crop;
|
||||||
private int maxSize;
|
private int maxSize;
|
||||||
private final int lockVideoOrientation;
|
private final int lockVideoOrientation;
|
||||||
|
|
||||||
|
private Size deviceSize;
|
||||||
private ScreenInfo screenInfo;
|
private ScreenInfo screenInfo;
|
||||||
private RotationListener rotationListener;
|
private RotationListener rotationListener;
|
||||||
private FoldListener foldListener;
|
private FoldListener foldListener;
|
||||||
@ -116,8 +116,8 @@ public final class Device {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
screenInfo = ScreenInfo.computeScreenInfo(displayInfo.getRotation(), displayInfo.getSize(), options.getCrop(),
|
deviceSize = displayInfo.getSize();
|
||||||
options.getMaxSize(), options.getLockVideoOrientation());
|
screenInfo = ScreenInfo.computeScreenInfo(displayInfo.getRotation(), deviceSize, crop, maxSize, lockVideoOrientation);
|
||||||
// notify
|
// notify
|
||||||
if (foldListener != null) {
|
if (foldListener != null) {
|
||||||
foldListener.onFoldChanged(displayId, folded);
|
foldListener.onFoldChanged(displayId, folded);
|
||||||
|
@ -285,16 +285,28 @@ public final class Workarounds {
|
|||||||
Method getParcelMethod = attributionSourceState.getClass().getDeclaredMethod("getParcel");
|
Method getParcelMethod = attributionSourceState.getClass().getDeclaredMethod("getParcel");
|
||||||
Parcel attributionSourceParcel = (Parcel) getParcelMethod.invoke(attributionSourceState);
|
Parcel attributionSourceParcel = (Parcel) getParcelMethod.invoke(attributionSourceState);
|
||||||
|
|
||||||
// private native int native_setup(Object audiorecordThis,
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||||
// Object /*AudioAttributes*/ attributes,
|
// private native int native_setup(Object audiorecordThis,
|
||||||
// int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
|
// Object /*AudioAttributes*/ attributes,
|
||||||
// int buffSizeInBytes, int[] sessionId, @NonNull Parcel attributionSource,
|
// int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
|
||||||
// long nativeRecordInJavaObj, int maxSharedAudioHistoryMs);
|
// int buffSizeInBytes, int[] sessionId, @NonNull Parcel attributionSource,
|
||||||
Method nativeSetupMethod = AudioRecord.class.getDeclaredMethod("native_setup", Object.class, Object.class, int[].class, int.class,
|
// long nativeRecordInJavaObj, int maxSharedAudioHistoryMs);
|
||||||
int.class, int.class, int.class, int[].class, Parcel.class, long.class, int.class);
|
Method nativeSetupMethod = AudioRecord.class.getDeclaredMethod("native_setup", Object.class, Object.class, int[].class,
|
||||||
nativeSetupMethod.setAccessible(true);
|
int.class, int.class, int.class, int.class, int[].class, Parcel.class, long.class, int.class);
|
||||||
initResult = (int) nativeSetupMethod.invoke(audioRecord, new WeakReference<AudioRecord>(audioRecord), attributes, sampleRateArray,
|
nativeSetupMethod.setAccessible(true);
|
||||||
channelMask, channelIndexMask, audioRecord.getAudioFormat(), bufferSizeInBytes, session, attributionSourceParcel, 0L, 0);
|
initResult = (int) nativeSetupMethod.invoke(audioRecord, new WeakReference<AudioRecord>(audioRecord), attributes,
|
||||||
|
sampleRateArray, channelMask, channelIndexMask, audioRecord.getAudioFormat(), bufferSizeInBytes, session,
|
||||||
|
attributionSourceParcel, 0L, 0);
|
||||||
|
} else {
|
||||||
|
// Android 14 added a new int parameter "halInputFlags"
|
||||||
|
// <https://github.com/aosp-mirror/platform_frameworks_base/commit/f6135d75db79b1d48fad3a3b3080d37be20a2313>
|
||||||
|
Method nativeSetupMethod = AudioRecord.class.getDeclaredMethod("native_setup", Object.class, Object.class, int[].class,
|
||||||
|
int.class, int.class, int.class, int.class, int[].class, Parcel.class, long.class, int.class, int.class);
|
||||||
|
nativeSetupMethod.setAccessible(true);
|
||||||
|
initResult = (int) nativeSetupMethod.invoke(audioRecord, new WeakReference<AudioRecord>(audioRecord), attributes,
|
||||||
|
sampleRateArray, channelMask, channelIndexMask, audioRecord.getAudioFormat(), bufferSizeInBytes, session,
|
||||||
|
attributionSourceParcel, 0L, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,8 +41,14 @@ public final class ClipboardManager {
|
|||||||
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, String.class, int.class, int.class);
|
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, String.class, int.class, int.class);
|
||||||
getMethodVersion = 2;
|
getMethodVersion = 2;
|
||||||
} catch (NoSuchMethodException e3) {
|
} catch (NoSuchMethodException e3) {
|
||||||
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, int.class, String.class);
|
try {
|
||||||
getMethodVersion = 3;
|
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, int.class, String.class);
|
||||||
|
getMethodVersion = 3;
|
||||||
|
} catch (NoSuchMethodException e4) {
|
||||||
|
getPrimaryClipMethod = manager.getClass()
|
||||||
|
.getMethod("getPrimaryClip", String.class, String.class, int.class, int.class, boolean.class);
|
||||||
|
getMethodVersion = 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,8 +93,11 @@ public final class ClipboardManager {
|
|||||||
return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID);
|
return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID);
|
||||||
case 2:
|
case 2:
|
||||||
return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0);
|
return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0);
|
||||||
default:
|
case 3:
|
||||||
return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID, null);
|
return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID, null);
|
||||||
|
default:
|
||||||
|
// The last boolean parameter is "userOperate"
|
||||||
|
return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user