mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-02-18 12:24:37 +01:00
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] commit91418c79ab[2] commit8c650e53cdRefs #2974 <https://github.com/Genymobile/scrcpy/pull/2974> Refs #3978 <https://github.com/Genymobile/scrcpy/pull/3978> PR #6649 <https://github.com/Genymobile/scrcpy/pull/6649>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,327 +0,0 @@
|
||||
#include "screen_otg.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
#ifndef SC_SCREEN_OTG_H
|
||||
#define SC_SCREEN_OTG_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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
|
||||
Reference in New Issue
Block a user