Compare commits
12 Commits
nocleanup
...
libusb-mac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ee3f8dc02 | ||
|
|
9db42341e4 | ||
|
|
82a99f69ec | ||
|
|
33202491e1 | ||
|
|
b4fd882ece | ||
|
|
c4ab65eb79 | ||
|
|
6edf50d447 | ||
|
|
4b018be789 | ||
|
|
fa93c8a91b | ||
|
|
03705b828b | ||
|
|
85edba20e7 | ||
|
|
2a872c3865 |
2
BUILD.md
2
BUILD.md
@@ -199,7 +199,7 @@ Install the packages with [Homebrew]:
|
||||
|
||||
```bash
|
||||
# runtime dependencies
|
||||
brew install sdl2 ffmpeg
|
||||
brew install sdl2 ffmpeg libusb
|
||||
|
||||
# client build dependencies
|
||||
brew install pkg-config meson
|
||||
|
||||
@@ -215,6 +215,15 @@ scrcpy --max-fps 15
|
||||
|
||||
This is officially supported since Android 10, but may work on earlier versions.
|
||||
|
||||
The actual capture framerate may be printed to the console:
|
||||
|
||||
```
|
||||
scrcpy --print-fps
|
||||
```
|
||||
|
||||
It may also be enabled or disabled at any time with <kbd>MOD</kbd>+<kbd>i</kbd>.
|
||||
|
||||
|
||||
#### Crop
|
||||
|
||||
The device screen may be cropped to mirror only part of the screen.
|
||||
|
||||
@@ -74,7 +74,7 @@ if v4l2_support
|
||||
src += [ 'src/v4l2_sink.c' ]
|
||||
endif
|
||||
|
||||
usb_support = get_option('usb') and host_machine.system() == 'linux'
|
||||
usb_support = get_option('usb') and host_machine.system() != 'windows'
|
||||
if usb_support
|
||||
src += [
|
||||
'src/usb/aoa_hid.c',
|
||||
|
||||
10
app/scrcpy.1
10
app/scrcpy.1
@@ -100,7 +100,7 @@ Simulate a physical keyboard by using HID over AOAv2.
|
||||
|
||||
This provides a better experience for IME users, and allows to generate non-ASCII characters, contrary to the default injection method.
|
||||
|
||||
It may only work over USB, and is currently only supported on Linux.
|
||||
It may only work over USB.
|
||||
|
||||
The keyboard layout must be configured (once and for all) on the device, via Settings -> System -> Languages and input -> Physical keyboard. This settings page can be started directly:
|
||||
|
||||
@@ -142,7 +142,7 @@ In this mode, the computer mouse is captured to control the device directly (rel
|
||||
|
||||
LAlt, LSuper or RSuper toggle the capture mode, to give control of the mouse back to the computer.
|
||||
|
||||
It may only work over USB, and is currently only supported on Linux.
|
||||
It may only work over USB.
|
||||
|
||||
Also see \fB\-\-hid\-keyboard\fR.
|
||||
|
||||
@@ -190,7 +190,7 @@ LAlt, LSuper or RSuper toggle the mouse capture mode, to give control of the mou
|
||||
|
||||
If any of \fB\-\-hid\-keyboard\fR or \fB\-\-hid\-mouse\fR is set, only enable keyboard or mouse respectively, otherwise enable both.
|
||||
|
||||
It may only work over USB, and is currently only supported on Linux.
|
||||
It may only work over USB.
|
||||
|
||||
See \fB\-\-hid\-keyboard\fR and \fB\-\-hid\-mouse\fR.
|
||||
|
||||
@@ -211,6 +211,10 @@ Inject alpha characters and space as text events instead of key events.
|
||||
This avoids issues when combining multiple keys to enter special characters,
|
||||
but breaks the expected behavior of alpha keys in games (typically WASD).
|
||||
|
||||
.TP
|
||||
.B "\-\-print\-fps
|
||||
Start FPS counter, to print framerate logs to the console. It can be started or stopped at any time with MOD+i.
|
||||
|
||||
.TP
|
||||
.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".
|
||||
|
||||
@@ -412,7 +412,7 @@ sc_adb_list_devices(struct sc_intr *intr, unsigned flags,
|
||||
// The implementation assumes that the output of "adb devices -l" fits
|
||||
// in the buffer in a single pass
|
||||
LOGW("Result of \"adb devices -l\" does not fit in 4Kb. "
|
||||
"Please report an issue.\n");
|
||||
"Please report an issue.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -676,7 +676,7 @@ sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags) {
|
||||
// The implementation assumes that the output of "ip route" fits in the
|
||||
// buffer in a single pass
|
||||
LOGW("Result of \"ip route\" does not fit in 1Kb. "
|
||||
"Please report an issue.\n");
|
||||
"Please report an issue.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#define OPT_NO_DOWNSIZE_ON_ERROR 1035
|
||||
#define OPT_OTG 1036
|
||||
#define OPT_NO_CLEANUP 1037
|
||||
#define OPT_PRINT_FPS 1038
|
||||
|
||||
struct sc_option {
|
||||
char shortopt;
|
||||
@@ -117,7 +118,7 @@ static const struct sc_option options[] = {
|
||||
.text = "Crop the device screen on the server.\n"
|
||||
"The values are expressed in the device natural orientation "
|
||||
"(typically, portrait for a phone, landscape for a tablet). "
|
||||
"Any --max-size value is cmoputed on the cropped size.",
|
||||
"Any --max-size value is computed on the cropped size.",
|
||||
},
|
||||
{
|
||||
.shortopt = 'd',
|
||||
@@ -185,8 +186,7 @@ static const struct sc_option options[] = {
|
||||
"It provides a better experience for IME users, and allows to "
|
||||
"generate non-ASCII characters, contrary to the default "
|
||||
"injection method.\n"
|
||||
"It may only work over USB, and is currently only supported "
|
||||
"on Linux.\n"
|
||||
"It may only work over USB.\n"
|
||||
"The keyboard layout must be configured (once and for all) on "
|
||||
"the device, via Settings -> System -> Languages and input -> "
|
||||
"Physical keyboard. This settings page can be started "
|
||||
@@ -238,8 +238,7 @@ static const struct sc_option options[] = {
|
||||
"device directly (relative mouse mode).\n"
|
||||
"LAlt, LSuper or RSuper toggle the capture mode, to give "
|
||||
"control of the mouse back to the computer.\n"
|
||||
"It may only work over USB, and is currently only supported "
|
||||
"on Linux.\n"
|
||||
"It may only work over USB.\n"
|
||||
"Also see --hid-keyboard.",
|
||||
},
|
||||
{
|
||||
@@ -310,8 +309,7 @@ static const struct sc_option options[] = {
|
||||
"control of the mouse back to the computer.\n"
|
||||
"If any of --hid-keyboard or --hid-mouse is set, only enable "
|
||||
"keyboard or mouse respectively, otherwise enable both.\n"
|
||||
"It may only work over USB, and is currently only supported "
|
||||
"on Linux.\n"
|
||||
"It may only work over USB.\n"
|
||||
"See --hid-keyboard and --hid-mouse.",
|
||||
},
|
||||
{
|
||||
@@ -336,6 +334,12 @@ static const struct sc_option options[] = {
|
||||
"special character, but breaks the expected behavior of alpha "
|
||||
"keys in games (typically WASD).",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_PRINT_FPS,
|
||||
.longopt = "print-fps",
|
||||
.text = "Start FPS counter, to print framerate logs to the console. "
|
||||
"It can be started or stopped at any time with MOD+i.",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_PUSH_TARGET,
|
||||
.longopt = "push-target",
|
||||
@@ -1547,6 +1551,9 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
case OPT_NO_CLEANUP:
|
||||
opts->cleanup = false;
|
||||
break;
|
||||
case OPT_PRINT_FPS:
|
||||
opts->start_fps_counter = true;
|
||||
break;
|
||||
case OPT_OTG:
|
||||
#ifdef HAVE_USB
|
||||
opts->otg = true;
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#define FPS_COUNTER_INTERVAL SC_TICK_FROM_SEC(1)
|
||||
#define SC_FPS_COUNTER_INTERVAL SC_TICK_FROM_SEC(1)
|
||||
|
||||
bool
|
||||
fps_counter_init(struct fps_counter *counter) {
|
||||
sc_fps_counter_init(struct sc_fps_counter *counter) {
|
||||
bool ok = sc_mutex_init(&counter->mutex);
|
||||
if (!ok) {
|
||||
return false;
|
||||
@@ -27,26 +27,26 @@ fps_counter_init(struct fps_counter *counter) {
|
||||
}
|
||||
|
||||
void
|
||||
fps_counter_destroy(struct fps_counter *counter) {
|
||||
sc_fps_counter_destroy(struct sc_fps_counter *counter) {
|
||||
sc_cond_destroy(&counter->state_cond);
|
||||
sc_mutex_destroy(&counter->mutex);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_started(struct fps_counter *counter) {
|
||||
is_started(struct sc_fps_counter *counter) {
|
||||
return atomic_load_explicit(&counter->started, memory_order_acquire);
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_started(struct fps_counter *counter, bool started) {
|
||||
set_started(struct sc_fps_counter *counter, bool started) {
|
||||
atomic_store_explicit(&counter->started, started, memory_order_release);
|
||||
}
|
||||
|
||||
// must be called with mutex locked
|
||||
static void
|
||||
display_fps(struct fps_counter *counter) {
|
||||
display_fps(struct sc_fps_counter *counter) {
|
||||
unsigned rendered_per_second =
|
||||
counter->nr_rendered * SC_TICK_FREQ / FPS_COUNTER_INTERVAL;
|
||||
counter->nr_rendered * SC_TICK_FREQ / SC_FPS_COUNTER_INTERVAL;
|
||||
if (counter->nr_skipped) {
|
||||
LOGI("%u fps (+%u frames skipped)", rendered_per_second,
|
||||
counter->nr_skipped);
|
||||
@@ -57,7 +57,7 @@ display_fps(struct fps_counter *counter) {
|
||||
|
||||
// must be called with mutex locked
|
||||
static void
|
||||
check_interval_expired(struct fps_counter *counter, uint32_t now) {
|
||||
check_interval_expired(struct sc_fps_counter *counter, sc_tick now) {
|
||||
if (now < counter->next_timestamp) {
|
||||
return;
|
||||
}
|
||||
@@ -67,13 +67,13 @@ check_interval_expired(struct fps_counter *counter, uint32_t now) {
|
||||
counter->nr_skipped = 0;
|
||||
// add a multiple of the interval
|
||||
uint32_t elapsed_slices =
|
||||
(now - counter->next_timestamp) / FPS_COUNTER_INTERVAL + 1;
|
||||
counter->next_timestamp += FPS_COUNTER_INTERVAL * elapsed_slices;
|
||||
(now - counter->next_timestamp) / SC_FPS_COUNTER_INTERVAL + 1;
|
||||
counter->next_timestamp += SC_FPS_COUNTER_INTERVAL * elapsed_slices;
|
||||
}
|
||||
|
||||
static int
|
||||
run_fps_counter(void *data) {
|
||||
struct fps_counter *counter = data;
|
||||
struct sc_fps_counter *counter = data;
|
||||
|
||||
sc_mutex_lock(&counter->mutex);
|
||||
while (!counter->interrupted) {
|
||||
@@ -94,9 +94,9 @@ run_fps_counter(void *data) {
|
||||
}
|
||||
|
||||
bool
|
||||
fps_counter_start(struct fps_counter *counter) {
|
||||
sc_fps_counter_start(struct sc_fps_counter *counter) {
|
||||
sc_mutex_lock(&counter->mutex);
|
||||
counter->next_timestamp = sc_tick_now() + FPS_COUNTER_INTERVAL;
|
||||
counter->next_timestamp = sc_tick_now() + SC_FPS_COUNTER_INTERVAL;
|
||||
counter->nr_rendered = 0;
|
||||
counter->nr_skipped = 0;
|
||||
sc_mutex_unlock(&counter->mutex);
|
||||
@@ -117,22 +117,24 @@ fps_counter_start(struct fps_counter *counter) {
|
||||
counter->thread_started = true;
|
||||
}
|
||||
|
||||
LOGI("FPS counter started");
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
fps_counter_stop(struct fps_counter *counter) {
|
||||
sc_fps_counter_stop(struct sc_fps_counter *counter) {
|
||||
set_started(counter, false);
|
||||
sc_cond_signal(&counter->state_cond);
|
||||
LOGI("FPS counter stopped");
|
||||
}
|
||||
|
||||
bool
|
||||
fps_counter_is_started(struct fps_counter *counter) {
|
||||
sc_fps_counter_is_started(struct sc_fps_counter *counter) {
|
||||
return is_started(counter);
|
||||
}
|
||||
|
||||
void
|
||||
fps_counter_interrupt(struct fps_counter *counter) {
|
||||
sc_fps_counter_interrupt(struct sc_fps_counter *counter) {
|
||||
if (!counter->thread_started) {
|
||||
return;
|
||||
}
|
||||
@@ -145,7 +147,7 @@ fps_counter_interrupt(struct fps_counter *counter) {
|
||||
}
|
||||
|
||||
void
|
||||
fps_counter_join(struct fps_counter *counter) {
|
||||
sc_fps_counter_join(struct sc_fps_counter *counter) {
|
||||
if (counter->thread_started) {
|
||||
// interrupted must be set by the thread calling join(), so no need to
|
||||
// lock for the assertion
|
||||
@@ -156,7 +158,7 @@ fps_counter_join(struct fps_counter *counter) {
|
||||
}
|
||||
|
||||
void
|
||||
fps_counter_add_rendered_frame(struct fps_counter *counter) {
|
||||
sc_fps_counter_add_rendered_frame(struct sc_fps_counter *counter) {
|
||||
if (!is_started(counter)) {
|
||||
return;
|
||||
}
|
||||
@@ -169,7 +171,7 @@ fps_counter_add_rendered_frame(struct fps_counter *counter) {
|
||||
}
|
||||
|
||||
void
|
||||
fps_counter_add_skipped_frame(struct fps_counter *counter) {
|
||||
sc_fps_counter_add_skipped_frame(struct sc_fps_counter *counter) {
|
||||
if (!is_started(counter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "util/thread.h"
|
||||
|
||||
struct fps_counter {
|
||||
struct sc_fps_counter {
|
||||
sc_thread thread;
|
||||
sc_mutex mutex;
|
||||
sc_cond state_cond;
|
||||
@@ -28,32 +28,32 @@ struct fps_counter {
|
||||
};
|
||||
|
||||
bool
|
||||
fps_counter_init(struct fps_counter *counter);
|
||||
sc_fps_counter_init(struct sc_fps_counter *counter);
|
||||
|
||||
void
|
||||
fps_counter_destroy(struct fps_counter *counter);
|
||||
sc_fps_counter_destroy(struct sc_fps_counter *counter);
|
||||
|
||||
bool
|
||||
fps_counter_start(struct fps_counter *counter);
|
||||
sc_fps_counter_start(struct sc_fps_counter *counter);
|
||||
|
||||
void
|
||||
fps_counter_stop(struct fps_counter *counter);
|
||||
sc_fps_counter_stop(struct sc_fps_counter *counter);
|
||||
|
||||
bool
|
||||
fps_counter_is_started(struct fps_counter *counter);
|
||||
sc_fps_counter_is_started(struct sc_fps_counter *counter);
|
||||
|
||||
// request to stop the thread (on quit)
|
||||
// must be called before fps_counter_join()
|
||||
// must be called before sc_fps_counter_join()
|
||||
void
|
||||
fps_counter_interrupt(struct fps_counter *counter);
|
||||
sc_fps_counter_interrupt(struct sc_fps_counter *counter);
|
||||
|
||||
void
|
||||
fps_counter_join(struct fps_counter *counter);
|
||||
sc_fps_counter_join(struct sc_fps_counter *counter);
|
||||
|
||||
void
|
||||
fps_counter_add_rendered_frame(struct fps_counter *counter);
|
||||
sc_fps_counter_add_rendered_frame(struct sc_fps_counter *counter);
|
||||
|
||||
void
|
||||
fps_counter_add_skipped_frame(struct fps_counter *counter);
|
||||
sc_fps_counter_add_skipped_frame(struct sc_fps_counter *counter);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -242,18 +242,14 @@ set_screen_power_mode(struct sc_controller *controller,
|
||||
}
|
||||
|
||||
static void
|
||||
switch_fps_counter_state(struct fps_counter *fps_counter) {
|
||||
switch_fps_counter_state(struct sc_fps_counter *fps_counter) {
|
||||
// the started state can only be written from the current thread, so there
|
||||
// is no ToCToU issue
|
||||
if (fps_counter_is_started(fps_counter)) {
|
||||
fps_counter_stop(fps_counter);
|
||||
LOGI("FPS counter stopped");
|
||||
if (sc_fps_counter_is_started(fps_counter)) {
|
||||
sc_fps_counter_stop(fps_counter);
|
||||
} else {
|
||||
if (fps_counter_start(fps_counter)) {
|
||||
LOGI("FPS counter started");
|
||||
} else {
|
||||
LOGE("FPS counter starting failed");
|
||||
}
|
||||
sc_fps_counter_start(fps_counter);
|
||||
// Any error is already logged
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,4 +63,5 @@ const struct scrcpy_options scrcpy_options_default = {
|
||||
.select_tcpip = false,
|
||||
.select_usb = false,
|
||||
.cleanup = true,
|
||||
.start_fps_counter = false,
|
||||
};
|
||||
|
||||
@@ -138,6 +138,7 @@ struct scrcpy_options {
|
||||
bool select_usb;
|
||||
bool select_tcpip;
|
||||
bool cleanup;
|
||||
bool start_fps_counter;
|
||||
};
|
||||
|
||||
extern const struct scrcpy_options scrcpy_options_default;
|
||||
|
||||
@@ -588,6 +588,7 @@ aoa_hid_end:
|
||||
.rotation = options->rotation,
|
||||
.mipmaps = options->mipmaps,
|
||||
.fullscreen = options->fullscreen,
|
||||
.start_fps_counter = options->start_fps_counter,
|
||||
.buffering_time = options->display_buffer,
|
||||
};
|
||||
|
||||
|
||||
@@ -163,7 +163,27 @@ sc_screen_is_relative_mode(struct sc_screen *screen) {
|
||||
}
|
||||
|
||||
static void
|
||||
sc_screen_set_mouse_capture(bool capture) {
|
||||
sc_screen_set_mouse_capture(struct sc_screen *screen, bool capture) {
|
||||
#ifdef __APPLE__
|
||||
// Workaround for SDL bug on macOS:
|
||||
// <https://github.com/libsdl-org/SDL/issues/5340>
|
||||
if (capture) {
|
||||
int mouse_x, mouse_y;
|
||||
SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
|
||||
|
||||
int x, y, w, h;
|
||||
SDL_GetWindowPosition(screen->window, &x, &y);
|
||||
SDL_GetWindowSize(screen->window, &w, &h);
|
||||
|
||||
bool outside_window = mouse_x < x || mouse_x >= x + w
|
||||
|| mouse_y < y || mouse_y >= y + h;
|
||||
if (outside_window) {
|
||||
SDL_WarpMouseInWindow(screen->window, w / 2, h / 2);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void) screen;
|
||||
#endif
|
||||
if (SDL_SetRelativeMouseMode(capture)) {
|
||||
LOGE("Could not set relative mouse mode to %s: %s",
|
||||
capture ? "true" : "false", SDL_GetError());
|
||||
@@ -171,13 +191,16 @@ sc_screen_set_mouse_capture(bool capture) {
|
||||
}
|
||||
|
||||
static inline bool
|
||||
sc_screen_get_mouse_capture(void) {
|
||||
sc_screen_get_mouse_capture(struct sc_screen *screen) {
|
||||
(void) screen;
|
||||
return SDL_GetRelativeMouseMode();
|
||||
}
|
||||
|
||||
static inline void
|
||||
sc_screen_toggle_mouse_capture(void) {
|
||||
sc_screen_set_mouse_capture(!sc_screen_get_mouse_capture());
|
||||
sc_screen_toggle_mouse_capture(struct sc_screen *screen) {
|
||||
(void) screen;
|
||||
bool new_value = !sc_screen_get_mouse_capture(screen);
|
||||
sc_screen_set_mouse_capture(screen, new_value);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -347,7 +370,7 @@ sc_video_buffer_on_new_frame(struct sc_video_buffer *vb, bool previous_skipped,
|
||||
|
||||
bool need_new_event;
|
||||
if (previous_skipped) {
|
||||
fps_counter_add_skipped_frame(&screen->fps_counter);
|
||||
sc_fps_counter_add_skipped_frame(&screen->fps_counter);
|
||||
// The EVENT_NEW_FRAME triggered for the previous frame will consume
|
||||
// this new frame instead, unless the previous event failed
|
||||
need_new_event = screen->event_failed;
|
||||
@@ -386,6 +409,7 @@ sc_screen_init(struct sc_screen *screen,
|
||||
screen->req.width = params->window_width;
|
||||
screen->req.height = params->window_height;
|
||||
screen->req.fullscreen = params->fullscreen;
|
||||
screen->req.start_fps_counter = params->start_fps_counter;
|
||||
|
||||
static const struct sc_video_buffer_callbacks cbs = {
|
||||
.on_new_frame = sc_video_buffer_on_new_frame,
|
||||
@@ -402,7 +426,7 @@ sc_screen_init(struct sc_screen *screen,
|
||||
goto error_destroy_video_buffer;
|
||||
}
|
||||
|
||||
if (!fps_counter_init(&screen->fps_counter)) {
|
||||
if (!sc_fps_counter_init(&screen->fps_counter)) {
|
||||
goto error_stop_and_join_video_buffer;
|
||||
}
|
||||
|
||||
@@ -534,7 +558,7 @@ error_destroy_renderer:
|
||||
error_destroy_window:
|
||||
SDL_DestroyWindow(screen->window);
|
||||
error_destroy_fps_counter:
|
||||
fps_counter_destroy(&screen->fps_counter);
|
||||
sc_fps_counter_destroy(&screen->fps_counter);
|
||||
error_stop_and_join_video_buffer:
|
||||
sc_video_buffer_stop(&screen->vb);
|
||||
sc_video_buffer_join(&screen->vb);
|
||||
@@ -562,6 +586,10 @@ sc_screen_show_initial_window(struct sc_screen *screen) {
|
||||
sc_screen_switch_fullscreen(screen);
|
||||
}
|
||||
|
||||
if (screen->req.start_fps_counter) {
|
||||
sc_fps_counter_start(&screen->fps_counter);
|
||||
}
|
||||
|
||||
SDL_ShowWindow(screen->window);
|
||||
}
|
||||
|
||||
@@ -573,13 +601,13 @@ sc_screen_hide_window(struct sc_screen *screen) {
|
||||
void
|
||||
sc_screen_interrupt(struct sc_screen *screen) {
|
||||
sc_video_buffer_stop(&screen->vb);
|
||||
fps_counter_interrupt(&screen->fps_counter);
|
||||
sc_fps_counter_interrupt(&screen->fps_counter);
|
||||
}
|
||||
|
||||
void
|
||||
sc_screen_join(struct sc_screen *screen) {
|
||||
sc_video_buffer_join(&screen->vb);
|
||||
fps_counter_join(&screen->fps_counter);
|
||||
sc_fps_counter_join(&screen->fps_counter);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -591,7 +619,7 @@ sc_screen_destroy(struct sc_screen *screen) {
|
||||
SDL_DestroyTexture(screen->texture);
|
||||
SDL_DestroyRenderer(screen->renderer);
|
||||
SDL_DestroyWindow(screen->window);
|
||||
fps_counter_destroy(&screen->fps_counter);
|
||||
sc_fps_counter_destroy(&screen->fps_counter);
|
||||
sc_video_buffer_destroy(&screen->vb);
|
||||
}
|
||||
|
||||
@@ -701,7 +729,7 @@ sc_screen_update_frame(struct sc_screen *screen) {
|
||||
sc_video_buffer_consume(&screen->vb, screen->frame);
|
||||
AVFrame *frame = screen->frame;
|
||||
|
||||
fps_counter_add_rendered_frame(&screen->fps_counter);
|
||||
sc_fps_counter_add_rendered_frame(&screen->fps_counter);
|
||||
|
||||
struct sc_size new_frame_size = {frame->width, frame->height};
|
||||
if (!prepare_for_frame(screen, new_frame_size)) {
|
||||
@@ -716,7 +744,7 @@ sc_screen_update_frame(struct sc_screen *screen) {
|
||||
|
||||
if (sc_screen_is_relative_mode(screen)) {
|
||||
// Capture mouse on start
|
||||
sc_screen_set_mouse_capture(true);
|
||||
sc_screen_set_mouse_capture(screen, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -829,7 +857,7 @@ sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event) {
|
||||
break;
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
if (relative_mode) {
|
||||
sc_screen_set_mouse_capture(false);
|
||||
sc_screen_set_mouse_capture(screen, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -859,7 +887,7 @@ sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event) {
|
||||
if (key == cap) {
|
||||
// A mouse capture key has been pressed then released:
|
||||
// toggle the capture mouse mode
|
||||
sc_screen_toggle_mouse_capture();
|
||||
sc_screen_toggle_mouse_capture(screen);
|
||||
}
|
||||
// Mouse capture keys are never forwarded to the device
|
||||
return;
|
||||
@@ -869,7 +897,7 @@ sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event) {
|
||||
case SDL_MOUSEWHEEL:
|
||||
case SDL_MOUSEMOTION:
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (relative_mode && !sc_screen_get_mouse_capture()) {
|
||||
if (relative_mode && !sc_screen_get_mouse_capture(screen)) {
|
||||
// Do not forward to input manager, the mouse will be captured
|
||||
// on SDL_MOUSEBUTTONUP
|
||||
return;
|
||||
@@ -885,8 +913,8 @@ sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event) {
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (relative_mode && !sc_screen_get_mouse_capture()) {
|
||||
sc_screen_set_mouse_capture(true);
|
||||
if (relative_mode && !sc_screen_get_mouse_capture(screen)) {
|
||||
sc_screen_set_mouse_capture(screen, true);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -26,7 +26,7 @@ struct sc_screen {
|
||||
|
||||
struct sc_input_manager im;
|
||||
struct sc_video_buffer vb;
|
||||
struct fps_counter fps_counter;
|
||||
struct sc_fps_counter fps_counter;
|
||||
|
||||
// The initial requested window properties
|
||||
struct {
|
||||
@@ -35,6 +35,7 @@ struct sc_screen {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
bool fullscreen;
|
||||
bool start_fps_counter;
|
||||
} req;
|
||||
|
||||
SDL_Window *window;
|
||||
@@ -93,6 +94,7 @@ struct sc_screen_params {
|
||||
bool mipmaps;
|
||||
|
||||
bool fullscreen;
|
||||
bool start_fps_counter;
|
||||
|
||||
sc_tick buffering_time;
|
||||
};
|
||||
|
||||
@@ -5,7 +5,27 @@
|
||||
#include "util/log.h"
|
||||
|
||||
static void
|
||||
sc_screen_otg_set_mouse_capture(bool capture) {
|
||||
sc_screen_otg_set_mouse_capture(struct sc_screen_otg *screen, bool capture) {
|
||||
#ifdef __APPLE__
|
||||
// Workaround for SDL bug on macOS:
|
||||
// <https://github.com/libsdl-org/SDL/issues/5340>
|
||||
if (capture) {
|
||||
int mouse_x, mouse_y;
|
||||
SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
|
||||
|
||||
int x, y, w, h;
|
||||
SDL_GetWindowPosition(screen->window, &x, &y);
|
||||
SDL_GetWindowSize(screen->window, &w, &h);
|
||||
|
||||
bool outside_window = mouse_x < x || mouse_x >= x + w
|
||||
|| mouse_y < y || mouse_y >= y + h;
|
||||
if (outside_window) {
|
||||
SDL_WarpMouseInWindow(screen->window, w / 2, h / 2);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void) screen;
|
||||
#endif
|
||||
if (SDL_SetRelativeMouseMode(capture)) {
|
||||
LOGE("Could not set relative mouse mode to %s: %s",
|
||||
capture ? "true" : "false", SDL_GetError());
|
||||
@@ -13,13 +33,16 @@ sc_screen_otg_set_mouse_capture(bool capture) {
|
||||
}
|
||||
|
||||
static inline bool
|
||||
sc_screen_otg_get_mouse_capture(void) {
|
||||
sc_screen_otg_get_mouse_capture(struct sc_screen_otg *screen) {
|
||||
(void) screen;
|
||||
return SDL_GetRelativeMouseMode();
|
||||
}
|
||||
|
||||
static inline void
|
||||
sc_screen_otg_toggle_mouse_capture(void) {
|
||||
sc_screen_otg_set_mouse_capture(!sc_screen_otg_get_mouse_capture());
|
||||
sc_screen_otg_toggle_mouse_capture(struct sc_screen_otg *screen) {
|
||||
(void) screen;
|
||||
bool new_value = !sc_screen_otg_get_mouse_capture(screen);
|
||||
sc_screen_otg_set_mouse_capture(screen, new_value);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -86,7 +109,7 @@ sc_screen_otg_init(struct sc_screen_otg *screen,
|
||||
|
||||
if (screen->mouse) {
|
||||
// Capture mouse on start
|
||||
sc_screen_otg_set_mouse_capture(true);
|
||||
sc_screen_otg_set_mouse_capture(screen, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -198,7 +221,7 @@ sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event) {
|
||||
break;
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
if (screen->mouse) {
|
||||
sc_screen_otg_set_mouse_capture(false);
|
||||
sc_screen_otg_set_mouse_capture(screen, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -232,7 +255,7 @@ sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event) {
|
||||
if (key == cap) {
|
||||
// A mouse capture key has been pressed then released:
|
||||
// toggle the capture mouse mode
|
||||
sc_screen_otg_toggle_mouse_capture();
|
||||
sc_screen_otg_toggle_mouse_capture(screen);
|
||||
}
|
||||
// Mouse capture keys are never forwarded to the device
|
||||
return;
|
||||
@@ -244,26 +267,26 @@ sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event) {
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
if (screen->mouse && sc_screen_otg_get_mouse_capture()) {
|
||||
if (screen->mouse && sc_screen_otg_get_mouse_capture(screen)) {
|
||||
sc_screen_otg_process_mouse_motion(screen, &event->motion);
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (screen->mouse && sc_screen_otg_get_mouse_capture()) {
|
||||
if (screen->mouse && sc_screen_otg_get_mouse_capture(screen)) {
|
||||
sc_screen_otg_process_mouse_button(screen, &event->button);
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (screen->mouse) {
|
||||
if (sc_screen_otg_get_mouse_capture()) {
|
||||
if (sc_screen_otg_get_mouse_capture(screen)) {
|
||||
sc_screen_otg_process_mouse_button(screen, &event->button);
|
||||
} else {
|
||||
sc_screen_otg_set_mouse_capture(true);
|
||||
sc_screen_otg_set_mouse_capture(screen, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEWHEEL:
|
||||
if (screen->mouse && sc_screen_otg_get_mouse_capture()) {
|
||||
if (screen->mouse && sc_screen_otg_get_mouse_capture(screen)) {
|
||||
sc_screen_otg_process_mouse_wheel(screen, &event->wheel);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -136,7 +136,9 @@ sc_cond_timedwait(sc_cond *cond, sc_mutex *mutex, sc_tick deadline) {
|
||||
return false; // timeout
|
||||
}
|
||||
|
||||
uint32_t ms = SC_TICK_TO_MS(deadline - now);
|
||||
// Round up to the next millisecond to guarantee that the deadline is
|
||||
// reached when returning due to timeout
|
||||
uint32_t ms = SC_TICK_TO_MS(deadline - now + SC_TICK_FROM_MS(1) - 1);
|
||||
int r = SDL_CondWaitTimeout(cond->cond, mutex->mutex, ms);
|
||||
#ifndef NDEBUG
|
||||
if (r < 0) {
|
||||
@@ -148,6 +150,8 @@ sc_cond_timedwait(sc_cond *cond, sc_mutex *mutex, sc_tick deadline) {
|
||||
memory_order_relaxed);
|
||||
#endif
|
||||
assert(r == 0 || r == SDL_MUTEX_TIMEDOUT);
|
||||
// The deadline is reached on timeout
|
||||
assert(r != SDL_MUTEX_TIMEDOUT || sc_tick_now() >= deadline);
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,6 @@ static void test_adb_devices_daemon_start_mixed() {
|
||||
struct sc_adb_device *device = &devices[0];
|
||||
assert(!strcmp("0123456789abcdef", device->serial));
|
||||
assert(!strcmp("unauthorized", device->state));
|
||||
fprintf(stderr, "==== [%s]\n", device->model);
|
||||
assert(!device->model);
|
||||
|
||||
device = &devices[1];
|
||||
|
||||
Reference in New Issue
Block a user