Compare commits
18 Commits
logical_si
...
fixhidpi.3
Author | SHA1 | Date | |
---|---|---|---|
73c0f3ee05 | |||
78d9d82091 | |||
c8c921caf5 | |||
39ff8d9900 | |||
683f7ca848 | |||
120f08ee96 | |||
0415672a75 | |||
3ea4742321 | |||
95fd64b5de | |||
ab205084dc | |||
4696878a97 | |||
3da95b52bd | |||
c72f677435 | |||
1380f6e00f | |||
d841718956 | |||
17d53be3ef | |||
f9938dbf88 | |||
f6c8460ebb |
14
BUILD.md
14
BUILD.md
@ -195,8 +195,7 @@ Then, build:
|
||||
|
||||
```bash
|
||||
meson x --buildtype release --strip -Db_lto=true
|
||||
cd x
|
||||
ninja
|
||||
ninja -Cx
|
||||
```
|
||||
|
||||
_Note: `ninja` [must][ninja-user] be run as a non-root user (only `ninja
|
||||
@ -219,13 +218,13 @@ To run without installing:
|
||||
After a successful build, you can install _scrcpy_ on the system:
|
||||
|
||||
```bash
|
||||
sudo ninja install # without sudo on Windows
|
||||
sudo ninja -Cx install # without sudo on Windows
|
||||
```
|
||||
|
||||
This installs two files:
|
||||
|
||||
- `/usr/local/bin/scrcpy`
|
||||
- `/usr/local/share/scrcpy/scrcpy-server.jar`
|
||||
- `/usr/local/share/scrcpy/scrcpy-server`
|
||||
|
||||
Just remove them to "uninstall" the application.
|
||||
|
||||
@ -244,8 +243,7 @@ configuration:
|
||||
|
||||
```bash
|
||||
meson x --buildtype release --strip -Db_lto=true \
|
||||
-Dprebuilt_server=/path/to/scrcpy-server.jar
|
||||
cd x
|
||||
ninja
|
||||
sudo ninja install
|
||||
-Dprebuilt_server=/path/to/scrcpy-server
|
||||
ninja -Cx
|
||||
sudo ninja -Cx install
|
||||
```
|
||||
|
34
DEVELOP.md
34
DEVELOP.md
@ -3,7 +3,7 @@
|
||||
## Overview
|
||||
|
||||
This application is composed of two parts:
|
||||
- the server (`scrcpy-server.jar`), to be executed on the device,
|
||||
- the server (`scrcpy-server`), to be executed on the device,
|
||||
- the client (the `scrcpy` binary), executed on the host computer.
|
||||
|
||||
The client is responsible to push the server to the device and start its
|
||||
@ -49,7 +49,7 @@ application may not replace the server just before the client executes it._
|
||||
Instead of a raw _dex_ file, `app_process` accepts a _jar_ containing
|
||||
`classes.dex` (e.g. an [APK]). For simplicity, and to benefit from the gradle
|
||||
build system, the server is built to an (unsigned) APK (renamed to
|
||||
`scrcpy-server.jar`).
|
||||
`scrcpy-server`).
|
||||
|
||||
[dex]: https://en.wikipedia.org/wiki/Dalvik_(software)
|
||||
[apk]: https://en.wikipedia.org/wiki/Android_application_package
|
||||
@ -268,3 +268,33 @@ For more details, go read the code!
|
||||
|
||||
If you find a bug, or have an awesome idea to implement, please discuss and
|
||||
contribute ;-)
|
||||
|
||||
|
||||
### Debug the server
|
||||
|
||||
The server is pushed to the device by the client on startup.
|
||||
|
||||
To debug it, enable the server debugger during configuration:
|
||||
|
||||
```bash
|
||||
meson x -Dserver_debugger=true
|
||||
# or, if x is already configured
|
||||
meson configure x -Dserver_debugger=true
|
||||
```
|
||||
|
||||
Then recompile.
|
||||
|
||||
When you start scrcpy, it will start a debugger on port 5005 on the device.
|
||||
Redirect that port to the computer:
|
||||
|
||||
```bash
|
||||
adb forward tcp:5005 tcp:5005
|
||||
```
|
||||
|
||||
In Android Studio, _Run_ > _Debug_ > _Edit configurations..._ On the left, click on
|
||||
`+`, _Remote_, and fill the form:
|
||||
|
||||
- Host: `localhost`
|
||||
- Port: `5005`
|
||||
|
||||
Then click on _Debug_.
|
||||
|
@ -3,7 +3,7 @@
|
||||
#
|
||||
# Here, "portable" means that the client and server binaries are expected to be
|
||||
# anywhere, but in the same directory, instead of well-defined separate
|
||||
# locations (e.g. /usr/bin/scrcpy and /usr/share/scrcpy/scrcpy-server.jar).
|
||||
# locations (e.g. /usr/bin/scrcpy and /usr/share/scrcpy/scrcpy-server).
|
||||
#
|
||||
# In particular, this implies to change the location from where the client push
|
||||
# the server to the device.
|
||||
@ -97,7 +97,7 @@ build-win64-noconsole: prepare-deps-win64
|
||||
|
||||
dist-win32: build-server build-win32 build-win32-noconsole
|
||||
mkdir -p "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server.jar "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp "$(WIN32_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp "$(WIN32_NOCONSOLE_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN32_TARGET_DIR)/scrcpy-noconsole.exe"
|
||||
cp prebuilt-deps/ffmpeg-4.1.4-win32-shared/bin/avutil-56.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
@ -112,7 +112,7 @@ dist-win32: build-server build-win32 build-win32-noconsole
|
||||
|
||||
dist-win64: build-server build-win64 build-win64-noconsole
|
||||
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server.jar "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp "$(WIN64_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp "$(WIN64_NOCONSOLE_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN64_TARGET_DIR)/scrcpy-noconsole.exe"
|
||||
cp prebuilt-deps/ffmpeg-4.1.4-win64-shared/bin/avutil-56.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
|
@ -358,7 +358,7 @@ To use a specific _adb_ binary, configure its path in the environment variable
|
||||
|
||||
ADB=/path/to/adb scrcpy
|
||||
|
||||
To override the path of the `scrcpy-server.jar` file, configure its path in
|
||||
To override the path of the `scrcpy-server` file, configure its path in
|
||||
`SCRCPY_SERVER_PATH`.
|
||||
|
||||
[useful]: https://github.com/Genymobile/scrcpy/issues/278#issuecomment-429330345
|
||||
|
@ -93,7 +93,7 @@ conf.set_quoted('SCRCPY_VERSION', meson.project_version())
|
||||
# the prefix used during configuration (meson --prefix=PREFIX)
|
||||
conf.set_quoted('PREFIX', get_option('prefix'))
|
||||
|
||||
# build a "portable" version (with scrcpy-server.jar accessible from the same
|
||||
# build a "portable" version (with scrcpy-server accessible from the same
|
||||
# directory as the executable)
|
||||
conf.set('PORTABLE', get_option('portable'))
|
||||
|
||||
@ -109,12 +109,15 @@ conf.set('DEFAULT_MAX_SIZE', '0') # 0: unlimited
|
||||
# overridden by option --bit-rate
|
||||
conf.set('DEFAULT_BIT_RATE', '8000000') # 8Mbps
|
||||
|
||||
# enable High DPI support
|
||||
conf.set('HIDPI_SUPPORT', get_option('hidpi_support'))
|
||||
|
||||
# disable console on Windows
|
||||
conf.set('WINDOWS_NOCONSOLE', get_option('windows_noconsole'))
|
||||
|
||||
# run a server debugger and wait for a client to be attached
|
||||
conf.set('SERVER_DEBUGGER', get_option('server_debugger'))
|
||||
|
||||
# enable a workaround for bug #15
|
||||
conf.set('HIDPI_WORKAROUND', get_option('hidpi_workaround'))
|
||||
|
||||
configure_file(configuration: conf, output: 'config.h')
|
||||
|
||||
src_dir = include_directories('src')
|
||||
@ -134,6 +137,8 @@ executable('scrcpy', src,
|
||||
c_args: c_args,
|
||||
link_args: link_args)
|
||||
|
||||
install_man('scrcpy.1')
|
||||
|
||||
|
||||
### TESTS
|
||||
|
||||
|
231
app/scrcpy.1
Normal file
231
app/scrcpy.1
Normal file
@ -0,0 +1,231 @@
|
||||
.TH "scrcpy" "1"
|
||||
.SH NAME
|
||||
scrcpy \- Display and control your Android device
|
||||
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B scrcpy
|
||||
.RI [ options ]
|
||||
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B scrcpy
|
||||
provides display and control of Android devices connected on USB (or over TCP/IP). It does not require any root access.
|
||||
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
.BI "\-b, \-\-bit\-rate " value
|
||||
Encode the video at the given bit\-rate, expressed in bits/s. Unit suffixes are supported: '\fBK\fR' (x1000) and '\fBM\fR' (x1000000).
|
||||
|
||||
Default is 8000000.
|
||||
|
||||
.TP
|
||||
.BI "\-c, \-\-crop " width\fR:\fIheight\fR:\fIx\fR:\fIy
|
||||
Crop the device screen on the server.
|
||||
|
||||
The values are expressed in the device natural orientation (typically, portrait for a phone, landscape for a tablet). Any
|
||||
.B \-\-max\-size
|
||||
value is computed on the cropped size.
|
||||
|
||||
.TP
|
||||
.B \-f, \-\-fullscreen
|
||||
Start in fullscreen.
|
||||
|
||||
.TP
|
||||
.BI "\-F, \-\-record\-format " format
|
||||
Force recording format (either mp4 or mkv).
|
||||
|
||||
.TP
|
||||
.B \-h, \-\-help
|
||||
Print this help.
|
||||
|
||||
.TP
|
||||
.BI "\-m, \-\-max\-size " value
|
||||
Limit both the width and height of the video to \fIvalue\fR. The other dimension is computed so that the device aspect\-ratio is preserved.
|
||||
|
||||
Default is 0 (unlimited).
|
||||
|
||||
.TP
|
||||
.B \-n, \-\-no\-control
|
||||
Disable device control (mirror the device in read\-only).
|
||||
|
||||
.TP
|
||||
.B \-N, \-\-no\-display
|
||||
Do not display device (only when screen recording is enabled).
|
||||
|
||||
.TP
|
||||
.BI "\-p, \-\-port " port
|
||||
Set the TCP port the client listens on.
|
||||
|
||||
Default is 27183.
|
||||
|
||||
.TP
|
||||
.BI "\-\-push\-target " path
|
||||
Set the target directory for pushing files to the device by drag & drop. It is passed as\-is to "adb push".
|
||||
|
||||
Default is "/sdcard/".
|
||||
|
||||
.TP
|
||||
.BI "\-r, \-\-record " file
|
||||
Record screen to
|
||||
.IR file .
|
||||
|
||||
The format is determined by the
|
||||
.B \-F/\-\-record\-format
|
||||
option if set, or by the file extension (.mp4 or .mkv).
|
||||
|
||||
.TP
|
||||
.B \-\-render\-expired\-frames
|
||||
By default, to minimize latency, scrcpy always renders the last available decoded frame, and drops any previous ones. This flag forces to render all frames, at a cost of a possible increased latency.
|
||||
|
||||
.TP
|
||||
.BI "\-s, \-\-serial " number
|
||||
The device serial number. Mandatory only if several devices are connected to adb.
|
||||
|
||||
.TP
|
||||
.B \-S, \-\-turn\-screen\-off
|
||||
Turn the device screen off immediately.
|
||||
|
||||
.TP
|
||||
.B \-t, \-\-show\-touches
|
||||
Enable "show touches" on start, disable on quit.
|
||||
|
||||
It only shows physical touches (not clicks from scrcpy).
|
||||
|
||||
.TP
|
||||
.B \-T, \-\-always\-on\-top
|
||||
Make scrcpy window always on top (above other windows).
|
||||
|
||||
.TP
|
||||
.B \-v, \-\-version
|
||||
Print the version of scrcpy.
|
||||
|
||||
.TP
|
||||
.BI \-\-window\-title " text
|
||||
Set a custom window title.
|
||||
|
||||
|
||||
.SH SHORTCUTS
|
||||
|
||||
.TP
|
||||
.B Ctrl+f
|
||||
switch fullscreen mode
|
||||
|
||||
.TP
|
||||
.B Ctrl+g
|
||||
resize window to 1:1 (pixel\-perfect)
|
||||
|
||||
.TP
|
||||
.B Ctrl+x, Double\-click on black borders
|
||||
resize window to remove black borders
|
||||
|
||||
.TP
|
||||
.B Ctrl+h, Home, Middle\-click
|
||||
Click on HOME
|
||||
|
||||
.TP
|
||||
.B Ctrl+b, Ctrl+Backspace, Right\-click (when screen is on)
|
||||
Click on BACK
|
||||
|
||||
.TP
|
||||
.B Ctrl+s
|
||||
Click on APP_SWITCH
|
||||
|
||||
.TP
|
||||
.B Ctrl+m
|
||||
Click on MENU
|
||||
|
||||
.TP
|
||||
.B Ctrl+Up
|
||||
Click on VOLUME_UP
|
||||
|
||||
.TP
|
||||
.B Ctrl+Down
|
||||
Click on VOLUME_DOWN
|
||||
|
||||
.TP
|
||||
.B Ctrl+p
|
||||
Click on POWER (turn screen on/off)
|
||||
|
||||
.TP
|
||||
.B Right\-click (when screen is off)
|
||||
turn screen on
|
||||
|
||||
.TP
|
||||
.B Ctrl+o
|
||||
turn device screen off (keep mirroring)
|
||||
|
||||
.TP
|
||||
.B Ctrl+n
|
||||
expand notification panel
|
||||
|
||||
.TP
|
||||
.B Ctrl+Shift+n
|
||||
collapse notification panel
|
||||
|
||||
.TP
|
||||
.B Ctrl+c
|
||||
copy device clipboard to computer
|
||||
|
||||
.TP
|
||||
.B Ctrl+v
|
||||
paste computer clipboard to device
|
||||
|
||||
.TP
|
||||
.B Ctrl+Shift+v
|
||||
copy computer clipboard to device
|
||||
|
||||
.TP
|
||||
.B Ctrl+i
|
||||
enable/disable FPS counter (print frames/second in logs)
|
||||
|
||||
.TP
|
||||
.B Drag & drop APK file
|
||||
install APK from computer
|
||||
|
||||
|
||||
.SH Environment variables
|
||||
|
||||
.TP
|
||||
.B ADB
|
||||
Specify the path to adb.
|
||||
|
||||
.TP
|
||||
.B SCRCPY_SERVER_PATH
|
||||
Specify the path to server binary.
|
||||
|
||||
|
||||
.SH AUTHORS
|
||||
.B scrcpy
|
||||
is written by Romain Vimont.
|
||||
|
||||
This manual page was written by
|
||||
.MT mmyangfl@gmail.com
|
||||
Yangfl
|
||||
.ME
|
||||
for the Debian Project (and may be used by others).
|
||||
|
||||
|
||||
.SH "REPORTING BUGS"
|
||||
Report bugs to
|
||||
.UR https://github.com/Genymobile/scrcpy/issues
|
||||
.UE .
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2018 Genymobile
|
||||
.UR https://www.genymobile.com
|
||||
Genymobile
|
||||
.UE
|
||||
|
||||
Copyright \(co 2018\-2019
|
||||
.MT rom@rom1v.com
|
||||
Romain Vimont
|
||||
.ME
|
||||
|
||||
Licensed under the Apache License, Version 2.0.
|
||||
|
||||
.SH WWW
|
||||
.UR https://github.com/Genymobile/scrcpy
|
||||
.UE
|
@ -140,10 +140,10 @@ convert_mouse_buttons(uint32_t state) {
|
||||
if (state & SDL_BUTTON_MMASK) {
|
||||
buttons |= AMOTION_EVENT_BUTTON_TERTIARY;
|
||||
}
|
||||
if (state & SDL_BUTTON_X1) {
|
||||
if (state & SDL_BUTTON_X1MASK) {
|
||||
buttons |= AMOTION_EVENT_BUTTON_BACK;
|
||||
}
|
||||
if (state & SDL_BUTTON_X2) {
|
||||
if (state & SDL_BUTTON_X2MASK) {
|
||||
buttons |= AMOTION_EVENT_BUTTON_FORWARD;
|
||||
}
|
||||
return buttons;
|
||||
|
@ -59,7 +59,7 @@ static void usage(const char *arg0) {
|
||||
" -f, --fullscreen\n"
|
||||
" Start in fullscreen.\n"
|
||||
"\n"
|
||||
" -F, --record-format\n"
|
||||
" -F, --record-format format\n"
|
||||
" Force recording format (either mp4 or mkv).\n"
|
||||
"\n"
|
||||
" -h, --help\n"
|
||||
|
@ -135,6 +135,9 @@ recorder_open(struct recorder *recorder, const AVCodec *input_codec) {
|
||||
// <https://github.com/FFmpeg/FFmpeg/commit/0694d8702421e7aff1340038559c438b61bb30dd>
|
||||
recorder->ctx->oformat = (AVOutputFormat *) format;
|
||||
|
||||
av_dict_set(&recorder->ctx->metadata, "comment",
|
||||
"Recorded by scrcpy " SCRCPY_VERSION, 0);
|
||||
|
||||
AVStream *ostream = avformat_new_stream(recorder->ctx, input_codec);
|
||||
if (!ostream) {
|
||||
avformat_free_context(recorder->ctx);
|
||||
|
@ -145,9 +145,11 @@ handle_event(SDL_Event *event, bool control) {
|
||||
case SDL_WINDOWEVENT:
|
||||
switch (event->window.event) {
|
||||
case SDL_WINDOWEVENT_EXPOSED:
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
screen_render(&screen);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
screen_window_resized(&screen);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
|
123
app/src/screen.c
123
app/src/screen.c
@ -16,7 +16,7 @@
|
||||
|
||||
// get the window size in a struct size
|
||||
static struct size
|
||||
get_native_window_size(SDL_Window *window) {
|
||||
get_window_size(SDL_Window *window) {
|
||||
int width;
|
||||
int height;
|
||||
SDL_GetWindowSize(window, &width, &height);
|
||||
@ -29,11 +29,11 @@ get_native_window_size(SDL_Window *window) {
|
||||
|
||||
// get the windowed window size
|
||||
static struct size
|
||||
get_window_size(const struct screen *screen) {
|
||||
get_windowed_window_size(const struct screen *screen) {
|
||||
if (screen->fullscreen) {
|
||||
return screen->windowed_window_size;
|
||||
}
|
||||
return get_native_window_size(screen->window);
|
||||
return get_window_size(screen->window);
|
||||
}
|
||||
|
||||
// set the window size to be applied when fullscreen is disabled
|
||||
@ -112,8 +112,8 @@ get_optimal_size(struct size current_size, struct size frame_size) {
|
||||
// same as get_optimal_size(), but read the current size from the window
|
||||
static inline struct size
|
||||
get_optimal_window_size(const struct screen *screen, struct size frame_size) {
|
||||
struct size current_size = get_window_size(screen);
|
||||
return get_optimal_size(current_size, frame_size);
|
||||
struct size windowed_size = get_windowed_window_size(screen);
|
||||
return get_optimal_size(windowed_size, frame_size);
|
||||
}
|
||||
|
||||
// initially, there is no current size, so use the frame size as current size
|
||||
@ -134,16 +134,57 @@ create_texture(SDL_Renderer *renderer, struct size frame_size) {
|
||||
frame_size.width, frame_size.height);
|
||||
}
|
||||
|
||||
#ifdef HIDPI_WORKAROUND
|
||||
static void
|
||||
screen_get_sizes(struct screen *screen, struct screen_sizes *out) {
|
||||
int ww, wh, dw, dh;
|
||||
SDL_GetWindowSize(screen->window, &ww, &wh);
|
||||
SDL_GL_GetDrawableSize(screen->window, &dw, &dh);
|
||||
out->window.width = ww;
|
||||
out->window.height = wh;
|
||||
out->window.width = dw;
|
||||
out->window.height = dh;
|
||||
}
|
||||
#endif
|
||||
|
||||
// This may be called more than once to work around SDL bugs
|
||||
static bool
|
||||
screen_init_renderer_and_texture(struct screen *screen) {
|
||||
screen->renderer = SDL_CreateRenderer(screen->window, -1,
|
||||
SDL_RENDERER_ACCELERATED);
|
||||
if (!screen->renderer) {
|
||||
LOGC("Could not create renderer: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SDL_RenderSetLogicalSize(screen->renderer, screen->frame_size.width,
|
||||
screen->frame_size.height)) {
|
||||
LOGE("Could not set renderer logical size: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
screen->texture = create_texture(screen->renderer, screen->frame_size);
|
||||
if (!screen->texture) {
|
||||
LOGC("Could not create texture: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef HIDPI_WORKAROUND
|
||||
screen_get_sizes(screen, &screen->sizes);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
screen_init_rendering(struct screen *screen, const char *window_title,
|
||||
struct size frame_size, bool always_on_top) {
|
||||
screen->frame_size = frame_size;
|
||||
|
||||
struct size window_size = get_initial_optimal_size(frame_size);
|
||||
uint32_t window_flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE;
|
||||
#ifdef HIDPI_SUPPORT
|
||||
window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
#endif
|
||||
uint32_t window_flags = SDL_WINDOW_HIDDEN
|
||||
| SDL_WINDOW_RESIZABLE
|
||||
| SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
if (always_on_top) {
|
||||
#ifdef SCRCPY_SDL_HAS_WINDOW_ALWAYS_ON_TOP
|
||||
window_flags |= SDL_WINDOW_ALWAYS_ON_TOP;
|
||||
@ -162,21 +203,6 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
||||
return false;
|
||||
}
|
||||
|
||||
screen->renderer = SDL_CreateRenderer(screen->window, -1,
|
||||
SDL_RENDERER_ACCELERATED);
|
||||
if (!screen->renderer) {
|
||||
LOGC("Could not create renderer: %s", SDL_GetError());
|
||||
screen_destroy(screen);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SDL_RenderSetLogicalSize(screen->renderer, frame_size.width,
|
||||
frame_size.height)) {
|
||||
LOGE("Could not set renderer logical size: %s", SDL_GetError());
|
||||
screen_destroy(screen);
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_Surface *icon = read_xpm(icon_xpm);
|
||||
if (icon) {
|
||||
SDL_SetWindowIcon(screen->window, icon);
|
||||
@ -187,9 +213,7 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
||||
|
||||
LOGI("Initial texture: %" PRIu16 "x%" PRIu16, frame_size.width,
|
||||
frame_size.height);
|
||||
screen->texture = create_texture(screen->renderer, frame_size);
|
||||
if (!screen->texture) {
|
||||
LOGC("Could not create texture: %s", SDL_GetError());
|
||||
if (!screen_init_renderer_and_texture(screen)) {
|
||||
screen_destroy(screen);
|
||||
return false;
|
||||
}
|
||||
@ -229,11 +253,11 @@ prepare_for_frame(struct screen *screen, struct size new_frame_size) {
|
||||
// frame dimension changed, destroy texture
|
||||
SDL_DestroyTexture(screen->texture);
|
||||
|
||||
struct size current_size = get_window_size(screen);
|
||||
struct size windowed_size = get_windowed_window_size(screen);
|
||||
struct size target_size = {
|
||||
(uint32_t) current_size.width * new_frame_size.width
|
||||
(uint32_t) windowed_size.width * new_frame_size.width
|
||||
/ screen->frame_size.width,
|
||||
(uint32_t) current_size.height * new_frame_size.height
|
||||
(uint32_t) windowed_size.height * new_frame_size.height
|
||||
/ screen->frame_size.height,
|
||||
};
|
||||
target_size = get_optimal_size(target_size, new_frame_size);
|
||||
@ -278,6 +302,43 @@ screen_update_frame(struct screen *screen, struct video_buffer *vb) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HIDPI_WORKAROUND
|
||||
// workaround for <https://github.com/Genymobile/scrcpy/issues/15>
|
||||
static inline bool
|
||||
screen_fix_hidpi(struct screen *screen) {
|
||||
struct screen_sizes cur;
|
||||
screen_get_sizes(screen, &cur);
|
||||
|
||||
struct screen_sizes *prev = &screen->sizes;
|
||||
|
||||
bool width_ratio_changed = cur.window.width * prev->drawable.width !=
|
||||
cur.drawable.width * prev->window.width;
|
||||
bool height_ratio_changed = cur.window.height * prev->drawable.height !=
|
||||
cur.drawable.height * prev->window.height;
|
||||
if (width_ratio_changed || height_ratio_changed) {
|
||||
SDL_DestroyTexture(screen->texture);
|
||||
SDL_DestroyRenderer(screen->renderer);
|
||||
if (!screen_init_renderer_and_texture(screen)) {
|
||||
screen->texture = NULL;
|
||||
screen->renderer = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGI("Renderer reset after hidpi scaling changed");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
screen_window_resized(struct screen *screen) {
|
||||
#ifdef HIDPI_WORKAROUND
|
||||
screen_fix_hidpi(screen);
|
||||
#endif
|
||||
screen_render(screen);
|
||||
}
|
||||
|
||||
void
|
||||
screen_render(struct screen *screen) {
|
||||
SDL_RenderClear(screen->renderer);
|
||||
@ -289,7 +350,7 @@ void
|
||||
screen_switch_fullscreen(struct screen *screen) {
|
||||
if (!screen->fullscreen) {
|
||||
// going to fullscreen, store the current windowed window size
|
||||
screen->windowed_window_size = get_native_window_size(screen->window);
|
||||
screen->windowed_window_size = get_window_size(screen->window);
|
||||
}
|
||||
uint32_t new_mode = screen->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
if (SDL_SetWindowFullscreen(screen->window, new_mode)) {
|
||||
|
@ -20,6 +20,12 @@ struct screen {
|
||||
bool has_frame;
|
||||
bool fullscreen;
|
||||
bool no_window;
|
||||
#ifdef HIDPI_WORKAROUND
|
||||
struct screen_sizes {
|
||||
struct size window;
|
||||
struct size drawable;
|
||||
} sizes;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define SCREEN_INITIALIZER { \
|
||||
@ -60,6 +66,10 @@ screen_destroy(struct screen *screen);
|
||||
bool
|
||||
screen_update_frame(struct screen *screen, struct video_buffer *vb);
|
||||
|
||||
// update content after window resizing
|
||||
void
|
||||
screen_window_resized(struct screen *screen);
|
||||
|
||||
// render the texture to the renderer
|
||||
void
|
||||
screen_render(struct screen *screen);
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "net.h"
|
||||
|
||||
#define SOCKET_NAME "scrcpy"
|
||||
#define SERVER_FILENAME "scrcpy-server.jar"
|
||||
#define SERVER_FILENAME "scrcpy-server"
|
||||
|
||||
#define DEFAULT_SERVER_PATH PREFIX "/share/scrcpy/" SERVER_FILENAME
|
||||
#define DEVICE_SERVER_PATH "/data/local/tmp/" SERVER_FILENAME
|
||||
@ -32,7 +32,7 @@ get_server_path(void) {
|
||||
// the absolute path is hardcoded
|
||||
return DEFAULT_SERVER_PATH;
|
||||
#else
|
||||
// use scrcpy-server.jar in the same directory as the executable
|
||||
// use scrcpy-server in the same directory as the executable
|
||||
char *executable_path = get_executable_path();
|
||||
if (!executable_path) {
|
||||
LOGE("Could not get executable path, "
|
||||
@ -124,6 +124,11 @@ execute_server(struct server *server, const struct server_params *params) {
|
||||
"shell",
|
||||
"CLASSPATH=/data/local/tmp/" SERVER_FILENAME,
|
||||
"app_process",
|
||||
#ifdef SERVER_DEBUGGER
|
||||
# define SERVER_DEBUGGER_PORT "5005"
|
||||
"-agentlib:jdwp=transport=dt_socket,suspend=y,server=y,address="
|
||||
SERVER_DEBUGGER_PORT,
|
||||
#endif
|
||||
"/", // unused
|
||||
"com.genymobile.scrcpy.Server",
|
||||
max_size_string,
|
||||
@ -133,6 +138,17 @@ execute_server(struct server *server, const struct server_params *params) {
|
||||
"true", // always send frame meta (packet boundaries + timestamp)
|
||||
params->control ? "true" : "false",
|
||||
};
|
||||
#ifdef SERVER_DEBUGGER
|
||||
LOGI("Server debugger waiting for a client on device port "
|
||||
SERVER_DEBUGGER_PORT "...");
|
||||
// From the computer, run
|
||||
// adb forward tcp:5005 tcp:5005
|
||||
// Then, from Android Studio: Run > Debug > Edit configurations...
|
||||
// On the left, click on '+', "Remote", with:
|
||||
// Host: localhost
|
||||
// Port: 5005
|
||||
// Then click on "Debug"
|
||||
#endif
|
||||
return adb_execute(server->serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
|
||||
}
|
||||
|
||||
|
@ -3,5 +3,6 @@ option('compile_server', type: 'boolean', value: true, description: 'Build the s
|
||||
option('crossbuild_windows', type: 'boolean', value: false, description: 'Build for Windows from Linux')
|
||||
option('windows_noconsole', type: 'boolean', value: false, description: 'Disable console on Windows (pass -mwindows flag)')
|
||||
option('prebuilt_server', type: 'string', description: 'Path of the prebuilt server')
|
||||
option('portable', type: 'boolean', value: false, description: 'Use scrcpy-server.jar from the same directory as the scrcpy executable')
|
||||
option('hidpi_support', type: 'boolean', value: true, description: 'Enable High DPI support')
|
||||
option('portable', type: 'boolean', value: false, description: 'Use scrcpy-server from the same directory as the scrcpy executable')
|
||||
option('server_debugger', type: 'boolean', value: false, description: 'Run a server debugger and wait for a client to be attached')
|
||||
option('hidpi_workaround', type: 'boolean', value: true, description: 'Enable a workaround for bug #15')
|
||||
|
@ -23,21 +23,21 @@ cd -
|
||||
make -f Makefile.CrossWindows
|
||||
|
||||
# the generated server must be the same everywhere
|
||||
cmp "$BUILDDIR/server/scrcpy-server.jar" dist/scrcpy-win32/scrcpy-server.jar
|
||||
cmp "$BUILDDIR/server/scrcpy-server.jar" dist/scrcpy-win64/scrcpy-server.jar
|
||||
cmp "$BUILDDIR/server/scrcpy-server" dist/scrcpy-win32/scrcpy-server
|
||||
cmp "$BUILDDIR/server/scrcpy-server" dist/scrcpy-win64/scrcpy-server
|
||||
|
||||
# get version name
|
||||
TAG=$(git describe --tags --always)
|
||||
|
||||
# create release directory
|
||||
mkdir -p "release-$TAG"
|
||||
cp "$BUILDDIR/server/scrcpy-server.jar" "release-$TAG/scrcpy-server-$TAG.jar"
|
||||
cp "$BUILDDIR/server/scrcpy-server" "release-$TAG/scrcpy-server-$TAG"
|
||||
cp "dist/scrcpy-win32-$TAG.zip" "release-$TAG/"
|
||||
cp "dist/scrcpy-win64-$TAG.zip" "release-$TAG/"
|
||||
|
||||
# generate checksums
|
||||
cd "release-$TAG"
|
||||
sha256sum "scrcpy-server-$TAG.jar" \
|
||||
sha256sum "scrcpy-server-$TAG" \
|
||||
"scrcpy-win32-$TAG.zip" \
|
||||
"scrcpy-win64-$TAG.zip" > SHA256SUMS.txt
|
||||
|
||||
|
2
run
2
run
@ -20,4 +20,4 @@ then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRCPY_SERVER_PATH="$BUILDDIR/server/scrcpy-server.jar" "$BUILDDIR/app/scrcpy" "$@"
|
||||
SCRCPY_SERVER_PATH="$BUILDDIR/server/scrcpy-server" "$BUILDDIR/app/scrcpy" "$@"
|
||||
|
@ -1,2 +1,2 @@
|
||||
#!/bin/bash
|
||||
SCRCPY_SERVER_PATH="$MESON_BUILD_ROOT/server/scrcpy-server.jar" "$MESON_BUILD_ROOT/app/scrcpy"
|
||||
SCRCPY_SERVER_PATH="$MESON_BUILD_ROOT/server/scrcpy-server" "$MESON_BUILD_ROOT/app/scrcpy"
|
||||
|
62
server/build_without_gradle.sh
Executable file
62
server/build_without_gradle.sh
Executable file
@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This script generates the scrcpy binary "manually" (without gradle).
|
||||
#
|
||||
# Adapt Android platform and build tools versions (via ANDROID_PLATFORM and
|
||||
# ANDROID_BUILD_TOOLS environment variables).
|
||||
#
|
||||
# Then execute:
|
||||
#
|
||||
# BUILD_DIR=my_build_dir ./build_without_gradle.sh
|
||||
|
||||
set -e
|
||||
|
||||
PLATFORM=${ANDROID_PLATFORM:-29}
|
||||
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-29.0.2}
|
||||
|
||||
BUILD_DIR="$(realpath ${BUILD_DIR:-build_manual})"
|
||||
CLASSES_DIR="$BUILD_DIR/classes"
|
||||
SERVER_DIR=$(dirname "$0")
|
||||
SERVER_BINARY=scrcpy-server
|
||||
|
||||
echo "Platform: android-$PLATFORM"
|
||||
echo "Build-tools: $BUILD_TOOLS"
|
||||
echo "Build dir: $BUILD_DIR"
|
||||
|
||||
rm -rf "$CLASSES_DIR" "$BUILD_DIR/$SERVER_BINARY" classes.dex
|
||||
mkdir -p "$CLASSES_DIR/com/genymobile/scrcpy"
|
||||
|
||||
<< EOF cat > "$CLASSES_DIR/com/genymobile/scrcpy/BuildConfig.java"
|
||||
package com.genymobile.scrcpy;
|
||||
|
||||
public final class BuildConfig {
|
||||
public static final boolean DEBUG = false;
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "Generating java from aidl..."
|
||||
cd "$SERVER_DIR/src/main/aidl"
|
||||
"$ANDROID_HOME/build-tools/$BUILD_TOOLS/aidl" -o "$CLASSES_DIR" \
|
||||
android/view/IRotationWatcher.aidl
|
||||
|
||||
echo "Compiling java sources..."
|
||||
cd ../java
|
||||
javac -bootclasspath "$ANDROID_HOME/platforms/android-$PLATFORM/android.jar" \
|
||||
-cp "$CLASSES_DIR" -d "$CLASSES_DIR" -source 1.8 -target 1.8 \
|
||||
com/genymobile/scrcpy/*.java \
|
||||
com/genymobile/scrcpy/wrappers/*.java
|
||||
|
||||
echo "Dexing..."
|
||||
cd "$CLASSES_DIR"
|
||||
"$ANDROID_HOME/build-tools/$BUILD_TOOLS/dx" --dex \
|
||||
--output "$BUILD_DIR/classes.dex" \
|
||||
android/view/*.class \
|
||||
com/genymobile/scrcpy/*.class \
|
||||
com/genymobile/scrcpy/wrappers/*.class
|
||||
|
||||
echo "Archiving..."
|
||||
cd "$BUILD_DIR"
|
||||
jar cvf "$SERVER_BINARY" classes.dex
|
||||
rm -rf classes.dex classes
|
||||
|
||||
echo "Server generated in $BUILD_DIR/$SERVER_BINARY"
|
@ -4,7 +4,7 @@ prebuilt_server = get_option('prebuilt_server')
|
||||
if prebuilt_server == ''
|
||||
custom_target('scrcpy-server',
|
||||
build_always: true, # gradle is responsible for tracking source changes
|
||||
output: 'scrcpy-server.jar',
|
||||
output: 'scrcpy-server',
|
||||
command: [find_program('./scripts/build-wrapper.sh'), meson.current_source_dir(), '@OUTPUT@', get_option('buildtype')],
|
||||
console: true,
|
||||
install: true,
|
||||
@ -16,7 +16,7 @@ else
|
||||
endif
|
||||
custom_target('scrcpy-server-prebuilt',
|
||||
input: prebuilt_server,
|
||||
output: 'scrcpy-server.jar',
|
||||
output: 'scrcpy-server',
|
||||
command: ['cp', '@INPUT@', '@OUTPUT@'],
|
||||
install: true,
|
||||
install_dir: 'share/scrcpy')
|
||||
|
@ -82,7 +82,7 @@ public class Controller {
|
||||
injectText(msg.getText());
|
||||
break;
|
||||
case ControlMessage.TYPE_INJECT_TOUCH_EVENT:
|
||||
injectTouch(msg.getAction(), msg.getPointerId(), msg.getPosition(), msg.getPressure(), 0);
|
||||
injectTouch(msg.getAction(), msg.getPointerId(), msg.getPosition(), msg.getPressure(), msg.getButtons());
|
||||
break;
|
||||
case ControlMessage.TYPE_INJECT_SCROLL_EVENT:
|
||||
injectScroll(msg.getPosition(), msg.getHScroll(), msg.getVScroll());
|
||||
@ -177,7 +177,7 @@ public class Controller {
|
||||
}
|
||||
|
||||
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, action, pointerCount, pointerProperties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
|
||||
pointerCoords, 0, buttons, 1f, 1f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
|
||||
return injectEvent(event);
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ import java.io.IOException;
|
||||
|
||||
public final class Server {
|
||||
|
||||
private static final String SERVER_PATH = "/data/local/tmp/scrcpy-server.jar";
|
||||
private static final String SERVER_PATH = "/data/local/tmp/scrcpy-server";
|
||||
|
||||
private Server() {
|
||||
// not instantiable
|
||||
|
Reference in New Issue
Block a user