Compare commits

..

4 Commits

Author SHA1 Message Date
Romain Vimont
532843d856 Always prefer text events by default
This improves text input, but it breaks the expected behavior in games
again: <https://github.com/Genymobile/scrcpy/issues/87>.

To get the previous behavior back, pass an explicit option:

    scrcpy --prefer-text-events=non-alpha
2019-11-06 23:25:15 +01:00
Romain Vimont
44791d6b40 Add --prefer-text-events option
Expose an option to configure how key/text events are forwarded to the
Android device.

Fixes <https://github.com/Genymobile/scrcpy/issues/650>
2019-11-06 23:20:51 +01:00
Romain Vimont
2d90e1befd Fix include recorder.h 2019-11-06 22:22:46 +01:00
Romain Vimont
0e301ddf19 Factorize scrcpy options and command-line args
Do not duplicate all scrcpy options fields in the structure storing the
parsed command-line arguments.
2019-11-06 22:06:54 +01:00
13 changed files with 181 additions and 185 deletions

View File

@@ -109,15 +109,15 @@ conf.set('DEFAULT_MAX_SIZE', '0') # 0: unlimited
# overridden by option --bit-rate # overridden by option --bit-rate
conf.set('DEFAULT_BIT_RATE', '8000000') # 8Mbps conf.set('DEFAULT_BIT_RATE', '8000000') # 8Mbps
# enable High DPI support
conf.set('HIDPI_SUPPORT', get_option('hidpi_support'))
# disable console on Windows # disable console on Windows
conf.set('WINDOWS_NOCONSOLE', get_option('windows_noconsole')) conf.set('WINDOWS_NOCONSOLE', get_option('windows_noconsole'))
# run a server debugger and wait for a client to be attached # run a server debugger and wait for a client to be attached
conf.set('SERVER_DEBUGGER', get_option('server_debugger')) conf.set('SERVER_DEBUGGER', get_option('server_debugger'))
# enable a workaround for bug #15
conf.set('HIDPI_WORKAROUND', get_option('hidpi_workaround'))
configure_file(configuration: conf, output: 'config.h') configure_file(configuration: conf, output: 'config.h')
src_dir = include_directories('src') src_dir = include_directories('src')

View File

@@ -61,6 +61,16 @@ Set the TCP port the client listens on.
Default is 27183. Default is 27183.
.TP
.BI \-\-prefer\-text\-events " mode
Configure how key/text events are forwarded to the Android device.
Possible \fImode\fRs are "always" (every text is sent as text), "non-alpha"
(only letters are sent as a sequence of key events, other characters are sent
as text) and "never" (every text is sent as a sequence of key events).
Default is "always".
.TP .TP
.BI "\-\-push\-target " path .BI "\-\-push\-target " path
Set the target directory for pushing files to the device by drag & drop. It is passed as\-is to "adb push". Set the target directory for pushing files to the device by drag & drop. It is passed as\-is to "adb push".

View File

@@ -75,7 +75,8 @@ convert_meta_state(SDL_Keymod mod) {
} }
bool bool
convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod) { convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod,
enum text_events_pref pref) {
switch (from) { switch (from) {
MAP(SDLK_RETURN, AKEYCODE_ENTER); MAP(SDLK_RETURN, AKEYCODE_ENTER);
MAP(SDLK_KP_ENTER, AKEYCODE_NUMPAD_ENTER); MAP(SDLK_KP_ENTER, AKEYCODE_NUMPAD_ENTER);
@@ -92,6 +93,16 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod) {
MAP(SDLK_DOWN, AKEYCODE_DPAD_DOWN); MAP(SDLK_DOWN, AKEYCODE_DPAD_DOWN);
MAP(SDLK_UP, AKEYCODE_DPAD_UP); MAP(SDLK_UP, AKEYCODE_DPAD_UP);
} }
if (pref == PREFER_TEXT_EVENTS_ALWAYS) {
// never forward key events
return false;
}
// forward all supported key events
SDL_assert(pref == PREFER_TEXT_EVENTS_NEVER ||
pref == PREFER_TEXT_EVENTS_NON_ALPHA);
if (mod & (KMOD_LALT | KMOD_RALT | KMOD_LGUI | KMOD_RGUI)) { if (mod & (KMOD_LALT | KMOD_RALT | KMOD_LGUI | KMOD_RGUI)) {
return false; return false;
} }

View File

@@ -2,10 +2,12 @@
#define CONVERT_H #define CONVERT_H
#include <stdbool.h> #include <stdbool.h>
#include <SDL2/SDL_assert.h>
#include <SDL2/SDL_events.h> #include <SDL2/SDL_events.h>
#include "config.h" #include "config.h"
#include "control_msg.h" #include "control_msg.h"
#include "input_manager.h"
bool bool
convert_keycode_action(SDL_EventType from, enum android_keyevent_action *to); convert_keycode_action(SDL_EventType from, enum android_keyevent_action *to);
@@ -14,7 +16,8 @@ enum android_metastate
convert_meta_state(SDL_Keymod mod); convert_meta_state(SDL_Keymod mod);
bool bool
convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod); convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod,
enum text_events_pref pref);
enum android_motionevent_buttons enum android_motionevent_buttons
convert_mouse_buttons(uint32_t state); convert_mouse_buttons(uint32_t state);

