Compare commits

..

1 Commits

Author SHA1 Message Date
hltdev8642
baa9116561 Add ZSH completion
PR #3012 <https://github.com/Genymobile/scrcpy/pull/3012>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2022-02-21 22:45:46 +01:00
50 changed files with 229 additions and 1518 deletions

View File

@@ -272,10 +272,10 @@ install` must be run as root)._
#### Option 2: Use prebuilt server #### Option 2: Use prebuilt server
- [`scrcpy-server-v1.23`][direct-scrcpy-server] - [`scrcpy-server-v1.22`][direct-scrcpy-server]
_(SHA-256: 2a913fd47478c0b306fca507cb0beb625e49a19ff9fc7ab904e36ef5b9fe7e68)_ _(SHA-256: c05d273eec7533c0e106282e0254cf04e7f5e8f0c2920ca39448865fab2a419b)_
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.23/scrcpy-server-v1.23 [direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.22/scrcpy-server-v1.22
Download the prebuilt server somewhere, and specify its path during the Meson Download the prebuilt server somewhere, and specify its path during the Meson
configuration: configuration:

88
FAQ.md
View File

@@ -4,16 +4,23 @@
Here are the common reported problems and their status. Here are the common reported problems and their status.
If you encounter any error, the first step is to upgrade to the latest version.
## `adb` issues ## `adb` issues
`scrcpy` execute `adb` commands to initialize the connection with the device. If `scrcpy` execute `adb` commands to initialize the connection with the device. If
`adb` fails, then scrcpy will not work. `adb` fails, then scrcpy will not work.
In that case, it will print this error:
> ERROR: "adb get-serialno" returned with value 1
This is typically not a bug in _scrcpy_, but a problem in your environment. This is typically not a bug in _scrcpy_, but a problem in your environment.
To find out the cause, execute:
```bash
adb devices
```
### `adb` not found ### `adb` not found
@@ -23,30 +30,13 @@ On Windows, the current directory is in your `PATH`, and `adb.exe` is included
in the release, so it should work out-of-the-box. in the release, so it should work out-of-the-box.
### Device not detected
> ERROR: Could not find any ADB device
Check that you correctly enabled [adb debugging][enable-adb].
Your device must be detected by `adb`:
```
adb devices
```
If your device is not detected, you may need some [drivers] (on Windows). There is a separate [USB driver for Google devices][google-usb-driver].
[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
[drivers]: https://developer.android.com/studio/run/oem-usb.html
[google-usb-driver]: https://developer.android.com/studio/run/win-usb
### Device unauthorized ### Device unauthorized
> ERROR: Device is unauthorized:
> ERROR: --> (usb) 0123456789abcdef unauthorized > error: device unauthorized.
> ERROR: A popup should open on the device to request authorization. > This adb server's $ADB_VENDOR_KEYS is not set
> Try 'adb kill-server' if that seems wrong.
> Otherwise check for a confirmation dialog on your device.
When connecting, a popup should open on the device. You must authorize USB When connecting, a popup should open on the device. You must authorize USB
debugging. debugging.
@@ -56,27 +46,29 @@ If it does not open, check [stackoverflow][device-unauthorized].
[device-unauthorized]: https://stackoverflow.com/questions/23081263/adb-android-device-unauthorized [device-unauthorized]: https://stackoverflow.com/questions/23081263/adb-android-device-unauthorized
### Device not detected
> error: no devices/emulators found
Check that you correctly enabled [adb debugging][enable-adb].
If your device is not detected, you may need some [drivers] (on Windows). There is a separate [USB driver for Google devices][google-usb-driver].
[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
[drivers]: https://developer.android.com/studio/run/oem-usb.html
[google-usb-driver]: https://developer.android.com/studio/run/win-usb
### Several devices connected ### Several devices connected
If several devices are connected, you will encounter this error: If several devices are connected, you will encounter this error:
ERROR: Multiple (2) ADB devices: > error: more than one device/emulator
ERROR: --> (usb) 0123456789abcdef device Nexus_5
ERROR: --> (tcpip) 192.168.1.5:5555 device GM1913
ERROR: Select a device via -s (--serial), -d (--select-usb) or -e (--select-tcpip)
In that case, you can either provide the identifier of the device you want to the identifier of the device you want to mirror must be provided:
mirror:
```bash ```bash
scrcpy -s 0123456789abcdef scrcpy -s 01234567890abcdef
```
Or request the single USB (or TCP/IP) device:
```bash
scrcpy -d # USB device
scrcpy -e # TCP/IP device
``` ```
Note that if your device is connected over TCP/IP, you might get this message: Note that if your device is connected over TCP/IP, you might get this message:
@@ -158,24 +150,22 @@ screen, then you might get poor quality, especially visible on text (see [#40]).
[#40]: https://github.com/Genymobile/scrcpy/issues/40 [#40]: https://github.com/Genymobile/scrcpy/issues/40
This problem should be fixed in scrcpy v1.22: **update to the latest version**. To improve downscaling quality, trilinear filtering is enabled automatically
if the renderer is OpenGL and if it supports mipmapping.
On older versions, you must configure the [scaling behavior]: On Windows, you might want to force OpenGL:
```
scrcpy --render-driver=opengl
```
You may also need to configure the [scaling behavior]:
> `scrcpy.exe` > Properties > Compatibility > Change high DPI settings > > `scrcpy.exe` > Properties > Compatibility > Change high DPI settings >
> Override high DPI scaling behavior > Scaling performed by: _Application_. > Override high DPI scaling behavior > Scaling performed by: _Application_.
[scaling behavior]: https://github.com/Genymobile/scrcpy/issues/40#issuecomment-424466723 [scaling behavior]: https://github.com/Genymobile/scrcpy/issues/40#issuecomment-424466723
Also, to improve downscaling quality, trilinear filtering is enabled
automatically if the renderer is OpenGL and if it supports mipmapping.
On Windows, you might want to force OpenGL to enable mipmapping:
```
scrcpy --render-driver=opengl
```
### Issue with Wayland ### Issue with Wayland

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
# scrcpy (v1.23) # scrcpy (v1.22)
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" /> <img src="data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
_pronounced "**scr**een **c**o**py**"_ _pronounced "**scr**een **c**o**py**"_
@@ -32,8 +32,10 @@ Its features include:
- [configurable quality](#capture-configuration) - [configurable quality](#capture-configuration)
- device screen [as a webcam (V4L2)](#v4l2loopback) (Linux-only) - device screen [as a webcam (V4L2)](#v4l2loopback) (Linux-only)
- [physical keyboard simulation (HID)](#physical-keyboard-simulation-hid) - [physical keyboard simulation (HID)](#physical-keyboard-simulation-hid)
(Linux-only)
- [physical mouse simulation (HID)](#physical-mouse-simulation-hid) - [physical mouse simulation (HID)](#physical-mouse-simulation-hid)
- [OTG mode](#otg) (Linux-only)
- [OTG mode](#otg) (Linux-only)
- and more… - and more…
## Requirements ## Requirements
@@ -106,10 +108,10 @@ process][BUILD_simple]).
For Windows, for simplicity, a prebuilt archive with all the dependencies For Windows, for simplicity, a prebuilt archive with all the dependencies
(including `adb`) is available: (including `adb`) is available:
- [`scrcpy-win64-v1.23.zip`][direct-win64] - [`scrcpy-win64-v1.22.zip`][direct-win64]
_(SHA-256: d2f601b1d0157faf65153d8a093d827fd65aec5d5842d677ac86fb2b5b7704cc)_ _(SHA-256: ce4d9b8cc761e29862c4a72d8ad6f538bdd1f1831d15fd1f36633cd3b403db82)_
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.23/scrcpy-win64-v1.23.zip [direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.22/scrcpy-win64-v1.22.zip
It is also available in [Chocolatey]: It is also available in [Chocolatey]:
@@ -404,30 +406,18 @@ connect to the device before starting.
Alternatively, it is possible to enable the TCP/IP connection manually using Alternatively, it is possible to enable the TCP/IP connection manually using
`adb`: `adb`:
1. Plug the device into a USB port on your computer. 1. Connect the device to the same Wi-Fi as your computer.
2. Connect the device to the same Wi-Fi network as your computer. 2. Get your device IP address, in Settings → About phone → Status, or by
3. Get your device IP address, in Settings → About phone → Status, or by
executing this command: executing this command:
```bash ```bash
adb shell ip route | awk '{print $9}' adb shell ip route | awk '{print $9}'
``` ```
4. Enable adb over TCP/IP on your device: `adb tcpip 5555`. 3. Enable adb over TCP/IP on your device: `adb tcpip 5555`.
5. Unplug your device. 4. Unplug your device.
6. Connect to your device: `adb connect DEVICE_IP:5555` _(replace `DEVICE_IP` 5. Connect to your device: `adb connect DEVICE_IP:5555` _(replace `DEVICE_IP`)_.
with the device IP address you found)_. 6. Run `scrcpy` as usual.
7. Run `scrcpy` as usual.
Since Android 11, a [Wireless debugging option][adb-wireless] allows to bypass
having to physically connect your device directly to your computer.
[adb-wireless]: https://developer.android.com/studio/command-line/adb#connect-to-a-device-over-wi-fi-android-11+
If the connection randomly drops, run your `scrcpy` command to reconnect. If it
says there are no devices/emulators found, try running `adb connect
DEVICE_IP:5555` again, and then `scrcpy` as usual. If it still says there are
none found, try running `adb disconnect` and then run those two commands again.
It may be useful to decrease the bit-rate and the definition: It may be useful to decrease the bit-rate and the definition:
@@ -448,9 +438,6 @@ scrcpy --serial 0123456789abcdef
scrcpy -s 0123456789abcdef # short version scrcpy -s 0123456789abcdef # short version
``` ```
The serial may also be provided via the environment variable `ANDROID_SERIAL`
(also used by `adb`).
If the device is connected over TCP/IP: If the device is connected over TCP/IP:
```bash ```bash
@@ -820,17 +807,14 @@ a location inverted through the center of the screen.
By default, scrcpy uses Android key or text injection: it works everywhere, but By default, scrcpy uses Android key or text injection: it works everywhere, but
is limited to ASCII. is limited to ASCII.
Alternatively, scrcpy can simulate a physical USB keyboard on Android to provide On Linux, scrcpy can simulate a physical USB keyboard on Android to provide a
a better input experience (using [USB HID over AOAv2][hid-aoav2]): the virtual better input experience (using [USB HID over AOAv2][hid-aoav2]): the virtual
keyboard is disabled and it works for all characters and IME. keyboard is disabled and it works for all characters and IME.
[hid-aoav2]: https://source.android.com/devices/accessories/aoa2#hid-support [hid-aoav2]: https://source.android.com/devices/accessories/aoa2#hid-support
However, it only works if the device is connected by USB. However, it only works if the device is connected by USB, and is currently only
supported on Linux.
Note: On Windows, it may only work in [OTG mode](#otg), not while mirroring (it
is not possible to open a USB device if it is already open by another process
like the adb daemon).
To enable this mode: To enable this mode:
@@ -863,7 +847,8 @@ a physical keyboard is connected).
#### Physical mouse simulation (HID) #### Physical mouse simulation (HID)
Similarly to the physical keyboard simulation, it is possible to simulate a Similarly to the physical keyboard simulation, it is possible to simulate a
physical mouse. Likewise, it only works if the device is connected by USB. physical mouse. Likewise, it only works if the device is connected by USB, and
is currently only supported on Linux.
By default, scrcpy uses Android mouse events injection, using absolute By default, scrcpy uses Android mouse events injection, using absolute
coordinates. By simulating a physical mouse, a mouse pointer appears on the coordinates. By simulating a physical mouse, a mouse pointer appears on the
@@ -916,7 +901,7 @@ scrcpy --otg # keyboard and mouse
``` ```
Like `--hid-keyboard` and `--hid-mouse`, it only works if the device is Like `--hid-keyboard` and `--hid-mouse`, it only works if the device is
connected by USB. connected by USB, and is currently only supported on Linux.
#### Text injection preference #### Text injection preference
@@ -1108,9 +1093,7 @@ See [BUILD].
## Common issues ## Common issues
See the [FAQ].md). See the [FAQ](FAQ.md).
[FAQ]: FAQ.md
## Developers ## Developers
@@ -1145,22 +1128,10 @@ Read the [developers page].
[article-intro]: https://blog.rom1v.com/2018/03/introducing-scrcpy/ [article-intro]: https://blog.rom1v.com/2018/03/introducing-scrcpy/
[article-tcpip]: https://www.genymotion.com/blog/open-source-project-scrcpy-now-works-wirelessly/ [article-tcpip]: https://www.genymotion.com/blog/open-source-project-scrcpy-now-works-wirelessly/
## Contact
If you encounter a bug, please read the [FAQ] first, then open an [issue].
[issue]: https://github.com/Genymobile/scrcpy/issues
For general questions or discussions, you could also use:
- Reddit: [`r/scrcpy`](https://www.reddit.com/r/scrcpy)
- Twitter: [`@scrcpy_app`](https://twitter.com/scrcpy_app)
## Translations ## Translations
This README is available in other languages: This README is available in other languages:
- [Deutsch (German, `de`) - v1.22](README.de.md)
- [Indonesian (Indonesia, `id`) - v1.16](README.id.md) - [Indonesian (Indonesia, `id`) - v1.16](README.id.md)
- [Italiano (Italiano, `it`) - v1.19](README.it.md) - [Italiano (Italiano, `it`) - v1.19](README.it.md)
- [日本語 (Japanese, `jp`) - v1.19](README.jp.md) - [日本語 (Japanese, `jp`) - v1.19](README.jp.md)

View File

@@ -1,121 +0,0 @@
_scrcpy() {
local cur prev words cword
local opts="
--always-on-top
-b --bit-rate=
--codec-options=
--crop=
-d --select-usb
--disable-screensaver
--display=
--display-buffer=
-e --select-tcpip
--encoder=
--force-adb-forward
--forward-all-clicks
-f --fullscreen
-K --hid-keyboard
-h --help
--legacy-paste
--lock-video-orientation
--lock-video-orientation=
--max-fps=
-M --hid-mouse
-m --max-size=
--no-cleanup
--no-clipboard-on-error
--no-downsize-on-error
-n --no-control
-N --no-display
--no-key-repeat
--no-mipmaps
--otg
-p --port=
--power-off-on-close
--prefer-text
--print-fps
--push-target=
--raw-key-events
-r --record=
--record-format=
--render-driver=
--rotation=
-s --serial=
--shortcut-mod=
-S --turn-screen-off
-t --show-touches
--tcpip
--tcpip=
--tunnel-host=
--tunnel-port=
--v4l2-buffer=
--v4l2-sink=
-V --verbosity=
-v --version
-w --stay-awake
--window-borderless
--window-title=
--window-x=
--window-y=
--window-width=
--window-height="
_init_completion -s || return
case "$prev" in
--lock-video-orientation)
COMPREPLY=($(compgen -W 'unlocked initial 0 1 2 3' -- "$cur"))
return
;;
-r|--record)
COMPREPLY=($(compgen -f -- "$cur"))
return
;;
--record-format)
COMPREPLY=($(compgen -W 'mkv mp4' -- "$cur"))
return
;;
--render-driver)
COMPREPLY=($(compgen -W 'direct3d opengl opengles2 opengles metal software' -- "$cur"))
return
;;
--rotation)
COMPREPLY=($(compgen -W '0 1 2 3' -- "$cur"))
return
;;
--shortcut-mod)
# Only auto-complete a single key
COMPREPLY=($(compgen -W 'lctrl rctrl lalt ralt lsuper rsuper' -- "$cur"))
return
;;
-V|--verbosity)
COMPREPLY=($(compgen -W 'verbose debug info warn error' -- "$cur"))
return
;;
-b|--bitrate \
|--codec-options \
|--crop \
|--display \
|--display-buffer \
|--encoder \
|--max-fps \
|-m|--max-size \
|-p|--port \
|--push-target \
|-s|--serial \
|--tunnel-host \
|--tunnel-port \
|--v4l2-buffer \
|--v4l2-sink \
|--tcpip \
|--window-*)
# Option accepting an argument, but nothing to auto-complete
return
;;
esac
COMPREPLY=($(compgen -W "$opts" -- "$cur"))
[[ $COMPREPLY == *= ]] && compopt -o nospace
}
complete -F _scrcpy scrcpy

View File

@@ -9,25 +9,25 @@ local arguments
arguments=( arguments=(
'--always-on-top[Make scrcpy window always on top \(above other windows\)]' '--always-on-top[Make scrcpy window always on top \(above other windows\)]'
{-b,--bit-rate=}'[Encode the video at the given bit-rate]' {-b,--bit-rate}'[\[value\] Encode the video at the given bit-rate]'
'--codec-options=[Set a list of comma-separated key\:type=value options for the device encoder]' '--codec-options[\[key\] Set a list of comma-separated key\:type=value options for the device encoder]'
'--crop=[\[width\:height\:x\:y\] Crop the device screen on the server]' '--crop[\[width\:height\:x\:y\] Crop the device screen on the server]'
{-d,--select-usb}'[Use USB device]' {-d,--select-usb}'[Use USB device]'
'--disable-screensaver[Disable screensaver while scrcpy is running]' '--disable-screensaver[Disable screensaver while scrcpy is running]'
'--display=[Specify the display id to mirror]' '--display[\[id\] Specify the display id to mirror]'
'--display-buffer=[Add a buffering delay \(in milliseconds\) before displaying]' '--display-buffer[\[ms\] Add a buffering delay \(in milliseconds\) before displaying]'
{-e,--select-tcpip}'[Use TCP/IP device]' {-e,--select-tcpip}'[Use TCP/IP device]'
'--encoder=[Use a specific MediaCodec encoder \(must be a H.264 encoder\)]' '--encoder[\[name\] Use a specific MediaCodec encoder \(must be a H.264 encoder\)]'
'--force-adb-forward[Do not attempt to use \"adb reverse\" to connect to the device]' '--force-adb-forward[Do not attempt to use \"adb reverse\" to connect to the device]'
'--forward-all-clicks[Forward clicks to device]' '--forward-all-clicks[Forward clicks to device]'
{-f,--fullscreen}'[Start in fullscreen]' {-f,--fullscreen}'[Start in fullscreen]'
{-K,--hid-keyboard}'[Simulate a physical keyboard by using HID over AOAv2]' {-K,--hid-keyboard}'[Simulate a physical keyboard by using HID over AOAv2]'
{-h,--help}'[Print the help]' {-h,--help}'[Print the help]'
'--legacy-paste[Inject computer clipboard text as a sequence of key events on Ctrl+v]' '--legacy-paste[Inject computer clipboard text as a sequence of key events on Ctrl+v]'
'--lock-video-orientation=[Lock video orientation]:orientation:(unlocked initial 0 1 2 3)' '--lock-video-orientation[\[value\] Lock video orientation to value \(unlocked, initial, 0, 1, 2, 3\)]'
'--max-fps=[Limit the frame rate of screen capture]' '--max-fps[\[value\] Limit the frame rate of screen capture]'
{-M,--hid-mouse}'[Simulate a physical mouse by using HID over AOAv2]' {-M,--hid-mouse}'[Simulate a physical mouse by using HID over AOAv2]'
{-m,--max-size=}'[Limit both the width and height of the video to value]' {-m,--max-size}'[\[value\] Limit both the width and height of the video to value]'
'--no-cleanup[Disable device cleanup actions on exit]' '--no-cleanup[Disable device cleanup actions on exit]'
'--no-clipboard-autosync[Disable automatic clipboard synchronization]' '--no-clipboard-autosync[Disable automatic clipboard synchronization]'
'--no-downsize-on-error[Disable lowering definition on MediaCodec error]' '--no-downsize-on-error[Disable lowering definition on MediaCodec error]'
@@ -36,34 +36,34 @@ arguments=(
'--no-key-repeat[Do not forward repeated key events when a key is held down]' '--no-key-repeat[Do not forward repeated key events when a key is held down]'
'--no-mipmaps[Disable the generation of mipmaps]' '--no-mipmaps[Disable the generation of mipmaps]'
'--otg[Run in OTG mode \(simulating physical keyboard and mouse\)]' '--otg[Run in OTG mode \(simulating physical keyboard and mouse\)]'
{-p,--port=}'[\[port\[\:port\]\] Set the TCP port \(range\) used by the client to listen]' {-p,--port}'[\[port\:port\] Set the TCP port \(range\) used by the client to listen]'
'--power-off-on-close[Turn the device screen off when closing scrcpy]' '--power-off-on-close[Turn the device screen off when closing scrcpy]'
'--prefer-text[Inject alpha characters and space as text events instead of key events]' '--prefer-text[Inject alpha characters and space as text events instead of key events]'
'--print-fps[Start FPS counter, to print frame logs to the console]' '--print-fps[Start FPS counter, to print frame logs to the console]'
'--push-target=[Set the target directory for pushing files to the device by drag and drop]' '--push-target[\[path\] Set the target directory for pushing files to the device by drag and drop]'
'--raw-key-events[Inject key events for all input keys, and ignore text events]' '--raw-key-events[Inject key events for all input keys, and ignore text events]'
{-r,--record=}'[Record screen to file]:record file:_files' {-r,--record}'[\[file.mp4\] Record screen to file]'
'--record-format=[Force recording format]:format:(mp4 mkv)' '--record-format[\[format\] Force recording format \(mp4, mkv\)]'
'--render-driver=[Request SDL to use the given render driver]:driver name:(direct3d opengl opengles2 opengles metal software)' '--render-driver[\[name\] Request SDL to use the given render driver \(direct3d, opengl, opengles2, opengles, metal, software\)]'
'--rotation=[Set the initial display rotation]:rotation values:(0 1 2 3)' '--rotation[\[value\] Set the initial display rotation \(0, 1, 2, 3\)]'
{-s,--serial=}'[The device serial number \(mandatory for multiple devices only\)]' {-s,--serial}'[\[serial\] The device serial number \(mandatory for multiple devices only\)]'
'--shortcut-mod=[\[key1,key2+key3,...\] Specify the modifiers to use for scrcpy shortcuts]:shortcut mod:(lctrl rctrl lalt ralt lsuper rsuper)' '--shortcut-mod[\[key1,key2+key3,...\] Specify the modifiers to use for scrcpy shortcuts \(lctrl, rctrl, lalt, ralt, lsuper, rsuper\)]'
{-S,--turn-screen-off}'[Turn the device screen off immediately]' {-S,--turn-screen-off}'[Turn the device screen off immediately]'
{-t,--show-touches}'[Show physical touches]' {-t,--show-touches}'[Show physical touches]'
'--tcpip[\(optional \[ip\:port\]\) Configure and connect the device over TCP/IP]' '--tunnel-host[\[ip\] Set the IP address of the adb tunnel to reach the scrcpy server]'
'--tunnel-host=[Set the IP address of the adb tunnel to reach the scrcpy server]' '--tunnel-port[\[port\] Set the TCP port of the adb tunnel to reach the scrcpy server]'
'--tunnel-port=[Set the TCP port of the adb tunnel to reach the scrcpy server]' '--v4l2-buffer[\[ms\] Add a buffering delay \(in milliseconds\) before pushing frames]'
'--v4l2-buffer=[Add a buffering delay \(in milliseconds\) before pushing frames]' '--v4l2-sink[\[\/dev\/videoN\] Output to v4l2loopback device]'
'--v4l2-sink=[\[\/dev\/videoN\] Output to v4l2loopback device]' {-V,--verbosity}'[\[value\] Set the log level \(verbose, debug, info, warn, error\)]'
{-V,--verbosity=}'[Set the log level]:verbosity:(verbose debug info warn error)'
{-v,--version}'[Print the version of scrcpy]' {-v,--version}'[Print the version of scrcpy]'
{-w,--stay-awake}'[Keep the device on while scrcpy is running, when the device is plugged in]' {-w,--stay-awake}'[Keep the device on while scrcpy is running, when the device is plugged in]'
'--tcpip[\[ip\:port\] Configure and connect the device over TCP/IP]'
'--window-borderless[Disable window decorations \(display borderless window\)]' '--window-borderless[Disable window decorations \(display borderless window\)]'
'--window-title=[Set a custom window title]' '--window-title[\[text\] Set a custom window title]'
'--window-x=[Set the initial window horizontal position]' '--window-x[\[value\] Set the initial window horizontal position]'
'--window-y=[Set the initial window vertical position]' '--window-y[\[value\] Set the initial window vertical position]'
'--window-width=[Set the initial window width]' '--window-width[\[value\] Set the initial window width]'
'--window-height=[Set the initial window height]' '--window-height[\[value\] Set the initial window height]'
) )
_arguments -s $arguments _arguments -s $arguments

View File

@@ -143,12 +143,12 @@ else
prebuilt_libusb = meson.get_cross_property('prebuilt_libusb') prebuilt_libusb = meson.get_cross_property('prebuilt_libusb')
prebuilt_libusb_root = meson.get_cross_property('prebuilt_libusb_root') prebuilt_libusb_root = meson.get_cross_property('prebuilt_libusb_root')
libusb_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_libusb libusb_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_libusb + '/dll'
libusb_include_dir = 'prebuilt-deps/data/' + prebuilt_libusb_root + '/include' libusb_include_dir = 'prebuilt-deps/data/' + prebuilt_libusb_root + '/include'
libusb = declare_dependency( libusb = declare_dependency(
dependencies: [ dependencies: [
cc.find_library('msys-usb-1.0', dirs: libusb_bin_dir), cc.find_library('libusb-1.0', dirs: libusb_bin_dir),
], ],
include_directories: include_directories(libusb_include_dir) include_directories: include_directories(libusb_include_dir)
) )
@@ -229,8 +229,6 @@ install_data('data/icon.png',
install_dir: 'share/icons/hicolor/256x256/apps') install_dir: 'share/icons/hicolor/256x256/apps')
install_data('data/zsh-completion/_scrcpy', install_data('data/zsh-completion/_scrcpy',
install_dir: 'share/zsh/site-functions') install_dir: 'share/zsh/site-functions')
install_data('data/bash-completion/scrcpy',
install_dir: 'share/bash-completion/completions')
### TESTS ### TESTS

View File

@@ -6,10 +6,10 @@ cd "$DIR"
mkdir -p "$PREBUILT_DATA_DIR" mkdir -p "$PREBUILT_DATA_DIR"
cd "$PREBUILT_DATA_DIR" cd "$PREBUILT_DATA_DIR"
DEP_DIR=platform-tools-33.0.1 DEP_DIR=platform-tools-31.0.3
FILENAME=platform-tools_r33.0.1-windows.zip FILENAME=platform-tools_r31.0.3-windows.zip
SHA256SUM=c1f02d42ea24ef4ff2a405ae7370e764ef4546f9b3e4520f5571a00ed5012c42 SHA256SUM=0f4b8fdd26af2c3733539d6eebb3c2ed499ea1d4bb1f4e0ecc2d6016961a6e24
if [[ -d "$DEP_DIR" ]] if [[ -d "$DEP_DIR" ]]
then then

View File

@@ -6,10 +6,10 @@ cd "$DIR"
mkdir -p "$PREBUILT_DATA_DIR" mkdir -p "$PREBUILT_DATA_DIR"
cd "$PREBUILT_DATA_DIR" cd "$PREBUILT_DATA_DIR"
DEP_DIR=libusb-1.0.26 DEP_DIR=libusb-1.0.25
FILENAME=libusb-1.0.26-binaries.7z FILENAME=libusb-1.0.25.7z
SHA256SUM=9c242696342dbde9cdc47239391f71833939bf9f7aa2bbb28cdaabe890465ec5 SHA256SUM=3d1c98416f454026034b2b5d67f8a294053898cb70a8b489874e75b136c6674d
if [[ -d "$DEP_DIR" ]] if [[ -d "$DEP_DIR" ]]
then then
@@ -17,18 +17,12 @@ then
exit 0 exit 0
fi fi
get_file "https://github.com/libusb/libusb/releases/download/v1.0.26/$FILENAME" "$FILENAME" "$SHA256SUM" get_file "https://github.com/libusb/libusb/releases/download/v1.0.25/$FILENAME" "$FILENAME" "$SHA256SUM"
mkdir "$DEP_DIR" mkdir "$DEP_DIR"
cd "$DEP_DIR" cd "$DEP_DIR"
# include/ is the same in all folders of the archive
7z x "../$FILENAME" \ 7z x "../$FILENAME" \
libusb-1.0.26-binaries/libusb-MinGW-Win32/bin/msys-usb-1.0.dll \ MinGW32/dll/libusb-1.0.dll \
libusb-1.0.26-binaries/libusb-MinGW-x64/bin/msys-usb-1.0.dll \ MinGW64/dll/libusb-1.0.dll \
libusb-1.0.26-binaries/libusb-MinGW-x64/include/ include /
mv libusb-1.0.26-binaries/libusb-MinGW-Win32/bin MinGW-Win32
mv libusb-1.0.26-binaries/libusb-MinGW-x64/bin MinGW-x64
mv libusb-1.0.26-binaries/libusb-MinGW-x64/include .
rm -rf libusb-1.0.26-binaries

View File

@@ -13,7 +13,7 @@ BEGIN
VALUE "LegalCopyright", "Romain Vimont, Genymobile" VALUE "LegalCopyright", "Romain Vimont, Genymobile"
VALUE "OriginalFilename", "scrcpy.exe" VALUE "OriginalFilename", "scrcpy.exe"
VALUE "ProductName", "scrcpy" VALUE "ProductName", "scrcpy"
VALUE "ProductVersion", "1.23" VALUE "ProductVersion", "1.22"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@@ -355,12 +355,6 @@ Set the initial window height.
Default is 0 (automatic). Default is 0 (automatic).
.SH EXIT STATUS
.B scrcpy
will exit with code 0 on normal program termination. If an initial
connection cannot be established, the exit code 1 will be returned. If the
device disconnects while a session is active, exit code 2 will be returned.
.SH SHORTCUTS .SH SHORTCUTS
In the following list, MOD is the shortcut modifier. By default, it's (left) In the following list, MOD is the shortcut modifier. By default, it's (left)
@@ -477,10 +471,6 @@ Push file to device (see \fB\-\-push\-target\fR)
.B ADB .B ADB
Path to adb. Path to adb.
.TP
.B ANDROID_SERIAL
Device serial to use if no selector (-s, -d, -e or --tcpip=<addr>) is specified.
.TP .TP
.B SCRCPY_ICON_PATH .B SCRCPY_ICON_PATH
Path to the program icon. Path to the program icon.

View File

@@ -473,12 +473,9 @@ sc_adb_accept_device(const struct sc_adb_device *device,
} }
return !strcmp(selector->serial, device->serial); return !strcmp(selector->serial, device->serial);
case SC_ADB_DEVICE_SELECT_USB: case SC_ADB_DEVICE_SELECT_USB:
return sc_adb_device_get_type(device->serial) == return !sc_adb_is_serial_tcpip(device->serial);
SC_ADB_DEVICE_TYPE_USB;
case SC_ADB_DEVICE_SELECT_TCPIP: case SC_ADB_DEVICE_SELECT_TCPIP:
// Both emulators and TCP/IP devices are selected via -e return sc_adb_is_serial_tcpip(device->serial);
return sc_adb_device_get_type(device->serial) !=
SC_ADB_DEVICE_TYPE_USB;
default: default:
assert(!"Missing SC_ADB_DEVICE_SELECT_* handling"); assert(!"Missing SC_ADB_DEVICE_SELECT_* handling");
break; break;
@@ -512,10 +509,8 @@ sc_adb_devices_log(enum sc_log_level level, struct sc_adb_device *devices,
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
struct sc_adb_device *d = &devices[i]; struct sc_adb_device *d = &devices[i];
const char *selection = d->selected ? "-->" : " "; const char *selection = d->selected ? "-->" : " ";
bool is_usb = const char *type = sc_adb_is_serial_tcpip(d->serial) ? "(tcpip)"
sc_adb_device_get_type(d->serial) == SC_ADB_DEVICE_TYPE_USB; : " (usb)";
const char *type = is_usb ? " (usb)"
: "(tcpip)";
LOG(level, " %s %s %-20s %16s %s", LOG(level, " %s %s %-20s %16s %s",
selection, type, d->serial, d->state, d->model ? d->model : ""); selection, type, d->serial, d->state, d->model ? d->model : "");
} }
@@ -536,8 +531,6 @@ sc_adb_device_check_state(struct sc_adb_device *device,
LOGE("A popup should open on the device to request authorization."); LOGE("A popup should open on the device to request authorization.");
LOGE("Check the FAQ: " LOGE("Check the FAQ: "
"<https://github.com/Genymobile/scrcpy/blob/master/FAQ.md>"); "<https://github.com/Genymobile/scrcpy/blob/master/FAQ.md>");
} else {
LOGE("Device could not be connected (state=%s)", state);
} }
return false; return false;
@@ -712,3 +705,8 @@ sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags) {
return sc_adb_parse_device_ip_from_output(buf); return sc_adb_parse_device_ip_from_output(buf);
} }
bool
sc_adb_is_serial_tcpip(const char *serial) {
return strchr(serial, ':');
}

View File

@@ -114,4 +114,13 @@ sc_adb_getprop(struct sc_intr *intr, const char *serial, const char *prop,
char * char *
sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags); sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags);
/**
* Indicate if the serial represents an IP address
*
* In practice, it just returns true if and only if it contains a ':', which is
* sufficient to distinguish an ip:port from a real USB serial.
*/
bool
sc_adb_is_serial_tcpip(const char *serial);
#endif #endif

View File

@@ -1,7 +1,6 @@
#include "adb_device.h" #include "adb_device.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
void void
sc_adb_device_destroy(struct sc_adb_device *device) { sc_adb_device_destroy(struct sc_adb_device *device) {
@@ -26,18 +25,3 @@ sc_adb_devices_destroy(struct sc_vec_adb_devices *devices) {
sc_vector_destroy(devices); sc_vector_destroy(devices);
} }
enum sc_adb_device_type
sc_adb_device_get_type(const char *serial) {
// Starts with "emulator-"
if (!strncmp(serial, "emulator-", sizeof("emulator-") - 1)) {
return SC_ADB_DEVICE_TYPE_EMULATOR;
}
// If the serial contains a ':', then it is a TCP/IP device (it is
// sufficient to distinguish an ip:port from a real USB serial)
if (strchr(serial, ':')) {
return SC_ADB_DEVICE_TYPE_TCPIP;
}
return SC_ADB_DEVICE_TYPE_USB;
}

View File

@@ -15,12 +15,6 @@ struct sc_adb_device {
bool selected; bool selected;
}; };
enum sc_adb_device_type {
SC_ADB_DEVICE_TYPE_USB,
SC_ADB_DEVICE_TYPE_TCPIP,
SC_ADB_DEVICE_TYPE_EMULATOR,
};
struct sc_vec_adb_devices SC_VECTOR(struct sc_adb_device); struct sc_vec_adb_devices SC_VECTOR(struct sc_adb_device);
void void
@@ -41,10 +35,4 @@ sc_adb_device_move(struct sc_adb_device *dst, struct sc_adb_device *src);
void void
sc_adb_devices_destroy(struct sc_vec_adb_devices *devices); sc_adb_devices_destroy(struct sc_vec_adb_devices *devices);
/**
* Deduce the device type from the serial
*/
enum sc_adb_device_type
sc_adb_device_get_type(const char *serial);
#endif #endif

View File

@@ -80,11 +80,6 @@ struct sc_envvar {
const char *text; const char *text;
}; };
struct sc_exit_status {
unsigned value;
const char *text;
};
struct sc_getopt_adapter { struct sc_getopt_adapter {
char *optstring; char *optstring;
struct option *longopts; struct option *longopts;
@@ -427,20 +422,6 @@ static const struct sc_option options[] = {
"on exit.\n" "on exit.\n"
"It only shows physical touches (not clicks from scrcpy).", "It only shows physical touches (not clicks from scrcpy).",
}, },
{
.longopt_id = OPT_TCPIP,
.longopt = "tcpip",
.argdesc = "ip[:port]",
.optional_arg = true,
.text = "Configure and reconnect the device over TCP/IP.\n"
"If a destination address is provided, then scrcpy connects to "
"this address before starting. The device must listen on the "
"given TCP port (default is 5555).\n"
"If no destination address is provided, then scrcpy attempts "
"to find the IP address of the current device (typically "
"connected over USB), enables TCP/IP mode, then connects to "
"this address before starting.",
},
{ {
.longopt_id = OPT_TUNNEL_HOST, .longopt_id = OPT_TUNNEL_HOST,
.longopt = "tunnel-host", .longopt = "tunnel-host",
@@ -502,6 +483,20 @@ static const struct sc_option options[] = {
.text = "Keep the device on while scrcpy is running, when the device " .text = "Keep the device on while scrcpy is running, when the device "
"is plugged in.", "is plugged in.",
}, },
{
.longopt_id = OPT_TCPIP,
.longopt = "tcpip",
.argdesc = "ip[:port]",
.optional_arg = true,
.text = "Configure and reconnect the device over TCP/IP.\n"
"If a destination address is provided, then scrcpy connects to "
"this address before starting. The device must listen on the "
"given TCP port (default is 5555).\n"
"If no destination address is provided, then scrcpy attempts "
"to find the IP address of the current device (typically "
"connected over USB), enables TCP/IP mode, then connects to "
"this address before starting.",
},
{ {
.longopt_id = OPT_WINDOW_BORDERLESS, .longopt_id = OPT_WINDOW_BORDERLESS,
.longopt = "window-borderless", .longopt = "window-borderless",
@@ -660,11 +655,6 @@ static const struct sc_envvar envvars[] = {
.name = "ADB", .name = "ADB",
.text = "Path to adb executable", .text = "Path to adb executable",
}, },
{
.name = "ANDROID_SERIAL",
.text = "Device serial to use if no selector (-s, -d, -e or "
"--tcpip=<addr>) is specified",
},
{ {
.name = "SCRCPY_ICON_PATH", .name = "SCRCPY_ICON_PATH",
.text = "Path to the program icon", .text = "Path to the program icon",
@@ -672,22 +662,7 @@ static const struct sc_envvar envvars[] = {
{ {
.name = "SCRCPY_SERVER_PATH", .name = "SCRCPY_SERVER_PATH",
.text = "Path to the server binary", .text = "Path to the server binary",
}, }
};
static const struct sc_exit_status exit_statuses[] = {
{
.value = 0,
.text = "Normal program termination",
},
{
.value = 1,
.text = "Start failure",
},
{
.value = 2,
.text = "Device disconnected while running",
},
}; };
static char * static char *
@@ -926,25 +901,6 @@ print_envvar(const struct sc_envvar *envvar, unsigned cols) {
free(text); free(text);
} }
static void
print_exit_status(const struct sc_exit_status *status, unsigned cols) {
assert(cols > 8); // sc_str_wrap_lines() requires indent < columns
assert(status->text);
// The text starts at 9: 4 ident spaces, 3 chars for numeric value, 2 spaces
char *text = sc_str_wrap_lines(status->text, cols, 9);
if (!text) {
printf("<ERROR>\n");
return;
}
assert(strlen(text) >= 9); // Contains at least the initial identation
// text + 9 to remove the initial indentation
printf(" %3d %s\n", status->value, text + 9);
free(text);
}
void void
scrcpy_print_usage(const char *arg0) { scrcpy_print_usage(const char *arg0) {
#define SC_TERM_COLS_DEFAULT 80 #define SC_TERM_COLS_DEFAULT 80
@@ -983,11 +939,6 @@ scrcpy_print_usage(const char *arg0) {
for (size_t i = 0; i < ARRAY_LEN(envvars); ++i) { for (size_t i = 0; i < ARRAY_LEN(envvars); ++i) {
print_envvar(&envvars[i], cols); print_envvar(&envvars[i], cols);
} }
printf("\nExit status:\n\n");
for (size_t i = 0; i < ARRAY_LEN(exit_statuses); ++i) {
print_exit_status(&exit_statuses[i], cols);
}
} }
static bool static bool

View File

@@ -1,5 +1,5 @@
#ifndef SC_COMMON_H #ifndef COMMON_H
#define SC_COMMON_H #define COMMON_H
#include "config.h" #include "config.h"
#include "compat.h" #include "compat.h"

View File

@@ -1,5 +1,5 @@
#ifndef SC_COMPAT_H #ifndef COMPAT_H
#define SC_COMPAT_H #define COMPAT_H
#include "config.h" #include "config.h"

View File

@@ -1,5 +1,5 @@
#ifndef SC_CONTROLMSG_H #ifndef CONTROLMSG_H
#define SC_CONTROLMSG_H #define CONTROLMSG_H
#include "common.h" #include "common.h"

View File

@@ -1,5 +1,5 @@
#ifndef SC_CONTROLLER_H #ifndef CONTROLLER_H
#define SC_CONTROLLER_H #define CONTROLLER_H
#include "common.h" #include "common.h"

View File

@@ -1,5 +1,5 @@
#ifndef SC_DEVICEMSG_H #ifndef DEVICEMSG_H
#define SC_DEVICEMSG_H #define DEVICEMSG_H
#include "common.h" #include "common.h"

View File

@@ -1,5 +1,5 @@
#ifndef SC_FPSCOUNTER_H #ifndef FPSCOUNTER_H
#define SC_FPSCOUNTER_H #define FPSCOUNTER_H
#include "common.h" #include "common.h"

View File

@@ -1,5 +1,5 @@
#ifndef SC_ICON_H #ifndef ICON_H
#define SC_ICON_H #define ICON_H
#include "common.h" #include "common.h"

View File

@@ -1,5 +1,5 @@
#ifndef SC_INPUTMANAGER_H #ifndef INPUTMANAGER_H
#define SC_INPUTMANAGER_H #define INPUTMANAGER_H
#include "common.h" #include "common.h"

View File

@@ -40,19 +40,19 @@ main(int argc, char *argv[]) {
#endif #endif
if (!scrcpy_parse_args(&args, argc, argv)) { if (!scrcpy_parse_args(&args, argc, argv)) {
return SCRCPY_EXIT_FAILURE; return 1;
} }
sc_set_log_level(args.opts.log_level); sc_set_log_level(args.opts.log_level);
if (args.help) { if (args.help) {
scrcpy_print_usage(argv[0]); scrcpy_print_usage(argv[0]);
return SCRCPY_EXIT_SUCCESS; return 0;
} }
if (args.version) { if (args.version) {
scrcpy_print_version(); scrcpy_print_version();
return SCRCPY_EXIT_SUCCESS; return 0;
} }
#ifdef SCRCPY_LAVF_REQUIRES_REGISTER_ALL #ifdef SCRCPY_LAVF_REQUIRES_REGISTER_ALL
@@ -66,17 +66,17 @@ main(int argc, char *argv[]) {
#endif #endif
if (avformat_network_init()) { if (avformat_network_init()) {
return SCRCPY_EXIT_FAILURE; return 1;
} }
#ifdef HAVE_USB #ifdef HAVE_USB
enum scrcpy_exit_code ret = args.opts.otg ? scrcpy_otg(&args.opts) bool ok = args.opts.otg ? scrcpy_otg(&args.opts)
: scrcpy(&args.opts); : scrcpy(&args.opts);
#else #else
enum scrcpy_exit_code ret = scrcpy(&args.opts); bool ok = scrcpy(&args.opts);
#endif #endif
avformat_network_deinit(); // ignore failure avformat_network_deinit(); // ignore failure
return ret; return ok ? 0 : 1;
} }

View File

@@ -28,7 +28,7 @@ sc_opengl_init(struct sc_opengl *gl) {
sizeof(OPENGL_ES_PREFIX) - 1); sizeof(OPENGL_ES_PREFIX) - 1);
if (gl->is_opengles) { if (gl->is_opengles) {
/* skip the prefix */ /* skip the prefix */
version += sizeof(OPENGL_ES_PREFIX) - 1; version += sizeof(PREFIX) - 1;
} }
int r = sscanf(version, "%d.%d", &gl->version_major, &gl->version_minor); int r = sscanf(version, "%d.%d", &gl->version_major, &gl->version_minor);

View File

@@ -1,5 +1,5 @@
#ifndef SC_RECEIVER_H #ifndef RECEIVER_H
#define SC_RECEIVER_H #define RECEIVER_H
#include "common.h" #include "common.h"

View File

@@ -149,41 +149,38 @@ sdl_configure(bool display, bool disable_screensaver) {
} }
} }
static enum scrcpy_exit_code static bool
event_loop(struct scrcpy *s) { event_loop(struct scrcpy *s) {
SDL_Event event; SDL_Event event;
while (SDL_WaitEvent(&event)) { while (SDL_WaitEvent(&event)) {
switch (event.type) { switch (event.type) {
case EVENT_STREAM_STOPPED: case EVENT_STREAM_STOPPED:
LOGW("Device disconnected"); LOGW("Device disconnected");
return SCRCPY_EXIT_DISCONNECTED; return false;
case SDL_QUIT: case SDL_QUIT:
LOGD("User requested to quit"); LOGD("User requested to quit");
return SCRCPY_EXIT_SUCCESS; return true;
default: default:
sc_screen_handle_event(&s->screen, &event); sc_screen_handle_event(&s->screen, &event);
break; break;
} }
} }
return SCRCPY_EXIT_FAILURE; return false;
} }
// Return true on success, false on error
static bool static bool
await_for_server(bool *connected) { await_for_server(void) {
SDL_Event event; SDL_Event event;
while (SDL_WaitEvent(&event)) { while (SDL_WaitEvent(&event)) {
switch (event.type) { switch (event.type) {
case SDL_QUIT: case SDL_QUIT:
LOGD("User requested to quit"); LOGD("User requested to quit");
*connected = false; return false;
return true;
case EVENT_SERVER_CONNECTION_FAILED: case EVENT_SERVER_CONNECTION_FAILED:
LOGE("Server connection failed"); LOGE("Server connection failed");
return false; return false;
case EVENT_SERVER_CONNECTED: case EVENT_SERVER_CONNECTED:
LOGD("Server connected"); LOGD("Server connected");
*connected = true;
return true; return true;
default: default:
break; break;
@@ -265,7 +262,7 @@ sc_server_on_disconnected(struct sc_server *server, void *userdata) {
// event // event
} }
enum scrcpy_exit_code bool
scrcpy(struct scrcpy_options *options) { scrcpy(struct scrcpy_options *options) {
static struct scrcpy scrcpy; static struct scrcpy scrcpy;
struct scrcpy *s = &scrcpy; struct scrcpy *s = &scrcpy;
@@ -273,12 +270,12 @@ scrcpy(struct scrcpy_options *options) {
// Minimal SDL initialization // Minimal SDL initialization
if (SDL_Init(SDL_INIT_EVENTS)) { if (SDL_Init(SDL_INIT_EVENTS)) {
LOGE("Could not initialize SDL: %s", SDL_GetError()); LOGE("Could not initialize SDL: %s", SDL_GetError());
return SCRCPY_EXIT_FAILURE; return false;
} }
atexit(SDL_Quit); atexit(SDL_Quit);
enum scrcpy_exit_code ret = SCRCPY_EXIT_FAILURE; bool ret = false;
bool server_started = false; bool server_started = false;
bool file_pusher_initialized = false; bool file_pusher_initialized = false;
@@ -332,7 +329,7 @@ scrcpy(struct scrcpy_options *options) {
.on_disconnected = sc_server_on_disconnected, .on_disconnected = sc_server_on_disconnected,
}; };
if (!sc_server_init(&s->server, &params, &cbs, NULL)) { if (!sc_server_init(&s->server, &params, &cbs, NULL)) {
return SCRCPY_EXIT_FAILURE; return false;
} }
if (!sc_server_start(&s->server)) { if (!sc_server_start(&s->server)) {
@@ -354,14 +351,7 @@ scrcpy(struct scrcpy_options *options) {
sdl_configure(options->display, options->disable_screensaver); sdl_configure(options->display, options->disable_screensaver);
// Await for server without blocking Ctrl+C handling // Await for server without blocking Ctrl+C handling
bool connected; if (!await_for_server()) {
if (!await_for_server(&connected)) {
goto end;
}
if (!connected) {
// This is not an error, user requested to quit
ret = SCRCPY_EXIT_SUCCESS;
goto end; goto end;
} }

View File

@@ -6,18 +6,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "options.h" #include "options.h"
enum scrcpy_exit_code { bool
// Normal program termination
SCRCPY_EXIT_SUCCESS,
// No connection could be established
SCRCPY_EXIT_FAILURE,
// Device was disconnected while running
SCRCPY_EXIT_DISCONNECTED,
};
enum scrcpy_exit_code
scrcpy(struct scrcpy_options *options); scrcpy(struct scrcpy_options *options);
#endif #endif

View File

@@ -649,8 +649,7 @@ sc_server_configure_tcpip_known_address(struct sc_server *server,
static bool static bool
sc_server_configure_tcpip_unknown_address(struct sc_server *server, sc_server_configure_tcpip_unknown_address(struct sc_server *server,
const char *serial) { const char *serial) {
bool is_already_tcpip = bool is_already_tcpip = sc_adb_is_serial_tcpip(serial);
sc_adb_device_get_type(serial) == SC_ADB_DEVICE_TYPE_TCPIP;
if (is_already_tcpip) { if (is_already_tcpip) {
// Nothing to do // Nothing to do
LOGI("Device already connected via TCP/IP: %s", serial); LOGI("Device already connected via TCP/IP: %s", serial);
@@ -707,17 +706,9 @@ run_server(void *data) {
selector.type = SC_ADB_DEVICE_SELECT_USB; selector.type = SC_ADB_DEVICE_SELECT_USB;
} else if (params->select_tcpip) { } else if (params->select_tcpip) {
selector.type = SC_ADB_DEVICE_SELECT_TCPIP; selector.type = SC_ADB_DEVICE_SELECT_TCPIP;
} else {
// No explicit selection, check $ANDROID_SERIAL
const char *env_serial = getenv("ANDROID_SERIAL");
if (env_serial) {
LOGI("Using ANDROID_SERIAL: %s", env_serial);
selector.type = SC_ADB_DEVICE_SELECT_SERIAL;
selector.serial = env_serial;
} else { } else {
selector.type = SC_ADB_DEVICE_SELECT_ALL; selector.type = SC_ADB_DEVICE_SELECT_ALL;
} }
}
struct sc_adb_device device; struct sc_adb_device device;
ok = sc_adb_select_device(&server->intr, &selector, 0, &device); ok = sc_adb_select_device(&server->intr, &selector, 0, &device);
if (!ok) { if (!ok) {

View File

@@ -340,7 +340,7 @@ push_mod_lock_state(struct sc_hid_keyboard *kb, uint16_t mods_state) {
if (!sc_aoa_push_hid_event(kb->aoa, &hid_event)) { if (!sc_aoa_push_hid_event(kb->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event); sc_hid_event_destroy(&hid_event);
LOGW("Could not request HID event (mod lock state)"); LOGW("Could request HID event");
return false; return false;
} }
@@ -382,7 +382,7 @@ sc_key_processor_process_key(struct sc_key_processor *kp,
if (!sc_aoa_push_hid_event(kb->aoa, &hid_event)) { if (!sc_aoa_push_hid_event(kb->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event); sc_hid_event_destroy(&hid_event);
LOGW("Could not request HID event (key)"); LOGW("Could request HID event");
} }
} }
} }

View File

@@ -181,7 +181,7 @@ sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp,
if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) { if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event); sc_hid_event_destroy(&hid_event);
LOGW("Could not request HID event (mouse motion)"); LOGW("Could request HID event");
} }
} }
@@ -203,7 +203,7 @@ sc_mouse_processor_process_mouse_click(struct sc_mouse_processor *mp,
if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) { if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event); sc_hid_event_destroy(&hid_event);
LOGW("Could not request HID event (mouse click)"); LOGW("Could request HID event");
} }
} }
@@ -228,7 +228,7 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) { if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event); sc_hid_event_destroy(&hid_event);
LOGW("Could not request HID event (mouse scroll)"); LOGW("Could request HID event");
} }
} }

View File

@@ -29,26 +29,26 @@ sc_usb_on_disconnected(struct sc_usb *usb, void *userdata) {
} }
} }
static enum scrcpy_exit_code static bool
event_loop(struct scrcpy_otg *s) { event_loop(struct scrcpy_otg *s) {
SDL_Event event; SDL_Event event;
while (SDL_WaitEvent(&event)) { while (SDL_WaitEvent(&event)) {
switch (event.type) { switch (event.type) {
case EVENT_USB_DEVICE_DISCONNECTED: case EVENT_USB_DEVICE_DISCONNECTED:
LOGW("Device disconnected"); LOGW("Device disconnected");
return SCRCPY_EXIT_DISCONNECTED; return false;
case SDL_QUIT: case SDL_QUIT:
LOGD("User requested to quit"); LOGD("User requested to quit");
return SCRCPY_EXIT_SUCCESS; return true;
default: default:
sc_screen_otg_handle_event(&s->screen_otg, &event); sc_screen_otg_handle_event(&s->screen_otg, &event);
break; break;
} }
} }
return SCRCPY_EXIT_FAILURE; return false;
} }
enum scrcpy_exit_code bool
scrcpy_otg(struct scrcpy_options *options) { scrcpy_otg(struct scrcpy_options *options) {
static struct scrcpy_otg scrcpy_otg; static struct scrcpy_otg scrcpy_otg;
struct scrcpy_otg *s = &scrcpy_otg; struct scrcpy_otg *s = &scrcpy_otg;
@@ -67,7 +67,7 @@ scrcpy_otg(struct scrcpy_options *options) {
LOGW("Could not enable mouse focus clickthrough"); LOGW("Could not enable mouse focus clickthrough");
} }
enum scrcpy_exit_code ret = SCRCPY_EXIT_FAILURE; bool ret = false;
struct sc_hid_keyboard *keyboard = NULL; struct sc_hid_keyboard *keyboard = NULL;
struct sc_hid_mouse *mouse = NULL; struct sc_hid_mouse *mouse = NULL;
@@ -90,7 +90,7 @@ scrcpy_otg(struct scrcpy_options *options) {
}; };
bool ok = sc_usb_init(&s->usb); bool ok = sc_usb_init(&s->usb);
if (!ok) { if (!ok) {
return SCRCPY_EXIT_FAILURE; return false;
} }
struct sc_usb_device usb_device; struct sc_usb_device usb_device;

View File

@@ -3,10 +3,10 @@
#include "common.h" #include "common.h"
#include <stdbool.h>
#include "options.h" #include "options.h"
#include "scrcpy.h"
enum scrcpy_exit_code bool
scrcpy_otg(struct scrcpy_options *options); scrcpy_otg(struct scrcpy_options *options);
#endif #endif

View File

@@ -15,7 +15,6 @@ read_string(libusb_device_handle *handle, uint8_t desc_index) {
(unsigned char *) buffer, (unsigned char *) buffer,
sizeof(buffer)); sizeof(buffer));
if (result < 0) { if (result < 0) {
LOGD("Read string: libusb error: %s", libusb_strerror(result));
return NULL; return NULL;
} }

View File

@@ -1,6 +1,6 @@
// generic circular buffer (bounded queue) implementation // generic circular buffer (bounded queue) implementation
#ifndef SC_CBUF_H #ifndef CBUF_H
#define SC_CBUF_H #define CBUF_H
#include "common.h" #include "common.h"

View File

@@ -1,5 +1,5 @@
#ifndef SC_NET_H #ifndef NET_H
#define SC_NET_H #define NET_H
#include "common.h" #include "common.h"

View File

@@ -5,7 +5,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
// Adapted from vlc_vector: // Adapted from vlc_vector:
// <https://code.videolan.org/videolan/vlc/-/blob/0857947abaed9c89810cd96353aaa1b7e6ba3b0d/include/vlc_vector.h> // <https://code.videolan.org/videolan/vlc/-/blob/0857947abaed9c89810cd96353aaa1b7e6ba3b0d/include/vlc_vector.h>

View File

@@ -21,5 +21,5 @@ ffmpeg_avformat = 'avformat-58'
ffmpeg_avutil = 'avutil-56' ffmpeg_avutil = 'avutil-56'
prebuilt_ffmpeg = 'ffmpeg-win32-4.3.1' prebuilt_ffmpeg = 'ffmpeg-win32-4.3.1'
prebuilt_sdl2 = 'SDL2-2.0.20/i686-w64-mingw32' prebuilt_sdl2 = 'SDL2-2.0.20/i686-w64-mingw32'
prebuilt_libusb_root = 'libusb-1.0.26' prebuilt_libusb_root = 'libusb-1.0.25'
prebuilt_libusb = prebuilt_libusb_root + '/MinGW-Win32' prebuilt_libusb = prebuilt_libusb_root + '/MinGW32'

View File

@@ -21,5 +21,5 @@ ffmpeg_avformat = 'avformat-59'
ffmpeg_avutil = 'avutil-57' ffmpeg_avutil = 'avutil-57'
prebuilt_ffmpeg = 'ffmpeg-win64-5.0' prebuilt_ffmpeg = 'ffmpeg-win64-5.0'
prebuilt_sdl2 = 'SDL2-2.0.20/x86_64-w64-mingw32' prebuilt_sdl2 = 'SDL2-2.0.20/x86_64-w64-mingw32'
prebuilt_libusb_root = 'libusb-1.0.26' prebuilt_libusb_root = 'libusb-1.0.25'
prebuilt_libusb = prebuilt_libusb_root + '/MinGW-x64' prebuilt_libusb = prebuilt_libusb_root + '/MinGW64'

View File

@@ -2,8 +2,8 @@
set -e set -e
BUILDDIR=build-auto BUILDDIR=build-auto
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v1.23/scrcpy-server-v1.23 PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v1.22/scrcpy-server-v1.22
PREBUILT_SERVER_SHA256=2a913fd47478c0b306fca507cb0beb625e49a19ff9fc7ab904e36ef5b9fe7e68 PREBUILT_SERVER_SHA256=c05d273eec7533c0e106282e0254cf04e7f5e8f0c2920ca39448865fab2a419b
echo "[scrcpy] Downloading prebuilt server..." echo "[scrcpy] Downloading prebuilt server..."
wget "$PREBUILT_SERVER_URL" -O scrcpy-server wget "$PREBUILT_SERVER_URL" -O scrcpy-server

View File

@@ -1,5 +1,5 @@
project('scrcpy', 'c', project('scrcpy', 'c',
version: '1.23', version: '1.22',
meson_version: '>= 0.48', meson_version: '>= 0.48',
default_options: [ default_options: [
'c_std=c11', 'c_std=c11',

View File

@@ -75,10 +75,12 @@ prepare-deps-win64:
@app/prebuilt-deps/prepare-libusb.sh @app/prebuilt-deps/prepare-libusb.sh
build-win32: prepare-deps-win32 build-win32: prepare-deps-win32
# -Dusb=false because of libusb-win32 build issue, cf #3011
[ -d "$(WIN32_BUILD_DIR)" ] || ( mkdir "$(WIN32_BUILD_DIR)" && \ [ -d "$(WIN32_BUILD_DIR)" ] || ( mkdir "$(WIN32_BUILD_DIR)" && \
meson "$(WIN32_BUILD_DIR)" \ meson "$(WIN32_BUILD_DIR)" \
--cross-file cross_win32.txt \ --cross-file cross_win32.txt \
--buildtype release --strip -Db_lto=true \ --buildtype release --strip -Db_lto=true \
-Dusb=false \
-Dcompile_server=false \ -Dcompile_server=false \
-Dportable=true ) -Dportable=true )
ninja -C "$(WIN32_BUILD_DIR)" ninja -C "$(WIN32_BUILD_DIR)"
@@ -109,7 +111,7 @@ dist-win32: build-server build-win32
cp app/prebuilt-deps/data/platform-tools-31.0.3/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/" cp app/prebuilt-deps/data/platform-tools-31.0.3/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp app/prebuilt-deps/data/platform-tools-31.0.3/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/" cp app/prebuilt-deps/data/platform-tools-31.0.3/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp app/prebuilt-deps/data/SDL2-2.0.20/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/" cp app/prebuilt-deps/data/SDL2-2.0.20/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp app/prebuilt-deps/data/libusb-1.0.26/MinGW-Win32/msys-usb-1.0.dll "$(DIST)/$(WIN32_TARGET_DIR)/" #cp app/prebuilt-deps/data/libusb-1.0.25/MinGW32/dll/libusb-1.0.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
dist-win64: build-server build-win64 dist-win64: build-server build-win64
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)" mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
@@ -128,7 +130,7 @@ dist-win64: build-server build-win64
cp app/prebuilt-deps/data/platform-tools-31.0.3/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp app/prebuilt-deps/data/platform-tools-31.0.3/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp app/prebuilt-deps/data/platform-tools-31.0.3/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp app/prebuilt-deps/data/platform-tools-31.0.3/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp app/prebuilt-deps/data/SDL2-2.0.20/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp app/prebuilt-deps/data/SDL2-2.0.20/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp app/prebuilt-deps/data/libusb-1.0.26/MinGW-x64/msys-usb-1.0.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp app/prebuilt-deps/data/libusb-1.0.25/MinGW64/dll/libusb-1.0.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
zip-win32: dist-win32 zip-win32: dist-win32
cd "$(DIST)/$(WIN32_TARGET_DIR)"; \ cd "$(DIST)/$(WIN32_TARGET_DIR)"; \

2
run
View File

@@ -20,6 +20,6 @@ then
exit 1 exit 1
fi fi
SCRCPY_ICON_PATH="app/data/icon.png" \ SCRCPY_ICON_PATH="data/icon.png" \
SCRCPY_SERVER_PATH="$BUILDDIR/server/scrcpy-server" \ SCRCPY_SERVER_PATH="$BUILDDIR/server/scrcpy-server" \
"$BUILDDIR/app/scrcpy" "$@" "$BUILDDIR/app/scrcpy" "$@"

View File

@@ -6,8 +6,8 @@ android {
applicationId "com.genymobile.scrcpy" applicationId "com.genymobile.scrcpy"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 31 targetSdkVersion 31
versionCode 12300 versionCode 12200
versionName "1.23" versionName "1.22"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {

View File

@@ -12,7 +12,7 @@
set -e set -e
SCRCPY_DEBUG=false SCRCPY_DEBUG=false
SCRCPY_VERSION_NAME=1.23 SCRCPY_VERSION_NAME=1.22
PLATFORM=${ANDROID_PLATFORM:-31} PLATFORM=${ANDROID_PLATFORM:-31}
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-31.0.0} BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-31.0.0}

View File

@@ -102,7 +102,7 @@ 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 (IllegalStateException | IllegalArgumentException e) { } catch (IllegalStateException e) {
Ln.e("Encoding error: " + e.getClass().getName() + ": " + e.getMessage()); Ln.e("Encoding error: " + e.getClass().getName() + ": " + e.getMessage());
if (!downsizeOnError || firstFrameSent) { if (!downsizeOnError || firstFrameSent) {
// Fail immediately // Fail immediately

View File

@@ -11,6 +11,7 @@ import java.util.Locale;
public final class Server { public final class Server {
private Server() { private Server() {
// not instantiable // not instantiable
} }

View File

@@ -2,6 +2,7 @@ package com.genymobile.scrcpy.wrappers;
import com.genymobile.scrcpy.Ln; import com.genymobile.scrcpy.Ln;
import android.os.IInterface;
import android.view.InputEvent; import android.view.InputEvent;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@@ -13,18 +14,24 @@ public final class InputManager {
public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT = 1; public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT = 1;
public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2; public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2;
private final android.hardware.input.InputManager manager; private final IInterface manager;
private Method injectInputEventMethod; private Method injectInputEventMethod;
private boolean alternativeInjectInputEventMethod;
private static Method setDisplayIdMethod; private static Method setDisplayIdMethod;
public InputManager(android.hardware.input.InputManager manager) { public InputManager(IInterface manager) {
this.manager = manager; this.manager = manager;
} }
private Method getInjectInputEventMethod() throws NoSuchMethodException { private Method getInjectInputEventMethod() throws NoSuchMethodException {
if (injectInputEventMethod == null) { if (injectInputEventMethod == null) {
try {
injectInputEventMethod = manager.getClass().getMethod("injectInputEvent", InputEvent.class, int.class); 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;
} }
@@ -32,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);

View File

@@ -4,7 +4,6 @@ import android.annotation.SuppressLint;
import android.os.IBinder; import android.os.IBinder;
import android.os.IInterface; import android.os.IInterface;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@SuppressLint("PrivateApi,DiscouragedPrivateApi") @SuppressLint("PrivateApi,DiscouragedPrivateApi")
@@ -57,13 +56,7 @@ public final class ServiceManager {
public InputManager getInputManager() { public InputManager getInputManager() {
if (inputManager == null) { if (inputManager == null) {
try { inputManager = new InputManager(getService("input", "android.hardware.input.IInputManager"));
Method getInstanceMethod = android.hardware.input.InputManager.class.getDeclaredMethod("getInstance");
android.hardware.input.InputManager im = (android.hardware.input.InputManager) getInstanceMethod.invoke(null);
inputManager = new InputManager(im);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
} }
return inputManager; return inputManager;
} }