mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-04-21 01:33:36 +00:00
Merge e479405095 into 4671927c34
This commit is contained in:
commit
290d1e084c
12 changed files with 116 additions and 12 deletions
|
|
@ -114,6 +114,7 @@ enum {
|
|||
OPT_NO_VD_SYSTEM_DECORATIONS,
|
||||
OPT_NO_VD_DESTROY_CONTENT,
|
||||
OPT_DISPLAY_IME_POLICY,
|
||||
OPT_OTG_AUTOMATIC_SCREENSHOT,
|
||||
};
|
||||
|
||||
struct sc_option {
|
||||
|
|
@ -1063,6 +1064,13 @@ static const struct sc_option options[] = {
|
|||
.text = "Set the initial window height.\n"
|
||||
"Default is 0 (automatic).",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_OTG_AUTOMATIC_SCREENSHOT,
|
||||
.longopt = "otg-automatic-screenshot",
|
||||
.text = "Take a screenshot automatically each time mouse capture is exited in OTG mode.\n"
|
||||
"This is particularly useful when OTG mode is used to enable USB debugging on a phone with a broken screen.\n"
|
||||
"The screenshot will display the mouse pointer that will indicate where to move next."
|
||||
},
|
||||
};
|
||||
|
||||
static const struct sc_shortcut shortcuts[] = {
|
||||
|
|
@ -2821,6 +2829,9 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||
return false;
|
||||
}
|
||||
break;
|
||||
case OPT_OTG_AUTOMATIC_SCREENSHOT:
|
||||
opts->otg_automatic_screenshot = true;
|
||||
break;
|
||||
default:
|
||||
// getopt prints the error message on stderr
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -343,3 +343,17 @@ void sc_hid_keyboard_generate_open(struct sc_hid_open *hid_open) {
|
|||
void sc_hid_keyboard_generate_close(struct sc_hid_close *hid_close) {
|
||||
hid_close->hid_id = SC_HID_ID_KEYBOARD;
|
||||
}
|
||||
|
||||
void
|
||||
sc_hid_keyboard_generate_screenshot_press_input(struct sc_hid_input *hid_input) {
|
||||
sc_hid_keyboard_input_init(hid_input);
|
||||
|
||||
uint8_t *keys_data = &hid_input->data[SC_HID_KEYBOARD_INDEX_KEYS];
|
||||
keys_data[0] = 0x66; // Power : Usage ID 0x66
|
||||
keys_data[1] = 0x81; // Volume Down : Usage ID 0x81
|
||||
}
|
||||
|
||||
void
|
||||
sc_hid_keyboard_generate_screenshot_release_input(struct sc_hid_input *hid_input) {
|
||||
sc_hid_keyboard_input_init(hid_input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@
|
|||
// Maybe SDL_Keycode is used by most people, but SDL_Scancode is taken from USB
|
||||
// HID protocol.
|
||||
// 0x65 is Application, typically AT-101 Keyboard ends here.
|
||||
#define SC_HID_KEYBOARD_KEYS 0x66
|
||||
// Increase the maximum value to 0x82 instead of the previous value 0x66 so that
|
||||
// we can send Power (0x66) and Volume Down (0x81) to take screenshots.
|
||||
#define SC_HID_KEYBOARD_KEYS 0x82
|
||||
|
||||
#define SC_HID_ID_KEYBOARD 1
|
||||
|
||||
|
|
@ -51,4 +53,10 @@ bool
|
|||
sc_hid_keyboard_generate_input_from_mods(struct sc_hid_input *hid_input,
|
||||
uint16_t mods_state);
|
||||
|
||||
void
|
||||
sc_hid_keyboard_generate_screenshot_press_input(struct sc_hid_input *hid_input);
|
||||
|
||||
void
|
||||
sc_hid_keyboard_generate_screenshot_release_input(struct sc_hid_input *hid_input);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ sc_mouse_capture_is_capture_key(struct sc_mouse_capture *mc, SDL_Keycode key) {
|
|||
return sc_shortcut_mods_is_shortcut_key(mc->sdl_mouse_capture_keys, key);
|
||||
}
|
||||
|
||||
bool
|
||||
int
|
||||
sc_mouse_capture_handle_event(struct sc_mouse_capture *mc,
|
||||
const SDL_Event *event) {
|
||||
switch (event->type) {
|
||||
case SDL_WINDOWEVENT:
|
||||
if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST) {
|
||||
sc_mouse_capture_set_active(mc, false);
|
||||
return true;
|
||||
return SC_MOUSE_CAPTURE_EVENT_CONSUMED;
|
||||
}
|
||||
break;
|
||||
case SDL_KEYDOWN: {
|
||||
|
|
@ -37,7 +37,7 @@ sc_mouse_capture_handle_event(struct sc_mouse_capture *mc,
|
|||
mc->mouse_capture_key_pressed = 0;
|
||||
}
|
||||
// Mouse capture keys are never forwarded to the device
|
||||
return true;
|
||||
return SC_MOUSE_CAPTURE_EVENT_CONSUMED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -52,7 +52,11 @@ sc_mouse_capture_handle_event(struct sc_mouse_capture *mc,
|
|||
sc_mouse_capture_toggle(mc);
|
||||
}
|
||||
// Mouse capture keys are never forwarded to the device
|
||||
return true;
|
||||
if (sc_mouse_capture_is_active(mc)) {
|
||||
return SC_MOUSE_CAPTURE_EVENT_CONSUMED;
|
||||
} else {
|
||||
return SC_MOUSE_CAPTURE_EVENT_CONSUMED_EXIT_CAPTURE_MODE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -62,13 +66,13 @@ sc_mouse_capture_handle_event(struct sc_mouse_capture *mc,
|
|||
if (!sc_mouse_capture_is_active(mc)) {
|
||||
// The mouse will be captured on SDL_MOUSEBUTTONUP, so consume
|
||||
// the event
|
||||
return true;
|
||||
return SC_MOUSE_CAPTURE_EVENT_CONSUMED;
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (!sc_mouse_capture_is_active(mc)) {
|
||||
sc_mouse_capture_set_active(mc, true);
|
||||
return true;
|
||||
return SC_MOUSE_CAPTURE_EVENT_CONSUMED;
|
||||
}
|
||||
break;
|
||||
case SDL_FINGERMOTION:
|
||||
|
|
@ -76,10 +80,10 @@ sc_mouse_capture_handle_event(struct sc_mouse_capture *mc,
|
|||
case SDL_FINGERUP:
|
||||
// Touch events are not compatible with relative mode
|
||||
// (coordinates are not relative), so consume the event
|
||||
return true;
|
||||
return SC_MOUSE_CAPTURE_EVENT_CONSUMED;
|
||||
}
|
||||
|
||||
return false;
|
||||
return SC_MOUSE_CAPTURE_EVENT_UNCONSUMED;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@ struct sc_mouse_capture {
|
|||
|
||||
};
|
||||
|
||||
enum {
|
||||
SC_MOUSE_CAPTURE_EVENT_UNCONSUMED,
|
||||
SC_MOUSE_CAPTURE_EVENT_CONSUMED,
|
||||
SC_MOUSE_CAPTURE_EVENT_CONSUMED_EXIT_CAPTURE_MODE,
|
||||
};
|
||||
|
||||
void
|
||||
sc_mouse_capture_init(struct sc_mouse_capture *mc, SDL_Window *window,
|
||||
uint8_t shortcut_mods);
|
||||
|
|
@ -30,8 +36,8 @@ sc_mouse_capture_is_active(struct sc_mouse_capture *mc);
|
|||
void
|
||||
sc_mouse_capture_toggle(struct sc_mouse_capture *mc);
|
||||
|
||||
// Return true if it consumed the event
|
||||
bool
|
||||
// Return if it consumed the event
|
||||
int
|
||||
sc_mouse_capture_handle_event(struct sc_mouse_capture *mc,
|
||||
const SDL_Event *event);
|
||||
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||
.angle = NULL,
|
||||
.vd_destroy_content = true,
|
||||
.vd_system_decorations = true,
|
||||
.otg_automatic_screenshot = false,
|
||||
};
|
||||
|
||||
enum sc_orientation
|
||||
|
|
|
|||
|
|
@ -327,6 +327,7 @@ struct scrcpy_options {
|
|||
const char *start_app;
|
||||
bool vd_destroy_content;
|
||||
bool vd_system_decorations;
|
||||
bool otg_automatic_screenshot;
|
||||
};
|
||||
|
||||
extern const struct scrcpy_options scrcpy_options_default;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,14 @@ struct sc_key_processor_ops {
|
|||
void
|
||||
(*process_text)(struct sc_key_processor *kp,
|
||||
const struct sc_text_event *event);
|
||||
|
||||
/**
|
||||
* Take screenshot
|
||||
*
|
||||
* This function is optional.
|
||||
*/
|
||||
bool
|
||||
(*take_screenshot)(struct sc_key_processor *kp);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "keyboard_aoa.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "input_events.h"
|
||||
#include "util/log.h"
|
||||
|
|
@ -62,6 +63,31 @@ sc_key_processor_process_key(struct sc_key_processor *kp,
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
sc_key_processor_take_screenshot(struct sc_key_processor *kp) {
|
||||
|
||||
struct sc_keyboard_aoa *kb = DOWNCAST(kp);
|
||||
|
||||
struct sc_hid_input hid_input;
|
||||
|
||||
sc_hid_keyboard_generate_screenshot_press_input(&hid_input);
|
||||
if (!sc_aoa_push_input(kb->aoa, &hid_input)) {
|
||||
LOGW("Could not push AOA HID input (screenshot press)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// sleep for 100ms
|
||||
usleep(100000);
|
||||
|
||||
sc_hid_keyboard_generate_screenshot_release_input(&hid_input);
|
||||
if (!sc_aoa_push_input(kb->aoa, &hid_input)) {
|
||||
LOGW("Could not push AOA HID input (screenshot release)");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
sc_keyboard_aoa_init(struct sc_keyboard_aoa *kb, struct sc_aoa *aoa) {
|
||||
kb->aoa = aoa;
|
||||
|
|
@ -84,6 +110,7 @@ sc_keyboard_aoa_init(struct sc_keyboard_aoa *kb, struct sc_aoa *aoa) {
|
|||
// Never forward text input via HID (all the keys are injected
|
||||
// separately)
|
||||
.process_text = NULL,
|
||||
.take_screenshot = sc_key_processor_take_screenshot,
|
||||
};
|
||||
|
||||
// Clipboard synchronization is requested over the control socket, while HID
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@ scrcpy_otg(struct scrcpy_options *options) {
|
|||
.window_height = options->window_height,
|
||||
.window_borderless = options->window_borderless,
|
||||
.shortcut_mods = options->shortcut_mods,
|
||||
.otg_automatic_screenshot = options->otg_automatic_screenshot,
|
||||
};
|
||||
|
||||
ok = sc_screen_otg_init(&s->screen_otg, ¶ms);
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ sc_screen_otg_init(struct sc_screen_otg *screen,
|
|||
sc_mouse_capture_set_active(&screen->mc, true);
|
||||
}
|
||||
|
||||
screen->otg_automatic_screenshot = params->otg_automatic_screenshot;
|
||||
|
||||
return true;
|
||||
|
||||
error_destroy_window:
|
||||
|
|
@ -118,6 +120,15 @@ sc_screen_otg_process_key(struct sc_screen_otg *screen,
|
|||
kp->ops->process_key(kp, &evt, SC_SEQUENCE_INVALID);
|
||||
}
|
||||
|
||||
static void
|
||||
sc_screen_otg_take_screenshot(struct sc_screen_otg *screen) {
|
||||
assert(screen->keyboard);
|
||||
struct sc_key_processor *kp = &screen->keyboard->key_processor;
|
||||
|
||||
assert(kp->ops->take_screenshot);
|
||||
kp->ops->take_screenshot(kp);
|
||||
}
|
||||
|
||||
static void
|
||||
sc_screen_otg_process_mouse_motion(struct sc_screen_otg *screen,
|
||||
const SDL_MouseMotionEvent *event) {
|
||||
|
|
@ -261,11 +272,21 @@ sc_screen_otg_process_gamepad_button(struct sc_screen_otg *screen,
|
|||
|
||||
void
|
||||
sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event) {
|
||||
if (sc_mouse_capture_handle_event(&screen->mc, event)) {
|
||||
int event_state = sc_mouse_capture_handle_event(&screen->mc, event);
|
||||
if (event_state == SC_MOUSE_CAPTURE_EVENT_CONSUMED) {
|
||||
// The mouse capture handler consumed the event
|
||||
return;
|
||||
} else if (event_state == SC_MOUSE_CAPTURE_EVENT_CONSUMED_EXIT_CAPTURE_MODE) {
|
||||
if (screen->otg_automatic_screenshot) {
|
||||
// send Volume Down + Power event to take a screenshot
|
||||
LOGI("Taking screenshot");
|
||||
sc_screen_otg_take_screenshot(screen);
|
||||
}
|
||||
// The mouse capture handler consumed the event
|
||||
return;
|
||||
}
|
||||
|
||||
// assume event_state is SC_MOUSE_CAPTURE_EVENT_UNCONSUMED
|
||||
switch (event->type) {
|
||||
case SDL_WINDOWEVENT:
|
||||
switch (event->window.event) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ struct sc_screen_otg {
|
|||
SDL_Texture *texture;
|
||||
|
||||
struct sc_mouse_capture mc;
|
||||
bool otg_automatic_screenshot;
|
||||
};
|
||||
|
||||
struct sc_screen_otg_params {
|
||||
|
|
@ -37,6 +38,7 @@ struct sc_screen_otg_params {
|
|||
uint16_t window_height;
|
||||
bool window_borderless;
|
||||
uint8_t shortcut_mods; // OR of enum sc_shortcut_mod values
|
||||
bool otg_automatic_screenshot;
|
||||
};
|
||||
|
||||
bool
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue