Compare commits
25 Commits
hidmouse
...
downsize_o
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2eb6fe7d81 | ||
|
|
3a0ba7d0a4 | ||
|
|
75c5dc6859 | ||
|
|
fa30f9806a | ||
|
|
4fb61ac83d | ||
|
|
8fa9e6b01a | ||
|
|
0ec64baad4 | ||
|
|
15bf27afdd | ||
|
|
26b4104844 | ||
|
|
723faa5dee | ||
|
|
162043911e | ||
|
|
117fe32626 | ||
|
|
b7a06278fe | ||
|
|
b3ff1f6b3b | ||
|
|
a2495c5ef1 | ||
|
|
37c7827d46 | ||
|
|
5e8fa56e7a | ||
|
|
60bf133ac2 | ||
|
|
1c71bd16be | ||
|
|
afa4a1b728 | ||
|
|
3a4d5c7f18 | ||
|
|
5f7ddff8ae | ||
|
|
2a0c2e5e99 | ||
|
|
a6644e831b | ||
|
|
75655194fb |
3
FAQ.md
3
FAQ.md
@@ -219,6 +219,9 @@ scrcpy -m 1024
|
|||||||
scrcpy -m 800
|
scrcpy -m 800
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Since scrcpy v1.22, scrcpy automatically tries again with a lower definition
|
||||||
|
before failing. This behavior can be disabled with `--no-downsize-on-error`.
|
||||||
|
|
||||||
You could also try another [encoder](README.md#encoder).
|
You could also try another [encoder](README.md#encoder).
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -118,15 +118,20 @@ else
|
|||||||
include_directories: include_directories(sdl2_include_dir)
|
include_directories: include_directories(sdl2_include_dir)
|
||||||
)
|
)
|
||||||
|
|
||||||
prebuilt_ffmpeg_shared = meson.get_cross_property('prebuilt_ffmpeg_shared')
|
prebuilt_ffmpeg = meson.get_cross_property('prebuilt_ffmpeg')
|
||||||
prebuilt_ffmpeg_dev = meson.get_cross_property('prebuilt_ffmpeg_dev')
|
ffmpeg_bin_dir = meson.current_source_dir() + '/../prebuilt-deps/' + prebuilt_ffmpeg + '/bin'
|
||||||
ffmpeg_bin_dir = meson.current_source_dir() + '/../prebuilt-deps/' + prebuilt_ffmpeg_shared + '/bin'
|
ffmpeg_include_dir = '../prebuilt-deps/' + prebuilt_ffmpeg + '/include'
|
||||||
ffmpeg_include_dir = '../prebuilt-deps/' + prebuilt_ffmpeg_dev + '/include'
|
|
||||||
|
# ffmpeg versions are different for win32 and win64 builds
|
||||||
|
ffmpeg_avcodec = meson.get_cross_property('ffmpeg_avcodec')
|
||||||
|
ffmpeg_avformat = meson.get_cross_property('ffmpeg_avformat')
|
||||||
|
ffmpeg_avutil = meson.get_cross_property('ffmpeg_avutil')
|
||||||
|
|
||||||
ffmpeg = declare_dependency(
|
ffmpeg = declare_dependency(
|
||||||
dependencies: [
|
dependencies: [
|
||||||
cc.find_library('avcodec-58', dirs: ffmpeg_bin_dir),
|
cc.find_library(ffmpeg_avcodec, dirs: ffmpeg_bin_dir),
|
||||||
cc.find_library('avformat-58', dirs: ffmpeg_bin_dir),
|
cc.find_library(ffmpeg_avformat, dirs: ffmpeg_bin_dir),
|
||||||
cc.find_library('avutil-56', dirs: ffmpeg_bin_dir),
|
cc.find_library(ffmpeg_avutil, dirs: ffmpeg_bin_dir),
|
||||||
],
|
],
|
||||||
include_directories: include_directories(ffmpeg_include_dir)
|
include_directories: include_directories(ffmpeg_include_dir)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -140,6 +140,12 @@ By default, scrcpy automatically synchronizes the computer clipboard to the devi
|
|||||||
|
|
||||||
This option disables this automatic synchronization.
|
This option disables this automatic synchronization.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B \-\-no\-downsize\-on\-error
|
||||||
|
By default, on MediaCodec error, scrcpy automatically tries again with a lower definition.
|
||||||
|
|
||||||
|
This option disables this behavior.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B \-n, \-\-no\-control
|
.B \-n, \-\-no\-control
|
||||||
Disable device control (mirror the device in read\-only).
|
Disable device control (mirror the device in read\-only).
|
||||||
|
|||||||
@@ -343,8 +343,8 @@ run_aoa_thread(void *data) {
|
|||||||
|
|
||||||
if (ack_to_wait != SC_SEQUENCE_INVALID) {
|
if (ack_to_wait != SC_SEQUENCE_INVALID) {
|
||||||
LOGD("Waiting ack from server sequence=%" PRIu64_, ack_to_wait);
|
LOGD("Waiting ack from server sequence=%" PRIu64_, ack_to_wait);
|
||||||
// Do not block the loop indefinitely if the ack never comes (it should
|
// Do not block the loop indefinitely if the ack never comes (it
|
||||||
// never happen)
|
// should never happen)
|
||||||
sc_tick deadline = sc_tick_now() + SC_TICK_FROM_MS(500);
|
sc_tick deadline = sc_tick_now() + SC_TICK_FROM_MS(500);
|
||||||
enum sc_acksync_wait_result result =
|
enum sc_acksync_wait_result result =
|
||||||
sc_acksync_wait(aoa->acksync, ack_to_wait, deadline);
|
sc_acksync_wait(aoa->acksync, ack_to_wait, deadline);
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
#define OPT_NO_CLIPBOARD_AUTOSYNC 1032
|
#define OPT_NO_CLIPBOARD_AUTOSYNC 1032
|
||||||
#define OPT_TCPIP 1033
|
#define OPT_TCPIP 1033
|
||||||
#define OPT_RAW_KEY_EVENTS 1034
|
#define OPT_RAW_KEY_EVENTS 1034
|
||||||
|
#define OPT_NO_DOWNSIZE_ON_ERROR 1035
|
||||||
|
|
||||||
struct sc_option {
|
struct sc_option {
|
||||||
char shortopt;
|
char shortopt;
|
||||||
@@ -236,6 +237,13 @@ static const struct sc_option options[] = {
|
|||||||
"is preserved.\n"
|
"is preserved.\n"
|
||||||
"Default is 0 (unlimited).",
|
"Default is 0 (unlimited).",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.longopt_id = OPT_NO_DOWNSIZE_ON_ERROR,
|
||||||
|
.longopt = "no-downsize-on-error",
|
||||||
|
.text = "By default, on MediaCodec error, scrcpy automatically tries "
|
||||||
|
"again with a lower definition.\n"
|
||||||
|
"This option disables this behavior.",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.longopt_id = OPT_NO_CLIPBOARD_AUTOSYNC,
|
.longopt_id = OPT_NO_CLIPBOARD_AUTOSYNC,
|
||||||
.longopt = "no-clipboard-autosync",
|
.longopt = "no-clipboard-autosync",
|
||||||
@@ -1489,6 +1497,9 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
opts->tcpip = true;
|
opts->tcpip = true;
|
||||||
opts->tcpip_dst = optarg;
|
opts->tcpip_dst = optarg;
|
||||||
break;
|
break;
|
||||||
|
case OPT_NO_DOWNSIZE_ON_ERROR:
|
||||||
|
opts->downsize_on_error = false;
|
||||||
|
break;
|
||||||
case OPT_V4L2_SINK:
|
case OPT_V4L2_SINK:
|
||||||
#ifdef HAVE_V4L2
|
#ifdef HAVE_V4L2
|
||||||
opts->v4l2_device = optarg;
|
opts->v4l2_device = optarg;
|
||||||
@@ -1534,11 +1545,18 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->v4l2_device && opts->lock_video_orientation
|
if (opts->v4l2_device) {
|
||||||
== SC_LOCK_VIDEO_ORIENTATION_UNLOCKED) {
|
if (opts->lock_video_orientation ==
|
||||||
LOGI("Video orientation is locked for v4l2 sink. "
|
SC_LOCK_VIDEO_ORIENTATION_UNLOCKED) {
|
||||||
"See --lock-video-orientation.");
|
LOGI("Video orientation is locked for v4l2 sink. "
|
||||||
opts->lock_video_orientation = SC_LOCK_VIDEO_ORIENTATION_INITIAL;
|
"See --lock-video-orientation.");
|
||||||
|
opts->lock_video_orientation = SC_LOCK_VIDEO_ORIENTATION_INITIAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// V4L2 could not handle size change.
|
||||||
|
// Do not log because downsizing on error is the default behavior,
|
||||||
|
// not an explicit request from the user.
|
||||||
|
opts->downsize_on_error = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->v4l2_buffer && !opts->v4l2_device) {
|
if (opts->v4l2_buffer && !opts->v4l2_device) {
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ to_fixed_point_16(float f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
|
sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
|
||||||
buf[0] = msg->type;
|
buf[0] = msg->type;
|
||||||
switch (msg->type) {
|
switch (msg->type) {
|
||||||
case CONTROL_MSG_TYPE_INJECT_KEYCODE:
|
case CONTROL_MSG_TYPE_INJECT_KEYCODE:
|
||||||
@@ -151,7 +151,7 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
control_msg_log(const struct control_msg *msg) {
|
sc_control_msg_log(const struct sc_control_msg *msg) {
|
||||||
#define LOG_CMSG(fmt, ...) LOGV("input: " fmt, ## __VA_ARGS__)
|
#define LOG_CMSG(fmt, ...) LOGV("input: " fmt, ## __VA_ARGS__)
|
||||||
switch (msg->type) {
|
switch (msg->type) {
|
||||||
case CONTROL_MSG_TYPE_INJECT_KEYCODE:
|
case CONTROL_MSG_TYPE_INJECT_KEYCODE:
|
||||||
@@ -237,7 +237,7 @@ control_msg_log(const struct control_msg *msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
control_msg_destroy(struct control_msg *msg) {
|
sc_control_msg_destroy(struct sc_control_msg *msg) {
|
||||||
switch (msg->type) {
|
switch (msg->type) {
|
||||||
case CONTROL_MSG_TYPE_INJECT_TEXT:
|
case CONTROL_MSG_TYPE_INJECT_TEXT:
|
||||||
free(msg->inject_text.text);
|
free(msg->inject_text.text);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#define POINTER_ID_MOUSE UINT64_C(-1)
|
#define POINTER_ID_MOUSE UINT64_C(-1)
|
||||||
#define POINTER_ID_VIRTUAL_FINGER UINT64_C(-2)
|
#define POINTER_ID_VIRTUAL_FINGER UINT64_C(-2)
|
||||||
|
|
||||||
enum control_msg_type {
|
enum sc_control_msg_type {
|
||||||
CONTROL_MSG_TYPE_INJECT_KEYCODE,
|
CONTROL_MSG_TYPE_INJECT_KEYCODE,
|
||||||
CONTROL_MSG_TYPE_INJECT_TEXT,
|
CONTROL_MSG_TYPE_INJECT_TEXT,
|
||||||
CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||||
@@ -47,8 +47,8 @@ enum get_clipboard_copy_key {
|
|||||||
GET_CLIPBOARD_COPY_KEY_CUT,
|
GET_CLIPBOARD_COPY_KEY_CUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct control_msg {
|
struct sc_control_msg {
|
||||||
enum control_msg_type type;
|
enum sc_control_msg_type type;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
enum android_keyevent_action action;
|
enum android_keyevent_action action;
|
||||||
@@ -93,12 +93,12 @@ struct control_msg {
|
|||||||
// buf size must be at least CONTROL_MSG_MAX_SIZE
|
// buf size must be at least CONTROL_MSG_MAX_SIZE
|
||||||
// return the number of bytes written
|
// return the number of bytes written
|
||||||
size_t
|
size_t
|
||||||
control_msg_serialize(const struct control_msg *msg, unsigned char *buf);
|
sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf);
|
||||||
|
|
||||||
void
|
void
|
||||||
control_msg_log(const struct control_msg *msg);
|
sc_control_msg_log(const struct sc_control_msg *msg);
|
||||||
|
|
||||||
void
|
void
|
||||||
control_msg_destroy(struct control_msg *msg);
|
sc_control_msg_destroy(struct sc_control_msg *msg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
|
|
||||||
bool
|
bool
|
||||||
controller_init(struct controller *controller, sc_socket control_socket,
|
sc_controller_init(struct sc_controller *controller, sc_socket control_socket,
|
||||||
struct sc_acksync *acksync) {
|
struct sc_acksync *acksync) {
|
||||||
cbuf_init(&controller->queue);
|
cbuf_init(&controller->queue);
|
||||||
|
|
||||||
bool ok = receiver_init(&controller->receiver, control_socket, acksync);
|
bool ok = receiver_init(&controller->receiver, control_socket, acksync);
|
||||||
@@ -34,23 +34,23 @@ controller_init(struct controller *controller, sc_socket control_socket,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
controller_destroy(struct controller *controller) {
|
sc_controller_destroy(struct sc_controller *controller) {
|
||||||
sc_cond_destroy(&controller->msg_cond);
|
sc_cond_destroy(&controller->msg_cond);
|
||||||
sc_mutex_destroy(&controller->mutex);
|
sc_mutex_destroy(&controller->mutex);
|
||||||
|
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
while (cbuf_take(&controller->queue, &msg)) {
|
while (cbuf_take(&controller->queue, &msg)) {
|
||||||
control_msg_destroy(&msg);
|
sc_control_msg_destroy(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
receiver_destroy(&controller->receiver);
|
receiver_destroy(&controller->receiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
controller_push_msg(struct controller *controller,
|
sc_controller_push_msg(struct sc_controller *controller,
|
||||||
const struct control_msg *msg) {
|
const struct sc_control_msg *msg) {
|
||||||
if (sc_get_log_level() <= SC_LOG_LEVEL_VERBOSE) {
|
if (sc_get_log_level() <= SC_LOG_LEVEL_VERBOSE) {
|
||||||
control_msg_log(msg);
|
sc_control_msg_log(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_mutex_lock(&controller->mutex);
|
sc_mutex_lock(&controller->mutex);
|
||||||
@@ -64,9 +64,10 @@ controller_push_msg(struct controller *controller,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
process_msg(struct controller *controller, const struct control_msg *msg) {
|
process_msg(struct sc_controller *controller,
|
||||||
|
const struct sc_control_msg *msg) {
|
||||||
static unsigned char serialized_msg[CONTROL_MSG_MAX_SIZE];
|
static unsigned char serialized_msg[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t length = control_msg_serialize(msg, serialized_msg);
|
size_t length = sc_control_msg_serialize(msg, serialized_msg);
|
||||||
if (!length) {
|
if (!length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -77,7 +78,7 @@ process_msg(struct controller *controller, const struct control_msg *msg) {
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
run_controller(void *data) {
|
run_controller(void *data) {
|
||||||
struct controller *controller = data;
|
struct sc_controller *controller = data;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
sc_mutex_lock(&controller->mutex);
|
sc_mutex_lock(&controller->mutex);
|
||||||
@@ -89,14 +90,14 @@ run_controller(void *data) {
|
|||||||
sc_mutex_unlock(&controller->mutex);
|
sc_mutex_unlock(&controller->mutex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
bool non_empty = cbuf_take(&controller->queue, &msg);
|
bool non_empty = cbuf_take(&controller->queue, &msg);
|
||||||
assert(non_empty);
|
assert(non_empty);
|
||||||
(void) non_empty;
|
(void) non_empty;
|
||||||
sc_mutex_unlock(&controller->mutex);
|
sc_mutex_unlock(&controller->mutex);
|
||||||
|
|
||||||
bool ok = process_msg(controller, &msg);
|
bool ok = process_msg(controller, &msg);
|
||||||
control_msg_destroy(&msg);
|
sc_control_msg_destroy(&msg);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGD("Could not write msg to socket");
|
LOGD("Could not write msg to socket");
|
||||||
break;
|
break;
|
||||||
@@ -106,7 +107,7 @@ run_controller(void *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
controller_start(struct controller *controller) {
|
sc_controller_start(struct sc_controller *controller) {
|
||||||
LOGD("Starting controller thread");
|
LOGD("Starting controller thread");
|
||||||
|
|
||||||
bool ok = sc_thread_create(&controller->thread, run_controller,
|
bool ok = sc_thread_create(&controller->thread, run_controller,
|
||||||
@@ -117,7 +118,7 @@ controller_start(struct controller *controller) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!receiver_start(&controller->receiver)) {
|
if (!receiver_start(&controller->receiver)) {
|
||||||
controller_stop(controller);
|
sc_controller_stop(controller);
|
||||||
sc_thread_join(&controller->thread, NULL);
|
sc_thread_join(&controller->thread, NULL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -126,7 +127,7 @@ controller_start(struct controller *controller) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
controller_stop(struct controller *controller) {
|
sc_controller_stop(struct sc_controller *controller) {
|
||||||
sc_mutex_lock(&controller->mutex);
|
sc_mutex_lock(&controller->mutex);
|
||||||
controller->stopped = true;
|
controller->stopped = true;
|
||||||
sc_cond_signal(&controller->msg_cond);
|
sc_cond_signal(&controller->msg_cond);
|
||||||
@@ -134,7 +135,7 @@ controller_stop(struct controller *controller) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
controller_join(struct controller *controller) {
|
sc_controller_join(struct sc_controller *controller) {
|
||||||
sc_thread_join(&controller->thread, NULL);
|
sc_thread_join(&controller->thread, NULL);
|
||||||
receiver_join(&controller->receiver);
|
receiver_join(&controller->receiver);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,36 +12,36 @@
|
|||||||
#include "util/net.h"
|
#include "util/net.h"
|
||||||
#include "util/thread.h"
|
#include "util/thread.h"
|
||||||
|
|
||||||
struct control_msg_queue CBUF(struct control_msg, 64);
|
struct sc_control_msg_queue CBUF(struct sc_control_msg, 64);
|
||||||
|
|
||||||
struct controller {
|
struct sc_controller {
|
||||||
sc_socket control_socket;
|
sc_socket control_socket;
|
||||||
sc_thread thread;
|
sc_thread thread;
|
||||||
sc_mutex mutex;
|
sc_mutex mutex;
|
||||||
sc_cond msg_cond;
|
sc_cond msg_cond;
|
||||||
bool stopped;
|
bool stopped;
|
||||||
struct control_msg_queue queue;
|
struct sc_control_msg_queue queue;
|
||||||
struct receiver receiver;
|
struct receiver receiver;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
controller_init(struct controller *controller, sc_socket control_socket,
|
sc_controller_init(struct sc_controller *controller, sc_socket control_socket,
|
||||||
struct sc_acksync *acksync);
|
struct sc_acksync *acksync);
|
||||||
|
|
||||||
void
|
void
|
||||||
controller_destroy(struct controller *controller);
|
sc_controller_destroy(struct sc_controller *controller);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
controller_start(struct controller *controller);
|
sc_controller_start(struct sc_controller *controller);
|
||||||
|
|
||||||
void
|
void
|
||||||
controller_stop(struct controller *controller);
|
sc_controller_stop(struct sc_controller *controller);
|
||||||
|
|
||||||
void
|
void
|
||||||
controller_join(struct controller *controller);
|
sc_controller_join(struct sc_controller *controller);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
controller_push_msg(struct controller *controller,
|
sc_controller_push_msg(struct sc_controller *controller,
|
||||||
const struct control_msg *msg);
|
const struct sc_control_msg *msg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "trait/packet_sink.h"
|
#include "trait/packet_sink.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
|
|
||||||
#define DECODER_MAX_SINKS 2
|
#define DECODER_MAX_SINKS 2
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
#include <libavutil/pixdesc.h>
|
#include <libavutil/pixdesc.h>
|
||||||
#include <libavutil/pixfmt.h>
|
#include <libavutil/pixfmt.h>
|
||||||
@@ -85,7 +86,7 @@ decode_image(const char *path) {
|
|||||||
|
|
||||||
AVCodecParameters *params = ctx->streams[stream]->codecpar;
|
AVCodecParameters *params = ctx->streams[stream]->codecpar;
|
||||||
|
|
||||||
AVCodec *codec = avcodec_find_decoder(params->codec_id);
|
const AVCodec *codec = avcodec_find_decoder(params->codec_id);
|
||||||
if (!codec) {
|
if (!codec) {
|
||||||
LOGE("Could not find image decoder");
|
LOGE("Could not find image decoder");
|
||||||
goto close_input;
|
goto close_input;
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ to_sdl_mod(unsigned shortcut_mod) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
is_shortcut_mod(struct input_manager *im, uint16_t sdl_mod) {
|
is_shortcut_mod(struct sc_input_manager *im, uint16_t sdl_mod) {
|
||||||
// keep only the relevant modifier keys
|
// keep only the relevant modifier keys
|
||||||
sdl_mod &= SC_SDL_SHORTCUT_MODS_MASK;
|
sdl_mod &= SC_SDL_SHORTCUT_MODS_MASK;
|
||||||
|
|
||||||
@@ -122,8 +122,8 @@ is_shortcut_mod(struct input_manager *im, uint16_t sdl_mod) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
input_manager_init(struct input_manager *im,
|
sc_input_manager_init(struct sc_input_manager *im,
|
||||||
const struct input_manager_params *params) {
|
const struct sc_input_manager_params *params) {
|
||||||
assert(!params->control || (params->kp && params->kp->ops));
|
assert(!params->control || (params->kp && params->kp->ops));
|
||||||
assert(!params->control || (params->mp && params->mp->ops));
|
assert(!params->control || (params->mp && params->mp->ops));
|
||||||
|
|
||||||
@@ -157,10 +157,10 @@ input_manager_init(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
send_keycode(struct controller *controller, enum android_keycode keycode,
|
send_keycode(struct sc_controller *controller, enum android_keycode keycode,
|
||||||
enum sc_action action, const char *name) {
|
enum sc_action action, const char *name) {
|
||||||
// send DOWN event
|
// send DOWN event
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_INJECT_KEYCODE;
|
msg.type = CONTROL_MSG_TYPE_INJECT_KEYCODE;
|
||||||
msg.inject_keycode.action = action == SC_ACTION_DOWN
|
msg.inject_keycode.action = action == SC_ACTION_DOWN
|
||||||
? AKEY_EVENT_ACTION_DOWN
|
? AKEY_EVENT_ACTION_DOWN
|
||||||
@@ -169,100 +169,100 @@ send_keycode(struct controller *controller, enum android_keycode keycode,
|
|||||||
msg.inject_keycode.metastate = 0;
|
msg.inject_keycode.metastate = 0;
|
||||||
msg.inject_keycode.repeat = 0;
|
msg.inject_keycode.repeat = 0;
|
||||||
|
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request 'inject %s'", name);
|
LOGW("Could not request 'inject %s'", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
action_home(struct controller *controller, enum sc_action action) {
|
action_home(struct sc_controller *controller, enum sc_action action) {
|
||||||
send_keycode(controller, AKEYCODE_HOME, action, "HOME");
|
send_keycode(controller, AKEYCODE_HOME, action, "HOME");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
action_back(struct controller *controller, enum sc_action action) {
|
action_back(struct sc_controller *controller, enum sc_action action) {
|
||||||
send_keycode(controller, AKEYCODE_BACK, action, "BACK");
|
send_keycode(controller, AKEYCODE_BACK, action, "BACK");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
action_app_switch(struct controller *controller, enum sc_action action) {
|
action_app_switch(struct sc_controller *controller, enum sc_action action) {
|
||||||
send_keycode(controller, AKEYCODE_APP_SWITCH, action, "APP_SWITCH");
|
send_keycode(controller, AKEYCODE_APP_SWITCH, action, "APP_SWITCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
action_power(struct controller *controller, enum sc_action action) {
|
action_power(struct sc_controller *controller, enum sc_action action) {
|
||||||
send_keycode(controller, AKEYCODE_POWER, action, "POWER");
|
send_keycode(controller, AKEYCODE_POWER, action, "POWER");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
action_volume_up(struct controller *controller, enum sc_action action) {
|
action_volume_up(struct sc_controller *controller, enum sc_action action) {
|
||||||
send_keycode(controller, AKEYCODE_VOLUME_UP, action, "VOLUME_UP");
|
send_keycode(controller, AKEYCODE_VOLUME_UP, action, "VOLUME_UP");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
action_volume_down(struct controller *controller, enum sc_action action) {
|
action_volume_down(struct sc_controller *controller, enum sc_action action) {
|
||||||
send_keycode(controller, AKEYCODE_VOLUME_DOWN, action, "VOLUME_DOWN");
|
send_keycode(controller, AKEYCODE_VOLUME_DOWN, action, "VOLUME_DOWN");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
action_menu(struct controller *controller, enum sc_action action) {
|
action_menu(struct sc_controller *controller, enum sc_action action) {
|
||||||
send_keycode(controller, AKEYCODE_MENU, action, "MENU");
|
send_keycode(controller, AKEYCODE_MENU, action, "MENU");
|
||||||
}
|
}
|
||||||
|
|
||||||
// turn the screen on if it was off, press BACK otherwise
|
// turn the screen on if it was off, press BACK otherwise
|
||||||
// If the screen is off, it is turned on only on ACTION_DOWN
|
// If the screen is off, it is turned on only on ACTION_DOWN
|
||||||
static void
|
static void
|
||||||
press_back_or_turn_screen_on(struct controller *controller,
|
press_back_or_turn_screen_on(struct sc_controller *controller,
|
||||||
enum sc_action action) {
|
enum sc_action action) {
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON;
|
msg.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON;
|
||||||
msg.back_or_screen_on.action = action == SC_ACTION_DOWN
|
msg.back_or_screen_on.action = action == SC_ACTION_DOWN
|
||||||
? AKEY_EVENT_ACTION_DOWN
|
? AKEY_EVENT_ACTION_DOWN
|
||||||
: AKEY_EVENT_ACTION_UP;
|
: AKEY_EVENT_ACTION_UP;
|
||||||
|
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request 'press back or turn screen on'");
|
LOGW("Could not request 'press back or turn screen on'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
expand_notification_panel(struct controller *controller) {
|
expand_notification_panel(struct sc_controller *controller) {
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL;
|
msg.type = CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL;
|
||||||
|
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request 'expand notification panel'");
|
LOGW("Could not request 'expand notification panel'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
expand_settings_panel(struct controller *controller) {
|
expand_settings_panel(struct sc_controller *controller) {
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL;
|
msg.type = CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL;
|
||||||
|
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request 'expand settings panel'");
|
LOGW("Could not request 'expand settings panel'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
collapse_panels(struct controller *controller) {
|
collapse_panels(struct sc_controller *controller) {
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_COLLAPSE_PANELS;
|
msg.type = CONTROL_MSG_TYPE_COLLAPSE_PANELS;
|
||||||
|
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request 'collapse notification panel'");
|
LOGW("Could not request 'collapse notification panel'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
get_device_clipboard(struct controller *controller,
|
get_device_clipboard(struct sc_controller *controller,
|
||||||
enum get_clipboard_copy_key copy_key) {
|
enum get_clipboard_copy_key copy_key) {
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_GET_CLIPBOARD;
|
msg.type = CONTROL_MSG_TYPE_GET_CLIPBOARD;
|
||||||
msg.get_clipboard.copy_key = copy_key;
|
msg.get_clipboard.copy_key = copy_key;
|
||||||
|
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request 'get device clipboard'");
|
LOGW("Could not request 'get device clipboard'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -271,7 +271,7 @@ get_device_clipboard(struct controller *controller,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
set_device_clipboard(struct controller *controller, bool paste,
|
set_device_clipboard(struct sc_controller *controller, bool paste,
|
||||||
uint64_t sequence) {
|
uint64_t sequence) {
|
||||||
char *text = SDL_GetClipboardText();
|
char *text = SDL_GetClipboardText();
|
||||||
if (!text) {
|
if (!text) {
|
||||||
@@ -286,13 +286,13 @@ set_device_clipboard(struct controller *controller, bool paste,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_SET_CLIPBOARD;
|
msg.type = CONTROL_MSG_TYPE_SET_CLIPBOARD;
|
||||||
msg.set_clipboard.sequence = sequence;
|
msg.set_clipboard.sequence = sequence;
|
||||||
msg.set_clipboard.text = text_dup;
|
msg.set_clipboard.text = text_dup;
|
||||||
msg.set_clipboard.paste = paste;
|
msg.set_clipboard.paste = paste;
|
||||||
|
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
free(text_dup);
|
free(text_dup);
|
||||||
LOGW("Could not request 'set device clipboard'");
|
LOGW("Could not request 'set device clipboard'");
|
||||||
return false;
|
return false;
|
||||||
@@ -302,13 +302,13 @@ set_device_clipboard(struct controller *controller, bool paste,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_screen_power_mode(struct controller *controller,
|
set_screen_power_mode(struct sc_controller *controller,
|
||||||
enum screen_power_mode mode) {
|
enum screen_power_mode mode) {
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;
|
msg.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;
|
||||||
msg.set_screen_power_mode.mode = mode;
|
msg.set_screen_power_mode.mode = mode;
|
||||||
|
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request 'set screen power mode'");
|
LOGW("Could not request 'set screen power mode'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -330,7 +330,7 @@ switch_fps_counter_state(struct fps_counter *fps_counter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clipboard_paste(struct controller *controller) {
|
clipboard_paste(struct sc_controller *controller) {
|
||||||
char *text = SDL_GetClipboardText();
|
char *text = SDL_GetClipboardText();
|
||||||
if (!text) {
|
if (!text) {
|
||||||
LOGW("Could not get clipboard text: %s", SDL_GetError());
|
LOGW("Could not get clipboard text: %s", SDL_GetError());
|
||||||
@@ -349,40 +349,40 @@ clipboard_paste(struct controller *controller) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
|
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
|
||||||
msg.inject_text.text = text_dup;
|
msg.inject_text.text = text_dup;
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
free(text_dup);
|
free(text_dup);
|
||||||
LOGW("Could not request 'paste clipboard'");
|
LOGW("Could not request 'paste clipboard'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rotate_device(struct controller *controller) {
|
rotate_device(struct sc_controller *controller) {
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_ROTATE_DEVICE;
|
msg.type = CONTROL_MSG_TYPE_ROTATE_DEVICE;
|
||||||
|
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request device rotation");
|
LOGW("Could not request device rotation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rotate_client_left(struct screen *screen) {
|
rotate_client_left(struct sc_screen *screen) {
|
||||||
unsigned new_rotation = (screen->rotation + 1) % 4;
|
unsigned new_rotation = (screen->rotation + 1) % 4;
|
||||||
screen_set_rotation(screen, new_rotation);
|
sc_screen_set_rotation(screen, new_rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rotate_client_right(struct screen *screen) {
|
rotate_client_right(struct sc_screen *screen) {
|
||||||
unsigned new_rotation = (screen->rotation + 3) % 4;
|
unsigned new_rotation = (screen->rotation + 3) % 4;
|
||||||
screen_set_rotation(screen, new_rotation);
|
sc_screen_set_rotation(screen, new_rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
input_manager_process_text_input(struct input_manager *im,
|
sc_input_manager_process_text_input(struct sc_input_manager *im,
|
||||||
const SDL_TextInputEvent *event) {
|
const SDL_TextInputEvent *event) {
|
||||||
if (!im->kp->ops->process_text) {
|
if (!im->kp->ops->process_text) {
|
||||||
// The key processor does not support text input
|
// The key processor does not support text input
|
||||||
return;
|
return;
|
||||||
@@ -401,12 +401,12 @@ input_manager_process_text_input(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
simulate_virtual_finger(struct input_manager *im,
|
simulate_virtual_finger(struct sc_input_manager *im,
|
||||||
enum android_motionevent_action action,
|
enum android_motionevent_action action,
|
||||||
struct sc_point point) {
|
struct sc_point point) {
|
||||||
bool up = action == AMOTION_EVENT_ACTION_UP;
|
bool up = action == AMOTION_EVENT_ACTION_UP;
|
||||||
|
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
|
msg.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
|
||||||
msg.inject_touch_event.action = action;
|
msg.inject_touch_event.action = action;
|
||||||
msg.inject_touch_event.position.screen_size = im->screen->frame_size;
|
msg.inject_touch_event.position.screen_size = im->screen->frame_size;
|
||||||
@@ -415,7 +415,7 @@ simulate_virtual_finger(struct input_manager *im,
|
|||||||
msg.inject_touch_event.pressure = up ? 0.0f : 1.0f;
|
msg.inject_touch_event.pressure = up ? 0.0f : 1.0f;
|
||||||
msg.inject_touch_event.buttons = 0;
|
msg.inject_touch_event.buttons = 0;
|
||||||
|
|
||||||
if (!controller_push_msg(im->controller, &msg)) {
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
||||||
LOGW("Could not request 'inject virtual finger event'");
|
LOGW("Could not request 'inject virtual finger event'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -431,12 +431,12 @@ inverse_point(struct sc_point point, struct sc_size size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
input_manager_process_key(struct input_manager *im,
|
sc_input_manager_process_key(struct sc_input_manager *im,
|
||||||
const SDL_KeyboardEvent *event) {
|
const SDL_KeyboardEvent *event) {
|
||||||
// control: indicates the state of the command-line option --no-control
|
// control: indicates the state of the command-line option --no-control
|
||||||
bool control = im->control;
|
bool control = im->control;
|
||||||
|
|
||||||
struct controller *controller = im->controller;
|
struct sc_controller *controller = im->controller;
|
||||||
|
|
||||||
SDL_Keycode keycode = event->keysym.sym;
|
SDL_Keycode keycode = event->keysym.sym;
|
||||||
uint16_t mod = event->keysym.mod;
|
uint16_t mod = event->keysym.mod;
|
||||||
@@ -544,17 +544,17 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
return;
|
return;
|
||||||
case SDLK_f:
|
case SDLK_f:
|
||||||
if (!shift && !repeat && down) {
|
if (!shift && !repeat && down) {
|
||||||
screen_switch_fullscreen(im->screen);
|
sc_screen_switch_fullscreen(im->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_w:
|
case SDLK_w:
|
||||||
if (!shift && !repeat && down) {
|
if (!shift && !repeat && down) {
|
||||||
screen_resize_to_fit(im->screen);
|
sc_screen_resize_to_fit(im->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_g:
|
case SDLK_g:
|
||||||
if (!shift && !repeat && down) {
|
if (!shift && !repeat && down) {
|
||||||
screen_resize_to_pixel_perfect(im->screen);
|
sc_screen_resize_to_pixel_perfect(im->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_i:
|
case SDLK_i:
|
||||||
@@ -629,8 +629,8 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
input_manager_process_mouse_motion(struct input_manager *im,
|
sc_input_manager_process_mouse_motion(struct sc_input_manager *im,
|
||||||
const SDL_MouseMotionEvent *event) {
|
const SDL_MouseMotionEvent *event) {
|
||||||
|
|
||||||
if (event->which == SDL_TOUCH_MOUSEID) {
|
if (event->which == SDL_TOUCH_MOUSEID) {
|
||||||
// simulated from touch events, so it's a duplicate
|
// simulated from touch events, so it's a duplicate
|
||||||
@@ -640,8 +640,9 @@ input_manager_process_mouse_motion(struct input_manager *im,
|
|||||||
struct sc_mouse_motion_event evt = {
|
struct sc_mouse_motion_event evt = {
|
||||||
.position = {
|
.position = {
|
||||||
.screen_size = im->screen->frame_size,
|
.screen_size = im->screen->frame_size,
|
||||||
.point = screen_convert_window_to_frame_coords(im->screen,
|
.point = sc_screen_convert_window_to_frame_coords(im->screen,
|
||||||
event->x, event->y),
|
event->x,
|
||||||
|
event->y),
|
||||||
},
|
},
|
||||||
.xrel = event->xrel,
|
.xrel = event->xrel,
|
||||||
.yrel = event->yrel,
|
.yrel = event->yrel,
|
||||||
@@ -659,16 +660,16 @@ input_manager_process_mouse_motion(struct input_manager *im,
|
|||||||
if (im->vfinger_down) {
|
if (im->vfinger_down) {
|
||||||
assert(!im->mp->relative_mode); // assert one more time
|
assert(!im->mp->relative_mode); // assert one more time
|
||||||
struct sc_point mouse =
|
struct sc_point mouse =
|
||||||
screen_convert_window_to_frame_coords(im->screen, event->x,
|
sc_screen_convert_window_to_frame_coords(im->screen, event->x,
|
||||||
event->y);
|
event->y);
|
||||||
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size);
|
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size);
|
||||||
simulate_virtual_finger(im, AMOTION_EVENT_ACTION_MOVE, vfinger);
|
simulate_virtual_finger(im, AMOTION_EVENT_ACTION_MOVE, vfinger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
input_manager_process_touch(struct input_manager *im,
|
sc_input_manager_process_touch(struct sc_input_manager *im,
|
||||||
const SDL_TouchFingerEvent *event) {
|
const SDL_TouchFingerEvent *event) {
|
||||||
if (!im->mp->ops->process_touch) {
|
if (!im->mp->ops->process_touch) {
|
||||||
// The mouse processor does not support touch events
|
// The mouse processor does not support touch events
|
||||||
return;
|
return;
|
||||||
@@ -685,7 +686,8 @@ input_manager_process_touch(struct input_manager *im,
|
|||||||
struct sc_touch_event evt = {
|
struct sc_touch_event evt = {
|
||||||
.position = {
|
.position = {
|
||||||
.screen_size = im->screen->frame_size,
|
.screen_size = im->screen->frame_size,
|
||||||
.point = screen_convert_drawable_to_frame_coords(im->screen, x, y),
|
.point =
|
||||||
|
sc_screen_convert_drawable_to_frame_coords(im->screen, x, y),
|
||||||
},
|
},
|
||||||
.action = sc_touch_action_from_sdl(event->type),
|
.action = sc_touch_action_from_sdl(event->type),
|
||||||
.pointer_id = event->fingerId,
|
.pointer_id = event->fingerId,
|
||||||
@@ -696,8 +698,8 @@ input_manager_process_touch(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
input_manager_process_mouse_button(struct input_manager *im,
|
sc_input_manager_process_mouse_button(struct sc_input_manager *im,
|
||||||
const SDL_MouseButtonEvent *event) {
|
const SDL_MouseButtonEvent *event) {
|
||||||
bool control = im->control;
|
bool control = im->control;
|
||||||
|
|
||||||
if (event->which == SDL_TOUCH_MOUSEID) {
|
if (event->which == SDL_TOUCH_MOUSEID) {
|
||||||
@@ -734,13 +736,13 @@ input_manager_process_mouse_button(struct input_manager *im,
|
|||||||
if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) {
|
if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) {
|
||||||
int32_t x = event->x;
|
int32_t x = event->x;
|
||||||
int32_t y = event->y;
|
int32_t y = event->y;
|
||||||
screen_hidpi_scale_coords(im->screen, &x, &y);
|
sc_screen_hidpi_scale_coords(im->screen, &x, &y);
|
||||||
SDL_Rect *r = &im->screen->rect;
|
SDL_Rect *r = &im->screen->rect;
|
||||||
bool outside = x < r->x || x >= r->x + r->w
|
bool outside = x < r->x || x >= r->x + r->w
|
||||||
|| y < r->y || y >= r->y + r->h;
|
|| y < r->y || y >= r->y + r->h;
|
||||||
if (outside) {
|
if (outside) {
|
||||||
if (down) {
|
if (down) {
|
||||||
screen_resize_to_fit(im->screen);
|
sc_screen_resize_to_fit(im->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -757,8 +759,9 @@ input_manager_process_mouse_button(struct input_manager *im,
|
|||||||
struct sc_mouse_click_event evt = {
|
struct sc_mouse_click_event evt = {
|
||||||
.position = {
|
.position = {
|
||||||
.screen_size = im->screen->frame_size,
|
.screen_size = im->screen->frame_size,
|
||||||
.point = screen_convert_window_to_frame_coords(im->screen, event->x,
|
.point = sc_screen_convert_window_to_frame_coords(im->screen,
|
||||||
event->y),
|
event->x,
|
||||||
|
event->y),
|
||||||
},
|
},
|
||||||
.action = sc_action_from_sdl_mousebutton_type(event->type),
|
.action = sc_action_from_sdl_mousebutton_type(event->type),
|
||||||
.button = sc_mouse_button_from_sdl(event->button),
|
.button = sc_mouse_button_from_sdl(event->button),
|
||||||
@@ -790,8 +793,8 @@ input_manager_process_mouse_button(struct input_manager *im,
|
|||||||
((down && !im->vfinger_down && CTRL_PRESSED) ||
|
((down && !im->vfinger_down && CTRL_PRESSED) ||
|
||||||
(!down && im->vfinger_down))) {
|
(!down && im->vfinger_down))) {
|
||||||
struct sc_point mouse =
|
struct sc_point mouse =
|
||||||
screen_convert_window_to_frame_coords(im->screen, event->x,
|
sc_screen_convert_window_to_frame_coords(im->screen, event->x,
|
||||||
event->y);
|
event->y);
|
||||||
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size);
|
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size);
|
||||||
enum android_motionevent_action action = down
|
enum android_motionevent_action action = down
|
||||||
? AMOTION_EVENT_ACTION_DOWN
|
? AMOTION_EVENT_ACTION_DOWN
|
||||||
@@ -804,8 +807,8 @@ input_manager_process_mouse_button(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
input_manager_process_mouse_wheel(struct input_manager *im,
|
sc_input_manager_process_mouse_wheel(struct sc_input_manager *im,
|
||||||
const SDL_MouseWheelEvent *event) {
|
const SDL_MouseWheelEvent *event) {
|
||||||
if (!im->mp->ops->process_mouse_scroll) {
|
if (!im->mp->ops->process_mouse_scroll) {
|
||||||
// The mouse processor does not support scroll events
|
// The mouse processor does not support scroll events
|
||||||
return;
|
return;
|
||||||
@@ -819,8 +822,8 @@ input_manager_process_mouse_wheel(struct input_manager *im,
|
|||||||
struct sc_mouse_scroll_event evt = {
|
struct sc_mouse_scroll_event evt = {
|
||||||
.position = {
|
.position = {
|
||||||
.screen_size = im->screen->frame_size,
|
.screen_size = im->screen->frame_size,
|
||||||
.point = screen_convert_window_to_frame_coords(im->screen,
|
.point = sc_screen_convert_window_to_frame_coords(im->screen,
|
||||||
mouse_x, mouse_y),
|
mouse_x, mouse_y),
|
||||||
},
|
},
|
||||||
.hscroll = event->x,
|
.hscroll = event->x,
|
||||||
.vscroll = event->y,
|
.vscroll = event->y,
|
||||||
@@ -832,42 +835,42 @@ input_manager_process_mouse_wheel(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
input_manager_handle_event(struct input_manager *im, SDL_Event *event) {
|
sc_input_manager_handle_event(struct sc_input_manager *im, SDL_Event *event) {
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case SDL_TEXTINPUT:
|
case SDL_TEXTINPUT:
|
||||||
if (!im->control) {
|
if (!im->control) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
input_manager_process_text_input(im, &event->text);
|
sc_input_manager_process_text_input(im, &event->text);
|
||||||
return true;
|
return true;
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
case SDL_KEYUP:
|
case SDL_KEYUP:
|
||||||
// some key events do not interact with the device, so process the
|
// some key events do not interact with the device, so process the
|
||||||
// event even if control is disabled
|
// event even if control is disabled
|
||||||
input_manager_process_key(im, &event->key);
|
sc_input_manager_process_key(im, &event->key);
|
||||||
return true;
|
return true;
|
||||||
case SDL_MOUSEMOTION:
|
case SDL_MOUSEMOTION:
|
||||||
if (!im->control) {
|
if (!im->control) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
input_manager_process_mouse_motion(im, &event->motion);
|
sc_input_manager_process_mouse_motion(im, &event->motion);
|
||||||
return true;
|
return true;
|
||||||
case SDL_MOUSEWHEEL:
|
case SDL_MOUSEWHEEL:
|
||||||
if (!im->control) {
|
if (!im->control) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
input_manager_process_mouse_wheel(im, &event->wheel);
|
sc_input_manager_process_mouse_wheel(im, &event->wheel);
|
||||||
return true;
|
return true;
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
case SDL_MOUSEBUTTONUP:
|
case SDL_MOUSEBUTTONUP:
|
||||||
// some mouse events do not interact with the device, so process
|
// some mouse events do not interact with the device, so process
|
||||||
// the event even if control is disabled
|
// the event even if control is disabled
|
||||||
input_manager_process_mouse_button(im, &event->button);
|
sc_input_manager_process_mouse_button(im, &event->button);
|
||||||
return true;
|
return true;
|
||||||
case SDL_FINGERMOTION:
|
case SDL_FINGERMOTION:
|
||||||
case SDL_FINGERDOWN:
|
case SDL_FINGERDOWN:
|
||||||
case SDL_FINGERUP:
|
case SDL_FINGERUP:
|
||||||
input_manager_process_touch(im, &event->tfinger);
|
sc_input_manager_process_touch(im, &event->tfinger);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
#include "trait/key_processor.h"
|
#include "trait/key_processor.h"
|
||||||
#include "trait/mouse_processor.h"
|
#include "trait/mouse_processor.h"
|
||||||
|
|
||||||
struct input_manager {
|
struct sc_input_manager {
|
||||||
struct controller *controller;
|
struct sc_controller *controller;
|
||||||
struct screen *screen;
|
struct sc_screen *screen;
|
||||||
|
|
||||||
struct sc_key_processor *kp;
|
struct sc_key_processor *kp;
|
||||||
struct sc_mouse_processor *mp;
|
struct sc_mouse_processor *mp;
|
||||||
@@ -42,9 +42,9 @@ struct input_manager {
|
|||||||
uint64_t next_sequence; // used for request acknowledgements
|
uint64_t next_sequence; // used for request acknowledgements
|
||||||
};
|
};
|
||||||
|
|
||||||
struct input_manager_params {
|
struct sc_input_manager_params {
|
||||||
struct controller *controller;
|
struct sc_controller *controller;
|
||||||
struct screen *screen;
|
struct sc_screen *screen;
|
||||||
struct sc_key_processor *kp;
|
struct sc_key_processor *kp;
|
||||||
struct sc_mouse_processor *mp;
|
struct sc_mouse_processor *mp;
|
||||||
|
|
||||||
@@ -56,10 +56,10 @@ struct input_manager_params {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
input_manager_init(struct input_manager *im,
|
sc_input_manager_init(struct sc_input_manager *im,
|
||||||
const struct input_manager_params *params);
|
const struct sc_input_manager_params *params);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
input_manager_handle_event(struct input_manager *im, SDL_Event *event);
|
sc_input_manager_handle_event(struct sc_input_manager *im, SDL_Event *event);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ convert_meta_state(uint16_t mod) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
convert_input_key(const struct sc_key_event *event, struct control_msg *msg,
|
convert_input_key(const struct sc_key_event *event, struct sc_control_msg *msg,
|
||||||
enum sc_key_inject_mode key_inject_mode, uint32_t repeat) {
|
enum sc_key_inject_mode key_inject_mode, uint32_t repeat) {
|
||||||
msg->type = CONTROL_MSG_TYPE_INJECT_KEYCODE;
|
msg->type = CONTROL_MSG_TYPE_INJECT_KEYCODE;
|
||||||
|
|
||||||
@@ -282,9 +282,9 @@ sc_key_processor_process_key(struct sc_key_processor *kp,
|
|||||||
ki->repeat = 0;
|
ki->repeat = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
if (convert_input_key(event, &msg, ki->key_inject_mode, ki->repeat)) {
|
if (convert_input_key(event, &msg, ki->key_inject_mode, ki->repeat)) {
|
||||||
if (!controller_push_msg(ki->controller, &msg)) {
|
if (!sc_controller_push_msg(ki->controller, &msg)) {
|
||||||
LOGW("Could not request 'inject keycode'");
|
LOGW("Could not request 'inject keycode'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -309,14 +309,14 @@ sc_key_processor_process_text(struct sc_key_processor *kp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
|
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
|
||||||
msg.inject_text.text = strdup(event->text);
|
msg.inject_text.text = strdup(event->text);
|
||||||
if (!msg.inject_text.text) {
|
if (!msg.inject_text.text) {
|
||||||
LOGW("Could not strdup input text");
|
LOGW("Could not strdup input text");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!controller_push_msg(ki->controller, &msg)) {
|
if (!sc_controller_push_msg(ki->controller, &msg)) {
|
||||||
free(msg.inject_text.text);
|
free(msg.inject_text.text);
|
||||||
LOGW("Could not request 'inject text'");
|
LOGW("Could not request 'inject text'");
|
||||||
}
|
}
|
||||||
@@ -324,11 +324,12 @@ sc_key_processor_process_text(struct sc_key_processor *kp,
|
|||||||
|
|
||||||
void
|
void
|
||||||
sc_keyboard_inject_init(struct sc_keyboard_inject *ki,
|
sc_keyboard_inject_init(struct sc_keyboard_inject *ki,
|
||||||
struct controller *controller,
|
struct sc_controller *controller,
|
||||||
const struct scrcpy_options *options) {
|
enum sc_key_inject_mode key_inject_mode,
|
||||||
|
bool forward_key_repeat) {
|
||||||
ki->controller = controller;
|
ki->controller = controller;
|
||||||
ki->key_inject_mode = options->key_inject_mode;
|
ki->key_inject_mode = key_inject_mode;
|
||||||
ki->forward_key_repeat = options->forward_key_repeat;
|
ki->forward_key_repeat = forward_key_repeat;
|
||||||
|
|
||||||
ki->repeat = 0;
|
ki->repeat = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
struct sc_keyboard_inject {
|
struct sc_keyboard_inject {
|
||||||
struct sc_key_processor key_processor; // key processor trait
|
struct sc_key_processor key_processor; // key processor trait
|
||||||
|
|
||||||
struct controller *controller;
|
struct sc_controller *controller;
|
||||||
|
|
||||||
// SDL reports repeated events as a boolean, but Android expects the actual
|
// SDL reports repeated events as a boolean, but Android expects the actual
|
||||||
// number of repetitions. This variable keeps track of the count.
|
// number of repetitions. This variable keeps track of the count.
|
||||||
@@ -24,7 +24,8 @@ struct sc_keyboard_inject {
|
|||||||
|
|
||||||
void
|
void
|
||||||
sc_keyboard_inject_init(struct sc_keyboard_inject *ki,
|
sc_keyboard_inject_init(struct sc_keyboard_inject *ki,
|
||||||
struct controller *controller,
|
struct sc_controller *controller,
|
||||||
const struct scrcpy_options *options);
|
enum sc_key_inject_mode key_inject_mode,
|
||||||
|
bool forward_key_repeat);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp,
|
|||||||
|
|
||||||
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
||||||
|
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||||
.inject_touch_event = {
|
.inject_touch_event = {
|
||||||
.action = AMOTION_EVENT_ACTION_MOVE,
|
.action = AMOTION_EVENT_ACTION_MOVE,
|
||||||
@@ -76,7 +76,7 @@ sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp,
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!controller_push_msg(mi->controller, &msg)) {
|
if (!sc_controller_push_msg(mi->controller, &msg)) {
|
||||||
LOGW("Could not request 'inject mouse motion event'");
|
LOGW("Could not request 'inject mouse motion event'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ sc_mouse_processor_process_mouse_click(struct sc_mouse_processor *mp,
|
|||||||
const struct sc_mouse_click_event *event) {
|
const struct sc_mouse_click_event *event) {
|
||||||
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
||||||
|
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||||
.inject_touch_event = {
|
.inject_touch_event = {
|
||||||
.action = convert_mouse_action(event->action),
|
.action = convert_mouse_action(event->action),
|
||||||
@@ -97,7 +97,7 @@ sc_mouse_processor_process_mouse_click(struct sc_mouse_processor *mp,
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!controller_push_msg(mi->controller, &msg)) {
|
if (!sc_controller_push_msg(mi->controller, &msg)) {
|
||||||
LOGW("Could not request 'inject mouse click event'");
|
LOGW("Could not request 'inject mouse click event'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
|
|||||||
const struct sc_mouse_scroll_event *event) {
|
const struct sc_mouse_scroll_event *event) {
|
||||||
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
||||||
|
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
.type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
||||||
.inject_scroll_event = {
|
.inject_scroll_event = {
|
||||||
.position = event->position,
|
.position = event->position,
|
||||||
@@ -117,7 +117,7 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!controller_push_msg(mi->controller, &msg)) {
|
if (!sc_controller_push_msg(mi->controller, &msg)) {
|
||||||
LOGW("Could not request 'inject mouse scroll event'");
|
LOGW("Could not request 'inject mouse scroll event'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ sc_mouse_processor_process_touch(struct sc_mouse_processor *mp,
|
|||||||
const struct sc_touch_event *event) {
|
const struct sc_touch_event *event) {
|
||||||
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
||||||
|
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||||
.inject_touch_event = {
|
.inject_touch_event = {
|
||||||
.action = convert_touch_action(event->action),
|
.action = convert_touch_action(event->action),
|
||||||
@@ -138,14 +138,14 @@ sc_mouse_processor_process_touch(struct sc_mouse_processor *mp,
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!controller_push_msg(mi->controller, &msg)) {
|
if (!sc_controller_push_msg(mi->controller, &msg)) {
|
||||||
LOGW("Could not request 'inject touch event'");
|
LOGW("Could not request 'inject touch event'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sc_mouse_inject_init(struct sc_mouse_inject *mi,
|
sc_mouse_inject_init(struct sc_mouse_inject *mi,
|
||||||
struct controller *controller) {
|
struct sc_controller *controller) {
|
||||||
mi->controller = controller;
|
mi->controller = controller;
|
||||||
|
|
||||||
static const struct sc_mouse_processor_ops ops = {
|
static const struct sc_mouse_processor_ops ops = {
|
||||||
|
|||||||
@@ -12,10 +12,11 @@
|
|||||||
struct sc_mouse_inject {
|
struct sc_mouse_inject {
|
||||||
struct sc_mouse_processor mouse_processor; // mouse processor trait
|
struct sc_mouse_processor mouse_processor; // mouse processor trait
|
||||||
|
|
||||||
struct controller *controller;
|
struct sc_controller *controller;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
sc_mouse_inject_init(struct sc_mouse_inject *mi, struct controller *controller);
|
sc_mouse_inject_init(struct sc_mouse_inject *mi,
|
||||||
|
struct sc_controller *controller);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||||||
.legacy_paste = false,
|
.legacy_paste = false,
|
||||||
.power_off_on_close = false,
|
.power_off_on_close = false,
|
||||||
.clipboard_autosync = true,
|
.clipboard_autosync = true,
|
||||||
|
.downsize_on_error = true,
|
||||||
.tcpip = false,
|
.tcpip = false,
|
||||||
.tcpip_dst = NULL,
|
.tcpip_dst = NULL,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ struct scrcpy_options {
|
|||||||
bool legacy_paste;
|
bool legacy_paste;
|
||||||
bool power_off_on_close;
|
bool power_off_on_close;
|
||||||
bool clipboard_autosync;
|
bool clipboard_autosync;
|
||||||
|
bool downsize_on_error;
|
||||||
bool tcpip;
|
bool tcpip;
|
||||||
const char *tcpip_dst;
|
const char *tcpip_dst;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -36,14 +36,14 @@
|
|||||||
|
|
||||||
struct scrcpy {
|
struct scrcpy {
|
||||||
struct sc_server server;
|
struct sc_server server;
|
||||||
struct screen screen;
|
struct sc_screen screen;
|
||||||
struct stream stream;
|
struct stream stream;
|
||||||
struct decoder decoder;
|
struct decoder decoder;
|
||||||
struct recorder recorder;
|
struct recorder recorder;
|
||||||
#ifdef HAVE_V4L2
|
#ifdef HAVE_V4L2
|
||||||
struct sc_v4l2_sink v4l2_sink;
|
struct sc_v4l2_sink v4l2_sink;
|
||||||
#endif
|
#endif
|
||||||
struct controller controller;
|
struct sc_controller controller;
|
||||||
struct file_handler file_handler;
|
struct file_handler file_handler;
|
||||||
#ifdef HAVE_AOA_HID
|
#ifdef HAVE_AOA_HID
|
||||||
struct sc_aoa aoa;
|
struct sc_aoa aoa;
|
||||||
@@ -192,7 +192,7 @@ handle_event(struct scrcpy *s, const struct scrcpy_options *options,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool consumed = screen_handle_event(&s->screen, event);
|
bool consumed = sc_screen_handle_event(&s->screen, event);
|
||||||
(void) consumed;
|
(void) consumed;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
@@ -364,6 +364,7 @@ scrcpy(struct scrcpy_options *options) {
|
|||||||
.force_adb_forward = options->force_adb_forward,
|
.force_adb_forward = options->force_adb_forward,
|
||||||
.power_off_on_close = options->power_off_on_close,
|
.power_off_on_close = options->power_off_on_close,
|
||||||
.clipboard_autosync = options->clipboard_autosync,
|
.clipboard_autosync = options->clipboard_autosync,
|
||||||
|
.downsize_on_error = options->downsize_on_error,
|
||||||
.tcpip = options->tcpip,
|
.tcpip = options->tcpip,
|
||||||
.tcpip_dst = options->tcpip_dst,
|
.tcpip_dst = options->tcpip_dst,
|
||||||
};
|
};
|
||||||
@@ -535,7 +536,8 @@ aoa_hid_end:
|
|||||||
// keyboard_input_mode may have been reset if HID mode failed
|
// keyboard_input_mode may have been reset if HID mode failed
|
||||||
if (options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_INJECT) {
|
if (options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_INJECT) {
|
||||||
sc_keyboard_inject_init(&s->keyboard_inject, &s->controller,
|
sc_keyboard_inject_init(&s->keyboard_inject, &s->controller,
|
||||||
options);
|
options->key_inject_mode,
|
||||||
|
options->forward_key_repeat);
|
||||||
kp = &s->keyboard_inject.key_processor;
|
kp = &s->keyboard_inject.key_processor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,23 +547,23 @@ aoa_hid_end:
|
|||||||
mp = &s->mouse_inject.mouse_processor;
|
mp = &s->mouse_inject.mouse_processor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!controller_init(&s->controller, s->server.control_socket,
|
if (!sc_controller_init(&s->controller, s->server.control_socket,
|
||||||
acksync)) {
|
acksync)) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
controller_initialized = true;
|
controller_initialized = true;
|
||||||
|
|
||||||
if (!controller_start(&s->controller)) {
|
if (!sc_controller_start(&s->controller)) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
controller_started = true;
|
controller_started = true;
|
||||||
|
|
||||||
if (options->turn_screen_off) {
|
if (options->turn_screen_off) {
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;
|
msg.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;
|
||||||
msg.set_screen_power_mode.mode = SCREEN_POWER_MODE_OFF;
|
msg.set_screen_power_mode.mode = SCREEN_POWER_MODE_OFF;
|
||||||
|
|
||||||
if (!controller_push_msg(&s->controller, &msg)) {
|
if (!sc_controller_push_msg(&s->controller, &msg)) {
|
||||||
LOGW("Could not request 'set screen power mode'");
|
LOGW("Could not request 'set screen power mode'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -572,7 +574,7 @@ aoa_hid_end:
|
|||||||
const char *window_title =
|
const char *window_title =
|
||||||
options->window_title ? options->window_title : info->device_name;
|
options->window_title ? options->window_title : info->device_name;
|
||||||
|
|
||||||
struct screen_params screen_params = {
|
struct sc_screen_params screen_params = {
|
||||||
.controller = &s->controller,
|
.controller = &s->controller,
|
||||||
.kp = kp,
|
.kp = kp,
|
||||||
.mp = mp,
|
.mp = mp,
|
||||||
@@ -595,7 +597,7 @@ aoa_hid_end:
|
|||||||
.buffering_time = options->display_buffer,
|
.buffering_time = options->display_buffer,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!screen_init(&s->screen, &screen_params)) {
|
if (!sc_screen_init(&s->screen, &screen_params)) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
screen_initialized = true;
|
screen_initialized = true;
|
||||||
@@ -628,7 +630,7 @@ aoa_hid_end:
|
|||||||
|
|
||||||
// Close the window immediately on closing, because screen_destroy() may
|
// Close the window immediately on closing, because screen_destroy() may
|
||||||
// only be called once the stream thread is joined (it may take time)
|
// only be called once the stream thread is joined (it may take time)
|
||||||
screen_hide_window(&s->screen);
|
sc_screen_hide_window(&s->screen);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
// The stream is not stopped explicitly, because it will stop by itself on
|
// The stream is not stopped explicitly, because it will stop by itself on
|
||||||
@@ -645,13 +647,13 @@ end:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (controller_started) {
|
if (controller_started) {
|
||||||
controller_stop(&s->controller);
|
sc_controller_stop(&s->controller);
|
||||||
}
|
}
|
||||||
if (file_handler_initialized) {
|
if (file_handler_initialized) {
|
||||||
file_handler_stop(&s->file_handler);
|
file_handler_stop(&s->file_handler);
|
||||||
}
|
}
|
||||||
if (screen_initialized) {
|
if (screen_initialized) {
|
||||||
screen_interrupt(&s->screen);
|
sc_screen_interrupt(&s->screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server_started) {
|
if (server_started) {
|
||||||
@@ -681,15 +683,15 @@ end:
|
|||||||
// Destroy the screen only after the stream is guaranteed to be finished,
|
// Destroy the screen only after the stream is guaranteed to be finished,
|
||||||
// because otherwise the screen could receive new frames after destruction
|
// because otherwise the screen could receive new frames after destruction
|
||||||
if (screen_initialized) {
|
if (screen_initialized) {
|
||||||
screen_join(&s->screen);
|
sc_screen_join(&s->screen);
|
||||||
screen_destroy(&s->screen);
|
sc_screen_destroy(&s->screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controller_started) {
|
if (controller_started) {
|
||||||
controller_join(&s->controller);
|
sc_controller_join(&s->controller);
|
||||||
}
|
}
|
||||||
if (controller_initialized) {
|
if (controller_initialized) {
|
||||||
controller_destroy(&s->controller);
|
sc_controller_destroy(&s->controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recorder_initialized) {
|
if (recorder_initialized) {
|
||||||
|
|||||||
183
app/src/screen.c
183
app/src/screen.c
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#define DISPLAY_MARGINS 96
|
#define DISPLAY_MARGINS 96
|
||||||
|
|
||||||
#define DOWNCAST(SINK) container_of(SINK, struct screen, frame_sink)
|
#define DOWNCAST(SINK) container_of(SINK, struct sc_screen, frame_sink)
|
||||||
|
|
||||||
static inline struct sc_size
|
static inline struct sc_size
|
||||||
get_rotated_size(struct sc_size size, int rotation) {
|
get_rotated_size(struct sc_size size, int rotation) {
|
||||||
@@ -29,7 +29,7 @@ get_rotated_size(struct sc_size size, int rotation) {
|
|||||||
|
|
||||||
// get the window size in a struct sc_size
|
// get the window size in a struct sc_size
|
||||||
static struct sc_size
|
static struct sc_size
|
||||||
get_window_size(const struct screen *screen) {
|
get_window_size(const struct sc_screen *screen) {
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
SDL_GetWindowSize(screen->window, &width, &height);
|
SDL_GetWindowSize(screen->window, &width, &height);
|
||||||
@@ -41,7 +41,7 @@ get_window_size(const struct screen *screen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct sc_point
|
static struct sc_point
|
||||||
get_window_position(const struct screen *screen) {
|
get_window_position(const struct sc_screen *screen) {
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
SDL_GetWindowPosition(screen->window, &x, &y);
|
SDL_GetWindowPosition(screen->window, &x, &y);
|
||||||
@@ -54,7 +54,7 @@ get_window_position(const struct screen *screen) {
|
|||||||
|
|
||||||
// set the window size to be applied when fullscreen is disabled
|
// set the window size to be applied when fullscreen is disabled
|
||||||
static void
|
static void
|
||||||
set_window_size(struct screen *screen, struct sc_size new_size) {
|
set_window_size(struct sc_screen *screen, struct sc_size new_size) {
|
||||||
assert(!screen->fullscreen);
|
assert(!screen->fullscreen);
|
||||||
assert(!screen->maximized);
|
assert(!screen->maximized);
|
||||||
SDL_SetWindowSize(screen->window, new_size.width, new_size.height);
|
SDL_SetWindowSize(screen->window, new_size.width, new_size.height);
|
||||||
@@ -157,7 +157,7 @@ get_initial_optimal_size(struct sc_size content_size, uint16_t req_width,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
screen_capture_mouse(struct screen *screen, bool capture) {
|
sc_screen_capture_mouse(struct sc_screen *screen, bool capture) {
|
||||||
if (SDL_SetRelativeMouseMode(capture)) {
|
if (SDL_SetRelativeMouseMode(capture)) {
|
||||||
LOGE("Could not set relative mouse mode to %s: %s",
|
LOGE("Could not set relative mouse mode to %s: %s",
|
||||||
capture ? "true" : "false", SDL_GetError());
|
capture ? "true" : "false", SDL_GetError());
|
||||||
@@ -168,7 +168,7 @@ screen_capture_mouse(struct screen *screen, bool capture) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
screen_update_content_rect(struct screen *screen) {
|
sc_screen_update_content_rect(struct sc_screen *screen) {
|
||||||
int dw;
|
int dw;
|
||||||
int dh;
|
int dh;
|
||||||
SDL_GL_GetDrawableSize(screen->window, &dw, &dh);
|
SDL_GL_GetDrawableSize(screen->window, &dw, &dh);
|
||||||
@@ -205,7 +205,7 @@ screen_update_content_rect(struct screen *screen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline SDL_Texture *
|
static inline SDL_Texture *
|
||||||
create_texture(struct screen *screen) {
|
create_texture(struct sc_screen *screen) {
|
||||||
SDL_Renderer *renderer = screen->renderer;
|
SDL_Renderer *renderer = screen->renderer;
|
||||||
struct sc_size size = screen->frame_size;
|
struct sc_size size = screen->frame_size;
|
||||||
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12,
|
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12,
|
||||||
@@ -236,9 +236,9 @@ create_texture(struct screen *screen) {
|
|||||||
// Set the update_content_rect flag if the window or content size may have
|
// Set the update_content_rect flag if the window or content size may have
|
||||||
// changed, so that the content rectangle is recomputed
|
// changed, so that the content rectangle is recomputed
|
||||||
static void
|
static void
|
||||||
screen_render(struct screen *screen, bool update_content_rect) {
|
sc_screen_render(struct sc_screen *screen, bool update_content_rect) {
|
||||||
if (update_content_rect) {
|
if (update_content_rect) {
|
||||||
screen_update_content_rect(screen);
|
sc_screen_update_content_rect(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_RenderClear(screen->renderer);
|
SDL_RenderClear(screen->renderer);
|
||||||
@@ -282,20 +282,20 @@ screen_render(struct screen *screen, bool update_content_rect) {
|
|||||||
// <https://stackoverflow.com/a/40693139/1987178>
|
// <https://stackoverflow.com/a/40693139/1987178>
|
||||||
static int
|
static int
|
||||||
event_watcher(void *data, SDL_Event *event) {
|
event_watcher(void *data, SDL_Event *event) {
|
||||||
struct screen *screen = data;
|
struct sc_screen *screen = data;
|
||||||
if (event->type == SDL_WINDOWEVENT
|
if (event->type == SDL_WINDOWEVENT
|
||||||
&& event->window.event == SDL_WINDOWEVENT_RESIZED) {
|
&& event->window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||||
// In practice, it seems to always be called from the same thread in
|
// In practice, it seems to always be called from the same thread in
|
||||||
// that specific case. Anyway, it's just a workaround.
|
// that specific case. Anyway, it's just a workaround.
|
||||||
screen_render(screen, true);
|
sc_screen_render(screen, true);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
screen_frame_sink_open(struct sc_frame_sink *sink) {
|
sc_screen_frame_sink_open(struct sc_frame_sink *sink) {
|
||||||
struct screen *screen = DOWNCAST(sink);
|
struct sc_screen *screen = DOWNCAST(sink);
|
||||||
(void) screen;
|
(void) screen;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
screen->open = true;
|
screen->open = true;
|
||||||
@@ -306,8 +306,8 @@ screen_frame_sink_open(struct sc_frame_sink *sink) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
screen_frame_sink_close(struct sc_frame_sink *sink) {
|
sc_screen_frame_sink_close(struct sc_frame_sink *sink) {
|
||||||
struct screen *screen = DOWNCAST(sink);
|
struct sc_screen *screen = DOWNCAST(sink);
|
||||||
(void) screen;
|
(void) screen;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
screen->open = false;
|
screen->open = false;
|
||||||
@@ -317,8 +317,8 @@ screen_frame_sink_close(struct sc_frame_sink *sink) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
screen_frame_sink_push(struct sc_frame_sink *sink, const AVFrame *frame) {
|
sc_screen_frame_sink_push(struct sc_frame_sink *sink, const AVFrame *frame) {
|
||||||
struct screen *screen = DOWNCAST(sink);
|
struct sc_screen *screen = DOWNCAST(sink);
|
||||||
return sc_video_buffer_push(&screen->vb, frame);
|
return sc_video_buffer_push(&screen->vb, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +326,7 @@ static void
|
|||||||
sc_video_buffer_on_new_frame(struct sc_video_buffer *vb, bool previous_skipped,
|
sc_video_buffer_on_new_frame(struct sc_video_buffer *vb, bool previous_skipped,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
(void) vb;
|
(void) vb;
|
||||||
struct screen *screen = userdata;
|
struct sc_screen *screen = userdata;
|
||||||
|
|
||||||
// event_failed implies previous_skipped (the previous frame may not have
|
// event_failed implies previous_skipped (the previous frame may not have
|
||||||
// been consumed if the event was not sent)
|
// been consumed if the event was not sent)
|
||||||
@@ -359,7 +359,8 @@ sc_video_buffer_on_new_frame(struct sc_video_buffer *vb, bool previous_skipped,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
screen_init(struct screen *screen, const struct screen_params *params) {
|
sc_screen_init(struct sc_screen *screen,
|
||||||
|
const struct sc_screen_params *params) {
|
||||||
screen->resize_pending = false;
|
screen->resize_pending = false;
|
||||||
screen->has_frame = false;
|
screen->has_frame = false;
|
||||||
screen->fullscreen = false;
|
screen->fullscreen = false;
|
||||||
@@ -368,6 +369,12 @@ screen_init(struct screen *screen, const struct screen_params *params) {
|
|||||||
screen->mouse_captured = false;
|
screen->mouse_captured = false;
|
||||||
screen->mouse_capture_key_pressed = 0;
|
screen->mouse_capture_key_pressed = 0;
|
||||||
|
|
||||||
|
screen->req.x = params->window_x;
|
||||||
|
screen->req.y = params->window_y;
|
||||||
|
screen->req.width = params->window_width;
|
||||||
|
screen->req.height = params->window_height;
|
||||||
|
screen->req.fullscreen = params->fullscreen;
|
||||||
|
|
||||||
static const struct sc_video_buffer_callbacks cbs = {
|
static const struct sc_video_buffer_callbacks cbs = {
|
||||||
.on_new_frame = sc_video_buffer_on_new_frame,
|
.on_new_frame = sc_video_buffer_on_new_frame,
|
||||||
};
|
};
|
||||||
@@ -396,9 +403,6 @@ screen_init(struct screen *screen, const struct screen_params *params) {
|
|||||||
get_rotated_size(screen->frame_size, screen->rotation);
|
get_rotated_size(screen->frame_size, screen->rotation);
|
||||||
screen->content_size = content_size;
|
screen->content_size = content_size;
|
||||||
|
|
||||||
struct sc_size window_size =
|
|
||||||
get_initial_optimal_size(content_size,params->window_width,
|
|
||||||
params->window_height);
|
|
||||||
uint32_t window_flags = SDL_WINDOW_HIDDEN
|
uint32_t window_flags = SDL_WINDOW_HIDDEN
|
||||||
| SDL_WINDOW_RESIZABLE
|
| SDL_WINDOW_RESIZABLE
|
||||||
| SDL_WINDOW_ALLOW_HIGHDPI;
|
| SDL_WINDOW_ALLOW_HIGHDPI;
|
||||||
@@ -409,13 +413,9 @@ screen_init(struct screen *screen, const struct screen_params *params) {
|
|||||||
window_flags |= SDL_WINDOW_BORDERLESS;
|
window_flags |= SDL_WINDOW_BORDERLESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int x = params->window_x != SC_WINDOW_POSITION_UNDEFINED
|
// The window will be positioned and sized on first video frame
|
||||||
? params->window_x : (int) SDL_WINDOWPOS_UNDEFINED;
|
screen->window =
|
||||||
int y = params->window_y != SC_WINDOW_POSITION_UNDEFINED
|
SDL_CreateWindow(params->window_title, 0, 0, 0, 0, window_flags);
|
||||||
? params->window_y : (int) SDL_WINDOWPOS_UNDEFINED;
|
|
||||||
screen->window = SDL_CreateWindow(params->window_title, x, y,
|
|
||||||
window_size.width, window_size.height,
|
|
||||||
window_flags);
|
|
||||||
if (!screen->window) {
|
if (!screen->window) {
|
||||||
LOGC("Could not create window: %s", SDL_GetError());
|
LOGC("Could not create window: %s", SDL_GetError());
|
||||||
goto error_destroy_fps_counter;
|
goto error_destroy_fps_counter;
|
||||||
@@ -483,7 +483,7 @@ screen_init(struct screen *screen, const struct screen_params *params) {
|
|||||||
goto error_destroy_texture;
|
goto error_destroy_texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct input_manager_params im_params = {
|
struct sc_input_manager_params im_params = {
|
||||||
.controller = params->controller,
|
.controller = params->controller,
|
||||||
.screen = screen,
|
.screen = screen,
|
||||||
.kp = params->kp,
|
.kp = params->kp,
|
||||||
@@ -495,27 +495,16 @@ screen_init(struct screen *screen, const struct screen_params *params) {
|
|||||||
.shortcut_mods = params->shortcut_mods,
|
.shortcut_mods = params->shortcut_mods,
|
||||||
};
|
};
|
||||||
|
|
||||||
input_manager_init(&screen->im, &im_params);
|
sc_input_manager_init(&screen->im, &im_params);
|
||||||
|
|
||||||
// Reset the window size to trigger a SIZE_CHANGED event, to workaround
|
|
||||||
// HiDPI issues with some SDL renderers when several displays having
|
|
||||||
// different HiDPI scaling are connected
|
|
||||||
SDL_SetWindowSize(screen->window, window_size.width, window_size.height);
|
|
||||||
|
|
||||||
screen_update_content_rect(screen);
|
|
||||||
|
|
||||||
if (params->fullscreen) {
|
|
||||||
screen_switch_fullscreen(screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONTINUOUS_RESIZING_WORKAROUND
|
#ifdef CONTINUOUS_RESIZING_WORKAROUND
|
||||||
SDL_AddEventWatch(event_watcher, screen);
|
SDL_AddEventWatch(event_watcher, screen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const struct sc_frame_sink_ops ops = {
|
static const struct sc_frame_sink_ops ops = {
|
||||||
.open = screen_frame_sink_open,
|
.open = sc_screen_frame_sink_open,
|
||||||
.close = screen_frame_sink_close,
|
.close = sc_screen_frame_sink_close,
|
||||||
.push = screen_frame_sink_push,
|
.push = sc_screen_frame_sink_push,
|
||||||
};
|
};
|
||||||
|
|
||||||
screen->frame_sink.ops = &ops;
|
screen->frame_sink.ops = &ops;
|
||||||
@@ -544,29 +533,45 @@ error_destroy_video_buffer:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
screen_show_window(struct screen *screen) {
|
sc_screen_show_initial_window(struct sc_screen *screen) {
|
||||||
|
int x = screen->req.x != SC_WINDOW_POSITION_UNDEFINED
|
||||||
|
? screen->req.x : (int) SDL_WINDOWPOS_CENTERED;
|
||||||
|
int y = screen->req.y != SC_WINDOW_POSITION_UNDEFINED
|
||||||
|
? screen->req.y : (int) SDL_WINDOWPOS_CENTERED;
|
||||||
|
|
||||||
|
struct sc_size window_size =
|
||||||
|
get_initial_optimal_size(screen->content_size, screen->req.width,
|
||||||
|
screen->req.height);
|
||||||
|
|
||||||
|
set_window_size(screen, window_size);
|
||||||
|
SDL_SetWindowPosition(screen->window, x, y);
|
||||||
|
|
||||||
|
if (screen->req.fullscreen) {
|
||||||
|
sc_screen_switch_fullscreen(screen);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_ShowWindow(screen->window);
|
SDL_ShowWindow(screen->window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_hide_window(struct screen *screen) {
|
sc_screen_hide_window(struct sc_screen *screen) {
|
||||||
SDL_HideWindow(screen->window);
|
SDL_HideWindow(screen->window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_interrupt(struct screen *screen) {
|
sc_screen_interrupt(struct sc_screen *screen) {
|
||||||
sc_video_buffer_stop(&screen->vb);
|
sc_video_buffer_stop(&screen->vb);
|
||||||
fps_counter_interrupt(&screen->fps_counter);
|
fps_counter_interrupt(&screen->fps_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_join(struct screen *screen) {
|
sc_screen_join(struct sc_screen *screen) {
|
||||||
sc_video_buffer_join(&screen->vb);
|
sc_video_buffer_join(&screen->vb);
|
||||||
fps_counter_join(&screen->fps_counter);
|
fps_counter_join(&screen->fps_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_destroy(struct screen *screen) {
|
sc_screen_destroy(struct sc_screen *screen) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
assert(!screen->open);
|
assert(!screen->open);
|
||||||
#endif
|
#endif
|
||||||
@@ -579,7 +584,7 @@ screen_destroy(struct screen *screen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
resize_for_content(struct screen *screen, struct sc_size old_content_size,
|
resize_for_content(struct sc_screen *screen, struct sc_size old_content_size,
|
||||||
struct sc_size new_content_size) {
|
struct sc_size new_content_size) {
|
||||||
struct sc_size window_size = get_window_size(screen);
|
struct sc_size window_size = get_window_size(screen);
|
||||||
struct sc_size target_size = {
|
struct sc_size target_size = {
|
||||||
@@ -593,7 +598,7 @@ resize_for_content(struct screen *screen, struct sc_size old_content_size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_content_size(struct screen *screen, struct sc_size new_content_size) {
|
set_content_size(struct sc_screen *screen, struct sc_size new_content_size) {
|
||||||
if (!screen->fullscreen && !screen->maximized) {
|
if (!screen->fullscreen && !screen->maximized) {
|
||||||
resize_for_content(screen, screen->content_size, new_content_size);
|
resize_for_content(screen, screen->content_size, new_content_size);
|
||||||
} else if (!screen->resize_pending) {
|
} else if (!screen->resize_pending) {
|
||||||
@@ -607,7 +612,7 @@ set_content_size(struct screen *screen, struct sc_size new_content_size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
apply_pending_resize(struct screen *screen) {
|
apply_pending_resize(struct sc_screen *screen) {
|
||||||
assert(!screen->fullscreen);
|
assert(!screen->fullscreen);
|
||||||
assert(!screen->maximized);
|
assert(!screen->maximized);
|
||||||
if (screen->resize_pending) {
|
if (screen->resize_pending) {
|
||||||
@@ -618,7 +623,7 @@ apply_pending_resize(struct screen *screen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_set_rotation(struct screen *screen, unsigned rotation) {
|
sc_screen_set_rotation(struct sc_screen *screen, unsigned rotation) {
|
||||||
assert(rotation < 4);
|
assert(rotation < 4);
|
||||||
if (rotation == screen->rotation) {
|
if (rotation == screen->rotation) {
|
||||||
return;
|
return;
|
||||||
@@ -632,12 +637,12 @@ screen_set_rotation(struct screen *screen, unsigned rotation) {
|
|||||||
screen->rotation = rotation;
|
screen->rotation = rotation;
|
||||||
LOGI("Display rotation set to %u", rotation);
|
LOGI("Display rotation set to %u", rotation);
|
||||||
|
|
||||||
screen_render(screen, true);
|
sc_screen_render(screen, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// recreate the texture and resize the window if the frame size has changed
|
// recreate the texture and resize the window if the frame size has changed
|
||||||
static bool
|
static bool
|
||||||
prepare_for_frame(struct screen *screen, struct sc_size new_frame_size) {
|
prepare_for_frame(struct sc_screen *screen, struct sc_size new_frame_size) {
|
||||||
if (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) {
|
|| screen->frame_size.height != new_frame_size.height) {
|
||||||
// frame dimension changed, destroy texture
|
// frame dimension changed, destroy texture
|
||||||
@@ -649,7 +654,7 @@ prepare_for_frame(struct screen *screen, struct sc_size new_frame_size) {
|
|||||||
get_rotated_size(new_frame_size, screen->rotation);
|
get_rotated_size(new_frame_size, screen->rotation);
|
||||||
set_content_size(screen, new_content_size);
|
set_content_size(screen, new_content_size);
|
||||||
|
|
||||||
screen_update_content_rect(screen);
|
sc_screen_update_content_rect(screen);
|
||||||
|
|
||||||
LOGI("New texture: %" PRIu16 "x%" PRIu16,
|
LOGI("New texture: %" PRIu16 "x%" PRIu16,
|
||||||
screen->frame_size.width, screen->frame_size.height);
|
screen->frame_size.width, screen->frame_size.height);
|
||||||
@@ -665,7 +670,7 @@ prepare_for_frame(struct screen *screen, struct sc_size new_frame_size) {
|
|||||||
|
|
||||||
// write the frame into the texture
|
// write the frame into the texture
|
||||||
static void
|
static void
|
||||||
update_texture(struct screen *screen, const AVFrame *frame) {
|
update_texture(struct sc_screen *screen, const AVFrame *frame) {
|
||||||
SDL_UpdateYUVTexture(screen->texture, NULL,
|
SDL_UpdateYUVTexture(screen->texture, NULL,
|
||||||
frame->data[0], frame->linesize[0],
|
frame->data[0], frame->linesize[0],
|
||||||
frame->data[1], frame->linesize[1],
|
frame->data[1], frame->linesize[1],
|
||||||
@@ -679,7 +684,7 @@ update_texture(struct screen *screen, const AVFrame *frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
screen_update_frame(struct screen *screen) {
|
sc_screen_update_frame(struct sc_screen *screen) {
|
||||||
av_frame_unref(screen->frame);
|
av_frame_unref(screen->frame);
|
||||||
sc_video_buffer_consume(&screen->vb, screen->frame);
|
sc_video_buffer_consume(&screen->vb, screen->frame);
|
||||||
AVFrame *frame = screen->frame;
|
AVFrame *frame = screen->frame;
|
||||||
@@ -692,12 +697,18 @@ screen_update_frame(struct screen *screen) {
|
|||||||
}
|
}
|
||||||
update_texture(screen, frame);
|
update_texture(screen, frame);
|
||||||
|
|
||||||
screen_render(screen, false);
|
if (!screen->has_frame) {
|
||||||
|
screen->has_frame = true;
|
||||||
|
// this is the very first frame, show the window
|
||||||
|
sc_screen_show_initial_window(screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc_screen_render(screen, false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_switch_fullscreen(struct screen *screen) {
|
sc_screen_switch_fullscreen(struct sc_screen *screen) {
|
||||||
uint32_t new_mode = screen->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP;
|
uint32_t new_mode = screen->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||||
if (SDL_SetWindowFullscreen(screen->window, new_mode)) {
|
if (SDL_SetWindowFullscreen(screen->window, new_mode)) {
|
||||||
LOGW("Could not switch fullscreen mode: %s", SDL_GetError());
|
LOGW("Could not switch fullscreen mode: %s", SDL_GetError());
|
||||||
@@ -710,11 +721,11 @@ screen_switch_fullscreen(struct screen *screen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOGD("Switched to %s mode", screen->fullscreen ? "fullscreen" : "windowed");
|
LOGD("Switched to %s mode", screen->fullscreen ? "fullscreen" : "windowed");
|
||||||
screen_render(screen, true);
|
sc_screen_render(screen, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_resize_to_fit(struct screen *screen) {
|
sc_screen_resize_to_fit(struct sc_screen *screen) {
|
||||||
if (screen->fullscreen || screen->maximized) {
|
if (screen->fullscreen || screen->maximized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -738,7 +749,7 @@ screen_resize_to_fit(struct screen *screen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_resize_to_pixel_perfect(struct screen *screen) {
|
sc_screen_resize_to_pixel_perfect(struct sc_screen *screen) {
|
||||||
if (screen->fullscreen) {
|
if (screen->fullscreen) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -755,24 +766,20 @@ screen_resize_to_pixel_perfect(struct screen *screen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
screen_is_mouse_capture_key(SDL_Keycode key) {
|
sc_screen_is_mouse_capture_key(SDL_Keycode key) {
|
||||||
return key == SDLK_LALT || key == SDLK_LGUI || key == SDLK_RGUI;
|
return key == SDLK_LALT || key == SDLK_LGUI || key == SDLK_RGUI;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
screen_handle_event(struct screen *screen, SDL_Event *event) {
|
sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event) {
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case EVENT_NEW_FRAME:
|
case EVENT_NEW_FRAME: {
|
||||||
if (!screen->has_frame) {
|
bool ok = sc_screen_update_frame(screen);
|
||||||
screen->has_frame = true;
|
|
||||||
// this is the very first frame, show the window
|
|
||||||
screen_show_window(screen);
|
|
||||||
}
|
|
||||||
bool ok = screen_update_frame(screen);
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGW("Frame update failed\n");
|
LOGW("Frame update failed\n");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_WINDOWEVENT:
|
||||||
if (!screen->has_frame) {
|
if (!screen->has_frame) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
@@ -780,10 +787,10 @@ screen_handle_event(struct screen *screen, SDL_Event *event) {
|
|||||||
}
|
}
|
||||||
switch (event->window.event) {
|
switch (event->window.event) {
|
||||||
case SDL_WINDOWEVENT_EXPOSED:
|
case SDL_WINDOWEVENT_EXPOSED:
|
||||||
screen_render(screen, true);
|
sc_screen_render(screen, true);
|
||||||
break;
|
break;
|
||||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||||
screen_render(screen, true);
|
sc_screen_render(screen, true);
|
||||||
break;
|
break;
|
||||||
case SDL_WINDOWEVENT_MAXIMIZED:
|
case SDL_WINDOWEVENT_MAXIMIZED:
|
||||||
screen->maximized = true;
|
screen->maximized = true;
|
||||||
@@ -799,11 +806,11 @@ screen_handle_event(struct screen *screen, SDL_Event *event) {
|
|||||||
}
|
}
|
||||||
screen->maximized = false;
|
screen->maximized = false;
|
||||||
apply_pending_resize(screen);
|
apply_pending_resize(screen);
|
||||||
screen_render(screen, true);
|
sc_screen_render(screen, true);
|
||||||
break;
|
break;
|
||||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||||
if (screen->im.mp->relative_mode) {
|
if (screen->im.mp->relative_mode) {
|
||||||
screen_capture_mouse(screen, false);
|
sc_screen_capture_mouse(screen, false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -811,7 +818,7 @@ screen_handle_event(struct screen *screen, SDL_Event *event) {
|
|||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
if (screen->im.mp->relative_mode) {
|
if (screen->im.mp->relative_mode) {
|
||||||
SDL_Keycode key = event->key.keysym.sym;
|
SDL_Keycode key = event->key.keysym.sym;
|
||||||
if (screen_is_mouse_capture_key(key)) {
|
if (sc_screen_is_mouse_capture_key(key)) {
|
||||||
if (!screen->mouse_capture_key_pressed) {
|
if (!screen->mouse_capture_key_pressed) {
|
||||||
screen->mouse_capture_key_pressed = key;
|
screen->mouse_capture_key_pressed = key;
|
||||||
return true;
|
return true;
|
||||||
@@ -833,7 +840,7 @@ screen_handle_event(struct screen *screen, SDL_Event *event) {
|
|||||||
if (key == cap) {
|
if (key == cap) {
|
||||||
// A mouse capture key has been pressed then released:
|
// A mouse capture key has been pressed then released:
|
||||||
// toggle the capture mouse mode
|
// toggle the capture mouse mode
|
||||||
screen_capture_mouse(screen, !screen->mouse_captured);
|
sc_screen_capture_mouse(screen, !screen->mouse_captured);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Do not return, the event must be forwarded to the input
|
// Do not return, the event must be forwarded to the input
|
||||||
@@ -860,17 +867,17 @@ screen_handle_event(struct screen *screen, SDL_Event *event) {
|
|||||||
break;
|
break;
|
||||||
case SDL_MOUSEBUTTONUP:
|
case SDL_MOUSEBUTTONUP:
|
||||||
if (screen->im.mp->relative_mode && !screen->mouse_captured) {
|
if (screen->im.mp->relative_mode && !screen->mouse_captured) {
|
||||||
screen_capture_mouse(screen, true);
|
sc_screen_capture_mouse(screen, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return input_manager_handle_event(&screen->im, event);
|
return sc_input_manager_handle_event(&screen->im, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sc_point
|
struct sc_point
|
||||||
screen_convert_drawable_to_frame_coords(struct screen *screen,
|
sc_screen_convert_drawable_to_frame_coords(struct sc_screen *screen,
|
||||||
int32_t x, int32_t y) {
|
int32_t x, int32_t y) {
|
||||||
unsigned rotation = screen->rotation;
|
unsigned rotation = screen->rotation;
|
||||||
assert(rotation < 4);
|
assert(rotation < 4);
|
||||||
|
|
||||||
@@ -906,14 +913,14 @@ screen_convert_drawable_to_frame_coords(struct screen *screen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct sc_point
|
struct sc_point
|
||||||
screen_convert_window_to_frame_coords(struct screen *screen,
|
sc_screen_convert_window_to_frame_coords(struct sc_screen *screen,
|
||||||
int32_t x, int32_t y) {
|
int32_t x, int32_t y) {
|
||||||
screen_hidpi_scale_coords(screen, &x, &y);
|
sc_screen_hidpi_scale_coords(screen, &x, &y);
|
||||||
return screen_convert_drawable_to_frame_coords(screen, x, y);
|
return sc_screen_convert_drawable_to_frame_coords(screen, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_hidpi_scale_coords(struct screen *screen, int32_t *x, int32_t *y) {
|
sc_screen_hidpi_scale_coords(struct sc_screen *screen, int32_t *x, int32_t *y) {
|
||||||
// take the HiDPI scaling (dw/ww and dh/wh) into account
|
// take the HiDPI scaling (dw/ww and dh/wh) into account
|
||||||
int ww, wh, dw, dh;
|
int ww, wh, dw, dh;
|
||||||
SDL_GetWindowSize(screen->window, &ww, &wh);
|
SDL_GetWindowSize(screen->window, &ww, &wh);
|
||||||
|
|||||||
@@ -17,17 +17,26 @@
|
|||||||
#include "trait/mouse_processor.h"
|
#include "trait/mouse_processor.h"
|
||||||
#include "video_buffer.h"
|
#include "video_buffer.h"
|
||||||
|
|
||||||
struct screen {
|
struct sc_screen {
|
||||||
struct sc_frame_sink frame_sink; // frame sink trait
|
struct sc_frame_sink frame_sink; // frame sink trait
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
bool open; // track the open/close state to assert correct behavior
|
bool open; // track the open/close state to assert correct behavior
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct input_manager im;
|
struct sc_input_manager im;
|
||||||
struct sc_video_buffer vb;
|
struct sc_video_buffer vb;
|
||||||
struct fps_counter fps_counter;
|
struct fps_counter fps_counter;
|
||||||
|
|
||||||
|
// The initial requested window properties
|
||||||
|
struct {
|
||||||
|
int16_t x;
|
||||||
|
int16_t y;
|
||||||
|
uint16_t width;
|
||||||
|
uint16_t height;
|
||||||
|
bool fullscreen;
|
||||||
|
} req;
|
||||||
|
|
||||||
SDL_Window *window;
|
SDL_Window *window;
|
||||||
SDL_Renderer *renderer;
|
SDL_Renderer *renderer;
|
||||||
SDL_Texture *texture;
|
SDL_Texture *texture;
|
||||||
@@ -59,8 +68,8 @@ struct screen {
|
|||||||
AVFrame *frame;
|
AVFrame *frame;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct screen_params {
|
struct sc_screen_params {
|
||||||
struct controller *controller;
|
struct sc_controller *controller;
|
||||||
struct sc_key_processor *kp;
|
struct sc_key_processor *kp;
|
||||||
struct sc_mouse_processor *mp;
|
struct sc_mouse_processor *mp;
|
||||||
|
|
||||||
@@ -74,10 +83,10 @@ struct screen_params {
|
|||||||
struct sc_size frame_size;
|
struct sc_size frame_size;
|
||||||
bool always_on_top;
|
bool always_on_top;
|
||||||
|
|
||||||
int16_t window_x;
|
int16_t window_x; // accepts SC_WINDOW_POSITION_UNDEFINED
|
||||||
int16_t window_y;
|
int16_t window_y; // accepts SC_WINDOW_POSITION_UNDEFINED
|
||||||
uint16_t window_width; // accepts SC_WINDOW_POSITION_UNDEFINED
|
uint16_t window_width;
|
||||||
uint16_t window_height; // accepts SC_WINDOW_POSITION_UNDEFINED
|
uint16_t window_height;
|
||||||
|
|
||||||
bool window_borderless;
|
bool window_borderless;
|
||||||
|
|
||||||
@@ -91,65 +100,65 @@ struct screen_params {
|
|||||||
|
|
||||||
// initialize screen, create window, renderer and texture (window is hidden)
|
// initialize screen, create window, renderer and texture (window is hidden)
|
||||||
bool
|
bool
|
||||||
screen_init(struct screen *screen, const struct screen_params *params);
|
sc_screen_init(struct sc_screen *screen, const struct sc_screen_params *params);
|
||||||
|
|
||||||
// request to interrupt any inner thread
|
// request to interrupt any inner thread
|
||||||
// must be called before screen_join()
|
// must be called before screen_join()
|
||||||
void
|
void
|
||||||
screen_interrupt(struct screen *screen);
|
sc_screen_interrupt(struct sc_screen *screen);
|
||||||
|
|
||||||
// join any inner thread
|
// join any inner thread
|
||||||
void
|
void
|
||||||
screen_join(struct screen *screen);
|
sc_screen_join(struct sc_screen *screen);
|
||||||
|
|
||||||
// destroy window, renderer and texture (if any)
|
// destroy window, renderer and texture (if any)
|
||||||
void
|
void
|
||||||
screen_destroy(struct screen *screen);
|
sc_screen_destroy(struct sc_screen *screen);
|
||||||
|
|
||||||
// hide the window
|
// hide the window
|
||||||
//
|
//
|
||||||
// It is used to hide the window immediately on closing without waiting for
|
// It is used to hide the window immediately on closing without waiting for
|
||||||
// screen_destroy()
|
// screen_destroy()
|
||||||
void
|
void
|
||||||
screen_hide_window(struct screen *screen);
|
sc_screen_hide_window(struct sc_screen *screen);
|
||||||
|
|
||||||
// switch the fullscreen mode
|
// switch the fullscreen mode
|
||||||
void
|
void
|
||||||
screen_switch_fullscreen(struct screen *screen);
|
sc_screen_switch_fullscreen(struct sc_screen *screen);
|
||||||
|
|
||||||
// resize window to optimal size (remove black borders)
|
// resize window to optimal size (remove black borders)
|
||||||
void
|
void
|
||||||
screen_resize_to_fit(struct screen *screen);
|
sc_screen_resize_to_fit(struct sc_screen *screen);
|
||||||
|
|
||||||
// resize window to 1:1 (pixel-perfect)
|
// resize window to 1:1 (pixel-perfect)
|
||||||
void
|
void
|
||||||
screen_resize_to_pixel_perfect(struct screen *screen);
|
sc_screen_resize_to_pixel_perfect(struct sc_screen *screen);
|
||||||
|
|
||||||
// set the display rotation (0, 1, 2 or 3, x90 degrees counterclockwise)
|
// set the display rotation (0, 1, 2 or 3, x90 degrees counterclockwise)
|
||||||
void
|
void
|
||||||
screen_set_rotation(struct screen *screen, unsigned rotation);
|
sc_screen_set_rotation(struct sc_screen *screen, unsigned rotation);
|
||||||
|
|
||||||
// react to SDL events
|
// react to SDL events
|
||||||
bool
|
bool
|
||||||
screen_handle_event(struct screen *screen, SDL_Event *event);
|
sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event);
|
||||||
|
|
||||||
// convert point from window coordinates to frame coordinates
|
// convert point from window coordinates to frame coordinates
|
||||||
// x and y are expressed in pixels
|
// x and y are expressed in pixels
|
||||||
struct sc_point
|
struct sc_point
|
||||||
screen_convert_window_to_frame_coords(struct screen *screen,
|
sc_screen_convert_window_to_frame_coords(struct sc_screen *screen,
|
||||||
int32_t x, int32_t y);
|
int32_t x, int32_t y);
|
||||||
|
|
||||||
// convert point from drawable coordinates to frame coordinates
|
// convert point from drawable coordinates to frame coordinates
|
||||||
// x and y are expressed in pixels
|
// x and y are expressed in pixels
|
||||||
struct sc_point
|
struct sc_point
|
||||||
screen_convert_drawable_to_frame_coords(struct screen *screen,
|
sc_screen_convert_drawable_to_frame_coords(struct sc_screen *screen,
|
||||||
int32_t x, int32_t y);
|
int32_t x, int32_t y);
|
||||||
|
|
||||||
// Convert coordinates from window to drawable.
|
// Convert coordinates from window to drawable.
|
||||||
// Events are expressed in window coordinates, but content is expressed in
|
// Events are expressed in window coordinates, but content is expressed in
|
||||||
// drawable coordinates. They are the same if HiDPI scaling is 1, but differ
|
// drawable coordinates. They are the same if HiDPI scaling is 1, but differ
|
||||||
// otherwise.
|
// otherwise.
|
||||||
void
|
void
|
||||||
screen_hidpi_scale_coords(struct screen *screen, int32_t *x, int32_t *y);
|
sc_screen_hidpi_scale_coords(struct sc_screen *screen, int32_t *x, int32_t *y);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -188,7 +188,6 @@ execute_server(struct sc_server *server,
|
|||||||
} \
|
} \
|
||||||
cmd[count++] = p; \
|
cmd[count++] = p; \
|
||||||
}
|
}
|
||||||
#define STRBOOL(v) (v ? "true" : "false")
|
|
||||||
|
|
||||||
ADD_PARAM("log_level=%s", log_level_to_server_string(params->log_level));
|
ADD_PARAM("log_level=%s", log_level_to_server_string(params->log_level));
|
||||||
ADD_PARAM("bit_rate=%" PRIu32, params->bit_rate);
|
ADD_PARAM("bit_rate=%" PRIu32, params->bit_rate);
|
||||||
@@ -204,23 +203,23 @@ execute_server(struct sc_server *server,
|
|||||||
params->lock_video_orientation);
|
params->lock_video_orientation);
|
||||||
}
|
}
|
||||||
if (server->tunnel.forward) {
|
if (server->tunnel.forward) {
|
||||||
ADD_PARAM("tunnel_forward=%s", STRBOOL(server->tunnel.forward));
|
ADD_PARAM("tunnel_forward=true");
|
||||||
}
|
}
|
||||||
if (params->crop) {
|
if (params->crop) {
|
||||||
ADD_PARAM("crop=%s", params->crop);
|
ADD_PARAM("crop=%s", params->crop);
|
||||||
}
|
}
|
||||||
if (!params->control) {
|
if (!params->control) {
|
||||||
// By default, control is true
|
// By default, control is true
|
||||||
ADD_PARAM("control=%s", STRBOOL(params->control));
|
ADD_PARAM("control=false");
|
||||||
}
|
}
|
||||||
if (params->display_id) {
|
if (params->display_id) {
|
||||||
ADD_PARAM("display_id=%" PRIu32, params->display_id);
|
ADD_PARAM("display_id=%" PRIu32, params->display_id);
|
||||||
}
|
}
|
||||||
if (params->show_touches) {
|
if (params->show_touches) {
|
||||||
ADD_PARAM("show_touches=%s", STRBOOL(params->show_touches));
|
ADD_PARAM("show_touches=true");
|
||||||
}
|
}
|
||||||
if (params->stay_awake) {
|
if (params->stay_awake) {
|
||||||
ADD_PARAM("stay_awake=%s", STRBOOL(params->stay_awake));
|
ADD_PARAM("stay_awake=true");
|
||||||
}
|
}
|
||||||
if (params->codec_options) {
|
if (params->codec_options) {
|
||||||
ADD_PARAM("codec_options=%s", params->codec_options);
|
ADD_PARAM("codec_options=%s", params->codec_options);
|
||||||
@@ -229,11 +228,15 @@ execute_server(struct sc_server *server,
|
|||||||
ADD_PARAM("encoder_name=%s", params->encoder_name);
|
ADD_PARAM("encoder_name=%s", params->encoder_name);
|
||||||
}
|
}
|
||||||
if (params->power_off_on_close) {
|
if (params->power_off_on_close) {
|
||||||
ADD_PARAM("power_off_on_close=%s", STRBOOL(params->power_off_on_close));
|
ADD_PARAM("power_off_on_close=true");
|
||||||
}
|
}
|
||||||
if (!params->clipboard_autosync) {
|
if (!params->clipboard_autosync) {
|
||||||
// By default, clipboard_autosync is true
|
// By default, clipboard_autosync is true
|
||||||
ADD_PARAM("clipboard_autosync=%s", STRBOOL(params->clipboard_autosync));
|
ADD_PARAM("clipboard_autosync=false");
|
||||||
|
}
|
||||||
|
if (!params->downsize_on_error) {
|
||||||
|
// By default, downsize_on_error is true
|
||||||
|
ADD_PARAM("downsize_on_error=false");
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef ADD_PARAM
|
#undef ADD_PARAM
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ struct sc_server_params {
|
|||||||
bool force_adb_forward;
|
bool force_adb_forward;
|
||||||
bool power_off_on_close;
|
bool power_off_on_close;
|
||||||
bool clipboard_autosync;
|
bool clipboard_autosync;
|
||||||
|
bool downsize_on_error;
|
||||||
bool tcpip;
|
bool tcpip;
|
||||||
const char *tcpip_dst;
|
const char *tcpip_dst;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <libavformat/avformat.h>
|
|
||||||
#include <libavutil/time.h>
|
#include <libavutil/time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@@ -192,7 +191,7 @@ static int
|
|||||||
run_stream(void *data) {
|
run_stream(void *data) {
|
||||||
struct stream *stream = data;
|
struct stream *stream = data;
|
||||||
|
|
||||||
AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
||||||
if (!codec) {
|
if (!codec) {
|
||||||
LOGE("H.264 decoder not found");
|
LOGE("H.264 decoder not found");
|
||||||
goto end;
|
goto end;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
|
|
||||||
#include "trait/packet_sink.h"
|
#include "trait/packet_sink.h"
|
||||||
|
|||||||
@@ -3,13 +3,14 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
|
||||||
#include "coords.h"
|
#include "coords.h"
|
||||||
#include "trait/frame_sink.h"
|
#include "trait/frame_sink.h"
|
||||||
#include "video_buffer.h"
|
#include "video_buffer.h"
|
||||||
#include "util/tick.h"
|
#include "util/tick.h"
|
||||||
|
|
||||||
#include <libavformat/avformat.h>
|
|
||||||
|
|
||||||
struct sc_v4l2_sink {
|
struct sc_v4l2_sink {
|
||||||
struct sc_frame_sink frame_sink; // frame sink trait
|
struct sc_frame_sink frame_sink; // frame sink trait
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "control_msg.h"
|
#include "control_msg.h"
|
||||||
|
|
||||||
static void test_serialize_inject_keycode(void) {
|
static void test_serialize_inject_keycode(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_INJECT_KEYCODE,
|
.type = CONTROL_MSG_TYPE_INJECT_KEYCODE,
|
||||||
.inject_keycode = {
|
.inject_keycode = {
|
||||||
.action = AKEY_EVENT_ACTION_UP,
|
.action = AKEY_EVENT_ACTION_UP,
|
||||||
@@ -17,7 +17,7 @@ static void test_serialize_inject_keycode(void) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 14);
|
assert(size == 14);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
@@ -31,7 +31,7 @@ static void test_serialize_inject_keycode(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_inject_text(void) {
|
static void test_serialize_inject_text(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_INJECT_TEXT,
|
.type = CONTROL_MSG_TYPE_INJECT_TEXT,
|
||||||
.inject_text = {
|
.inject_text = {
|
||||||
.text = "hello, world!",
|
.text = "hello, world!",
|
||||||
@@ -39,7 +39,7 @@ static void test_serialize_inject_text(void) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 18);
|
assert(size == 18);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
@@ -51,7 +51,7 @@ static void test_serialize_inject_text(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_inject_text_long(void) {
|
static void test_serialize_inject_text_long(void) {
|
||||||
struct control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
|
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
|
||||||
char text[CONTROL_MSG_INJECT_TEXT_MAX_LENGTH + 1];
|
char text[CONTROL_MSG_INJECT_TEXT_MAX_LENGTH + 1];
|
||||||
memset(text, 'a', CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
|
memset(text, 'a', CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
|
||||||
@@ -59,7 +59,7 @@ static void test_serialize_inject_text_long(void) {
|
|||||||
msg.inject_text.text = text;
|
msg.inject_text.text = text;
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 5 + CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
|
assert(size == 5 + CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
|
||||||
|
|
||||||
unsigned char expected[5 + CONTROL_MSG_INJECT_TEXT_MAX_LENGTH];
|
unsigned char expected[5 + CONTROL_MSG_INJECT_TEXT_MAX_LENGTH];
|
||||||
@@ -74,7 +74,7 @@ static void test_serialize_inject_text_long(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_inject_touch_event(void) {
|
static void test_serialize_inject_touch_event(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||||
.inject_touch_event = {
|
.inject_touch_event = {
|
||||||
.action = AMOTION_EVENT_ACTION_DOWN,
|
.action = AMOTION_EVENT_ACTION_DOWN,
|
||||||
@@ -95,7 +95,7 @@ static void test_serialize_inject_touch_event(void) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 28);
|
assert(size == 28);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
@@ -111,7 +111,7 @@ static void test_serialize_inject_touch_event(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_inject_scroll_event(void) {
|
static void test_serialize_inject_scroll_event(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
.type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
||||||
.inject_scroll_event = {
|
.inject_scroll_event = {
|
||||||
.position = {
|
.position = {
|
||||||
@@ -131,7 +131,7 @@ static void test_serialize_inject_scroll_event(void) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 25);
|
assert(size == 25);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
@@ -146,7 +146,7 @@ static void test_serialize_inject_scroll_event(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_back_or_screen_on(void) {
|
static void test_serialize_back_or_screen_on(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
||||||
.back_or_screen_on = {
|
.back_or_screen_on = {
|
||||||
.action = AKEY_EVENT_ACTION_UP,
|
.action = AKEY_EVENT_ACTION_UP,
|
||||||
@@ -154,7 +154,7 @@ static void test_serialize_back_or_screen_on(void) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 2);
|
assert(size == 2);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
@@ -165,12 +165,12 @@ static void test_serialize_back_or_screen_on(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_expand_notification_panel(void) {
|
static void test_serialize_expand_notification_panel(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
|
.type = CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 1);
|
assert(size == 1);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
@@ -180,12 +180,12 @@ static void test_serialize_expand_notification_panel(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_expand_settings_panel(void) {
|
static void test_serialize_expand_settings_panel(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
.type = CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 1);
|
assert(size == 1);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
@@ -195,12 +195,12 @@ static void test_serialize_expand_settings_panel(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_collapse_panels(void) {
|
static void test_serialize_collapse_panels(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
.type = CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 1);
|
assert(size == 1);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
@@ -210,7 +210,7 @@ static void test_serialize_collapse_panels(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_get_clipboard(void) {
|
static void test_serialize_get_clipboard(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
.type = CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
||||||
.get_clipboard = {
|
.get_clipboard = {
|
||||||
.copy_key = GET_CLIPBOARD_COPY_KEY_COPY,
|
.copy_key = GET_CLIPBOARD_COPY_KEY_COPY,
|
||||||
@@ -218,7 +218,7 @@ static void test_serialize_get_clipboard(void) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 2);
|
assert(size == 2);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
@@ -229,7 +229,7 @@ static void test_serialize_get_clipboard(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_set_clipboard(void) {
|
static void test_serialize_set_clipboard(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
.type = CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||||
.set_clipboard = {
|
.set_clipboard = {
|
||||||
.sequence = UINT64_C(0x0102030405060708),
|
.sequence = UINT64_C(0x0102030405060708),
|
||||||
@@ -239,7 +239,7 @@ static void test_serialize_set_clipboard(void) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 27);
|
assert(size == 27);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
@@ -253,7 +253,7 @@ static void test_serialize_set_clipboard(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_set_clipboard_long(void) {
|
static void test_serialize_set_clipboard_long(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
.type = CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||||
.set_clipboard = {
|
.set_clipboard = {
|
||||||
.sequence = UINT64_C(0x0102030405060708),
|
.sequence = UINT64_C(0x0102030405060708),
|
||||||
@@ -268,7 +268,7 @@ static void test_serialize_set_clipboard_long(void) {
|
|||||||
msg.set_clipboard.text = text;
|
msg.set_clipboard.text = text;
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == CONTROL_MSG_MAX_SIZE);
|
assert(size == CONTROL_MSG_MAX_SIZE);
|
||||||
|
|
||||||
unsigned char expected[CONTROL_MSG_MAX_SIZE] = {
|
unsigned char expected[CONTROL_MSG_MAX_SIZE] = {
|
||||||
@@ -287,7 +287,7 @@ static void test_serialize_set_clipboard_long(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_set_screen_power_mode(void) {
|
static void test_serialize_set_screen_power_mode(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
||||||
.set_screen_power_mode = {
|
.set_screen_power_mode = {
|
||||||
.mode = SCREEN_POWER_MODE_NORMAL,
|
.mode = SCREEN_POWER_MODE_NORMAL,
|
||||||
@@ -295,7 +295,7 @@ static void test_serialize_set_screen_power_mode(void) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 2);
|
assert(size == 2);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
@@ -306,12 +306,12 @@ static void test_serialize_set_screen_power_mode(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_rotate_device(void) {
|
static void test_serialize_rotate_device(void) {
|
||||||
struct control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_ROTATE_DEVICE,
|
.type = CONTROL_MSG_TYPE_ROTATE_DEVICE,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 1);
|
assert(size == 1);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ cpu = 'i686'
|
|||||||
endian = 'little'
|
endian = 'little'
|
||||||
|
|
||||||
[properties]
|
[properties]
|
||||||
prebuilt_ffmpeg_shared = 'ffmpeg-4.3.1-win32-shared'
|
ffmpeg_avcodec = 'avcodec-58'
|
||||||
prebuilt_ffmpeg_dev = 'ffmpeg-4.3.1-win32-dev'
|
ffmpeg_avformat = 'avformat-58'
|
||||||
|
ffmpeg_avutil = 'avutil-56'
|
||||||
|
prebuilt_ffmpeg = 'ffmpeg-4.3.1-win32-shared'
|
||||||
prebuilt_sdl2 = 'SDL2-2.0.18/i686-w64-mingw32'
|
prebuilt_sdl2 = 'SDL2-2.0.18/i686-w64-mingw32'
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ cpu = 'x86_64'
|
|||||||
endian = 'little'
|
endian = 'little'
|
||||||
|
|
||||||
[properties]
|
[properties]
|
||||||
prebuilt_ffmpeg_shared = 'ffmpeg-4.3.1-win64-shared'
|
ffmpeg_avcodec = 'avcodec-59'
|
||||||
prebuilt_ffmpeg_dev = 'ffmpeg-4.3.1-win64-dev'
|
ffmpeg_avformat = 'avformat-59'
|
||||||
|
ffmpeg_avutil = 'avutil-57'
|
||||||
|
prebuilt_ffmpeg = 'ffmpeg-5.0-full_build-shared'
|
||||||
prebuilt_sdl2 = 'SDL2-2.0.18/x86_64-w64-mingw32'
|
prebuilt_sdl2 = 'SDL2-2.0.18/x86_64-w64-mingw32'
|
||||||
|
|||||||
@@ -1,33 +1,26 @@
|
|||||||
.PHONY: prepare-win32 prepare-win64 \
|
.PHONY: prepare-win32 prepare-win64 \
|
||||||
prepare-ffmpeg-shared-win32 \
|
prepare-ffmpeg-win32 \
|
||||||
prepare-ffmpeg-dev-win32 \
|
prepare-ffmpeg-win64 \
|
||||||
prepare-ffmpeg-shared-win64 \
|
|
||||||
prepare-ffmpeg-dev-win64 \
|
|
||||||
prepare-sdl2 \
|
prepare-sdl2 \
|
||||||
prepare-adb
|
prepare-adb
|
||||||
|
|
||||||
prepare-win32: prepare-sdl2 prepare-ffmpeg-shared-win32 prepare-ffmpeg-dev-win32 prepare-adb
|
prepare-win32: prepare-sdl2 prepare-ffmpeg-win32 prepare-adb
|
||||||
prepare-win64: prepare-sdl2 prepare-ffmpeg-shared-win64 prepare-ffmpeg-dev-win64 prepare-adb
|
prepare-win64: prepare-sdl2 prepare-ffmpeg-win64 prepare-adb
|
||||||
|
|
||||||
prepare-ffmpeg-shared-win32:
|
# Use old FFmpeg version for win32, there are no new prebuilts
|
||||||
|
prepare-ffmpeg-win32:
|
||||||
@./prepare-dep https://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win32-shared.zip \
|
@./prepare-dep https://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win32-shared.zip \
|
||||||
357af9901a456f4dcbacd107e83a934d344c9cb07ddad8aaf80612eeab7d26d2 \
|
357af9901a456f4dcbacd107e83a934d344c9cb07ddad8aaf80612eeab7d26d2 \
|
||||||
ffmpeg-4.3.1-win32-shared
|
ffmpeg-4.3.1-win32-shared
|
||||||
|
|
||||||
prepare-ffmpeg-dev-win32:
|
|
||||||
@./prepare-dep https://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win32-dev.zip \
|
@./prepare-dep https://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win32-dev.zip \
|
||||||
230efb08e9bcf225bd474da29676c70e591fc94d8790a740ca801408fddcb78b \
|
230efb08e9bcf225bd474da29676c70e591fc94d8790a740ca801408fddcb78b \
|
||||||
ffmpeg-4.3.1-win32-dev
|
ffmpeg-4.3.1-win32-dev
|
||||||
|
ln -sf ../ffmpeg-4.3.1-win32-dev/include ffmpeg-4.3.1-win32-shared/
|
||||||
|
|
||||||
prepare-ffmpeg-shared-win64:
|
prepare-ffmpeg-win64:
|
||||||
@./prepare-dep https://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win64-shared.zip \
|
@./prepare-dep https://github.com/GyanD/codexffmpeg/releases/download/5.0/ffmpeg-5.0-full_build-shared.7z \
|
||||||
dd29b7f92f48dead4dd940492c7509138c0f99db445076d0a597007298a79940 \
|
e5900f6cecd4c438d398bd2fc308736c10b857cd8dd61c11bcfb05bff5d1211a \
|
||||||
ffmpeg-4.3.1-win64-shared
|
ffmpeg-5.0-full_build-shared
|
||||||
|
|
||||||
prepare-ffmpeg-dev-win64:
|
|
||||||
@./prepare-dep https://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win64-dev.zip \
|
|
||||||
2e8038242cf8e1bd095c2978f196ff0462b122cc6ef7e74626a6af15459d8b81 \
|
|
||||||
ffmpeg-4.3.1-win64-dev
|
|
||||||
|
|
||||||
prepare-sdl2:
|
prepare-sdl2:
|
||||||
@./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.18-mingw.tar.gz \
|
@./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.18-mingw.tar.gz \
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ extract() {
|
|||||||
elif [[ "$file" == *.tar.gz ]]
|
elif [[ "$file" == *.tar.gz ]]
|
||||||
then
|
then
|
||||||
tar xf "$file"
|
tar xf "$file"
|
||||||
|
elif [[ "$file" == *.7z ]]
|
||||||
|
then
|
||||||
|
7z x "$file"
|
||||||
else
|
else
|
||||||
echo "Unsupported file: $file"
|
echo "Unsupported file: $file"
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
10
release.mk
10
release.mk
@@ -110,11 +110,11 @@ dist-win64: build-server build-win64
|
|||||||
cp data/scrcpy-console.bat "$(DIST)/$(WIN64_TARGET_DIR)"
|
cp data/scrcpy-console.bat "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||||
cp data/scrcpy-noconsole.vbs "$(DIST)/$(WIN64_TARGET_DIR)"
|
cp data/scrcpy-noconsole.vbs "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||||
cp data/icon.png "$(DIST)/$(WIN64_TARGET_DIR)"
|
cp data/icon.png "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win64-shared/bin/avutil-56.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-5.0-full_build-shared/bin/avutil-57.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win64-shared/bin/avcodec-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-5.0-full_build-shared/bin/avcodec-59.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win64-shared/bin/avformat-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-5.0-full_build-shared/bin/avformat-59.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win64-shared/bin/swresample-3.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-5.0-full_build-shared/bin/swresample-4.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win64-shared/bin/swscale-5.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-5.0-full_build-shared/bin/swscale-6.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ public final class Device {
|
|||||||
void onClipboardTextChanged(String text);
|
void onClipboardTextChanged(String text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final Size deviceSize;
|
||||||
|
private final Rect crop;
|
||||||
|
private int maxSize;
|
||||||
|
private final int lockVideoOrientation;
|
||||||
|
|
||||||
private ScreenInfo screenInfo;
|
private ScreenInfo screenInfo;
|
||||||
private RotationListener rotationListener;
|
private RotationListener rotationListener;
|
||||||
private ClipboardListener clipboardListener;
|
private ClipboardListener clipboardListener;
|
||||||
@@ -69,7 +74,12 @@ public final class Device {
|
|||||||
|
|
||||||
int displayInfoFlags = displayInfo.getFlags();
|
int displayInfoFlags = displayInfo.getFlags();
|
||||||
|
|
||||||
screenInfo = ScreenInfo.computeScreenInfo(displayInfo, options.getCrop(), options.getMaxSize(), options.getLockVideoOrientation());
|
deviceSize = displayInfo.getSize();
|
||||||
|
crop = options.getCrop();
|
||||||
|
maxSize = options.getMaxSize();
|
||||||
|
lockVideoOrientation = options.getLockVideoOrientation();
|
||||||
|
|
||||||
|
screenInfo = ScreenInfo.computeScreenInfo(displayInfo.getRotation(), deviceSize, crop, maxSize, lockVideoOrientation);
|
||||||
layerStack = displayInfo.getLayerStack();
|
layerStack = displayInfo.getLayerStack();
|
||||||
|
|
||||||
SERVICE_MANAGER.getWindowManager().registerRotationWatcher(new IRotationWatcher.Stub() {
|
SERVICE_MANAGER.getWindowManager().registerRotationWatcher(new IRotationWatcher.Stub() {
|
||||||
@@ -123,6 +133,11 @@ public final class Device {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void setMaxSize(int newMaxSize) {
|
||||||
|
maxSize = newMaxSize;
|
||||||
|
screenInfo = ScreenInfo.computeScreenInfo(screenInfo.getReverseVideoRotation(), deviceSize, crop, newMaxSize, lockVideoOrientation);
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized ScreenInfo getScreenInfo() {
|
public synchronized ScreenInfo getScreenInfo() {
|
||||||
return screenInfo;
|
return screenInfo;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ public class Options {
|
|||||||
private String encoderName;
|
private String encoderName;
|
||||||
private boolean powerOffScreenOnClose;
|
private boolean powerOffScreenOnClose;
|
||||||
private boolean clipboardAutosync = true;
|
private boolean clipboardAutosync = true;
|
||||||
|
private boolean downsizeOnError = true;
|
||||||
|
|
||||||
public Ln.Level getLogLevel() {
|
public Ln.Level getLogLevel() {
|
||||||
return logLevel;
|
return logLevel;
|
||||||
@@ -149,4 +150,12 @@ public class Options {
|
|||||||
public void setClipboardAutosync(boolean clipboardAutosync) {
|
public void setClipboardAutosync(boolean clipboardAutosync) {
|
||||||
this.clipboardAutosync = clipboardAutosync;
|
this.clipboardAutosync = clipboardAutosync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getDownsizeOnError() {
|
||||||
|
return downsizeOnError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDownsizeOnError(boolean downsizeOnError) {
|
||||||
|
this.downsizeOnError = downsizeOnError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,24 +25,32 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||||||
private static final int REPEAT_FRAME_DELAY_US = 100_000; // repeat after 100ms
|
private static final int REPEAT_FRAME_DELAY_US = 100_000; // repeat after 100ms
|
||||||
private static final String KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder";
|
private static final String KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder";
|
||||||
|
|
||||||
|
// Keep the values in descending order
|
||||||
|
private static final int[] MAX_SIZE_FALLBACK = {2560, 1920, 1600, 1280, 1024, 800};
|
||||||
|
|
||||||
private static final int NO_PTS = -1;
|
private static final int NO_PTS = -1;
|
||||||
|
|
||||||
private final AtomicBoolean rotationChanged = new AtomicBoolean();
|
private final AtomicBoolean rotationChanged = new AtomicBoolean();
|
||||||
private final ByteBuffer headerBuffer = ByteBuffer.allocate(12);
|
private final ByteBuffer headerBuffer = ByteBuffer.allocate(12);
|
||||||
|
|
||||||
private String encoderName;
|
private final String encoderName;
|
||||||
private List<CodecOption> codecOptions;
|
private final List<CodecOption> codecOptions;
|
||||||
private int bitRate;
|
private final int bitRate;
|
||||||
private int maxFps;
|
private final int maxFps;
|
||||||
private boolean sendFrameMeta;
|
private final boolean sendFrameMeta;
|
||||||
|
private final boolean downsizeOnError;
|
||||||
private long ptsOrigin;
|
private long ptsOrigin;
|
||||||
|
|
||||||
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, List<CodecOption> codecOptions, String encoderName) {
|
private boolean firstFrameSent;
|
||||||
|
|
||||||
|
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, List<CodecOption> codecOptions, String encoderName,
|
||||||
|
boolean downsizeOnError) {
|
||||||
this.sendFrameMeta = sendFrameMeta;
|
this.sendFrameMeta = sendFrameMeta;
|
||||||
this.bitRate = bitRate;
|
this.bitRate = bitRate;
|
||||||
this.maxFps = maxFps;
|
this.maxFps = maxFps;
|
||||||
this.codecOptions = codecOptions;
|
this.codecOptions = codecOptions;
|
||||||
this.encoderName = encoderName;
|
this.encoderName = encoderName;
|
||||||
|
this.downsizeOnError = downsizeOnError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -91,6 +99,23 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||||||
alive = encode(codec, fd);
|
alive = encode(codec, fd);
|
||||||
// do not call stop() on exception, it would trigger an IllegalStateException
|
// do not call stop() on exception, it would trigger an IllegalStateException
|
||||||
codec.stop();
|
codec.stop();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Ln.e("Encoding error: " + e.getClass().getName() + ": " + e.getMessage());
|
||||||
|
if (!downsizeOnError || firstFrameSent) {
|
||||||
|
// Fail immediately
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
int newMaxSize = chooseMaxSizeFallback(screenInfo.getVideoSize());
|
||||||
|
if (newMaxSize == 0) {
|
||||||
|
// Definitively fail
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry with a smaller device size
|
||||||
|
Ln.i("Retrying with -m" + newMaxSize + "...");
|
||||||
|
device.setMaxSize(newMaxSize);
|
||||||
|
alive = true;
|
||||||
} finally {
|
} finally {
|
||||||
destroyDisplay(display);
|
destroyDisplay(display);
|
||||||
codec.release();
|
codec.release();
|
||||||
@@ -102,6 +127,18 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int chooseMaxSizeFallback(Size failedSize) {
|
||||||
|
int currentMaxSize = Math.max(failedSize.getWidth(), failedSize.getHeight());
|
||||||
|
for (int value : MAX_SIZE_FALLBACK) {
|
||||||
|
if (value < currentMaxSize) {
|
||||||
|
// We found a smaller value to reduce the video size
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No fallback, fail definitively
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean encode(MediaCodec codec, FileDescriptor fd) throws IOException {
|
private boolean encode(MediaCodec codec, FileDescriptor fd) throws IOException {
|
||||||
boolean eof = false;
|
boolean eof = false;
|
||||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||||
@@ -122,6 +159,7 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IO.writeFully(fd, codecBuffer);
|
IO.writeFully(fd, codecBuffer);
|
||||||
|
firstFrameSent = true;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (outputBufferId >= 0) {
|
if (outputBufferId >= 0) {
|
||||||
|
|||||||
@@ -80,15 +80,12 @@ public final class ScreenInfo {
|
|||||||
return new ScreenInfo(newContentRect, newUnlockedVideoSize, newDeviceRotation, lockedVideoOrientation);
|
return new ScreenInfo(newContentRect, newUnlockedVideoSize, newDeviceRotation, lockedVideoOrientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ScreenInfo computeScreenInfo(DisplayInfo displayInfo, Rect crop, int maxSize, int lockedVideoOrientation) {
|
public static ScreenInfo computeScreenInfo(int rotation, Size deviceSize, Rect crop, int maxSize, int lockedVideoOrientation) {
|
||||||
int rotation = displayInfo.getRotation();
|
|
||||||
|
|
||||||
if (lockedVideoOrientation == Device.LOCK_VIDEO_ORIENTATION_INITIAL) {
|
if (lockedVideoOrientation == Device.LOCK_VIDEO_ORIENTATION_INITIAL) {
|
||||||
// The user requested to lock the video orientation to the current orientation
|
// The user requested to lock the video orientation to the current orientation
|
||||||
lockedVideoOrientation = rotation;
|
lockedVideoOrientation = rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
Size deviceSize = displayInfo.getSize();
|
|
||||||
Rect contentRect = new Rect(0, 0, deviceSize.getWidth(), deviceSize.getHeight());
|
Rect contentRect = new Rect(0, 0, deviceSize.getWidth(), deviceSize.getHeight());
|
||||||
if (crop != null) {
|
if (crop != null) {
|
||||||
if (rotation % 2 != 0) { // 180s preserve dimensions
|
if (rotation % 2 != 0) { // 180s preserve dimensions
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.genymobile.scrcpy;
|
package com.genymobile.scrcpy;
|
||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.media.MediaCodec;
|
|
||||||
import android.media.MediaCodecInfo;
|
import android.media.MediaCodecInfo;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@@ -70,7 +69,7 @@ public final class Server {
|
|||||||
|
|
||||||
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward, control)) {
|
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward, control)) {
|
||||||
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions,
|
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions,
|
||||||
options.getEncoderName());
|
options.getEncoderName(), options.getDownsizeOnError());
|
||||||
|
|
||||||
Thread controllerThread = null;
|
Thread controllerThread = null;
|
||||||
Thread deviceMessageSenderThread = null;
|
Thread deviceMessageSenderThread = null;
|
||||||
@@ -237,6 +236,10 @@ public final class Server {
|
|||||||
boolean clipboardAutosync = Boolean.parseBoolean(value);
|
boolean clipboardAutosync = Boolean.parseBoolean(value);
|
||||||
options.setClipboardAutosync(clipboardAutosync);
|
options.setClipboardAutosync(clipboardAutosync);
|
||||||
break;
|
break;
|
||||||
|
case "downsize_on_error":
|
||||||
|
boolean downsizeOnError = Boolean.parseBoolean(value);
|
||||||
|
options.setDownsizeOnError(downsizeOnError);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Ln.w("Unknown server option: " + key);
|
Ln.w("Unknown server option: " + key);
|
||||||
break;
|
break;
|
||||||
@@ -263,16 +266,6 @@ public final class Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void suggestFix(Throwable e) {
|
private static void suggestFix(Throwable e) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
if (e instanceof MediaCodec.CodecException) {
|
|
||||||
MediaCodec.CodecException mce = (MediaCodec.CodecException) e;
|
|
||||||
if (mce.getErrorCode() == 0xfffffc0e) {
|
|
||||||
Ln.e("The hardware encoder is not able to encode at the given definition.");
|
|
||||||
Ln.e("Try with a lower definition:");
|
|
||||||
Ln.e(" scrcpy -m 1024");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (e instanceof InvalidDisplayIdException) {
|
if (e instanceof InvalidDisplayIdException) {
|
||||||
InvalidDisplayIdException idie = (InvalidDisplayIdException) e;
|
InvalidDisplayIdException idie = (InvalidDisplayIdException) e;
|
||||||
int[] displayIds = idie.getAvailableDisplayIds();
|
int[] displayIds = idie.getAvailableDisplayIds();
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public final class InputManager {
|
|||||||
|
|
||||||
private final IInterface manager;
|
private final IInterface manager;
|
||||||
private Method injectInputEventMethod;
|
private Method injectInputEventMethod;
|
||||||
|
private boolean alternativeInjectInputEventMethod;
|
||||||
|
|
||||||
private static Method setDisplayIdMethod;
|
private static Method setDisplayIdMethod;
|
||||||
|
|
||||||
@@ -25,7 +26,12 @@ public final class InputManager {
|
|||||||
|
|
||||||
private Method getInjectInputEventMethod() throws NoSuchMethodException {
|
private Method getInjectInputEventMethod() throws NoSuchMethodException {
|
||||||
if (injectInputEventMethod == null) {
|
if (injectInputEventMethod == null) {
|
||||||
injectInputEventMethod = manager.getClass().getMethod("injectInputEvent", InputEvent.class, int.class);
|
try {
|
||||||
|
injectInputEventMethod = manager.getClass().getMethod("injectInputEvent", InputEvent.class, int.class);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
injectInputEventMethod = manager.getClass().getMethod("injectInputEvent", InputEvent.class, int.class, int.class);
|
||||||
|
alternativeInjectInputEventMethod = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return injectInputEventMethod;
|
return injectInputEventMethod;
|
||||||
}
|
}
|
||||||
@@ -33,6 +39,10 @@ public final class InputManager {
|
|||||||
public boolean injectInputEvent(InputEvent inputEvent, int mode) {
|
public boolean injectInputEvent(InputEvent inputEvent, int mode) {
|
||||||
try {
|
try {
|
||||||
Method method = getInjectInputEventMethod();
|
Method method = getInjectInputEventMethod();
|
||||||
|
if (alternativeInjectInputEventMethod) {
|
||||||
|
// See <https://github.com/Genymobile/scrcpy/issues/2250>
|
||||||
|
return (boolean) method.invoke(manager, inputEvent, mode, 0);
|
||||||
|
}
|
||||||
return (boolean) method.invoke(manager, inputEvent, mode);
|
return (boolean) method.invoke(manager, inputEvent, mode);
|
||||||
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||||
Ln.e("Could not invoke method", e);
|
Ln.e("Could not invoke method", e);
|
||||||
|
|||||||
Reference in New Issue
Block a user