From 07f056353bf4295c3721dac066bd2cc1b9f7ae04 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Tue, 3 Feb 2026 19:29:07 +0100 Subject: [PATCH] Use common sc_screen for normal and OTG modes Originally, the default scrcpy window always displayed the video stream. Since the OTG mode window only contains the scrcpy logo, it was implemented as a separate component [1]. Later, the --no-video option was added [2] to control the device without mirroring (while still using an adb connection, unlike OTG mode). To support this, sc_screen gained the ability to display a window containing only the scrcpy logo, like in OTG mode. As a result, the main sc_screen component can now be reused in OTG mode, allowing removal of the OTG-specific duplicate implementation (sc_screen_otg). [1] commit 91418c79ab3b7056c21ef6c64f903704c8f00a52 [2] commit 8c650e53cd37a53d5c3aa746c30a71c6b742a4e2 Refs #2974 Refs #3978 PR #6649 --- app/meson.build | 1 - app/src/input_manager.c | 2 - app/src/usb/scrcpy_otg.c | 58 ++++--- app/src/usb/screen_otg.c | 327 --------------------------------------- app/src/usb/screen_otg.h | 52 ------- 5 files changed, 40 insertions(+), 400 deletions(-) delete mode 100644 app/src/usb/screen_otg.c delete mode 100644 app/src/usb/screen_otg.h diff --git a/app/meson.build b/app/meson.build index 6f6f64c1..36b72cfd 100644 --- a/app/meson.build +++ b/app/meson.build @@ -104,7 +104,6 @@ if usb_support 'src/usb/keyboard_aoa.c', 'src/usb/mouse_aoa.c', 'src/usb/scrcpy_otg.c', - 'src/usb/screen_otg.c', 'src/usb/usb.c', ] endif diff --git a/app/src/input_manager.c b/app/src/input_manager.c index e622ddb2..951b8e15 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -16,8 +16,6 @@ void sc_input_manager_init(struct sc_input_manager *im, const struct sc_input_manager_params *params) { - // A key/mouse processor may not be present if there is no controller - assert((!params->kp && !params->mp && !params->gp) || params->controller); // A processor must have ops initialized assert(!params->kp || params->kp->ops); assert(!params->mp || params->mp->ops); diff --git a/app/src/usb/scrcpy_otg.c b/app/src/usb/scrcpy_otg.c index 483720f8..c79aee74 100644 --- a/app/src/usb/scrcpy_otg.c +++ b/app/src/usb/scrcpy_otg.c @@ -9,7 +9,7 @@ # include "adb/adb.h" #endif #include "events.h" -#include "usb/screen_otg.h" +#include "screen.h" #include "usb/aoa_hid.h" #include "usb/gamepad_aoa.h" #include "usb/keyboard_aoa.h" @@ -23,7 +23,7 @@ struct scrcpy_otg { struct sc_mouse_aoa mouse; struct sc_gamepad_aoa gamepad; - struct sc_screen_otg screen_otg; + struct sc_screen screen; }; static void @@ -49,7 +49,7 @@ event_loop(struct scrcpy_otg *s) { LOGD("User requested to quit"); return SCRCPY_EXIT_SUCCESS; default: - sc_screen_otg_handle_event(&s->screen_otg, &event); + sc_screen_handle_event(&s->screen, &event); break; } } @@ -88,13 +88,14 @@ scrcpy_otg(struct scrcpy_options *options) { enum scrcpy_exit_code ret = SCRCPY_EXIT_FAILURE; - struct sc_keyboard_aoa *keyboard = NULL; - struct sc_mouse_aoa *mouse = NULL; - struct sc_gamepad_aoa *gamepad = NULL; + struct sc_key_processor *kp = NULL; + struct sc_mouse_processor *mp = NULL; + struct sc_gamepad_processor *gp = NULL; bool usb_device_initialized = false; bool usb_connected = false; bool aoa_started = false; bool aoa_initialized = false; + bool screen_initialized = false; #ifdef _WIN32 // On Windows, only one process could open a USB device @@ -157,7 +158,7 @@ scrcpy_otg(struct scrcpy_options *options) { if (!ok) { goto end; } - keyboard = &s->keyboard; + kp = &s->keyboard.key_processor; } if (enable_mouse) { @@ -165,12 +166,12 @@ scrcpy_otg(struct scrcpy_options *options) { if (!ok) { goto end; } - mouse = &s->mouse; + mp = &s->mouse.mouse_processor; } if (enable_gamepad) { sc_gamepad_aoa_init(&s->gamepad, &s->aoa); - gamepad = &s->gamepad; + gp = &s->gamepad.gamepad_processor; } ok = sc_aoa_start(&s->aoa); @@ -184,10 +185,18 @@ scrcpy_otg(struct scrcpy_options *options) { window_title = usb_device.product ? usb_device.product : "scrcpy"; } - struct sc_screen_otg_params params = { - .keyboard = keyboard, - .mouse = mouse, - .gamepad = gamepad, + struct sc_screen_params params = { + .video = false, + .camera = false, + .controller = false, + .fp = NULL, + .kp = kp, + .mp = mp, + .gp = gp, + .mouse_bindings = options->mouse_bindings, + .legacy_paste = false, + .clipboard_autosync = false, + .shortcut_mods = options->shortcut_mods, .window_title = window_title, .always_on_top = options->always_on_top, .window_x = options->window_x, @@ -195,13 +204,17 @@ scrcpy_otg(struct scrcpy_options *options) { .window_width = options->window_width, .window_height = options->window_height, .window_borderless = options->window_borderless, - .shortcut_mods = options->shortcut_mods, + .orientation = SC_ORIENTATION_0, + .mipmaps = options->mipmaps, + .fullscreen = false, + .start_fps_counter = false, }; - ok = sc_screen_otg_init(&s->screen_otg, ¶ms); + ok = sc_screen_init(&s->screen, ¶ms); if (!ok) { goto end; } + screen_initialized = true; // usb_device not needed anymore sc_usb_device_destroy(&usb_device); @@ -216,13 +229,17 @@ end: } sc_usb_stop(&s->usb); - if (mouse) { + if (screen_initialized) { + sc_screen_interrupt(&s->screen); + } + + if (mp) { sc_mouse_aoa_destroy(&s->mouse); } - if (keyboard) { + if (kp) { sc_keyboard_aoa_destroy(&s->keyboard); } - if (gamepad) { + if (gp) { sc_gamepad_aoa_destroy(&s->gamepad); } @@ -243,5 +260,10 @@ end: sc_usb_destroy(&s->usb); + if (screen_initialized) { + sc_screen_join(&s->screen); + sc_screen_destroy(&s->screen); + } + return ret; } diff --git a/app/src/usb/screen_otg.c b/app/src/usb/screen_otg.c deleted file mode 100644 index 4fbccfb0..00000000 --- a/app/src/usb/screen_otg.c +++ /dev/null @@ -1,327 +0,0 @@ -#include "screen_otg.h" - -#include -#include - -#include "icon.h" -#include "options.h" -#include "util/acksync.h" -#include "util/log.h" -#include "util/sdl.h" - -static void -sc_screen_otg_render(struct sc_screen_otg *screen) { - sc_sdl_render_clear(screen->renderer); - if (screen->texture) { - bool ok = - SDL_RenderTexture(screen->renderer, screen->texture, NULL, NULL); - if (!ok) { - LOGW("Could not render texture: %s", SDL_GetError()); - } - } - sc_sdl_render_present(screen->renderer); -} - -bool -sc_screen_otg_init(struct sc_screen_otg *screen, - const struct sc_screen_otg_params *params) { - screen->keyboard = params->keyboard; - screen->mouse = params->mouse; - screen->gamepad = params->gamepad; - - const char *title = params->window_title; - assert(title); - - int x = params->window_x != SC_WINDOW_POSITION_UNDEFINED - ? params->window_x : (int) SDL_WINDOWPOS_UNDEFINED; - int y = params->window_y != SC_WINDOW_POSITION_UNDEFINED - ? params->window_y : (int) SDL_WINDOWPOS_UNDEFINED; - int width = params->window_width ? params->window_width : 256; - int height = params->window_height ? params->window_height : 256; - - uint32_t window_flags = SDL_WINDOW_HIGH_PIXEL_DENSITY; - if (params->always_on_top) { - window_flags |= SDL_WINDOW_ALWAYS_ON_TOP; - } - if (params->window_borderless) { - window_flags |= SDL_WINDOW_BORDERLESS; - } - - screen->window = - sc_sdl_create_window(title, x, y, width, height, window_flags); - if (!screen->window) { - LOGE("Could not create window: %s", SDL_GetError()); - return false; - } - - screen->renderer = SDL_CreateRenderer(screen->window, NULL); - if (!screen->renderer) { - LOGE("Could not create renderer: %s", SDL_GetError()); - goto error_destroy_window; - } - - SDL_Surface *icon = scrcpy_icon_load(); - - if (icon) { - bool ok = SDL_SetWindowIcon(screen->window, icon); - if (!ok) { - LOGW("Could not set window icon: %s", SDL_GetError()); - } - - ok = SDL_SetRenderLogicalPresentation(screen->renderer, icon->w, - icon->h, - SDL_LOGICAL_PRESENTATION_LETTERBOX); - if (!ok) { - LOGW("Could not set renderer logical size: %s", SDL_GetError()); - // don't fail - } - - screen->texture = SDL_CreateTextureFromSurface(screen->renderer, icon); - scrcpy_icon_destroy(icon); - if (!screen->texture) { - goto error_destroy_renderer; - } - } else { - screen->texture = NULL; - LOGW("Could not load icon"); - } - - sc_mouse_capture_init(&screen->mc, screen->window, params->shortcut_mods); - - if (screen->mouse) { - // Capture mouse on start - sc_mouse_capture_set_active(&screen->mc, true); - } - - return true; - -error_destroy_window: - SDL_DestroyWindow(screen->window); -error_destroy_renderer: - SDL_DestroyRenderer(screen->renderer); - - return false; -} - -void -sc_screen_otg_destroy(struct sc_screen_otg *screen) { - if (screen->texture) { - SDL_DestroyTexture(screen->texture); - } - SDL_DestroyRenderer(screen->renderer); - SDL_DestroyWindow(screen->window); -} - -static void -sc_screen_otg_process_key(struct sc_screen_otg *screen, - const SDL_KeyboardEvent *event) { - assert(screen->keyboard); - struct sc_key_processor *kp = &screen->keyboard->key_processor; - - struct sc_key_event evt = { - .action = sc_action_from_sdl_keyboard_type(event->type), - .keycode = sc_keycode_from_sdl(event->key), - .scancode = sc_scancode_from_sdl(event->scancode), - .repeat = event->repeat, - .mods_state = sc_mods_state_from_sdl(event->mod), - }; - - assert(kp->ops->process_key); - kp->ops->process_key(kp, &evt, SC_SEQUENCE_INVALID); -} - -static void -sc_screen_otg_process_mouse_motion(struct sc_screen_otg *screen, - const SDL_MouseMotionEvent *event) { - assert(screen->mouse); - struct sc_mouse_processor *mp = &screen->mouse->mouse_processor; - - struct sc_mouse_motion_event evt = { - // .position not used for HID events - .xrel = event->xrel, - .yrel = event->yrel, - .buttons_state = sc_mouse_buttons_state_from_sdl(event->state), - }; - - assert(mp->ops->process_mouse_motion); - mp->ops->process_mouse_motion(mp, &evt); -} - -static void -sc_screen_otg_process_mouse_button(struct sc_screen_otg *screen, - const SDL_MouseButtonEvent *event) { - assert(screen->mouse); - struct sc_mouse_processor *mp = &screen->mouse->mouse_processor; - - uint32_t sdl_buttons_state = SDL_GetMouseState(NULL, NULL); - - struct sc_mouse_click_event evt = { - // .position not used for HID events - .action = sc_action_from_sdl_mousebutton_type(event->type), - .button = sc_mouse_button_from_sdl(event->button), - .buttons_state = sc_mouse_buttons_state_from_sdl(sdl_buttons_state), - }; - - assert(mp->ops->process_mouse_click); - mp->ops->process_mouse_click(mp, &evt); -} - -static void -sc_screen_otg_process_mouse_wheel(struct sc_screen_otg *screen, - const SDL_MouseWheelEvent *event) { - assert(screen->mouse); - struct sc_mouse_processor *mp = &screen->mouse->mouse_processor; - - uint32_t sdl_buttons_state = SDL_GetMouseState(NULL, NULL); - - struct sc_mouse_scroll_event evt = { - // .position not used for HID events - .hscroll = event->x, - .vscroll = event->y, - .buttons_state = sc_mouse_buttons_state_from_sdl(sdl_buttons_state), - }; - - assert(mp->ops->process_mouse_scroll); - mp->ops->process_mouse_scroll(mp, &evt); -} - -static void -sc_screen_otg_process_gamepad_device(struct sc_screen_otg *screen, - const SDL_GamepadDeviceEvent *event) { - assert(screen->gamepad); - struct sc_gamepad_processor *gp = &screen->gamepad->gamepad_processor; - - if (event->type == SDL_EVENT_GAMEPAD_ADDED) { - SDL_Gamepad *sdl_gamepad = SDL_OpenGamepad(event->which); - if (!sdl_gamepad) { - LOGW("Could not open gamepad"); - return; - } - - SDL_Joystick *joystick = SDL_GetGamepadJoystick(sdl_gamepad); - if (!joystick) { - LOGW("Could not get gamepad joystick"); - SDL_CloseGamepad(sdl_gamepad); - return; - } - - struct sc_gamepad_device_event evt = { - .gamepad_id = SDL_GetJoystickID(joystick), - }; - gp->ops->process_gamepad_added(gp, &evt); - } else if (event->type == SDL_EVENT_GAMEPAD_REMOVED) { - SDL_JoystickID id = event->which; - - SDL_Gamepad *sdl_gamepad = SDL_GetGamepadFromID(id); - if (sdl_gamepad) { - SDL_CloseGamepad(sdl_gamepad); - } else { - LOGW("Unknown gamepad device removed"); - } - - struct sc_gamepad_device_event evt = { - .gamepad_id = id, - }; - gp->ops->process_gamepad_removed(gp, &evt); - } -} - -static void -sc_screen_otg_process_gamepad_axis(struct sc_screen_otg *screen, - const SDL_GamepadAxisEvent *event) { - assert(screen->gamepad); - struct sc_gamepad_processor *gp = &screen->gamepad->gamepad_processor; - - enum sc_gamepad_axis axis = sc_gamepad_axis_from_sdl(event->axis); - if (axis == SC_GAMEPAD_AXIS_UNKNOWN) { - return; - } - - struct sc_gamepad_axis_event evt = { - .gamepad_id = event->which, - .axis = axis, - .value = event->value, - }; - gp->ops->process_gamepad_axis(gp, &evt); -} - -static void -sc_screen_otg_process_gamepad_button(struct sc_screen_otg *screen, - const SDL_GamepadButtonEvent *event) { - assert(screen->gamepad); - struct sc_gamepad_processor *gp = &screen->gamepad->gamepad_processor; - - enum sc_gamepad_button button = sc_gamepad_button_from_sdl(event->button); - if (button == SC_GAMEPAD_BUTTON_UNKNOWN) { - return; - } - - struct sc_gamepad_button_event evt = { - .gamepad_id = event->which, - .action = sc_action_from_sdl_gamepad_button_type(event->type), - .button = button, - }; - gp->ops->process_gamepad_button(gp, &evt); -} - -void -sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event) { - if (sc_mouse_capture_handle_event(&screen->mc, event)) { - // The mouse capture handler consumed the event - return; - } - - switch (event->type) { - case SDL_EVENT_WINDOW_EXPOSED: - sc_screen_otg_render(screen); - break; - case SDL_EVENT_KEY_DOWN: - if (screen->keyboard) { - sc_screen_otg_process_key(screen, &event->key); - } - break; - case SDL_EVENT_KEY_UP: - if (screen->keyboard) { - sc_screen_otg_process_key(screen, &event->key); - } - break; - case SDL_EVENT_MOUSE_MOTION: - if (screen->mouse) { - sc_screen_otg_process_mouse_motion(screen, &event->motion); - } - break; - case SDL_EVENT_MOUSE_BUTTON_DOWN: - if (screen->mouse) { - sc_screen_otg_process_mouse_button(screen, &event->button); - } - break; - case SDL_EVENT_MOUSE_BUTTON_UP: - if (screen->mouse) { - sc_screen_otg_process_mouse_button(screen, &event->button); - } - break; - case SDL_EVENT_MOUSE_WHEEL: - if (screen->mouse) { - sc_screen_otg_process_mouse_wheel(screen, &event->wheel); - } - break; - case SDL_EVENT_GAMEPAD_ADDED: - case SDL_EVENT_GAMEPAD_REMOVED: - // Handle device added or removed even if paused - if (screen->gamepad) { - sc_screen_otg_process_gamepad_device(screen, &event->gdevice); - } - break; - case SDL_EVENT_GAMEPAD_AXIS_MOTION: - if (screen->gamepad) { - sc_screen_otg_process_gamepad_axis(screen, &event->gaxis); - } - break; - case SDL_EVENT_GAMEPAD_BUTTON_DOWN: - case SDL_EVENT_GAMEPAD_BUTTON_UP: - if (screen->gamepad) { - sc_screen_otg_process_gamepad_button(screen, &event->gbutton); - } - break; - } -} diff --git a/app/src/usb/screen_otg.h b/app/src/usb/screen_otg.h deleted file mode 100644 index 32d9da96..00000000 --- a/app/src/usb/screen_otg.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef SC_SCREEN_OTG_H -#define SC_SCREEN_OTG_H - -#include "common.h" - -#include -#include -#include - -#include "mouse_capture.h" -#include "usb/gamepad_aoa.h" -#include "usb/keyboard_aoa.h" -#include "usb/mouse_aoa.h" - -struct sc_screen_otg { - struct sc_keyboard_aoa *keyboard; - struct sc_mouse_aoa *mouse; - struct sc_gamepad_aoa *gamepad; - - SDL_Window *window; - SDL_Renderer *renderer; - SDL_Texture *texture; - - struct sc_mouse_capture mc; -}; - -struct sc_screen_otg_params { - struct sc_keyboard_aoa *keyboard; - struct sc_mouse_aoa *mouse; - struct sc_gamepad_aoa *gamepad; - - const char *window_title; - bool always_on_top; - int16_t window_x; // accepts SC_WINDOW_POSITION_UNDEFINED - int16_t window_y; // accepts SC_WINDOW_POSITION_UNDEFINED - uint16_t window_width; - uint16_t window_height; - bool window_borderless; - uint8_t shortcut_mods; // OR of enum sc_shortcut_mod values -}; - -bool -sc_screen_otg_init(struct sc_screen_otg *screen, - const struct sc_screen_otg_params *params); - -void -sc_screen_otg_destroy(struct sc_screen_otg *screen); - -void -sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event); - -#endif