View File

@@ -214,12 +214,20 @@ clipboard_paste(struct controller *controller) {
void void
input_manager_process_text_input(struct input_manager *im, input_manager_process_text_input(struct input_manager *im,
const SDL_TextInputEvent *event) { const SDL_TextInputEvent *event) {
if (im->text_events_pref == PREFER_TEXT_EVENTS_NEVER) {
// ignore all text events (key events will be injected instead)
return;
}
if (im->text_events_pref == PREFER_TEXT_EVENTS_NON_ALPHA) {
char c = event->text[0]; char c = event->text[0];
if (isalpha(c) || c == ' ') { if (isalpha(c) || c == ' ') {
SDL_assert(event->text[1] == '\0'); SDL_assert(event->text[1] == '\0');
// letters and space are handled as raw key event // letters and space are handled as raw key event
return; return;
} }
}
struct control_msg msg; struct control_msg msg;
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT; msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
msg.inject_text.text = SDL_strdup(event->text); msg.inject_text.text = SDL_strdup(event->text);
@@ -234,7 +242,8 @@ input_manager_process_text_input(struct input_manager *im,
} }
static bool static bool
convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to) { convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to,
enum text_events_pref pref) {
to->type = CONTROL_MSG_TYPE_INJECT_KEYCODE; to->type = CONTROL_MSG_TYPE_INJECT_KEYCODE;
if (!convert_keycode_action(from->type, &to->inject_keycode.action)) { if (!convert_keycode_action(from->type, &to->inject_keycode.action)) {
@@ -242,7 +251,8 @@ convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to) {
} }
uint16_t mod = from->keysym.mod; uint16_t mod = from->keysym.mod;
if (!convert_keycode(from->keysym.sym, &to->inject_keycode.keycode, mod)) { if (!convert_keycode(from->keysym.sym, &to->inject_keycode.keycode, mod,
pref)) {
return false; return false;
} }
@@ -393,7 +403,7 @@ input_manager_process_key(struct input_manager *im,
} }
struct control_msg msg; struct control_msg msg;
if (convert_input_key(event, &msg)) { if (convert_input_key(event, &msg, im->text_events_pref)) {
if (!controller_push_msg(controller, &msg)) { if (!controller_push_msg(controller, &msg)) {
LOGW("Could not request 'inject keycode'"); LOGW("Could not request 'inject keycode'");
} }

View File

@@ -10,10 +10,17 @@
#include "video_buffer.h" #include "video_buffer.h"
#include "screen.h" #include "screen.h"
enum text_events_pref {
PREFER_TEXT_EVENTS_ALWAYS,
PREFER_TEXT_EVENTS_NON_ALPHA,
PREFER_TEXT_EVENTS_NEVER,
};
struct input_manager { struct input_manager {
struct controller *controller; struct controller *controller;
struct video_buffer *video_buffer; struct video_buffer *video_buffer;
struct screen *screen; struct screen *screen;
enum text_events_pref text_events_pref;
}; };
void void

View File

@@ -11,27 +11,13 @@
#include "config.h" #include "config.h"
#include "compat.h" #include "compat.h"
#include "log.h" #include "log.h"
#include "input_manager.h"
#include "recorder.h" #include "recorder.h"
struct args { struct args {
const char *serial; struct scrcpy_options opts;
const char *crop;
const char *record_filename;
const char *window_title;
const char *push_target;
enum recorder_format record_format;
bool fullscreen;
bool no_control;
bool no_display;
bool help; bool help;
bool version; bool version;
bool show_touches;
uint16_t port;
uint16_t max_size;
uint32_t bit_rate;
bool always_on_top;
bool turn_screen_off;
bool render_expired_frames;
}; };
static void usage(const char *arg0) { static void usage(const char *arg0) {
@@ -82,6 +68,18 @@ static void usage(const char *arg0) {
" Set the TCP port the client listens on.\n" " Set the TCP port the client listens on.\n"
" Default is %d.\n" " Default is %d.\n"
"\n" "\n"
" --prefer-text-events mode\n"
" Configure how key/text events are forwarded to the Android\n"
" device.\n"
" Possible values are:\n"
" always:\n"
" Every text is sent as text. (default)\n"
" non-alpha:\n"
" Only letters are sent as a sequence of key events, other\n"
" characters are sent as text.\n"
" never:\n"
" Every text is sent as a sequence of key events.\n"
"\n"
" --push-target path\n" " --push-target path\n"
" Set the target directory for pushing files to the device by\n" " Set the target directory for pushing files to the device by\n"
" drag & drop. It is passed as-is to \"adb push\".\n" " drag & drop. It is passed as-is to \"adb push\".\n"
@@ -309,9 +307,33 @@ guess_record_format(const char *filename) {
return 0; return 0;
} }
static bool
parse_prefer_text_events(const char *optarg,
enum text_events_pref *pref) {
if (!strcmp(optarg, "always")) {
*pref = PREFER_TEXT_EVENTS_ALWAYS;
return true;
}
if (!strcmp(optarg, "non-alpha")) {
*pref = PREFER_TEXT_EVENTS_NON_ALPHA;
return true;
}
if (!strcmp(optarg, "never")) {
*pref = PREFER_TEXT_EVENTS_NEVER;
return true;
}
LOGE("Unsupported text events preference: %s"
"(expected 'always', 'non-alpha' or 'never')", optarg);
return false;
}
#define OPT_RENDER_EXPIRED_FRAMES 1000 #define OPT_RENDER_EXPIRED_FRAMES 1000
#define OPT_WINDOW_TITLE 1001 #define OPT_WINDOW_TITLE 1001
#define OPT_PUSH_TARGET 1002 #define OPT_PUSH_TARGET 1002
#define OPT_PREFER_TEXT_EVENTS 1003
static bool static bool
parse_args(struct args *args, int argc, char *argv[]) { parse_args(struct args *args, int argc, char *argv[]) {
@@ -334,28 +356,33 @@ parse_args(struct args *args, int argc, char *argv[]) {
{"serial", required_argument, NULL, 's'}, {"serial", required_argument, NULL, 's'},
{"show-touches", no_argument, NULL, 't'}, {"show-touches", no_argument, NULL, 't'},
{"turn-screen-off", no_argument, NULL, 'S'}, {"turn-screen-off", no_argument, NULL, 'S'},
{"prefer-text-events", required_argument, NULL,
OPT_PREFER_TEXT_EVENTS},
{"version", no_argument, NULL, 'v'}, {"version", no_argument, NULL, 'v'},
{"window-title", required_argument, NULL, {"window-title", required_argument, NULL,
OPT_WINDOW_TITLE}, OPT_WINDOW_TITLE},
{NULL, 0, NULL, 0 }, {NULL, 0, NULL, 0 },
}; };
struct scrcpy_options *opts = &args->opts;
int c; int c;
while ((c = getopt_long(argc, argv, "b:c:fF:hm:nNp:r:s:StTv", long_options, while ((c = getopt_long(argc, argv, "b:c:fF:hm:nNp:r:s:StTv", long_options,
NULL)) != -1) { NULL)) != -1) {
switch (c) { switch (c) {
case 'b': case 'b':
if (!parse_bit_rate(optarg, &args->bit_rate)) { if (!parse_bit_rate(optarg, &opts->bit_rate)) {
return false; return false;
} }
break; break;
case 'c': case 'c':
args->crop = optarg; opts->crop = optarg;
break; break;
case 'f': case 'f':
args->fullscreen = true; opts->fullscreen = true;
break; break;
case 'F': case 'F':
if (!parse_record_format(optarg, &args->record_format)) { if (!parse_record_format(optarg, &opts->record_format)) {
return false; return false;
} }
break; break;
@@ -363,47 +390,53 @@ parse_args(struct args *args, int argc, char *argv[]) {
args->help = true; args->help = true;
break; break;
case 'm': case 'm':
if (!parse_max_size(optarg, &args->max_size)) { if (!parse_max_size(optarg, &opts->max_size)) {
return false; return false;
} }
break; break;
case 'n': case 'n':
args->no_control = true; opts->control = false;
break; break;
case 'N': case 'N':
args->no_display = true; opts->display = false;
break; break;
case 'p': case 'p':
if (!parse_port(optarg, &args->port)) { if (!parse_port(optarg, &opts->port)) {
return false; return false;
} }
break; break;
case 'r': case 'r':
args->record_filename = optarg; opts->record_filename = optarg;
break; break;
case 's': case 's':
args->serial = optarg; opts->serial = optarg;
break; break;
case 'S': case 'S':
args->turn_screen_off = true; opts->turn_screen_off = true;
break; break;
case 't': case 't':
args->show_touches = true; opts->show_touches = true;
break; break;
case 'T': case 'T':
args->always_on_top = true; opts->always_on_top = true;
break; break;
case 'v': case 'v':
args->version = true; args->version = true;
break; break;
case OPT_RENDER_EXPIRED_FRAMES: case OPT_RENDER_EXPIRED_FRAMES:
args->render_expired_frames = true; opts->render_expired_frames = true;
break; break;
case OPT_WINDOW_TITLE: case OPT_WINDOW_TITLE:
args->window_title = optarg; opts->window_title = optarg;
break; break;
case OPT_PUSH_TARGET: case OPT_PUSH_TARGET:
args->push_target = optarg; opts->push_target = optarg;
break;
case OPT_PREFER_TEXT_EVENTS:
if (!parse_prefer_text_events(optarg,
&opts->text_events_pref)) {
return false;
}
break; break;
default: default:
// getopt prints the error message on stderr // getopt prints the error message on stderr
@@ -411,12 +444,12 @@ parse_args(struct args *args, int argc, char *argv[]) {
} }
} }
if (args->no_display && !args->record_filename) { if (!opts->display && !opts->record_filename) {
LOGE("-N/--no-display requires screen recording (-r/--record)"); LOGE("-N/--no-display requires screen recording (-r/--record)");
return false; return false;
} }
if (args->no_display && args->fullscreen) { if (!opts->display && opts->fullscreen) {
LOGE("-f/--fullscreen-window is incompatible with -N/--no-display"); LOGE("-f/--fullscreen-window is incompatible with -N/--no-display");
return false; return false;
} }
@@ -427,21 +460,21 @@ parse_args(struct args *args, int argc, char *argv[]) {
return false; return false;
} }
if (args->record_format && !args->record_filename) { if (opts->record_format && !opts->record_filename) {
LOGE("Record format specified without recording"); LOGE("Record format specified without recording");
return false; return false;
} }
if (args->record_filename && !args->record_format) { if (opts->record_filename && !opts->record_format) {
args->record_format = guess_record_format(args->record_filename); opts->record_format = guess_record_format(opts->record_filename);
if (!args->record_format) { if (!opts->record_format) {
LOGE("No format specified for \"%s\" (try with -F mkv)", LOGE("No format specified for \"%s\" (try with -F mkv)",
args->record_filename); opts->record_filename);
return false; return false;
} }
} }
if (args->no_control && args->turn_screen_off) { if (!opts->control && opts->turn_screen_off) {
LOGE("Could not request to turn screen off if control is disabled"); LOGE("Could not request to turn screen off if control is disabled");
return false; return false;
} }
@@ -458,24 +491,11 @@ main(int argc, char *argv[]) {
setbuf(stderr, NULL); setbuf(stderr, NULL);
#endif #endif
struct args args = { struct args args = {
.serial = NULL, .opts = SCRCPY_OPTIONS_DEFAULT,
.crop = NULL,
.record_filename = NULL,
.window_title = NULL,
.push_target = NULL,
.record_format = 0,
.help = false, .help = false,
.version = false, .version = false,
.show_touches = false,
.port = DEFAULT_LOCAL_PORT,
.max_size = DEFAULT_MAX_SIZE,
.bit_rate = DEFAULT_BIT_RATE,
.always_on_top = false,
.no_control = false,
.no_display = false,
.turn_screen_off = false,
.render_expired_frames = false,
}; };
if (!parse_args(&args, argc, argv)) { if (!parse_args(&args, argc, argv)) {
return 1; return 1;
} }
@@ -504,25 +524,7 @@ main(int argc, char *argv[]) {
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_DEBUG); SDL_LogSetAllPriority(SDL_LOG_PRIORITY_DEBUG);
#endif #endif
struct scrcpy_options options = { int res = scrcpy(&args.opts) ? 0 : 1;
.serial = args.serial,
.crop = args.crop,
.port = args.port,
.record_filename = args.record_filename,
.window_title = args.window_title,
.push_target = args.push_target,
.record_format = args.record_format,
.max_size = args.max_size,
.bit_rate = args.bit_rate,
.show_touches = args.show_touches,
.fullscreen = args.fullscreen,
.always_on_top = args.always_on_top,
.control = !args.no_control,
.display = !args.no_display,
.turn_screen_off = args.turn_screen_off,
.render_expired_frames = args.render_expired_frames,
};
int res = scrcpy(&options) ? 0 : 1;
avformat_network_deinit(); // ignore failure avformat_network_deinit(); // ignore failure

View File

@@ -11,7 +11,8 @@
#include "queue.h" #include "queue.h"
enum recorder_format { enum recorder_format {
RECORDER_FORMAT_MP4 = 1, RECORDER_FORMAT_AUTO,
RECORDER_FORMAT_MP4,
RECORDER_FORMAT_MKV, RECORDER_FORMAT_MKV,
}; };

View File

@@ -42,6 +42,7 @@ static struct input_manager input_manager = {
.controller = &controller, .controller = &controller,
.video_buffer = &video_buffer, .video_buffer = &video_buffer,
.screen = &screen, .screen = &screen,
.text_events_pref = 0, // initialized later
}; };
// init SDL and set appropriate hints // init SDL and set appropriate hints
@@ -145,10 +146,8 @@ handle_event(SDL_Event *event, bool control) {
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
switch (event->window.event) { switch (event->window.event) {
case SDL_WINDOWEVENT_EXPOSED: case SDL_WINDOWEVENT_EXPOSED:
screen_render(&screen);
break;
case SDL_WINDOWEVENT_SIZE_CHANGED: case SDL_WINDOWEVENT_SIZE_CHANGED:
screen_window_resized(&screen); screen_render(&screen);
break; break;
} }
break; break;
@@ -416,6 +415,8 @@ scrcpy(const struct scrcpy_options *options) {
show_touches_waited = true; show_touches_waited = true;
} }
input_manager.text_events_pref = options->text_events_pref;
ret = event_loop(options->display, options->control); ret = event_loop(options->display, options->control);
LOGD("quit..."); LOGD("quit...");

View File

@@ -3,9 +3,10 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <recorder.h>
#include "config.h" #include "config.h"
#include "input_manager.h"
#include "recorder.h"
struct scrcpy_options { struct scrcpy_options {
const char *serial; const char *serial;
@@ -14,6 +15,7 @@ struct scrcpy_options {
const char *window_title; const char *window_title;
const char *push_target; const char *push_target;
enum recorder_format record_format; enum recorder_format record_format;
enum text_events_pref text_events_pref;
uint16_t port; uint16_t port;
uint16_t max_size; uint16_t max_size;
uint32_t bit_rate; uint32_t bit_rate;
@@ -26,6 +28,26 @@ struct scrcpy_options {
bool render_expired_frames; bool render_expired_frames;
}; };
#define SCRCPY_OPTIONS_DEFAULT { \
.serial = NULL, \
.crop = NULL, \
.record_filename = NULL, \
.window_title = NULL, \
.push_target = NULL, \
.record_format = RECORDER_FORMAT_AUTO, \
.text_events_pref = PREFER_TEXT_EVENTS_ALWAYS, \
.port = DEFAULT_LOCAL_PORT, \
.max_size = DEFAULT_LOCAL_PORT, \
.bit_rate = DEFAULT_BIT_RATE, \
.show_touches = false, \
.fullscreen = false, \
.always_on_top = false, \
.control = true, \
.display = true, \
.turn_screen_off = false, \
.render_expired_frames = false, \
}
bool bool
scrcpy(const struct scrcpy_options *options); scrcpy(const struct scrcpy_options *options);

View File

@@ -134,57 +134,16 @@ create_texture(SDL_Renderer *renderer, struct size frame_size) {
frame_size.width, frame_size.height); frame_size.width, frame_size.height);
} }
#ifdef HIDPI_WORKAROUND
static void
screen_get_sizes(struct screen *screen, struct screen_sizes *out) {
int ww, wh, dw, dh;
SDL_GetWindowSize(screen->window, &ww, &wh);
SDL_GL_GetDrawableSize(screen->window, &dw, &dh);
out->window.width = ww;
out->window.height = wh;
out->window.width = dw;
out->window.height = dh;
}
#endif
// This may be called more than once to work around SDL bugs
static bool
screen_init_renderer_and_texture(struct screen *screen) {
screen->renderer = SDL_CreateRenderer(screen->window, -1,
SDL_RENDERER_ACCELERATED);
if (!screen->renderer) {
LOGC("Could not create renderer: %s", SDL_GetError());
return false;
}
if (SDL_RenderSetLogicalSize(screen->renderer, screen->frame_size.width,
screen->frame_size.height)) {
LOGE("Could not set renderer logical size: %s", SDL_GetError());
return false;
}
screen->texture = create_texture(screen->renderer, screen->frame_size);
if (!screen->texture) {
LOGC("Could not create texture: %s", SDL_GetError());
return false;
}
#ifdef HIDPI_WORKAROUND
screen_get_sizes(screen, &screen->sizes);
#endif
return true;
}
bool bool
screen_init_rendering(struct screen *screen, const char *window_title, screen_init_rendering(struct screen *screen, const char *window_title,
struct size frame_size, bool always_on_top) { struct size frame_size, bool always_on_top) {
screen->frame_size = frame_size; screen->frame_size = frame_size;
struct size window_size = get_initial_optimal_size(frame_size); struct size window_size = get_initial_optimal_size(frame_size);
uint32_t window_flags = SDL_WINDOW_HIDDEN uint32_t window_flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE;
| SDL_WINDOW_RESIZABLE #ifdef HIDPI_SUPPORT
| SDL_WINDOW_ALLOW_HIGHDPI; window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
#endif
if (always_on_top) { if (always_on_top) {
#ifdef SCRCPY_SDL_HAS_WINDOW_ALWAYS_ON_TOP #ifdef SCRCPY_SDL_HAS_WINDOW_ALWAYS_ON_TOP
window_flags |= SDL_WINDOW_ALWAYS_ON_TOP; window_flags |= SDL_WINDOW_ALWAYS_ON_TOP;
@@ -203,6 +162,21 @@ screen_init_rendering(struct screen *screen, const char *window_title,
return false; return false;
} }
screen->renderer = SDL_CreateRenderer(screen->window, -1,
SDL_RENDERER_ACCELERATED);
if (!screen->renderer) {
LOGC("Could not create renderer: %s", SDL_GetError());
screen_destroy(screen);
return false;
}
if (SDL_RenderSetLogicalSize(screen->renderer, frame_size.width,
frame_size.height)) {
LOGE("Could not set renderer logical size: %s", SDL_GetError());
screen_destroy(screen);
return false;
}
SDL_Surface *icon = read_xpm(icon_xpm); SDL_Surface *icon = read_xpm(icon_xpm);
if (icon) { if (icon) {
SDL_SetWindowIcon(screen->window, icon); SDL_SetWindowIcon(screen->window, icon);
@@ -213,7 +187,9 @@ screen_init_rendering(struct screen *screen, const char *window_title,
LOGI("Initial texture: %" PRIu16 "x%" PRIu16, frame_size.width, LOGI("Initial texture: %" PRIu16 "x%" PRIu16, frame_size.width,
frame_size.height); frame_size.height);
if (!screen_init_renderer_and_texture(screen)) { screen->texture = create_texture(screen->renderer, frame_size);
if (!screen->texture) {
LOGC("Could not create texture: %s", SDL_GetError());
screen_destroy(screen); screen_destroy(screen);
return false; return false;
} }
@@ -302,43 +278,6 @@ screen_update_frame(struct screen *screen, struct video_buffer *vb) {
return true; return true;
} }
#ifdef HIDPI_WORKAROUND
// workaround for <https://github.com/Genymobile/scrcpy/issues/15>
static inline bool
screen_fix_hidpi(struct screen *screen) {
struct screen_sizes cur;
screen_get_sizes(screen, &cur);
struct screen_sizes *prev = &screen->sizes;
bool width_ratio_changed = cur.window.width * prev->drawable.width !=
cur.drawable.width * prev->window.width;
bool height_ratio_changed = cur.window.height * prev->drawable.height !=
cur.drawable.height * prev->window.height;
if (width_ratio_changed || height_ratio_changed) {
SDL_DestroyTexture(screen->texture);
SDL_DestroyRenderer(screen->renderer);
if (!screen_init_renderer_and_texture(screen)) {
screen->texture = NULL;
screen->renderer = NULL;
return false;
}
LOGI("Renderer reset after hidpi scaling changed");
}
return true;
}
#endif
void
screen_window_resized(struct screen *screen) {
#ifdef HIDPI_WORKAROUND
screen_fix_hidpi(screen);
#endif
screen_render(screen);
}
void void
screen_render(struct screen *screen) { screen_render(struct screen *screen) {
SDL_RenderClear(screen->renderer); SDL_RenderClear(screen->renderer);

View File

@@ -20,12 +20,6 @@ struct screen {
bool has_frame; bool has_frame;
bool fullscreen; bool fullscreen;
bool no_window; bool no_window;
#ifdef HIDPI_WORKAROUND
struct screen_sizes {
struct size window;
struct size drawable;
} sizes;
#endif
}; };
#define SCREEN_INITIALIZER { \ #define SCREEN_INITIALIZER { \
@@ -66,10 +60,6 @@ screen_destroy(struct screen *screen);
bool bool
screen_update_frame(struct screen *screen, struct video_buffer *vb); screen_update_frame(struct screen *screen, struct video_buffer *vb);
// update content after window resizing
void
screen_window_resized(struct screen *screen);
// render the texture to the renderer // render the texture to the renderer
void void
screen_render(struct screen *screen); screen_render(struct screen *screen);

View File

@@ -4,5 +4,5 @@ option('crossbuild_windows', type: 'boolean', value: false, description: 'Build
option('windows_noconsole', type: 'boolean', value: false, description: 'Disable console on Windows (pass -mwindows flag)') option('windows_noconsole', type: 'boolean', value: false, description: 'Disable console on Windows (pass -mwindows flag)')
option('prebuilt_server', type: 'string', description: 'Path of the prebuilt server') option('prebuilt_server', type: 'string', description: 'Path of the prebuilt server')
option('portable', type: 'boolean', value: false, description: 'Use scrcpy-server from the same directory as the scrcpy executable') option('portable', type: 'boolean', value: false, description: 'Use scrcpy-server from the same directory as the scrcpy executable')
option('hidpi_support', type: 'boolean', value: true, description: 'Enable High DPI support')
option('server_debugger', type: 'boolean', value: false, description: 'Run a server debugger and wait for a client to be attached') option('server_debugger', type: 'boolean', value: false, description: 'Run a server debugger and wait for a client to be attached')
option('hidpi_workaround', type: 'boolean', value: true, description: 'Enable a workaround for bug #15')