Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30714aba34 | ||
|
|
a973757fd1 | ||
|
|
deea29f52a | ||
|
|
5fa46ad0c7 | ||
|
|
334964c380 | ||
|
|
f7d4b6d0db | ||
|
|
e8a565f9ea | ||
|
|
3c1ed5d86c | ||
|
|
0ba74fbd9a | ||
|
|
29e5af76d4 |
@@ -3,10 +3,11 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "recorder.h"
|
#include "scrcpy.h"
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "util/str_util.h"
|
#include "util/str_util.h"
|
||||||
|
|
||||||
@@ -382,10 +383,10 @@ parse_rotation(const char *s, uint8_t *rotation) {
|
|||||||
static bool
|
static bool
|
||||||
parse_window_position(const char *s, int16_t *position) {
|
parse_window_position(const char *s, int16_t *position) {
|
||||||
// special value for "auto"
|
// special value for "auto"
|
||||||
static_assert(WINDOW_POSITION_UNDEFINED == -0x8000, "unexpected value");
|
static_assert(SC_WINDOW_POSITION_UNDEFINED == -0x8000, "unexpected value");
|
||||||
|
|
||||||
if (!strcmp(s, "auto")) {
|
if (!strcmp(s, "auto")) {
|
||||||
*position = WINDOW_POSITION_UNDEFINED;
|
*position = SC_WINDOW_POSITION_UNDEFINED;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,7 +415,7 @@ parse_window_dimension(const char *s, uint16_t *dimension) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
parse_port_range(const char *s, struct port_range *port_range) {
|
parse_port_range(const char *s, struct sc_port_range *port_range) {
|
||||||
long values[2];
|
long values[2];
|
||||||
size_t count = parse_integers_arg(s, 2, values, 0, 0xFFFF, "port");
|
size_t count = parse_integers_arg(s, 2, values, 0, 0xFFFF, "port");
|
||||||
if (!count) {
|
if (!count) {
|
||||||
@@ -480,20 +481,20 @@ parse_log_level(const char *s, enum sc_log_level *log_level) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
parse_record_format(const char *optarg, enum recorder_format *format) {
|
parse_record_format(const char *optarg, enum sc_record_format *format) {
|
||||||
if (!strcmp(optarg, "mp4")) {
|
if (!strcmp(optarg, "mp4")) {
|
||||||
*format = RECORDER_FORMAT_MP4;
|
*format = SC_RECORD_FORMAT_MP4;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!strcmp(optarg, "mkv")) {
|
if (!strcmp(optarg, "mkv")) {
|
||||||
*format = RECORDER_FORMAT_MKV;
|
*format = SC_RECORD_FORMAT_MKV;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
LOGE("Unsupported format: %s (expected mp4 or mkv)", optarg);
|
LOGE("Unsupported format: %s (expected mp4 or mkv)", optarg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum recorder_format
|
static enum sc_record_format
|
||||||
guess_record_format(const char *filename) {
|
guess_record_format(const char *filename) {
|
||||||
size_t len = strlen(filename);
|
size_t len = strlen(filename);
|
||||||
if (len < 4) {
|
if (len < 4) {
|
||||||
@@ -501,10 +502,10 @@ guess_record_format(const char *filename) {
|
|||||||
}
|
}
|
||||||
const char *ext = &filename[len - 4];
|
const char *ext = &filename[len - 4];
|
||||||
if (!strcmp(ext, ".mp4")) {
|
if (!strcmp(ext, ".mp4")) {
|
||||||
return RECORDER_FORMAT_MP4;
|
return SC_RECORD_FORMAT_MP4;
|
||||||
}
|
}
|
||||||
if (!strcmp(ext, ".mkv")) {
|
if (!strcmp(ext, ".mkv")) {
|
||||||
return RECORDER_FORMAT_MKV;
|
return SC_RECORD_FORMAT_MKV;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -434,7 +434,7 @@ convert_mouse_motion(const SDL_MouseMotionEvent *from, struct screen *screen,
|
|||||||
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
|
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
|
||||||
to->inject_touch_event.position.screen_size = screen->frame_size;
|
to->inject_touch_event.position.screen_size = screen->frame_size;
|
||||||
to->inject_touch_event.position.point =
|
to->inject_touch_event.position.point =
|
||||||
screen_convert_to_frame_coords(screen, from->x, from->y);
|
screen_convert_window_to_frame_coords(screen, from->x, from->y);
|
||||||
to->inject_touch_event.pressure = 1.f;
|
to->inject_touch_event.pressure = 1.f;
|
||||||
to->inject_touch_event.buttons = convert_mouse_buttons(from->state);
|
to->inject_touch_event.buttons = convert_mouse_buttons(from->state);
|
||||||
|
|
||||||
@@ -472,15 +472,15 @@ convert_touch(const SDL_TouchFingerEvent *from, struct screen *screen,
|
|||||||
to->inject_touch_event.pointer_id = from->fingerId;
|
to->inject_touch_event.pointer_id = from->fingerId;
|
||||||
to->inject_touch_event.position.screen_size = screen->frame_size;
|
to->inject_touch_event.position.screen_size = screen->frame_size;
|
||||||
|
|
||||||
int ww;
|
int dw;
|
||||||
int wh;
|
int dh;
|
||||||
SDL_GL_GetDrawableSize(screen->window, &ww, &wh);
|
SDL_GL_GetDrawableSize(screen->window, &dw, &dh);
|
||||||
|
|
||||||
// SDL touch event coordinates are normalized in the range [0; 1]
|
// SDL touch event coordinates are normalized in the range [0; 1]
|
||||||
int32_t x = from->x * ww;
|
int32_t x = from->x * dw;
|
||||||
int32_t y = from->y * wh;
|
int32_t y = from->y * dh;
|
||||||
to->inject_touch_event.position.point =
|
to->inject_touch_event.position.point =
|
||||||
screen_convert_to_frame_coords(screen, x, y);
|
screen_convert_drawable_to_frame_coords(screen, x, y);
|
||||||
|
|
||||||
to->inject_touch_event.pressure = from->pressure;
|
to->inject_touch_event.pressure = from->pressure;
|
||||||
to->inject_touch_event.buttons = 0;
|
to->inject_touch_event.buttons = 0;
|
||||||
@@ -510,8 +510,9 @@ convert_mouse_button(const SDL_MouseButtonEvent *from, struct screen *screen,
|
|||||||
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
|
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
|
||||||
to->inject_touch_event.position.screen_size = screen->frame_size;
|
to->inject_touch_event.position.screen_size = screen->frame_size;
|
||||||
to->inject_touch_event.position.point =
|
to->inject_touch_event.position.point =
|
||||||
screen_convert_to_frame_coords(screen, from->x, from->y);
|
screen_convert_window_to_frame_coords(screen, from->x, from->y);
|
||||||
to->inject_touch_event.pressure = 1.f;
|
to->inject_touch_event.pressure =
|
||||||
|
from->type == SDL_MOUSEBUTTONDOWN ? 1.f : 0.f;
|
||||||
to->inject_touch_event.buttons =
|
to->inject_touch_event.buttons =
|
||||||
convert_mouse_buttons(SDL_BUTTON(from->button));
|
convert_mouse_buttons(SDL_BUTTON(from->button));
|
||||||
|
|
||||||
@@ -575,7 +576,8 @@ convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct screen *screen,
|
|||||||
|
|
||||||
struct position position = {
|
struct position position = {
|
||||||
.screen_size = screen->frame_size,
|
.screen_size = screen->frame_size,
|
||||||
.point = screen_convert_to_frame_coords(screen, mouse_x, mouse_y),
|
.point = screen_convert_window_to_frame_coords(screen,
|
||||||
|
mouse_x, mouse_y),
|
||||||
};
|
};
|
||||||
|
|
||||||
to->type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT;
|
to->type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "scrcpy.h"
|
#include "scrcpy.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ recorder_queue_clear(struct recorder_queue *queue) {
|
|||||||
bool
|
bool
|
||||||
recorder_init(struct recorder *recorder,
|
recorder_init(struct recorder *recorder,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
enum recorder_format format,
|
enum sc_record_format format,
|
||||||
struct size declared_frame_size) {
|
struct size declared_frame_size) {
|
||||||
recorder->filename = SDL_strdup(filename);
|
recorder->filename = SDL_strdup(filename);
|
||||||
if (!recorder->filename) {
|
if (!recorder->filename) {
|
||||||
@@ -105,10 +105,10 @@ recorder_destroy(struct recorder *recorder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
recorder_get_format_name(enum recorder_format format) {
|
recorder_get_format_name(enum sc_record_format format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case RECORDER_FORMAT_MP4: return "mp4";
|
case SC_RECORD_FORMAT_MP4: return "mp4";
|
||||||
case RECORDER_FORMAT_MKV: return "matroska";
|
case SC_RECORD_FORMAT_MKV: return "matroska";
|
||||||
default: return NULL;
|
default: return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,9 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "scrcpy.h"
|
||||||
#include "util/queue.h"
|
#include "util/queue.h"
|
||||||
|
|
||||||
enum recorder_format {
|
|
||||||
RECORDER_FORMAT_AUTO,
|
|
||||||
RECORDER_FORMAT_MP4,
|
|
||||||
RECORDER_FORMAT_MKV,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct record_packet {
|
struct record_packet {
|
||||||
AVPacket packet;
|
AVPacket packet;
|
||||||
struct record_packet *next;
|
struct record_packet *next;
|
||||||
@@ -25,7 +20,7 @@ struct recorder_queue QUEUE(struct record_packet);
|
|||||||
|
|
||||||
struct recorder {
|
struct recorder {
|
||||||
char *filename;
|
char *filename;
|
||||||
enum recorder_format format;
|
enum sc_record_format format;
|
||||||
AVFormatContext *ctx;
|
AVFormatContext *ctx;
|
||||||
struct size declared_frame_size;
|
struct size declared_frame_size;
|
||||||
bool header_written;
|
bool header_written;
|
||||||
@@ -46,7 +41,7 @@ struct recorder {
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
recorder_init(struct recorder *recorder, const char *filename,
|
recorder_init(struct recorder *recorder, const char *filename,
|
||||||
enum recorder_format format, struct size declared_frame_size);
|
enum sc_record_format format, struct size declared_frame_size);
|
||||||
|
|
||||||
void
|
void
|
||||||
recorder_destroy(struct recorder *recorder);
|
recorder_destroy(struct recorder *recorder);
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
// not needed here, but winsock2.h must never be included AFTER windows.h
|
||||||
|
# include <winsock2.h>
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,30 @@
|
|||||||
#define SCRCPY_H
|
#define SCRCPY_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "common.h"
|
|
||||||
#include "input_manager.h"
|
enum sc_log_level {
|
||||||
#include "recorder.h"
|
SC_LOG_LEVEL_DEBUG,
|
||||||
#include "util/log.h"
|
SC_LOG_LEVEL_INFO,
|
||||||
|
SC_LOG_LEVEL_WARN,
|
||||||
|
SC_LOG_LEVEL_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum sc_record_format {
|
||||||
|
SC_RECORD_FORMAT_AUTO,
|
||||||
|
SC_RECORD_FORMAT_MP4,
|
||||||
|
SC_RECORD_FORMAT_MKV,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sc_port_range {
|
||||||
|
uint16_t first;
|
||||||
|
uint16_t last;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SC_WINDOW_POSITION_UNDEFINED (-0x8000)
|
||||||
|
|
||||||
struct scrcpy_options {
|
struct scrcpy_options {
|
||||||
const char *serial;
|
const char *serial;
|
||||||
@@ -19,15 +36,15 @@ struct scrcpy_options {
|
|||||||
const char *render_driver;
|
const char *render_driver;
|
||||||
const char *codec_options;
|
const char *codec_options;
|
||||||
enum sc_log_level log_level;
|
enum sc_log_level log_level;
|
||||||
enum recorder_format record_format;
|
enum sc_record_format record_format;
|
||||||
struct port_range port_range;
|
struct sc_port_range port_range;
|
||||||
uint16_t max_size;
|
uint16_t max_size;
|
||||||
uint32_t bit_rate;
|
uint32_t bit_rate;
|
||||||
uint16_t max_fps;
|
uint16_t max_fps;
|
||||||
int8_t lock_video_orientation;
|
int8_t lock_video_orientation;
|
||||||
uint8_t rotation;
|
uint8_t rotation;
|
||||||
int16_t window_x; // WINDOW_POSITION_UNDEFINED for "auto"
|
int16_t window_x; // SC_WINDOW_POSITION_UNDEFINED for "auto"
|
||||||
int16_t window_y; // WINDOW_POSITION_UNDEFINED for "auto"
|
int16_t window_y; // SC_WINDOW_POSITION_UNDEFINED for "auto"
|
||||||
uint16_t window_width;
|
uint16_t window_width;
|
||||||
uint16_t window_height;
|
uint16_t window_height;
|
||||||
uint16_t display_id;
|
uint16_t display_id;
|
||||||
@@ -55,7 +72,7 @@ struct scrcpy_options {
|
|||||||
.render_driver = NULL, \
|
.render_driver = NULL, \
|
||||||
.codec_options = NULL, \
|
.codec_options = NULL, \
|
||||||
.log_level = SC_LOG_LEVEL_INFO, \
|
.log_level = SC_LOG_LEVEL_INFO, \
|
||||||
.record_format = RECORDER_FORMAT_AUTO, \
|
.record_format = SC_RECORD_FORMAT_AUTO, \
|
||||||
.port_range = { \
|
.port_range = { \
|
||||||
.first = DEFAULT_LOCAL_PORT_RANGE_FIRST, \
|
.first = DEFAULT_LOCAL_PORT_RANGE_FIRST, \
|
||||||
.last = DEFAULT_LOCAL_PORT_RANGE_LAST, \
|
.last = DEFAULT_LOCAL_PORT_RANGE_LAST, \
|
||||||
@@ -65,8 +82,8 @@ struct scrcpy_options {
|
|||||||
.max_fps = 0, \
|
.max_fps = 0, \
|
||||||
.lock_video_orientation = DEFAULT_LOCK_VIDEO_ORIENTATION, \
|
.lock_video_orientation = DEFAULT_LOCK_VIDEO_ORIENTATION, \
|
||||||
.rotation = 0, \
|
.rotation = 0, \
|
||||||
.window_x = WINDOW_POSITION_UNDEFINED, \
|
.window_x = SC_WINDOW_POSITION_UNDEFINED, \
|
||||||
.window_y = WINDOW_POSITION_UNDEFINED, \
|
.window_y = SC_WINDOW_POSITION_UNDEFINED, \
|
||||||
.window_width = 0, \
|
.window_width = 0, \
|
||||||
.window_height = 0, \
|
.window_height = 0, \
|
||||||
.display_id = 0, \
|
.display_id = 0, \
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "icon.xpm"
|
#include "icon.xpm"
|
||||||
|
#include "scrcpy.h"
|
||||||
#include "tiny_xpm.h"
|
#include "tiny_xpm.h"
|
||||||
#include "video_buffer.h"
|
#include "video_buffer.h"
|
||||||
#include "util/lock.h"
|
#include "util/lock.h"
|
||||||
@@ -257,9 +258,9 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
|||||||
window_flags |= SDL_WINDOW_BORDERLESS;
|
window_flags |= SDL_WINDOW_BORDERLESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int x = window_x != WINDOW_POSITION_UNDEFINED
|
int x = window_x != SC_WINDOW_POSITION_UNDEFINED
|
||||||
? window_x : (int) SDL_WINDOWPOS_UNDEFINED;
|
? window_x : (int) SDL_WINDOWPOS_UNDEFINED;
|
||||||
int y = window_y != WINDOW_POSITION_UNDEFINED
|
int y = window_y != SC_WINDOW_POSITION_UNDEFINED
|
||||||
? window_y : (int) SDL_WINDOWPOS_UNDEFINED;
|
? window_y : (int) SDL_WINDOWPOS_UNDEFINED;
|
||||||
screen->window = SDL_CreateWindow(window_title, x, y,
|
screen->window = SDL_CreateWindow(window_title, x, y,
|
||||||
window_size.width, window_size.height,
|
window_size.width, window_size.height,
|
||||||
@@ -579,14 +580,14 @@ screen_handle_window_event(struct screen *screen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct point
|
struct point
|
||||||
screen_convert_to_frame_coords(struct screen *screen, int32_t x, int32_t y) {
|
screen_convert_drawable_to_frame_coords(struct screen *screen,
|
||||||
|
int32_t x, int32_t y) {
|
||||||
unsigned rotation = screen->rotation;
|
unsigned rotation = screen->rotation;
|
||||||
assert(rotation < 4);
|
assert(rotation < 4);
|
||||||
|
|
||||||
int32_t w = screen->content_size.width;
|
int32_t w = screen->content_size.width;
|
||||||
int32_t h = screen->content_size.height;
|
int32_t h = screen->content_size.height;
|
||||||
|
|
||||||
screen_hidpi_scale_coords(screen, &x, &y);
|
|
||||||
|
|
||||||
x = (int64_t) (x - screen->rect.x) * w / screen->rect.w;
|
x = (int64_t) (x - screen->rect.x) * w / screen->rect.w;
|
||||||
y = (int64_t) (y - screen->rect.y) * h / screen->rect.h;
|
y = (int64_t) (y - screen->rect.y) * h / screen->rect.h;
|
||||||
@@ -615,6 +616,13 @@ screen_convert_to_frame_coords(struct screen *screen, int32_t x, int32_t y) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct point
|
||||||
|
screen_convert_window_to_frame_coords(struct screen *screen,
|
||||||
|
int32_t x, int32_t y) {
|
||||||
|
screen_hidpi_scale_coords(screen, &x, &y);
|
||||||
|
return screen_convert_drawable_to_frame_coords(screen, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_hidpi_scale_coords(struct screen *screen, int32_t *x, int32_t *y) {
|
screen_hidpi_scale_coords(struct 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
|
||||||
|
|||||||
@@ -9,8 +9,6 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "opengl.h"
|
#include "opengl.h"
|
||||||
|
|
||||||
#define WINDOW_POSITION_UNDEFINED (-0x8000)
|
|
||||||
|
|
||||||
struct video_buffer;
|
struct video_buffer;
|
||||||
|
|
||||||
struct screen {
|
struct screen {
|
||||||
@@ -76,7 +74,7 @@ void
|
|||||||
screen_init(struct screen *screen);
|
screen_init(struct screen *screen);
|
||||||
|
|
||||||
// initialize screen, create window, renderer and texture (window is hidden)
|
// initialize screen, create window, renderer and texture (window is hidden)
|
||||||
// window_x and window_y accept WINDOW_POSITION_UNDEFINED
|
// window_x and window_y accept SC_WINDOW_POSITION_UNDEFINED
|
||||||
bool
|
bool
|
||||||
screen_init_rendering(struct screen *screen, const char *window_title,
|
screen_init_rendering(struct screen *screen, const char *window_title,
|
||||||
struct size frame_size, bool always_on_top,
|
struct size frame_size, bool always_on_top,
|
||||||
@@ -126,7 +124,14 @@ screen_handle_window_event(struct screen *screen, const SDL_WindowEvent *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 point
|
struct point
|
||||||
screen_convert_to_frame_coords(struct screen *screen, int32_t x, int32_t y);
|
screen_convert_window_to_frame_coords(struct screen *screen,
|
||||||
|
int32_t x, int32_t y);
|
||||||
|
|
||||||
|
// convert point from drawable coordinates to frame coordinates
|
||||||
|
// x and y are expressed in pixels
|
||||||
|
struct point
|
||||||
|
screen_convert_drawable_to_frame_coords(struct screen *screen,
|
||||||
|
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
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ listen_on_port(uint16_t port) {
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
enable_tunnel_reverse_any_port(struct server *server,
|
enable_tunnel_reverse_any_port(struct server *server,
|
||||||
struct port_range port_range) {
|
struct sc_port_range port_range) {
|
||||||
uint16_t port = port_range.first;
|
uint16_t port = port_range.first;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!enable_tunnel_reverse(server->serial, port)) {
|
if (!enable_tunnel_reverse(server->serial, port)) {
|
||||||
@@ -189,7 +189,7 @@ enable_tunnel_reverse_any_port(struct server *server,
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
enable_tunnel_forward_any_port(struct server *server,
|
enable_tunnel_forward_any_port(struct server *server,
|
||||||
struct port_range port_range) {
|
struct sc_port_range port_range) {
|
||||||
server->tunnel_forward = true;
|
server->tunnel_forward = true;
|
||||||
uint16_t port = port_range.first;
|
uint16_t port = port_range.first;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -217,7 +217,7 @@ enable_tunnel_forward_any_port(struct server *server,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
enable_tunnel_any_port(struct server *server, struct port_range port_range,
|
enable_tunnel_any_port(struct server *server, struct sc_port_range port_range,
|
||||||
bool force_adb_forward) {
|
bool force_adb_forward) {
|
||||||
if (!force_adb_forward) {
|
if (!force_adb_forward) {
|
||||||
// Attempt to use "adb reverse"
|
// Attempt to use "adb reverse"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "scrcpy.h"
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "util/net.h"
|
#include "util/net.h"
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ struct server {
|
|||||||
socket_t server_socket; // only used if !tunnel_forward
|
socket_t server_socket; // only used if !tunnel_forward
|
||||||
socket_t video_socket;
|
socket_t video_socket;
|
||||||
socket_t control_socket;
|
socket_t control_socket;
|
||||||
struct port_range port_range;
|
struct sc_port_range port_range;
|
||||||
uint16_t local_port; // selected from port_range
|
uint16_t local_port; // selected from port_range
|
||||||
bool tunnel_enabled;
|
bool tunnel_enabled;
|
||||||
bool tunnel_forward; // use "adb forward" instead of "adb reverse"
|
bool tunnel_forward; // use "adb forward" instead of "adb reverse"
|
||||||
@@ -47,7 +48,7 @@ struct server_params {
|
|||||||
enum sc_log_level log_level;
|
enum sc_log_level log_level;
|
||||||
const char *crop;
|
const char *crop;
|
||||||
const char *codec_options;
|
const char *codec_options;
|
||||||
struct port_range port_range;
|
struct sc_port_range port_range;
|
||||||
uint16_t max_size;
|
uint16_t max_size;
|
||||||
uint32_t bit_rate;
|
uint32_t bit_rate;
|
||||||
uint16_t max_fps;
|
uint16_t max_fps;
|
||||||
|
|||||||
@@ -3,13 +3,6 @@
|
|||||||
|
|
||||||
#include <SDL2/SDL_log.h>
|
#include <SDL2/SDL_log.h>
|
||||||
|
|
||||||
enum sc_log_level {
|
|
||||||
SC_LOG_LEVEL_DEBUG,
|
|
||||||
SC_LOG_LEVEL_INFO,
|
|
||||||
SC_LOG_LEVEL_WARN,
|
|
||||||
SC_LOG_LEVEL_ERROR,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define LOGV(...) SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
|
#define LOGV(...) SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
|
||||||
#define LOGD(...) SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
|
#define LOGD(...) SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
|
||||||
#define LOGI(...) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
|
#define LOGI(...) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "cli.h"
|
#include "cli.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
@@ -73,7 +74,6 @@ static void test_options(void) {
|
|||||||
|
|
||||||
const struct scrcpy_options *opts = &args.opts;
|
const struct scrcpy_options *opts = &args.opts;
|
||||||
assert(opts->always_on_top);
|
assert(opts->always_on_top);
|
||||||
fprintf(stderr, "%d\n", (int) opts->bit_rate);
|
|
||||||
assert(opts->bit_rate == 5000000);
|
assert(opts->bit_rate == 5000000);
|
||||||
assert(!strcmp(opts->crop, "100:200:300:400"));
|
assert(!strcmp(opts->crop, "100:200:300:400"));
|
||||||
assert(opts->fullscreen);
|
assert(opts->fullscreen);
|
||||||
@@ -84,7 +84,7 @@ static void test_options(void) {
|
|||||||
assert(opts->port_range.last == 1236);
|
assert(opts->port_range.last == 1236);
|
||||||
assert(!strcmp(opts->push_target, "/sdcard/Movies"));
|
assert(!strcmp(opts->push_target, "/sdcard/Movies"));
|
||||||
assert(!strcmp(opts->record_filename, "file"));
|
assert(!strcmp(opts->record_filename, "file"));
|
||||||
assert(opts->record_format == RECORDER_FORMAT_MKV);
|
assert(opts->record_format == SC_RECORD_FORMAT_MKV);
|
||||||
assert(opts->render_expired_frames);
|
assert(opts->render_expired_frames);
|
||||||
assert(!strcmp(opts->serial, "0123456789abcdef"));
|
assert(!strcmp(opts->serial, "0123456789abcdef"));
|
||||||
assert(opts->show_touches);
|
assert(opts->show_touches);
|
||||||
@@ -119,7 +119,7 @@ static void test_options2(void) {
|
|||||||
assert(!opts->control);
|
assert(!opts->control);
|
||||||
assert(!opts->display);
|
assert(!opts->display);
|
||||||
assert(!strcmp(opts->record_filename, "file.mp4"));
|
assert(!strcmp(opts->record_filename, "file.mp4"));
|
||||||
assert(opts->record_format == RECORDER_FORMAT_MP4);
|
assert(opts->record_format == SC_RECORD_FORMAT_MP4);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
|||||||
@@ -19,18 +19,19 @@ public final class CleanUp {
|
|||||||
// not instantiable
|
// not instantiable
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void configure(boolean disableShowTouches, int restoreStayOn) throws IOException {
|
public static void configure(boolean disableShowTouches, int restoreStayOn, boolean restoreNormalPowerMode) throws IOException {
|
||||||
boolean needProcess = disableShowTouches || restoreStayOn != -1;
|
boolean needProcess = disableShowTouches || restoreStayOn != -1 || restoreNormalPowerMode;
|
||||||
if (needProcess) {
|
if (needProcess) {
|
||||||
startProcess(disableShowTouches, restoreStayOn);
|
startProcess(disableShowTouches, restoreStayOn, restoreNormalPowerMode);
|
||||||
} else {
|
} else {
|
||||||
// There is no additional clean up to do when scrcpy dies
|
// There is no additional clean up to do when scrcpy dies
|
||||||
unlinkSelf();
|
unlinkSelf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void startProcess(boolean disableShowTouches, int restoreStayOn) throws IOException {
|
private static void startProcess(boolean disableShowTouches, int restoreStayOn, boolean restoreNormalPowerMode) throws IOException {
|
||||||
String[] cmd = {"app_process", "/", CleanUp.class.getName(), String.valueOf(disableShowTouches), String.valueOf(restoreStayOn)};
|
String[] cmd = {"app_process", "/", CleanUp.class.getName(), String.valueOf(disableShowTouches), String.valueOf(
|
||||||
|
restoreStayOn), String.valueOf(restoreNormalPowerMode)};
|
||||||
|
|
||||||
ProcessBuilder builder = new ProcessBuilder(cmd);
|
ProcessBuilder builder = new ProcessBuilder(cmd);
|
||||||
builder.environment().put("CLASSPATH", SERVER_PATH);
|
builder.environment().put("CLASSPATH", SERVER_PATH);
|
||||||
@@ -59,6 +60,7 @@ public final class CleanUp {
|
|||||||
|
|
||||||
boolean disableShowTouches = Boolean.parseBoolean(args[0]);
|
boolean disableShowTouches = Boolean.parseBoolean(args[0]);
|
||||||
int restoreStayOn = Integer.parseInt(args[1]);
|
int restoreStayOn = Integer.parseInt(args[1]);
|
||||||
|
boolean restoreNormalPowerMode = Boolean.parseBoolean(args[2]);
|
||||||
|
|
||||||
if (disableShowTouches || restoreStayOn != -1) {
|
if (disableShowTouches || restoreStayOn != -1) {
|
||||||
ServiceManager serviceManager = new ServiceManager();
|
ServiceManager serviceManager = new ServiceManager();
|
||||||
@@ -73,5 +75,10 @@ public final class CleanUp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (restoreNormalPowerMode) {
|
||||||
|
Ln.i("Restoring normal power mode");
|
||||||
|
Device.setScreenPowerMode(Device.POWER_MODE_NORMAL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ public class Controller {
|
|||||||
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
|
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
|
||||||
if (device.supportsInputEvents()) {
|
if (device.supportsInputEvents()) {
|
||||||
int mode = msg.getAction();
|
int mode = msg.getAction();
|
||||||
boolean setPowerModeOk = device.setScreenPowerMode(mode);
|
boolean setPowerModeOk = Device.setScreenPowerMode(mode);
|
||||||
if (setPowerModeOk) {
|
if (setPowerModeOk) {
|
||||||
Ln.i("Device screen turned " + (mode == Device.POWER_MODE_OFF ? "off" : "on"));
|
Ln.i("Device screen turned " + (mode == Device.POWER_MODE_OFF ? "off" : "on"));
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ public class Controller {
|
|||||||
|
|
||||||
Point point = device.getPhysicalPoint(position);
|
Point point = device.getPhysicalPoint(position);
|
||||||
if (point == null) {
|
if (point == null) {
|
||||||
// ignore event
|
Ln.w("Ignore touch event, it was generated for a different device size");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.genymobile.scrcpy;
|
package com.genymobile.scrcpy;
|
||||||
|
|
||||||
|
import com.genymobile.scrcpy.wrappers.ClipboardManager;
|
||||||
import com.genymobile.scrcpy.wrappers.ContentProvider;
|
import com.genymobile.scrcpy.wrappers.ContentProvider;
|
||||||
import com.genymobile.scrcpy.wrappers.InputManager;
|
import com.genymobile.scrcpy.wrappers.InputManager;
|
||||||
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
||||||
@@ -80,23 +81,28 @@ public final class Device {
|
|||||||
|
|
||||||
if (options.getControl()) {
|
if (options.getControl()) {
|
||||||
// If control is enabled, synchronize Android clipboard to the computer automatically
|
// If control is enabled, synchronize Android clipboard to the computer automatically
|
||||||
serviceManager.getClipboardManager().addPrimaryClipChangedListener(new IOnPrimaryClipChangedListener.Stub() {
|
ClipboardManager clipboardManager = serviceManager.getClipboardManager();
|
||||||
@Override
|
if (clipboardManager != null) {
|
||||||
public void dispatchPrimaryClipChanged() {
|
clipboardManager.addPrimaryClipChangedListener(new IOnPrimaryClipChangedListener.Stub() {
|
||||||
if (isSettingClipboard.get()) {
|
@Override
|
||||||
// This is a notification for the change we are currently applying, ignore it
|
public void dispatchPrimaryClipChanged() {
|
||||||
return;
|
if (isSettingClipboard.get()) {
|
||||||
}
|
// This is a notification for the change we are currently applying, ignore it
|
||||||
synchronized (Device.this) {
|
return;
|
||||||
if (clipboardListener != null) {
|
}
|
||||||
String text = getClipboardText();
|
synchronized (Device.this) {
|
||||||
if (text != null) {
|
if (clipboardListener != null) {
|
||||||
clipboardListener.onClipboardTextChanged(text);
|
String text = getClipboardText();
|
||||||
|
if (text != null) {
|
||||||
|
clipboardListener.onClipboardTextChanged(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
} else {
|
||||||
|
Ln.w("No clipboard manager, copy-paste between device and computer will not work");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((displayInfoFlags & DisplayInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS) == 0) {
|
if ((displayInfoFlags & DisplayInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS) == 0) {
|
||||||
@@ -199,7 +205,11 @@ public final class Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getClipboardText() {
|
public String getClipboardText() {
|
||||||
CharSequence s = serviceManager.getClipboardManager().getText();
|
ClipboardManager clipboardManager = serviceManager.getClipboardManager();
|
||||||
|
if (clipboardManager == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
CharSequence s = clipboardManager.getText();
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -207,16 +217,20 @@ public final class Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean setClipboardText(String text) {
|
public boolean setClipboardText(String text) {
|
||||||
|
ClipboardManager clipboardManager = serviceManager.getClipboardManager();
|
||||||
|
if (clipboardManager == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
isSettingClipboard.set(true);
|
isSettingClipboard.set(true);
|
||||||
boolean ok = serviceManager.getClipboardManager().setText(text);
|
boolean ok = clipboardManager.setText(text);
|
||||||
isSettingClipboard.set(false);
|
isSettingClipboard.set(false);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mode one of the {@code SCREEN_POWER_MODE_*} constants
|
* @param mode one of the {@code POWER_MODE_*} constants
|
||||||
*/
|
*/
|
||||||
public boolean setScreenPowerMode(int mode) {
|
public static boolean setScreenPowerMode(int mode) {
|
||||||
IBinder d = SurfaceControl.getBuiltInDisplay();
|
IBinder d = SurfaceControl.getBuiltInDisplay();
|
||||||
if (d == null) {
|
if (d == null) {
|
||||||
Ln.e("Could not get built-in display");
|
Ln.e("Could not get built-in display");
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public final class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CleanUp.configure(mustDisableShowTouchesOnCleanUp, restoreStayOn);
|
CleanUp.configure(mustDisableShowTouchesOnCleanUp, restoreStayOn, true);
|
||||||
|
|
||||||
boolean tunnelForward = options.isTunnelForward();
|
boolean tunnelForward = options.isTunnelForward();
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,14 @@ public final class ServiceManager {
|
|||||||
|
|
||||||
public ClipboardManager getClipboardManager() {
|
public ClipboardManager getClipboardManager() {
|
||||||
if (clipboardManager == null) {
|
if (clipboardManager == null) {
|
||||||
clipboardManager = new ClipboardManager(getService("clipboard", "android.content.IClipboard"));
|
IInterface clipboard = getService("clipboard", "android.content.IClipboard");
|
||||||
|
if (clipboard == null) {
|
||||||
|
// Some devices have no clipboard manager
|
||||||
|
// <https://github.com/Genymobile/scrcpy/issues/1440>
|
||||||
|
// <https://github.com/Genymobile/scrcpy/issues/1556>
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
clipboardManager = new ClipboardManager(clipboard);
|
||||||
}
|
}
|
||||||
return clipboardManager;
|
return clipboardManager;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user