mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-03-17 09:34:36 +01:00
Compare commits
14 Commits
disconnect
...
disconnect
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c84937186 | ||
|
|
1da65bbc98 | ||
|
|
02949e7574 | ||
|
|
28ba0912d2 | ||
|
|
2145f6ddbd | ||
|
|
7f5fd43e4e | ||
|
|
8f51e23645 | ||
|
|
c4aefde96f | ||
|
|
bad2183087 | ||
|
|
e17a885f32 | ||
|
|
691a63761c | ||
|
|
57af6b9209 | ||
|
|
0597c5eb8d | ||
|
|
10e0c3226c |
@@ -1729,7 +1729,7 @@ parse_orientation(const char *s, enum sc_orientation *orientation) {
|
||||
return true;
|
||||
}
|
||||
LOGE("Unsupported orientation: %s (expected 0, 90, 180, 270, flip0, "
|
||||
"flip90, flip180 or flip270)", optarg);
|
||||
"flip90, flip180 or flip270)", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "util/thread.h"
|
||||
|
||||
bool
|
||||
sc_push_event_impl(uint32_t type, void* ptr, const char *name) {
|
||||
sc_push_event_impl(uint32_t type, void *ptr, const char *name) {
|
||||
SDL_Event event = {
|
||||
.user = {
|
||||
.type = type,
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
enum {
|
||||
SC_EVENT_NEW_FRAME = SDL_EVENT_USER,
|
||||
SC_EVENT_OPEN_WINDOW,
|
||||
SC_EVENT_RUN_ON_MAIN_THREAD,
|
||||
SC_EVENT_DEVICE_DISCONNECTED,
|
||||
SC_EVENT_SERVER_CONNECTION_FAILED,
|
||||
@@ -23,7 +24,7 @@ enum {
|
||||
};
|
||||
|
||||
bool
|
||||
sc_push_event_impl(uint32_t type, void* ptr, const char *name);
|
||||
sc_push_event_impl(uint32_t type, void *ptr, const char *name);
|
||||
|
||||
#define sc_push_event(TYPE) sc_push_event_impl(TYPE, NULL, # TYPE)
|
||||
#define sc_push_event_with_data(TYPE, PTR) sc_push_event_impl(TYPE, PTR, # TYPE)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "android/input.h"
|
||||
#include "android/keycodes.h"
|
||||
#include "events.h"
|
||||
#include "input_events.h"
|
||||
#include "screen.h"
|
||||
#include "shortcut_mod.h"
|
||||
@@ -46,6 +47,8 @@ sc_input_manager_init(struct sc_input_manager *im,
|
||||
im->key_repeat = 0;
|
||||
|
||||
im->next_sequence = 1; // 0 is reserved for SC_SEQUENCE_INVALID
|
||||
|
||||
im->disconnected = false;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -349,7 +352,7 @@ apply_orientation_transform(struct sc_input_manager *im,
|
||||
static void
|
||||
sc_input_manager_process_text_input(struct sc_input_manager *im,
|
||||
const SDL_TextInputEvent *event) {
|
||||
if (im->camera || !im->kp || im->screen->paused) {
|
||||
if (im->camera || !im->kp || im->screen->paused || im->disconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -417,6 +420,7 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
||||
bool control = im->controller;
|
||||
bool paused = im->screen->paused;
|
||||
bool video = im->screen->video;
|
||||
bool disconnected = im->disconnected;
|
||||
|
||||
SDL_Keycode sdl_keycode = event->key;
|
||||
uint16_t mod = event->mod;
|
||||
@@ -433,7 +437,7 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
||||
bool is_shortcut = sc_shortcut_mods_is_shortcut_mod(mods, mod)
|
||||
|| sc_shortcut_mods_is_shortcut_key(mods, sdl_keycode);
|
||||
|
||||
if (down && !repeat) {
|
||||
if (down && !repeat && !disconnected) {
|
||||
if (sdl_keycode == im->last_keycode && mod == im->last_mod) {
|
||||
++im->key_repeat;
|
||||
} else {
|
||||
@@ -510,6 +514,12 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
||||
return;
|
||||
}
|
||||
|
||||
if (disconnected) {
|
||||
// Only handle shortcuts that do not interact with the device (since
|
||||
// it is disconnected)
|
||||
return;
|
||||
}
|
||||
|
||||
// Flatten conditions to avoid additional indentation levels
|
||||
if (control) {
|
||||
// Controls for all sources
|
||||
@@ -718,7 +728,7 @@ sc_input_manager_get_position(struct sc_input_manager *im, int32_t x,
|
||||
static void
|
||||
sc_input_manager_process_mouse_motion(struct sc_input_manager *im,
|
||||
const SDL_MouseMotionEvent *event) {
|
||||
if (im->camera || !im->mp || im->screen->paused) {
|
||||
if (im->camera || !im->mp || im->screen->paused || im->disconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -757,7 +767,7 @@ sc_input_manager_process_mouse_motion(struct sc_input_manager *im,
|
||||
static void
|
||||
sc_input_manager_process_touch(struct sc_input_manager *im,
|
||||
const SDL_TouchFingerEvent *event) {
|
||||
if (im->camera || !im->mp || im->screen->paused) {
|
||||
if (im->camera || !im->mp || im->screen->paused || im->disconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -812,7 +822,7 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im,
|
||||
// some mouse events do not interact with the device, so process the event
|
||||
// even if control is disabled
|
||||
|
||||
if (im->camera) {
|
||||
if (im->camera || im->disconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -983,7 +993,7 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im,
|
||||
static void
|
||||
sc_input_manager_process_mouse_wheel(struct sc_input_manager *im,
|
||||
const SDL_MouseWheelEvent *event) {
|
||||
if (im->camera || !im->kp || im->screen->paused) {
|
||||
if (im->camera || !im->kp || im->screen->paused || im->disconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1013,7 +1023,7 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
|
||||
const SDL_GamepadDeviceEvent *event) {
|
||||
// Handle device added or removed even if paused
|
||||
|
||||
if (im->camera || !im->gp) {
|
||||
if (im->camera || !im->gp || im->disconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1058,7 +1068,7 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
|
||||
static void
|
||||
sc_input_manager_process_gamepad_axis(struct sc_input_manager *im,
|
||||
const SDL_GamepadAxisEvent *event) {
|
||||
if (im->camera || !im->gp || im->screen->paused) {
|
||||
if (im->camera || !im->gp || im->screen->paused || im->disconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1078,7 +1088,7 @@ sc_input_manager_process_gamepad_axis(struct sc_input_manager *im,
|
||||
static void
|
||||
sc_input_manager_process_gamepad_button(struct sc_input_manager *im,
|
||||
const SDL_GamepadButtonEvent *event) {
|
||||
if (im->camera || !im->gp || im->screen->paused) {
|
||||
if (im->camera || !im->gp || im->screen->paused || im->disconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1104,7 +1114,7 @@ is_apk(const char *file) {
|
||||
static void
|
||||
sc_input_manager_process_file(struct sc_input_manager *im,
|
||||
const SDL_DropEvent *event) {
|
||||
if (im->camera || !im->controller) {
|
||||
if (im->camera || !im->controller || im->disconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1127,6 +1137,16 @@ sc_input_manager_process_file(struct sc_input_manager *im,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sc_input_manager_on_device_disconnected(struct sc_input_manager *im) {
|
||||
im->disconnected = true;
|
||||
|
||||
struct sc_fps_counter *fps_counter = &im->screen->fps_counter;
|
||||
if (sc_fps_counter_is_started(fps_counter)) {
|
||||
sc_fps_counter_stop(fps_counter);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sc_input_manager_handle_event(struct sc_input_manager *im,
|
||||
const SDL_Event *event) {
|
||||
@@ -1167,5 +1187,8 @@ sc_input_manager_handle_event(struct sc_input_manager *im,
|
||||
case SDL_EVENT_DROP_FILE:
|
||||
sc_input_manager_process_file(im, &event->drop);
|
||||
break;
|
||||
case SC_EVENT_DEVICE_DISCONNECTED:
|
||||
sc_input_manager_on_device_disconnected(im);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ struct sc_input_manager {
|
||||
uint16_t last_mod;
|
||||
|
||||
uint64_t next_sequence; // used for request acknowledgements
|
||||
|
||||
bool disconnected;
|
||||
};
|
||||
|
||||
struct sc_input_manager_params {
|
||||
|
||||
@@ -205,14 +205,23 @@ sc_screen_render(struct sc_screen *screen, bool update_content_rect) {
|
||||
}
|
||||
|
||||
SDL_Renderer *renderer = screen->renderer;
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
||||
sc_sdl_render_clear(renderer);
|
||||
|
||||
bool ok = false;
|
||||
SDL_Texture *texture = screen->tex.texture;
|
||||
if (!texture) {
|
||||
if (!screen->disconnected) {
|
||||
LOGW("No texture to render");
|
||||
}
|
||||
// Draw a dark 10x10 square in the top-right corner to distinguish a
|
||||
// black frame from the absence of a frame
|
||||
struct sc_size render_size = sc_sdl_get_render_output_size(renderer);
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0x33, 0xff);
|
||||
SDL_FRect rect = {
|
||||
.x = render_size.width - 20,
|
||||
.y = 10,
|
||||
.w = 10,
|
||||
.h = 10,
|
||||
};
|
||||
SDL_RenderFillRect(renderer, &rect);
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -282,11 +291,8 @@ sc_screen_frame_sink_open(struct sc_frame_sink *sink,
|
||||
const AVCodecContext *ctx,
|
||||
const struct sc_stream_session *session) {
|
||||
assert(ctx->pix_fmt == AV_PIX_FMT_YUV420P);
|
||||
(void) ctx;
|
||||
(void) session;
|
||||
|
||||
struct sc_screen *screen = DOWNCAST(sink);
|
||||
(void) screen;
|
||||
|
||||
if (ctx->width <= 0 || ctx->width > 0xFFFF
|
||||
|| ctx->height <= 0 || ctx->height > 0xFFFF) {
|
||||
@@ -294,6 +300,19 @@ sc_screen_frame_sink_open(struct sc_frame_sink *sink,
|
||||
return false;
|
||||
}
|
||||
|
||||
// content_size can be written from this thread, because it is never read
|
||||
// from the main thread before handling SC_EVENT_OPEN_WINDOW (which acts as
|
||||
// a synchronization point) when video is enabled
|
||||
screen->frame_size.width = session->video.width;
|
||||
screen->frame_size.height = session->video.height;
|
||||
screen->content_size = get_oriented_size(screen->frame_size,
|
||||
screen->orientation);
|
||||
|
||||
bool ok = sc_push_event(SC_EVENT_OPEN_WINDOW);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
screen->open = true;
|
||||
#endif
|
||||
@@ -343,7 +362,6 @@ bool
|
||||
sc_screen_init(struct sc_screen *screen,
|
||||
const struct sc_screen_params *params) {
|
||||
screen->resize_pending = false;
|
||||
screen->has_frame = false;
|
||||
screen->window_shown = false;
|
||||
screen->paused = false;
|
||||
screen->resume_frame = NULL;
|
||||
@@ -723,14 +741,14 @@ sc_screen_set_orientation(struct sc_screen *screen,
|
||||
static bool
|
||||
sc_screen_apply_frame(struct sc_screen *screen) {
|
||||
assert(screen->video);
|
||||
assert(screen->window_shown);
|
||||
|
||||
sc_fps_counter_add_rendered_frame(&screen->fps_counter);
|
||||
|
||||
AVFrame *frame = screen->frame;
|
||||
struct sc_size new_frame_size = {frame->width, frame->height};
|
||||
|
||||
if (!screen->has_frame
|
||||
|| screen->frame_size.width != new_frame_size.width
|
||||
if (screen->frame_size.width != new_frame_size.width
|
||||
|| screen->frame_size.height != new_frame_size.height) {
|
||||
|
||||
// frame dimension changed
|
||||
@@ -738,14 +756,8 @@ sc_screen_apply_frame(struct sc_screen *screen) {
|
||||
|
||||
struct sc_size new_content_size =
|
||||
get_oriented_size(new_frame_size, screen->orientation);
|
||||
if (screen->has_frame) {
|
||||
set_content_size(screen, new_content_size);
|
||||
sc_screen_update_content_rect(screen);
|
||||
} else {
|
||||
// This is the first frame
|
||||
screen->has_frame = true;
|
||||
screen->content_size = new_content_size;
|
||||
}
|
||||
set_content_size(screen, new_content_size);
|
||||
sc_screen_update_content_rect(screen);
|
||||
}
|
||||
|
||||
bool ok = sc_texture_set_from_frame(&screen->tex, frame);
|
||||
@@ -753,17 +765,6 @@ sc_screen_apply_frame(struct sc_screen *screen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(screen->has_frame);
|
||||
if (!screen->window_shown) {
|
||||
// this is the very first frame, show the window
|
||||
sc_screen_show_initial_window(screen);
|
||||
|
||||
if (sc_screen_is_relative_mode(screen)) {
|
||||
// Capture mouse on start
|
||||
sc_mouse_capture_set_active(&screen->mc, true);
|
||||
}
|
||||
}
|
||||
|
||||
sc_screen_render(screen, false);
|
||||
return true;
|
||||
}
|
||||
@@ -906,6 +907,16 @@ sc_disconnect_on_timeout(struct sc_disconnect *d, void *userdata) {
|
||||
void
|
||||
sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) {
|
||||
switch (event->type) {
|
||||
case SC_EVENT_OPEN_WINDOW:
|
||||
sc_screen_show_initial_window(screen);
|
||||
|
||||
if (sc_screen_is_relative_mode(screen)) {
|
||||
// Capture mouse on start
|
||||
sc_mouse_capture_set_active(&screen->mc, true);
|
||||
}
|
||||
|
||||
sc_screen_render(screen, false);
|
||||
return;
|
||||
case SC_EVENT_NEW_FRAME: {
|
||||
bool ok = sc_screen_update_frame(screen);
|
||||
if (!ok) {
|
||||
@@ -948,6 +959,8 @@ sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) {
|
||||
return;
|
||||
}
|
||||
|
||||
sc_input_manager_handle_event(&screen->im, event);
|
||||
|
||||
sc_texture_reset(&screen->tex);
|
||||
sc_screen_render(screen, true);
|
||||
|
||||
@@ -989,11 +1002,15 @@ sc_screen_handle_disconnection(struct sc_screen *screen) {
|
||||
SDL_Event event;
|
||||
while (SDL_WaitEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_EVENT_WINDOW_EXPOSED:
|
||||
sc_screen_render(screen, true);
|
||||
break;
|
||||
case SC_EVENT_DISCONNECTED_ICON_LOADED: {
|
||||
SDL_Surface *icon_disconnected = event.user.data1;
|
||||
assert(icon_disconnected);
|
||||
|
||||
bool ok = sc_texture_set_from_surface(&screen->tex, icon_disconnected);
|
||||
bool ok = sc_texture_set_from_surface(&screen->tex,
|
||||
icon_disconnected);
|
||||
if (ok) {
|
||||
screen->content_size.width = icon_disconnected->w;
|
||||
screen->content_size.height = icon_disconnected->h;
|
||||
@@ -1013,6 +1030,8 @@ sc_screen_handle_disconnection(struct sc_screen *screen) {
|
||||
LOGD("User requested to quit");
|
||||
sc_screen_interrupt_disconnect(screen);
|
||||
return;
|
||||
default:
|
||||
sc_input_manager_handle_event(&screen->im, &event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ struct sc_screen {
|
||||
enum sc_orientation orientation;
|
||||
// rectangle of the content (excluding black borders)
|
||||
struct SDL_FRect rect;
|
||||
bool has_frame;
|
||||
bool window_shown;
|
||||
|
||||
AVFrame *frame;
|
||||
|
||||
@@ -93,4 +93,4 @@ Then just double-click on that file to run it.
|
||||
|
||||
To start scrcpy without opening a terminal, double-click `scrcpy-noconsole.vbs`
|
||||
(note that errors won't be shown). To pass arguments, edit (a copy of)
|
||||
`scrcpy-noconsole.vbs` add and the desired arguments.
|
||||
`scrcpy-noconsole.vbs` and add the desired arguments.
|
||||
|
||||
Reference in New Issue
Block a user