Compare commits
32 Commits
encoder_na
...
pr2004
Author | SHA1 | Date | |
---|---|---|---|
192fbd8450 | |||
c5c5fc18ae | |||
f682b87ba5 | |||
10b749e27d | |||
05e8c1a3c5 | |||
83910d3b9c | |||
90f8356630 | |||
3ba51211d6 | |||
ea3582d2c3 | |||
112adbba87 | |||
d039a7a39a | |||
6ab80e4ce8 | |||
230afd8966 | |||
a46733906a | |||
431c9ee33b | |||
43d3dcbd97 | |||
a5f4f58295 | |||
ea12783bbc | |||
904d470579 | |||
6d151eaef9 | |||
5dc3285dbf | |||
c9a4bdb890 | |||
d60ac65b32 | |||
d6078cf202 | |||
47c8971267 | |||
30434afc0a | |||
868e762d71 | |||
25aff00935 | |||
aade92fd10 | |||
15b81367c9 | |||
c136edf09d | |||
52560faa34 |
6
BUILD.md
6
BUILD.md
@ -254,10 +254,10 @@ You can then [run](README.md#run) _scrcpy_.
|
|||||||
|
|
||||||
## Prebuilt server
|
## Prebuilt server
|
||||||
|
|
||||||
- [`scrcpy-server-v1.16`][direct-scrcpy-server]
|
- [`scrcpy-server-v1.17`][direct-scrcpy-server]
|
||||||
_(SHA-256: 94a79e05b4498d0460ab7bd9d12cbf05156e3a47bf0c5d1420cee1d4493b3832)_
|
_(SHA-256: 11b5ad2d1bc9b9730fb7254a78efd71a8ff46b1938ff468e47a21b653a1b6725_
|
||||||
|
|
||||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.16/scrcpy-server-v1.16
|
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.17/scrcpy-server-v1.17
|
||||||
|
|
||||||
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:
|
||||||
|
@ -3,16 +3,16 @@
|
|||||||
다음은 자주 제보되는 문제들과 그들의 현황입니다.
|
다음은 자주 제보되는 문제들과 그들의 현황입니다.
|
||||||
|
|
||||||
|
|
||||||
### Window 운영체제에서, 디바이스가 발견되지 않습니다.
|
### Windows 운영체제에서, 디바이스가 발견되지 않습니다.
|
||||||
|
|
||||||
가장 흔한 제보는 `adb`에 발견되지 않는 디바이스 혹은 권한 관련 문제입니다.
|
가장 흔한 제보는 `adb`에 발견되지 않는 디바이스 혹은 권한 관련 문제입니다.
|
||||||
다음 명령어를 호출하여 모든 것들에 이상이 없는지 확인하세요:
|
다음 명령어를 호출하여 모든 것들에 이상이 없는지 확인하세요:
|
||||||
|
|
||||||
adb devices
|
adb devices
|
||||||
|
|
||||||
Window는 당신의 디바이스를 감지하기 위해 [drivers]가 필요할 수도 있습니다.
|
Windows는 당신의 디바이스를 감지하기 위해 [드라이버]가 필요할 수도 있습니다.
|
||||||
|
|
||||||
[drivers]: https://developer.android.com/studio/run/oem-usb.html
|
[드라이버]: https://developer.android.com/studio/run/oem-usb.html
|
||||||
|
|
||||||
|
|
||||||
### 내 디바이스의 미러링만 가능하고, 디바이스와 상호작용을 할 수 없습니다.
|
### 내 디바이스의 미러링만 가능하고, 디바이스와 상호작용을 할 수 없습니다.
|
||||||
|
38
FAQ.md
38
FAQ.md
@ -199,3 +199,41 @@ scrcpy -m 1920
|
|||||||
scrcpy -m 1024
|
scrcpy -m 1024
|
||||||
scrcpy -m 800
|
scrcpy -m 800
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You could also try another [encoder](README.md#encoder).
|
||||||
|
|
||||||
|
|
||||||
|
## Command line on Windows
|
||||||
|
|
||||||
|
Some Windows users are not familiar with the command line. Here is how to open a
|
||||||
|
terminal and run `scrcpy` with arguments:
|
||||||
|
|
||||||
|
1. Press <kbd>Windows</kbd>+<kbd>r</kbd>, this opens a dialog box.
|
||||||
|
2. Type `cmd` and press <kbd>Enter</kbd>, this opens a terminal.
|
||||||
|
3. Go to your _scrcpy_ directory, by typing (adapt the path):
|
||||||
|
|
||||||
|
```bat
|
||||||
|
cd C:\Users\user\Downloads\scrcpy-win64-xxx
|
||||||
|
```
|
||||||
|
|
||||||
|
and press <kbd>Enter</kbd>
|
||||||
|
4. Type your command. For example:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
scrcpy --record file.mkv
|
||||||
|
```
|
||||||
|
|
||||||
|
If you plan to always use the same arguments, create a file `myscrcpy.bat`
|
||||||
|
(enable [show file extensions] to avoid confusion) in the `scrcpy` directory,
|
||||||
|
containing your command. For example:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
scrcpy --prefer-text --turn-screen-off --stay-awake
|
||||||
|
```
|
||||||
|
|
||||||
|
Then just double-click on that file.
|
||||||
|
|
||||||
|
You could also edit (a copy of) `scrcpy-console.bat` or `scrcpy-noconsole.vbs`
|
||||||
|
to add some arguments.
|
||||||
|
|
||||||
|
[show file extensions]: https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/
|
||||||
|
2
LICENSE
2
LICENSE
@ -188,7 +188,7 @@
|
|||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright (C) 2018 Genymobile
|
Copyright (C) 2018 Genymobile
|
||||||
Copyright (C) 2018-2020 Romain Vimont
|
Copyright (C) 2018-2021 Romain Vimont
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
699
README.id.md
Normal file
699
README.id.md
Normal file
@ -0,0 +1,699 @@
|
|||||||
|
_Only the original [README](README.md) is guaranteed to be up-to-date._
|
||||||
|
|
||||||
|
# scrcpy (v1.16)
|
||||||
|
|
||||||
|
Aplikasi ini menyediakan tampilan dan kontrol perangkat Android yang terhubung pada USB (atau [melalui TCP/IP][article-tcpip]). Ini tidak membutuhkan akses _root_ apa pun. Ini bekerja pada _GNU/Linux_, _Windows_ and _macOS_.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Ini berfokus pada:
|
||||||
|
|
||||||
|
- **keringanan** (asli, hanya menampilkan layar perangkat)
|
||||||
|
- **kinerja** (30~60fps)
|
||||||
|
- **kualitas** (1920×1080 atau lebih)
|
||||||
|
- **latensi** rendah ([35~70ms][lowlatency])
|
||||||
|
- **waktu startup rendah** (~1 detik untuk menampilkan gambar pertama)
|
||||||
|
- **tidak mengganggu** (tidak ada yang terpasang di perangkat)
|
||||||
|
|
||||||
|
|
||||||
|
[lowlatency]: https://github.com/Genymobile/scrcpy/pull/646
|
||||||
|
|
||||||
|
|
||||||
|
## Persyaratan
|
||||||
|
Perangkat Android membutuhkan setidaknya API 21 (Android 5.0).
|
||||||
|
|
||||||
|
Pastikan Anda [mengaktifkan debugging adb][enable-adb] pada perangkat Anda.
|
||||||
|
|
||||||
|
[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
|
||||||
|
|
||||||
|
Di beberapa perangkat, Anda juga perlu mengaktifkan [opsi tambahan][control] untuk mengontrolnya menggunakan keyboard dan mouse.
|
||||||
|
|
||||||
|
[control]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323
|
||||||
|
|
||||||
|
|
||||||
|
## Dapatkan aplikasinya
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
Di Debian (_testing_ dan _sid_ untuk saat ini) dan Ubuntu (20.04):
|
||||||
|
|
||||||
|
```
|
||||||
|
apt install scrcpy
|
||||||
|
```
|
||||||
|
|
||||||
|
Paket [Snap] tersedia: [`scrcpy`][snap-link].
|
||||||
|
|
||||||
|
[snap-link]: https://snapstats.org/snaps/scrcpy
|
||||||
|
|
||||||
|
[snap]: https://en.wikipedia.org/wiki/Snappy_(package_manager)
|
||||||
|
|
||||||
|
Untuk Fedora, paket [COPR] tersedia: [`scrcpy`][copr-link].
|
||||||
|
|
||||||
|
[COPR]: https://fedoraproject.org/wiki/Category:Copr
|
||||||
|
[copr-link]: https://copr.fedorainfracloud.org/coprs/zeno/scrcpy/
|
||||||
|
|
||||||
|
Untuk Arch Linux, paket [AUR] tersedia: [`scrcpy`][aur-link].
|
||||||
|
|
||||||
|
[AUR]: https://wiki.archlinux.org/index.php/Arch_User_Repository
|
||||||
|
[aur-link]: https://aur.archlinux.org/packages/scrcpy/
|
||||||
|
|
||||||
|
Untuk Gentoo, tersedia [Ebuild]: [`scrcpy/`][ebuild-link].
|
||||||
|
|
||||||
|
[Ebuild]: https://wiki.gentoo.org/wiki/Ebuild
|
||||||
|
[ebuild-link]: https://github.com/maggu2810/maggu2810-overlay/tree/master/app-mobilephone/scrcpy
|
||||||
|
|
||||||
|
Anda juga bisa [membangun aplikasi secara manual][BUILD] (jangan khawatir, tidak terlalu sulit).
|
||||||
|
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
Untuk Windows, untuk kesederhanaan, arsip prebuilt dengan semua dependensi (termasuk `adb`) tersedia :
|
||||||
|
|
||||||
|
- [`scrcpy-win64-v1.16.zip`][direct-win64]
|
||||||
|
_(SHA-256: 3f30dc5db1a2f95c2b40a0f5de91ec1642d9f53799250a8c529bc882bc0918f0)_
|
||||||
|
|
||||||
|
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.16/scrcpy-win64-v1.16.zip
|
||||||
|
|
||||||
|
Ini juga tersedia di [Chocolatey]:
|
||||||
|
|
||||||
|
[Chocolatey]: https://chocolatey.org/
|
||||||
|
|
||||||
|
```bash
|
||||||
|
choco install scrcpy
|
||||||
|
choco install adb # jika Anda belum memilikinya
|
||||||
|
```
|
||||||
|
|
||||||
|
Dan di [Scoop]:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scoop install scrcpy
|
||||||
|
scoop install adb # jika Anda belum memilikinya
|
||||||
|
```
|
||||||
|
|
||||||
|
[Scoop]: https://scoop.sh
|
||||||
|
|
||||||
|
Anda juga dapat [membangun aplikasi secara manual][BUILD].
|
||||||
|
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
Aplikasi ini tersedia di [Homebrew]. Instal saja:
|
||||||
|
|
||||||
|
[Homebrew]: https://brew.sh/
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install scrcpy
|
||||||
|
```
|
||||||
|
Anda membutuhkan `adb`, dapat diakses dari `PATH` Anda. Jika Anda belum memilikinya:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew cask install android-platform-tools
|
||||||
|
```
|
||||||
|
|
||||||
|
Anda juga dapat [membangun aplikasi secara manual][BUILD].
|
||||||
|
|
||||||
|
|
||||||
|
## Menjalankan
|
||||||
|
|
||||||
|
Pasang perangkat Android, dan jalankan:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy
|
||||||
|
```
|
||||||
|
|
||||||
|
Ini menerima argumen baris perintah, didaftarkan oleh:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --help
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fitur
|
||||||
|
|
||||||
|
### Menangkap konfigurasi
|
||||||
|
|
||||||
|
#### Mengurangi ukuran
|
||||||
|
|
||||||
|
Kadang-kadang, berguna untuk mencerminkan perangkat Android dengan definisi yang lebih rendah untuk meningkatkan kinerja.
|
||||||
|
|
||||||
|
Untuk membatasi lebar dan tinggi ke beberapa nilai (mis. 1024):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --max-size 1024
|
||||||
|
scrcpy -m 1024 # versi pendek
|
||||||
|
```
|
||||||
|
|
||||||
|
Dimensi lain dihitung agar rasio aspek perangkat dipertahankan.
|
||||||
|
Dengan begitu, perangkat 1920×1080 akan dicerminkan pada 1024×576.
|
||||||
|
|
||||||
|
#### Ubah kecepatan bit
|
||||||
|
|
||||||
|
Kecepatan bit default adalah 8 Mbps. Untuk mengubah bitrate video (mis. Menjadi 2 Mbps):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --bit-rate 2M
|
||||||
|
scrcpy -b 2M # versi pendek
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Batasi frekuensi gambar
|
||||||
|
|
||||||
|
Kecepatan bingkai pengambilan dapat dibatasi:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --max-fps 15
|
||||||
|
```
|
||||||
|
|
||||||
|
Ini secara resmi didukung sejak Android 10, tetapi dapat berfungsi pada versi sebelumnya.
|
||||||
|
|
||||||
|
#### Memotong
|
||||||
|
|
||||||
|
Layar perangkat dapat dipotong untuk mencerminkan hanya sebagian dari layar.
|
||||||
|
|
||||||
|
Ini berguna misalnya untuk mencerminkan hanya satu mata dari Oculus Go:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --crop 1224:1440:0:0 # 1224x1440 Mengimbangi (0,0)
|
||||||
|
```
|
||||||
|
|
||||||
|
Jika `--max-size` juga ditentukan, pengubahan ukuran diterapkan setelah pemotongan.
|
||||||
|
|
||||||
|
|
||||||
|
#### Kunci orientasi video
|
||||||
|
|
||||||
|
Untuk mengunci orientasi pencerminan:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --lock-video-orientation 0 # orientasi alami
|
||||||
|
scrcpy --lock-video-orientation 1 # 90° berlawanan arah jarum jam
|
||||||
|
scrcpy --lock-video-orientation 2 # 180°
|
||||||
|
scrcpy --lock-video-orientation 3 # 90° searah jarum jam
|
||||||
|
```
|
||||||
|
|
||||||
|
Ini mempengaruhi orientasi perekaman.
|
||||||
|
|
||||||
|
|
||||||
|
### Rekaman
|
||||||
|
|
||||||
|
Anda dapat merekam layar saat melakukan mirroring:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --record file.mp4
|
||||||
|
scrcpy -r file.mkv
|
||||||
|
```
|
||||||
|
|
||||||
|
Untuk menonaktifkan pencerminan saat merekam:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --no-display --record file.mp4
|
||||||
|
scrcpy -Nr file.mkv
|
||||||
|
# berhenti merekam dengan Ctrl+C
|
||||||
|
```
|
||||||
|
|
||||||
|
"Skipped frames" are recorded, even if they are not displayed in real time (for
|
||||||
|
performance reasons). Frames are _timestamped_ on the device, so [packet delay
|
||||||
|
variation] does not impact the recorded file.
|
||||||
|
|
||||||
|
"Frame yang dilewati" direkam, meskipun tidak ditampilkan secara real time (untuk alasan performa). Bingkai *diberi stempel waktu* pada perangkat, jadi [variasi penundaan paket] tidak memengaruhi file yang direkam.
|
||||||
|
|
||||||
|
[variasi penundaan paket]: https://en.wikipedia.org/wiki/Packet_delay_variation
|
||||||
|
|
||||||
|
|
||||||
|
### Koneksi
|
||||||
|
|
||||||
|
#### Wireless
|
||||||
|
|
||||||
|
_Scrcpy_ menggunakan `adb` untuk berkomunikasi dengan perangkat, dan` adb` dapat [terhubung] ke perangkat melalui TCP / IP:
|
||||||
|
|
||||||
|
1. Hubungkan perangkat ke Wi-Fi yang sama dengan komputer Anda.
|
||||||
|
2. Dapatkan alamat IP perangkat Anda (dalam Pengaturan → Tentang ponsel → Status).
|
||||||
|
3. Aktifkan adb melalui TCP / IP pada perangkat Anda: `adb tcpip 5555`.
|
||||||
|
4. Cabut perangkat Anda.
|
||||||
|
5. Hubungkan ke perangkat Anda: `adb connect DEVICE_IP: 5555` (*ganti* *`DEVICE_IP`*).
|
||||||
|
6. Jalankan `scrcpy` seperti biasa.
|
||||||
|
|
||||||
|
Mungkin berguna untuk menurunkan kecepatan bit dan definisi:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --bit-rate 2M --max-size 800
|
||||||
|
scrcpy -b2M -m800 # versi pendek
|
||||||
|
```
|
||||||
|
|
||||||
|
[terhubung]: https://developer.android.com/studio/command-line/adb.html#wireless
|
||||||
|
|
||||||
|
|
||||||
|
#### Multi-perangkat
|
||||||
|
|
||||||
|
Jika beberapa perangkat dicantumkan di `adb devices`, Anda harus menentukan _serial_:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --serial 0123456789abcdef
|
||||||
|
scrcpy -s 0123456789abcdef # versi pendek
|
||||||
|
```
|
||||||
|
|
||||||
|
If the device is connected over TCP/IP:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --serial 192.168.0.1:5555
|
||||||
|
scrcpy -s 192.168.0.1:5555 # versi pendek
|
||||||
|
```
|
||||||
|
|
||||||
|
Anda dapat memulai beberapa contoh _scrcpy_ untuk beberapa perangkat.
|
||||||
|
|
||||||
|
#### Mulai otomatis pada koneksi perangkat
|
||||||
|
|
||||||
|
Anda bisa menggunakan [AutoAdb]:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
autoadb scrcpy -s '{}'
|
||||||
|
```
|
||||||
|
|
||||||
|
[AutoAdb]: https://github.com/rom1v/autoadb
|
||||||
|
|
||||||
|
#### Koneksi via SSH tunnel
|
||||||
|
|
||||||
|
Untuk menyambung ke perangkat jarak jauh, dimungkinkan untuk menghubungkan klien `adb` lokal ke server `adb` jarak jauh (asalkan mereka menggunakan versi yang sama dari _adb_ protocol):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb kill-server # matikan server adb lokal di 5037
|
||||||
|
ssh -CN -L5037:localhost:5037 -R27183:localhost:27183 komputer_jarak_jauh_anda
|
||||||
|
# jaga agar tetap terbuka
|
||||||
|
```
|
||||||
|
|
||||||
|
Dari terminal lain:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy
|
||||||
|
```
|
||||||
|
|
||||||
|
Untuk menghindari mengaktifkan penerusan port jarak jauh, Anda dapat memaksa sambungan maju sebagai gantinya (perhatikan `-L`, bukan` -R`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb kill-server # matikan server adb lokal di 5037
|
||||||
|
ssh -CN -L5037:localhost:5037 -L27183:localhost:27183 komputer_jarak_jauh_anda
|
||||||
|
# jaga agar tetap terbuka
|
||||||
|
```
|
||||||
|
|
||||||
|
Dari terminal lain:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --force-adb-forward
|
||||||
|
```
|
||||||
|
|
||||||
|
Seperti koneksi nirkabel, mungkin berguna untuk mengurangi kualitas:
|
||||||
|
|
||||||
|
```
|
||||||
|
scrcpy -b2M -m800 --max-fps 15
|
||||||
|
```
|
||||||
|
|
||||||
|
### Konfigurasi Jendela
|
||||||
|
|
||||||
|
#### Judul
|
||||||
|
|
||||||
|
Secara default, judul jendela adalah model perangkat. Itu bisa diubah:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --window-title 'Perangkat Saya'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Posisi dan ukuran
|
||||||
|
|
||||||
|
Posisi dan ukuran jendela awal dapat ditentukan:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --window-x 100 --window-y 100 --window-width 800 --window-height 600
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Jendela tanpa batas
|
||||||
|
|
||||||
|
Untuk menonaktifkan dekorasi jendela:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --window-borderless
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Selalu di atas
|
||||||
|
|
||||||
|
Untuk menjaga jendela scrcpy selalu di atas:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --always-on-top
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Layar penuh
|
||||||
|
|
||||||
|
Aplikasi dapat dimulai langsung dalam layar penuh::
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --fullscreen
|
||||||
|
scrcpy -f # versi pendek
|
||||||
|
```
|
||||||
|
|
||||||
|
Layar penuh kemudian dapat diubah secara dinamis dengan <kbd>MOD</kbd>+<kbd>f</kbd>.
|
||||||
|
|
||||||
|
#### Rotasi
|
||||||
|
|
||||||
|
Jendela mungkin diputar:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --rotation 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Nilai yang mungkin adalah:
|
||||||
|
- `0`: tidak ada rotasi
|
||||||
|
- `1`: 90 derajat berlawanan arah jarum jam
|
||||||
|
- `2`: 180 derajat
|
||||||
|
- `3`: 90 derajat searah jarum jam
|
||||||
|
|
||||||
|
Rotasi juga dapat diubah secara dinamis dengan <kbd>MOD</kbd>+<kbd>←</kbd>
|
||||||
|
_(kiri)_ and <kbd>MOD</kbd>+<kbd>→</kbd> _(kanan)_.
|
||||||
|
|
||||||
|
Perhatikan bahwa _scrcpy_ mengelola 3 rotasi berbeda::
|
||||||
|
- <kbd>MOD</kbd>+<kbd>r</kbd> meminta perangkat untuk beralih antara potret dan lanskap (aplikasi yang berjalan saat ini mungkin menolak, jika mendukung orientasi yang diminta).
|
||||||
|
- `--lock-video-orientation` mengubah orientasi pencerminan (orientasi video yang dikirim dari perangkat ke komputer). Ini mempengaruhi rekaman.
|
||||||
|
- `--rotation` (atau <kbd>MOD</kbd>+<kbd>←</kbd>/<kbd>MOD</kbd>+<kbd>→</kbd>)
|
||||||
|
memutar hanya konten jendela. Ini hanya mempengaruhi tampilan, bukan rekaman.
|
||||||
|
|
||||||
|
|
||||||
|
### Opsi pencerminan lainnya
|
||||||
|
|
||||||
|
#### Hanya-baca
|
||||||
|
|
||||||
|
Untuk menonaktifkan kontrol (semua yang dapat berinteraksi dengan perangkat: tombol input, peristiwa mouse, seret & lepas file):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --no-control
|
||||||
|
scrcpy -n
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Layar
|
||||||
|
|
||||||
|
Jika beberapa tampilan tersedia, Anda dapat memilih tampilan untuk cermin:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --display 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Daftar id tampilan dapat diambil dengan::
|
||||||
|
|
||||||
|
```
|
||||||
|
adb shell dumpsys display # cari "mDisplayId=" di keluaran
|
||||||
|
```
|
||||||
|
|
||||||
|
Tampilan sekunder hanya dapat dikontrol jika perangkat menjalankan setidaknya Android 10 (jika tidak maka akan dicerminkan dalam hanya-baca).
|
||||||
|
|
||||||
|
|
||||||
|
#### Tetap terjaga
|
||||||
|
|
||||||
|
Untuk mencegah perangkat tidur setelah beberapa penundaan saat perangkat dicolokkan:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --stay-awake
|
||||||
|
scrcpy -w
|
||||||
|
```
|
||||||
|
|
||||||
|
Keadaan awal dipulihkan ketika scrcpy ditutup.
|
||||||
|
|
||||||
|
|
||||||
|
#### Matikan layar
|
||||||
|
|
||||||
|
Dimungkinkan untuk mematikan layar perangkat saat pencerminan mulai dengan opsi baris perintah:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --turn-screen-off
|
||||||
|
scrcpy -S
|
||||||
|
```
|
||||||
|
|
||||||
|
Atau dengan menekan <kbd>MOD</kbd>+<kbd>o</kbd> kapan saja.
|
||||||
|
|
||||||
|
Untuk menyalakannya kembali, tekan <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>.
|
||||||
|
|
||||||
|
Di Android, tombol `POWER` selalu menyalakan layar. Untuk kenyamanan, jika `POWER` dikirim melalui scrcpy (melalui klik kanan atau<kbd>MOD</kbd>+<kbd>p</kbd>), itu akan memaksa untuk mematikan layar setelah penundaan kecil (atas dasar upaya terbaik).
|
||||||
|
Tombol fisik `POWER` masih akan menyebabkan layar dihidupkan.
|
||||||
|
|
||||||
|
Ini juga berguna untuk mencegah perangkat tidur:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --turn-screen-off --stay-awake
|
||||||
|
scrcpy -Sw
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Render frame kedaluwarsa
|
||||||
|
|
||||||
|
Secara default, untuk meminimalkan latensi, _scrcpy_ selalu menampilkan frame yang terakhir didekodekan tersedia, dan menghapus frame sebelumnya.
|
||||||
|
|
||||||
|
Untuk memaksa rendering semua frame (dengan kemungkinan peningkatan latensi), gunakan:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --render-expired-frames
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Tunjukkan sentuhan
|
||||||
|
|
||||||
|
Untuk presentasi, mungkin berguna untuk menunjukkan sentuhan fisik (pada perangkat fisik).
|
||||||
|
|
||||||
|
Android menyediakan fitur ini di _Opsi Pengembang_.
|
||||||
|
|
||||||
|
_Scrcpy_ menyediakan opsi untuk mengaktifkan fitur ini saat mulai dan mengembalikan nilai awal saat keluar:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --show-touches
|
||||||
|
scrcpy -t
|
||||||
|
```
|
||||||
|
|
||||||
|
Perhatikan bahwa ini hanya menunjukkan sentuhan _fisik_ (dengan jari di perangkat).
|
||||||
|
|
||||||
|
|
||||||
|
#### Nonaktifkan screensaver
|
||||||
|
|
||||||
|
Secara default, scrcpy tidak mencegah screensaver berjalan di komputer.
|
||||||
|
|
||||||
|
Untuk menonaktifkannya:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --disable-screensaver
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Kontrol masukan
|
||||||
|
|
||||||
|
#### Putar layar perangkat
|
||||||
|
|
||||||
|
Tekan <kbd>MOD</kbd>+<kbd>r</kbd> untuk beralih antara mode potret dan lanskap.
|
||||||
|
|
||||||
|
Perhatikan bahwa itu berputar hanya jika aplikasi di latar depan mendukung orientasi yang diminta.
|
||||||
|
|
||||||
|
#### Salin-tempel
|
||||||
|
|
||||||
|
Setiap kali papan klip Android berubah, secara otomatis disinkronkan ke papan klip komputer.
|
||||||
|
|
||||||
|
Apa saja <kbd>Ctrl</kbd> pintasan diteruskan ke perangkat. Khususnya:
|
||||||
|
- <kbd>Ctrl</kbd>+<kbd>c</kbd> biasanya salinan
|
||||||
|
- <kbd>Ctrl</kbd>+<kbd>x</kbd> biasanya memotong
|
||||||
|
- <kbd>Ctrl</kbd>+<kbd>v</kbd> biasanya menempel (setelah sinkronisasi papan klip komputer-ke-perangkat)
|
||||||
|
|
||||||
|
Ini biasanya berfungsi seperti yang Anda harapkan.
|
||||||
|
|
||||||
|
Perilaku sebenarnya tergantung pada aplikasi yang aktif. Sebagai contoh,
|
||||||
|
_Termux_ mengirim SIGINT ke <kbd>Ctrl</kbd>+<kbd>c</kbd> sebagai gantinya, dan _K-9 Mail_ membuat pesan baru.
|
||||||
|
|
||||||
|
Untuk menyalin, memotong dan menempel dalam kasus seperti itu (tetapi hanya didukung di Android> = 7):
|
||||||
|
- <kbd>MOD</kbd>+<kbd>c</kbd> injeksi `COPY` _(salin)_
|
||||||
|
- <kbd>MOD</kbd>+<kbd>x</kbd> injeksi `CUT` _(potong)_
|
||||||
|
- <kbd>MOD</kbd>+<kbd>v</kbd> injeksi `PASTE` (setelah sinkronisasi papan klip komputer-ke-perangkat)
|
||||||
|
|
||||||
|
Tambahan, <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd> memungkinkan untuk memasukkan teks papan klip komputer sebagai urutan peristiwa penting. Ini berguna ketika komponen tidak menerima penempelan teks (misalnya di _Termux_), tetapi dapat merusak konten non-ASCII.
|
||||||
|
|
||||||
|
**PERINGATAN:** Menempelkan papan klip komputer ke perangkat (baik melalui
|
||||||
|
<kbd>Ctrl</kbd>+<kbd>v</kbd> or <kbd>MOD</kbd>+<kbd>v</kbd>) menyalin konten ke clipboard perangkat. Akibatnya, aplikasi Android apa pun dapat membaca kontennya. Anda harus menghindari menempelkan konten sensitif (seperti kata sandi) seperti itu.
|
||||||
|
|
||||||
|
|
||||||
|
#### Cubit untuk memperbesar/memperkecil
|
||||||
|
|
||||||
|
Untuk mensimulasikan "cubit-untuk-memperbesar/memperkecil": <kbd>Ctrl</kbd>+_klik-dan-pindah_.
|
||||||
|
|
||||||
|
Lebih tepatnya, tahan <kbd>Ctrl</kbd> sambil menekan tombol klik kiri. Hingga tombol klik kiri dilepaskan, semua gerakan mouse berskala dan memutar konten (jika didukung oleh aplikasi) relatif ke tengah layar.
|
||||||
|
|
||||||
|
Secara konkret, scrcpy menghasilkan kejadian sentuh tambahan dari "jari virtual" di lokasi yang dibalik melalui bagian tengah layar.
|
||||||
|
|
||||||
|
|
||||||
|
#### Preferensi injeksi teks
|
||||||
|
|
||||||
|
Ada dua jenis [peristiwa][textevents] dihasilkan saat mengetik teks:
|
||||||
|
- _peristiwa penting_, menandakan bahwa tombol ditekan atau dilepaskan;
|
||||||
|
- _peristiwa teks_, menandakan bahwa teks telah dimasukkan.
|
||||||
|
|
||||||
|
Secara default, huruf dimasukkan menggunakan peristiwa kunci, sehingga keyboard berperilaku seperti yang diharapkan dalam game (biasanya untuk tombol WASD).
|
||||||
|
|
||||||
|
Tapi ini mungkin [menyebabkan masalah][prefertext]. Jika Anda mengalami masalah seperti itu, Anda dapat menghindarinya dengan:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --prefer-text
|
||||||
|
```
|
||||||
|
|
||||||
|
(tapi ini akan merusak perilaku keyboard dalam game)
|
||||||
|
|
||||||
|
[textevents]: https://blog.rom1v.com/2018/03/introducing-scrcpy/#handle-text-input
|
||||||
|
[prefertext]: https://github.com/Genymobile/scrcpy/issues/650#issuecomment-512945343
|
||||||
|
|
||||||
|
|
||||||
|
#### Ulangi kunci
|
||||||
|
|
||||||
|
Secara default, menahan tombol akan menghasilkan peristiwa kunci yang berulang. Ini dapat menyebabkan masalah kinerja di beberapa game, di mana acara ini tidak berguna.
|
||||||
|
|
||||||
|
Untuk menghindari penerusan peristiwa penting yang berulang:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --no-key-repeat
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Seret/jatuhkan file
|
||||||
|
|
||||||
|
#### Pasang APK
|
||||||
|
|
||||||
|
Untuk menginstal APK, seret & lepas file APK (diakhiri dengan `.apk`) ke jendela _scrcpy_.
|
||||||
|
|
||||||
|
Tidak ada umpan balik visual, log dicetak ke konsol.
|
||||||
|
|
||||||
|
|
||||||
|
#### Dorong file ke perangkat
|
||||||
|
|
||||||
|
Untuk mendorong file ke `/sdcard/` di perangkat, seret & jatuhkan file (non-APK) ke jendela _scrcpy_.
|
||||||
|
|
||||||
|
Tidak ada umpan balik visual, log dicetak ke konsol.
|
||||||
|
|
||||||
|
Direktori target dapat diubah saat mulai:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --push-target /sdcard/foo/bar/
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Penerusan audio
|
||||||
|
|
||||||
|
Audio tidak diteruskan oleh _scrcpy_. Gunakan [sndcpy].
|
||||||
|
|
||||||
|
Lihat juga [Masalah #14].
|
||||||
|
|
||||||
|
[sndcpy]: https://github.com/rom1v/sndcpy
|
||||||
|
[Masalah #14]: https://github.com/Genymobile/scrcpy/issues/14
|
||||||
|
|
||||||
|
|
||||||
|
## Pintasan
|
||||||
|
|
||||||
|
Dalam daftar berikut, <kbd>MOD</kbd> adalah pengubah pintasan. Secara default, ini (kiri) <kbd>Alt</kbd> atau (kiri) <kbd>Super</kbd>.
|
||||||
|
|
||||||
|
Ini dapat diubah menggunakan `--shortcut-mod`. Kunci yang memungkinkan adalah `lctrl`,`rctrl`, `lalt`,` ralt`, `lsuper` dan` rsuper`. Sebagai contoh:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# gunakan RCtrl untuk jalan pintas
|
||||||
|
scrcpy --shortcut-mod=rctrl
|
||||||
|
|
||||||
|
# gunakan baik LCtrl+LAlt atau LSuper untuk jalan pintas
|
||||||
|
scrcpy --shortcut-mod=lctrl+lalt,lsuper
|
||||||
|
```
|
||||||
|
|
||||||
|
_<kbd>[Super]</kbd> biasanya adalah <kbd>Windows</kbd> atau <kbd>Cmd</kbd> key._
|
||||||
|
|
||||||
|
[Super]: https://en.wikipedia.org/wiki/Super_key_(keyboard_button)
|
||||||
|
|
||||||
|
| Aksi | Pintasan
|
||||||
|
| ------------------------------------------------------|:-----------------------------
|
||||||
|
| Alihkan mode layar penuh | <kbd>MOD</kbd>+<kbd>f</kbd>
|
||||||
|
| Putar layar kiri | <kbd>MOD</kbd>+<kbd>←</kbd> _(kiri)_
|
||||||
|
| Putar layar kanan | <kbd>MOD</kbd>+<kbd>→</kbd> _(kanan)_
|
||||||
|
| Ubah ukuran jendela menjadi 1:1 (piksel-sempurna) | <kbd>MOD</kbd>+<kbd>g</kbd>
|
||||||
|
| Ubah ukuran jendela menjadi hapus batas hitam | <kbd>MOD</kbd>+<kbd>w</kbd> \| _klik-dua-kali¹_
|
||||||
|
| Klik `HOME` | <kbd>MOD</kbd>+<kbd>h</kbd> \| _Klik-tengah_
|
||||||
|
| Klik `BACK` | <kbd>MOD</kbd>+<kbd>b</kbd> \| _Klik-kanan²_
|
||||||
|
| Klik `APP_SWITCH` | <kbd>MOD</kbd>+<kbd>s</kbd>
|
||||||
|
| Klik `MENU` (buka kunci layar) | <kbd>MOD</kbd>+<kbd>m</kbd>
|
||||||
|
| Klik `VOLUME_UP` | <kbd>MOD</kbd>+<kbd>↑</kbd> _(naik)_
|
||||||
|
| Klik `VOLUME_DOWN` | <kbd>MOD</kbd>+<kbd>↓</kbd> _(turun)_
|
||||||
|
| Klik `POWER` | <kbd>MOD</kbd>+<kbd>p</kbd>
|
||||||
|
| Menyalakan | _Klik-kanan²_
|
||||||
|
| Matikan layar perangkat (tetap mirroring) | <kbd>MOD</kbd>+<kbd>o</kbd>
|
||||||
|
| Hidupkan layar perangkat | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>
|
||||||
|
| Putar layar perangkat | <kbd>MOD</kbd>+<kbd>r</kbd>
|
||||||
|
| Luaskan panel notifikasi | <kbd>MOD</kbd>+<kbd>n</kbd>
|
||||||
|
| Ciutkan panel notifikasi | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>n</kbd>
|
||||||
|
| Menyalin ke papan klip³ | <kbd>MOD</kbd>+<kbd>c</kbd>
|
||||||
|
| Potong ke papan klip³ | <kbd>MOD</kbd>+<kbd>x</kbd>
|
||||||
|
| Sinkronkan papan klip dan tempel³ | <kbd>MOD</kbd>+<kbd>v</kbd>
|
||||||
|
| Masukkan teks papan klip komputer | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>
|
||||||
|
| Mengaktifkan/menonaktifkan penghitung FPS (di stdout) | <kbd>MOD</kbd>+<kbd>i</kbd>
|
||||||
|
| Cubit-untuk-memperbesar/memperkecil | <kbd>Ctrl</kbd>+_klik-dan-pindah_
|
||||||
|
|
||||||
|
_¹Klik-dua-kali pada batas hitam untuk menghapusnya._
|
||||||
|
_²Klik-kanan akan menghidupkan layar jika mati, tekan BACK jika tidak._
|
||||||
|
_³Hanya di Android >= 7._
|
||||||
|
|
||||||
|
Semua <kbd>Ctrl</kbd>+_key_ pintasan diteruskan ke perangkat, demikian adanya
|
||||||
|
ditangani oleh aplikasi aktif.
|
||||||
|
|
||||||
|
|
||||||
|
## Jalur kustom
|
||||||
|
|
||||||
|
Untuk menggunakan biner _adb_ tertentu, konfigurasikan jalurnya di variabel lingkungan `ADB`:
|
||||||
|
|
||||||
|
ADB=/path/to/adb scrcpy
|
||||||
|
|
||||||
|
Untuk mengganti jalur file `scrcpy-server`, konfigurasikan jalurnya di
|
||||||
|
`SCRCPY_SERVER_PATH`.
|
||||||
|
|
||||||
|
[useful]: https://github.com/Genymobile/scrcpy/issues/278#issuecomment-429330345
|
||||||
|
|
||||||
|
|
||||||
|
## Mengapa _scrcpy_?
|
||||||
|
|
||||||
|
Seorang kolega menantang saya untuk menemukan nama yang tidak dapat diucapkan seperti [gnirehtet].
|
||||||
|
|
||||||
|
[`strcpy`] menyalin sebuah **str**ing; `scrcpy` menyalin sebuah **scr**een.
|
||||||
|
|
||||||
|
[gnirehtet]: https://github.com/Genymobile/gnirehtet
|
||||||
|
[`strcpy`]: http://man7.org/linux/man-pages/man3/strcpy.3.html
|
||||||
|
|
||||||
|
|
||||||
|
## Bagaimana Cara membangun?
|
||||||
|
|
||||||
|
Lihat [BUILD].
|
||||||
|
|
||||||
|
[BUILD]: BUILD.md
|
||||||
|
|
||||||
|
|
||||||
|
## Masalah umum
|
||||||
|
|
||||||
|
Lihat [FAQ](FAQ.md).
|
||||||
|
|
||||||
|
|
||||||
|
## Pengembang
|
||||||
|
|
||||||
|
Baca [halaman pengembang].
|
||||||
|
|
||||||
|
[halaman pengembang]: DEVELOP.md
|
||||||
|
|
||||||
|
|
||||||
|
## Lisensi
|
||||||
|
|
||||||
|
Copyright (C) 2018 Genymobile
|
||||||
|
Copyright (C) 2018-2021 Romain Vimont
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
## Artikel
|
||||||
|
|
||||||
|
- [Introducing scrcpy][article-intro]
|
||||||
|
- [Scrcpy now works wirelessly][article-tcpip]
|
||||||
|
|
||||||
|
[article-intro]: https://blog.rom1v.com/2018/03/introducing-scrcpy/
|
||||||
|
[article-tcpip]: https://www.genymotion.com/blog/open-source-project-scrcpy-now-works-wirelessly/
|
||||||
|
|
@ -477,7 +477,7 @@ _²화면이 꺼진 상태에서 우클릭 시 다시 켜지며, 그 외의 상
|
|||||||
## 라이선스
|
## 라이선스
|
||||||
|
|
||||||
Copyright (C) 2018 Genymobile
|
Copyright (C) 2018 Genymobile
|
||||||
Copyright (C) 2018-2020 Romain Vimont
|
Copyright (C) 2018-2021 Romain Vimont
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
40
README.md
40
README.md
@ -1,4 +1,4 @@
|
|||||||
# scrcpy (v1.16)
|
# scrcpy (v1.17)
|
||||||
|
|
||||||
[Read in another language](#translations)
|
[Read in another language](#translations)
|
||||||
|
|
||||||
@ -77,10 +77,10 @@ hard).
|
|||||||
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.16.zip`][direct-win64]
|
- [`scrcpy-win64-v1.17.zip`][direct-win64]
|
||||||
_(SHA-256: 3f30dc5db1a2f95c2b40a0f5de91ec1642d9f53799250a8c529bc882bc0918f0)_
|
_(SHA-256: 8b9e57993c707367ed10ebfe0e1ef563c7a29d9af4a355cd8b6a52a317c73eea)_
|
||||||
|
|
||||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.16/scrcpy-win64-v1.16.zip
|
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.17/scrcpy-win64-v1.17.zip
|
||||||
|
|
||||||
It is also available in [Chocolatey]:
|
It is also available in [Chocolatey]:
|
||||||
|
|
||||||
@ -116,6 +116,10 @@ brew install scrcpy
|
|||||||
You need `adb`, accessible from your `PATH`. If you don't have it yet:
|
You need `adb`, accessible from your `PATH`. If you don't have it yet:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Homebrew >= 2.6.0
|
||||||
|
brew install --cask android-platform-tools
|
||||||
|
|
||||||
|
# Homebrew < 2.6.0
|
||||||
brew cask install android-platform-tools
|
brew cask install android-platform-tools
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -202,6 +206,8 @@ scrcpy --lock-video-orientation 3 # 90° clockwise
|
|||||||
|
|
||||||
This affects recording orientation.
|
This affects recording orientation.
|
||||||
|
|
||||||
|
The [window may also be rotated](#rotation) independently.
|
||||||
|
|
||||||
|
|
||||||
#### Encoder
|
#### Encoder
|
||||||
|
|
||||||
@ -251,7 +257,13 @@ _Scrcpy_ uses `adb` to communicate with the device, and `adb` can [connect] to a
|
|||||||
device over TCP/IP:
|
device over TCP/IP:
|
||||||
|
|
||||||
1. Connect the device to the same Wi-Fi as your computer.
|
1. Connect the device to the same Wi-Fi as your computer.
|
||||||
2. Get your device IP address (in Settings → About phone → Status).
|
2. Get your device IP address, in Settings → About phone → Status, or by
|
||||||
|
executing this command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb shell ip route | awk '{print $9}'
|
||||||
|
```
|
||||||
|
|
||||||
3. Enable adb over TCP/IP on your device: `adb tcpip 5555`.
|
3. Enable adb over TCP/IP on your device: `adb tcpip 5555`.
|
||||||
4. Unplug your device.
|
4. Unplug your device.
|
||||||
5. 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`)_.
|
||||||
@ -398,12 +410,12 @@ The rotation can also be changed dynamically with <kbd>MOD</kbd>+<kbd>←</kbd>
|
|||||||
_(left)_ and <kbd>MOD</kbd>+<kbd>→</kbd> _(right)_.
|
_(left)_ and <kbd>MOD</kbd>+<kbd>→</kbd> _(right)_.
|
||||||
|
|
||||||
Note that _scrcpy_ manages 3 different rotations:
|
Note that _scrcpy_ manages 3 different rotations:
|
||||||
- <kbd>MOD</kbd>+<kbd>r</kbd> requests the device to switch between portrait and
|
- <kbd>MOD</kbd>+<kbd>r</kbd> requests the device to switch between portrait
|
||||||
landscape (the current running app may refuse, if it does support the
|
and landscape (the current running app may refuse, if it does support the
|
||||||
requested orientation).
|
requested orientation).
|
||||||
- `--lock-video-orientation` changes the mirroring orientation (the orientation
|
- [`--lock-video-orientation`](#lock-video-orientation) changes the mirroring
|
||||||
of the video sent from the device to the computer). This affects the
|
orientation (the orientation of the video sent from the device to the
|
||||||
recording.
|
computer). This affects the recording.
|
||||||
- `--rotation` (or <kbd>MOD</kbd>+<kbd>←</kbd>/<kbd>MOD</kbd>+<kbd>→</kbd>)
|
- `--rotation` (or <kbd>MOD</kbd>+<kbd>←</kbd>/<kbd>MOD</kbd>+<kbd>→</kbd>)
|
||||||
rotates only the window content. This affects only the display, not the
|
rotates only the window content. This affects only the display, not the
|
||||||
recording.
|
recording.
|
||||||
@ -760,7 +772,7 @@ Read the [developers page].
|
|||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
Copyright (C) 2018 Genymobile
|
Copyright (C) 2018 Genymobile
|
||||||
Copyright (C) 2018-2020 Romain Vimont
|
Copyright (C) 2018-2021 Romain Vimont
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -786,8 +798,10 @@ Read the [developers page].
|
|||||||
|
|
||||||
This README is available in other languages:
|
This README is available in other languages:
|
||||||
|
|
||||||
- [繁體中文 (Traditional Chinese, `zh-Hant`) - v1.15](README.zh-Hant.md)
|
- [Indonesian (Indonesia, `id`) - v1.16](README.id.md)
|
||||||
- [한국어 (Korean, `ko`) - v1.11](README.ko.md)
|
- [한국어 (Korean, `ko`) - v1.11](README.ko.md)
|
||||||
- [português brasileiro (Brazilian Portuguese, `pt-BR`) - v1.12.1](README.pt-br.md)
|
- [português brasileiro (Brazilian Portuguese, `pt-BR`) - v1.12.1](README.pt-br.md)
|
||||||
|
- [简体中文 (Simplified Chinese, `zh-Hans`) - v1.16](README.zh-Hans.md)
|
||||||
|
- [繁體中文 (Traditional Chinese, `zh-Hant`) - v1.15](README.zh-Hant.md)
|
||||||
|
|
||||||
Only this README file is guaranteed to be up-to-date.
|
Only this README file is guaranteed to be up-to-date.
|
||||||
|
@ -508,7 +508,7 @@ Leia a [developers page].
|
|||||||
## Licença
|
## Licença
|
||||||
|
|
||||||
Copyright (C) 2018 Genymobile
|
Copyright (C) 2018 Genymobile
|
||||||
Copyright (C) 2018-2020 Romain Vimont
|
Copyright (C) 2018-2021 Romain Vimont
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
726
README.zh-Hans.md
Normal file
726
README.zh-Hans.md
Normal file
@ -0,0 +1,726 @@
|
|||||||
|
_Only the original [README](README.md) is guaranteed to be up-to-date._
|
||||||
|
|
||||||
|
只有原版的[README](README.md)会保持最新。
|
||||||
|
|
||||||
|
本文根据[479d10d]进行翻译。
|
||||||
|
|
||||||
|
[479d10d]: https://github.com/Genymobile/scrcpy/commit/479d10dc22b70272187e0963c6ad24d754a669a2#diff-04c6e90faac2675aa89e2176d2eec7d8
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# scrcpy (v1.16)
|
||||||
|
|
||||||
|
本应用程序可以通过USB(或 [TCP/IP][article-tcpip] )连接用于显示或控制安卓设备。这不需要获取 _root_ 权限。
|
||||||
|
|
||||||
|
该应用程序可以在 _GNU/Linux_, _Windows_ 和 _macOS_ 环境下运行。
|
||||||
|
|
||||||
|
[article-tcpip]:https://www.genymotion.com/blog/open-source-project-scrcpy-now-works-wirelessly/
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
它专注于:
|
||||||
|
|
||||||
|
- **轻量** (原生,仅显示设备屏幕)
|
||||||
|
- **性能** (30~60fps)
|
||||||
|
- **质量** (分辨率可达1920x1080或更高)
|
||||||
|
- **低延迟** (35-70ms)
|
||||||
|
- **快速启动** (数秒内即能开始显示)
|
||||||
|
- **无侵入性** (不需要在安卓设备上安装任何程序)
|
||||||
|
|
||||||
|
|
||||||
|
## 使用要求
|
||||||
|
|
||||||
|
安卓设备系统版本需要在Android 5.0(API 21)或以上。
|
||||||
|
|
||||||
|
确保您在设备上开启了[adb调试]。
|
||||||
|
|
||||||
|
[adb调试]: https://developer.android.com/studio/command-line/adb.html#Enabling
|
||||||
|
|
||||||
|
在某些设备上,你还需要开启[额外的选项]以用鼠标和键盘进行控制。
|
||||||
|
|
||||||
|
[额外的选项]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323
|
||||||
|
|
||||||
|
|
||||||
|
## 获取scrcpy
|
||||||
|
|
||||||
|
<a href="https://repology.org/project/scrcpy/versions"><img src="https://repology.org/badge/vertical-allrepos/scrcpy.svg" alt="Packaging status" align="right"></a>
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
在Debian(目前仅测试版和不稳定版,即 _testing_ 和 _sid_ 版本)和Ubuntu (20.04)上:
|
||||||
|
|
||||||
|
```
|
||||||
|
apt install scrcpy
|
||||||
|
```
|
||||||
|
|
||||||
|
[Snap]包也是可用的: [`scrcpy`][snap-link].
|
||||||
|
|
||||||
|
[snap-link]: https://snapstats.org/snaps/scrcpy
|
||||||
|
|
||||||
|
[snap]: https://en.wikipedia.org/wiki/Snappy_(package_manager)
|
||||||
|
|
||||||
|
对于Fedora用户,我们提供[COPR]包: [`scrcpy`][copr-link].
|
||||||
|
|
||||||
|
[COPR]: https://fedoraproject.org/wiki/Category:Copr
|
||||||
|
[copr-link]: https://copr.fedorainfracloud.org/coprs/zeno/scrcpy/
|
||||||
|
|
||||||
|
对于Arch Linux用户,我们提供[AUR]包: [`scrcpy`][aur-link].
|
||||||
|
|
||||||
|
[AUR]: https://wiki.archlinux.org/index.php/Arch_User_Repository
|
||||||
|
[aur-link]: https://aur.archlinux.org/packages/scrcpy/
|
||||||
|
|
||||||
|
对于Gentoo用户,我们提供[Ebuild]包:[`scrcpy/`][ebuild-link].
|
||||||
|
|
||||||
|
[Ebuild]: https://wiki.gentoo.org/wiki/Ebuild
|
||||||
|
[ebuild-link]: https://github.com/maggu2810/maggu2810-overlay/tree/master/app-mobilephone/scrcpy
|
||||||
|
|
||||||
|
您也可以[自行编译][编译](不必担心,这并不困难)。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
在Windows上,简便起见,我们准备了包含所有依赖项(包括adb)的程序包。
|
||||||
|
|
||||||
|
- [`scrcpy-win64-v1.16.zip`][direct-win64]
|
||||||
|
_(SHA-256: 3f30dc5db1a2f95c2b40a0f5de91ec1642d9f53799250a8c529bc882bc0918f0)_
|
||||||
|
|
||||||
|
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.16/scrcpy-win64-v1.16.zip
|
||||||
|
|
||||||
|
您也可以在[Chocolatey]下载:
|
||||||
|
|
||||||
|
[Chocolatey]: https://chocolatey.org/
|
||||||
|
|
||||||
|
```bash
|
||||||
|
choco install scrcpy
|
||||||
|
choco install adb # 如果你没有adb
|
||||||
|
```
|
||||||
|
|
||||||
|
也可以使用 [Scoop]:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scoop install scrcpy
|
||||||
|
scoop install adb # 如果你没有adb
|
||||||
|
```
|
||||||
|
|
||||||
|
[Scoop]: https://scoop.sh
|
||||||
|
|
||||||
|
您也可以[自行编译][编译]。
|
||||||
|
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
您可以使用[Homebrew]下载scrcpy。直接安装就可以了:
|
||||||
|
|
||||||
|
[Homebrew]: https://brew.sh/
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install scrcpy
|
||||||
|
```
|
||||||
|
|
||||||
|
您需要 `adb`以使用scrcpy,并且它需要可以通过 `PATH`被访问。如果您没有:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew cask install android-platform-tools
|
||||||
|
```
|
||||||
|
|
||||||
|
您也可以[自行编译][编译]。
|
||||||
|
|
||||||
|
|
||||||
|
## 运行scrcpy
|
||||||
|
|
||||||
|
用USB链接电脑和安卓设备,并执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy
|
||||||
|
```
|
||||||
|
|
||||||
|
支持带命令行参数执行,查看参数列表:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --help
|
||||||
|
```
|
||||||
|
|
||||||
|
## 功能介绍
|
||||||
|
|
||||||
|
### 画面设置
|
||||||
|
|
||||||
|
#### 缩小分辨率
|
||||||
|
|
||||||
|
有时候,将设备屏幕镜像分辨率降低可以有效地提升性能。
|
||||||
|
|
||||||
|
我们可以将高度和宽度都限制在一定大小内(如 1024):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --max-size 1024
|
||||||
|
scrcpy -m 1024 # short version
|
||||||
|
```
|
||||||
|
|
||||||
|
较短的一边会被按比例缩小以保持设备的显示比例。
|
||||||
|
这样,1920x1080 的设备会以 1024x576 的分辨率显示。
|
||||||
|
|
||||||
|
|
||||||
|
#### 修改画面比特率
|
||||||
|
|
||||||
|
默认的比特率是8Mbps。如果要改变画面的比特率 (比如说改成2Mbps):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --bit-rate 2M
|
||||||
|
scrcpy -b 2M # short version
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 限制画面帧率
|
||||||
|
|
||||||
|
画面的帧率可以通过下面的命令被限制:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --max-fps 15
|
||||||
|
```
|
||||||
|
|
||||||
|
这个功能仅在Android 10和以后的版本被Android官方支持,但也有可能在更早的版本可用。
|
||||||
|
|
||||||
|
#### 画面裁剪
|
||||||
|
|
||||||
|
设备画面可在裁切后进行镜像,以显示部分屏幕。
|
||||||
|
|
||||||
|
这项功能可以用于,例如,只显示Oculus Go的一只眼睛。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --crop 1224:1440:0:0 # 1224x1440 at offset (0,0)
|
||||||
|
```
|
||||||
|
|
||||||
|
如果`--max-size`在同时被指定,分辨率的改变将在画面裁切后进行。
|
||||||
|
|
||||||
|
|
||||||
|
#### 锁定屏幕朝向
|
||||||
|
|
||||||
|
|
||||||
|
可以使用如下命令锁定屏幕朝向:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --lock-video-orientation 0 # 自然朝向
|
||||||
|
scrcpy --lock-video-orientation 1 # 90° 逆时针旋转
|
||||||
|
scrcpy --lock-video-orientation 2 # 180°
|
||||||
|
scrcpy --lock-video-orientation 3 # 90° 顺时针旋转
|
||||||
|
```
|
||||||
|
|
||||||
|
该设定影响录制。
|
||||||
|
|
||||||
|
|
||||||
|
### 屏幕录制
|
||||||
|
|
||||||
|
可以在屏幕镜像的同时录制视频:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --record file.mp4
|
||||||
|
scrcpy -r file.mkv
|
||||||
|
```
|
||||||
|
|
||||||
|
在不开启屏幕镜像的同时录制:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --no-display --record file.mp4
|
||||||
|
scrcpy -Nr file.mkv
|
||||||
|
# 按Ctrl+C以停止录制
|
||||||
|
```
|
||||||
|
|
||||||
|
在显示中“被跳过的帧”会被录制,虽然它们由于性能原因没有实时显示。
|
||||||
|
在传输中每一帧都有 _时间戳_ ,所以 [包时延变化] 并不影响录制的文件。
|
||||||
|
|
||||||
|
[包时延变化]: https://en.wikipedia.org/wiki/Packet_delay_variation
|
||||||
|
|
||||||
|
|
||||||
|
### 连接方式
|
||||||
|
|
||||||
|
#### 无线
|
||||||
|
|
||||||
|
_Scrcpy_ 使用`adb`来与安卓设备连接。同时,`adb`能够通过TCP/IP[连接]到安卓设备:
|
||||||
|
|
||||||
|
1. 将您的安卓设备和电脑连接至同一Wi-Fi。
|
||||||
|
2. 获取安卓设备的IP地址(在设置-关于手机-状态信息)。
|
||||||
|
3. 打开安卓设备的网络adb功能`adb tcpip 5555`。
|
||||||
|
4. 将您的设备与电脑断开连接。
|
||||||
|
5. 连接到您的设备:`adb connect DEVICE_IP:5555` _(用设备IP替换 `DEVICE_IP`)_.
|
||||||
|
6. 运行`scrcpy`。
|
||||||
|
|
||||||
|
降低比特率和分辨率可能有助于性能:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --bit-rate 2M --max-size 800
|
||||||
|
scrcpy -b2M -m800 # short version
|
||||||
|
```
|
||||||
|
|
||||||
|
[连接]: https://developer.android.com/studio/command-line/adb.html#wireless
|
||||||
|
|
||||||
|
|
||||||
|
#### 多设备
|
||||||
|
|
||||||
|
如果多个设备在执行`adb devices`后被列出,您必须指定设备的 _序列号_ :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --serial 0123456789abcdef
|
||||||
|
scrcpy -s 0123456789abcdef # short version
|
||||||
|
```
|
||||||
|
|
||||||
|
如果设备是通过TCP/IP方式连接到电脑的:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --serial 192.168.0.1:5555
|
||||||
|
scrcpy -s 192.168.0.1:5555 # short version
|
||||||
|
```
|
||||||
|
|
||||||
|
您可以同时启动多个 _scrcpy_ 实例以同时显示多个设备的画面。
|
||||||
|
|
||||||
|
#### 在设备连接时自动启动
|
||||||
|
|
||||||
|
您可以使用 [AutoAdb]:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
autoadb scrcpy -s '{}'
|
||||||
|
```
|
||||||
|
|
||||||
|
[AutoAdb]: https://github.com/rom1v/autoadb
|
||||||
|
|
||||||
|
#### SSH 连接
|
||||||
|
|
||||||
|
本地的 adb 可以远程连接到另一个 adb 服务器(假设两者的adb版本相同),来远程连接到设备:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb kill-server # 关闭本地5037端口上的adb服务器
|
||||||
|
ssh -CN -L5037:localhost:5037 -R27183:localhost:27183 your_remote_computer
|
||||||
|
# 保持该窗口开启
|
||||||
|
```
|
||||||
|
|
||||||
|
从另一个终端:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy
|
||||||
|
```
|
||||||
|
|
||||||
|
为了避免启动远程端口转发,你可以强制启动一个转发连接(注意`-L`和`-R`的区别:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb kill-server # kill the local adb server on 5037
|
||||||
|
ssh -CN -L5037:localhost:5037 -L27183:localhost:27183 your_remote_computer
|
||||||
|
# 保持该窗口开启
|
||||||
|
```
|
||||||
|
|
||||||
|
从另一个终端:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --force-adb-forward
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
和无线网络连接类似,下列设置可能对改善性能有帮助:
|
||||||
|
|
||||||
|
```
|
||||||
|
scrcpy -b2M -m800 --max-fps 15
|
||||||
|
```
|
||||||
|
|
||||||
|
### 窗口设置
|
||||||
|
|
||||||
|
#### 标题
|
||||||
|
|
||||||
|
窗口的标题默认为设备型号。您可以通过如下命令修改它:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --window-title 'My device'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 位置和大小
|
||||||
|
|
||||||
|
您可以指定初始的窗口位置和大小:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --window-x 100 --window-y 100 --window-width 800 --window-height 600
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 无边框
|
||||||
|
|
||||||
|
关闭边框:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --window-borderless
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 保持窗口在最前
|
||||||
|
|
||||||
|
您可以通过如下命令保持窗口在最前面:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --always-on-top
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 全屏
|
||||||
|
|
||||||
|
您可以通过如下命令直接全屏启动scrcpy:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --fullscreen
|
||||||
|
scrcpy -f # short version
|
||||||
|
```
|
||||||
|
|
||||||
|
全屏状态可以通过<kbd>MOD</kbd>+<kbd>f</kbd>实时改变。
|
||||||
|
|
||||||
|
#### 旋转
|
||||||
|
|
||||||
|
通过如下命令,窗口可以旋转:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --rotation 1
|
||||||
|
```
|
||||||
|
|
||||||
|
可选的值有:
|
||||||
|
- `0`: 无旋转
|
||||||
|
- `1`: 逆时针旋转90°
|
||||||
|
- `2`: 旋转180°
|
||||||
|
- `3`: 顺时针旋转90°
|
||||||
|
|
||||||
|
这同样可以使用<kbd>MOD</kbd>+<kbd>←</kbd>
|
||||||
|
_(左)_ 和 <kbd>MOD</kbd>+<kbd>→</kbd> _(右)_ 的快捷键实时更改。
|
||||||
|
|
||||||
|
需要注意的是, _scrcpy_ 控制三个不同的朝向:
|
||||||
|
- <kbd>MOD</kbd>+<kbd>r</kbd> 请求设备在竖屏和横屏之间切换(如果前台应用程序不支持所请求的朝向,可能会拒绝该请求)。
|
||||||
|
|
||||||
|
- `--lock-video-orientation` 改变镜像的朝向(设备镜像到电脑的画面朝向)。这会影响录制。
|
||||||
|
|
||||||
|
- `--rotation` (或<kbd>MOD</kbd>+<kbd>←</kbd>/<kbd>MOD</kbd>+<kbd>→</kbd>)
|
||||||
|
只旋转窗口的画面。这只影响显示,不影响录制。
|
||||||
|
|
||||||
|
|
||||||
|
### 其他镜像设置
|
||||||
|
|
||||||
|
#### 只读
|
||||||
|
|
||||||
|
关闭电脑对设备的控制(如键盘输入、鼠标移动和文件传输):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --no-control
|
||||||
|
scrcpy -n
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 显示屏
|
||||||
|
|
||||||
|
如果有多个显示屏可用,您可以选择特定显示屏进行镜像:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --display 1
|
||||||
|
```
|
||||||
|
|
||||||
|
您可以通过如下命令找到显示屏的id:
|
||||||
|
|
||||||
|
```
|
||||||
|
adb shell dumpsys display # 在回显中搜索“mDisplayId=”
|
||||||
|
```
|
||||||
|
|
||||||
|
第二显示屏可能只能在设备运行Android 10或以上的情况下被控制(它可能会在电脑上显示,但无法通过电脑操作)。
|
||||||
|
|
||||||
|
|
||||||
|
#### 保持常亮
|
||||||
|
|
||||||
|
防止设备在已连接的状态下休眠:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --stay-awake
|
||||||
|
scrcpy -w
|
||||||
|
```
|
||||||
|
|
||||||
|
程序关闭后,设备设置会恢复原样。
|
||||||
|
|
||||||
|
|
||||||
|
#### 关闭设备屏幕
|
||||||
|
|
||||||
|
在启动屏幕镜像时,可以通过如下命令关闭设备的屏幕:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --turn-screen-off
|
||||||
|
scrcpy -S
|
||||||
|
```
|
||||||
|
|
||||||
|
或者在需要的时候按<kbd>MOD</kbd>+<kbd>o</kbd>。
|
||||||
|
|
||||||
|
要重新打开屏幕的话,需要按<kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>.
|
||||||
|
|
||||||
|
在Android上,`电源`按钮始终能把屏幕打开。
|
||||||
|
|
||||||
|
为了方便,如果按下`电源`按钮的事件是通过 _scrcpy_ 发出的(通过点按鼠标右键或<kbd>MOD</kbd>+<kbd>p</kbd>),它会在短暂的延迟后将屏幕关闭。
|
||||||
|
|
||||||
|
物理的`电源`按钮仍然能打开设备屏幕。
|
||||||
|
|
||||||
|
同时,这项功能还能被用于防止设备休眠:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --turn-screen-off --stay-awake
|
||||||
|
scrcpy -Sw
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### 渲染超时帧
|
||||||
|
|
||||||
|
为了降低延迟, _scrcpy_ 默认渲染解码成功的最近一帧,并跳过前面任意帧。
|
||||||
|
|
||||||
|
强制渲染所有帧(可能导致延迟变高):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --render-expired-frames
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 显示触摸
|
||||||
|
|
||||||
|
在展示时,有些时候可能会用到显示触摸点这项功能(在设备上显示)。
|
||||||
|
|
||||||
|
Android在 _开发者设置_ 中提供了这项功能。
|
||||||
|
|
||||||
|
_Scrcpy_ 提供一个选项可以在启动时开启这项功能并在退出时恢复初始设置:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --show-touches
|
||||||
|
scrcpy -t
|
||||||
|
```
|
||||||
|
|
||||||
|
请注意这项功能只能显示 _物理_ 触摸(要用手在屏幕上触摸)。
|
||||||
|
|
||||||
|
|
||||||
|
#### 关闭屏保
|
||||||
|
|
||||||
|
_Scrcpy_ 不会默认关闭屏幕保护。
|
||||||
|
|
||||||
|
关闭屏幕保护:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --disable-screensaver
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### 输入控制
|
||||||
|
|
||||||
|
#### 旋转设备屏幕
|
||||||
|
|
||||||
|
使用<kbd>MOD</kbd>+<kbd>r</kbd>以在竖屏和横屏模式之间切换。
|
||||||
|
|
||||||
|
需要注意的是,只有在前台应用程序支持所要求的模式时,才会进行切换。
|
||||||
|
|
||||||
|
#### 复制黏贴
|
||||||
|
|
||||||
|
每次Android的剪贴板变化的时候,它都会被自动同步到电脑的剪贴板上。
|
||||||
|
|
||||||
|
所有的 <kbd>Ctrl</kbd> 快捷键都会被转发至设备。其中:
|
||||||
|
- <kbd>Ctrl</kbd>+<kbd>c</kbd> 复制
|
||||||
|
- <kbd>Ctrl</kbd>+<kbd>x</kbd> 剪切
|
||||||
|
- <kbd>Ctrl</kbd>+<kbd>v</kbd> 黏贴 (在电脑到设备的剪贴板同步完成之后)
|
||||||
|
|
||||||
|
这通常如您所期望的那样运作。
|
||||||
|
|
||||||
|
但实际的行为取决于设备上的前台程序。
|
||||||
|
例如 _Termux_ 在<kbd>Ctrl</kbd>+<kbd>c</kbd>被按下时发送 SIGINT,
|
||||||
|
又如 _K-9 Mail_ 会新建一封新邮件。
|
||||||
|
|
||||||
|
在这种情况下剪切复制黏贴(仅在Android >= 7时可用):
|
||||||
|
- <kbd>MOD</kbd>+<kbd>c</kbd> 注入 `COPY`(复制)
|
||||||
|
- <kbd>MOD</kbd>+<kbd>x</kbd> 注入 `CUT`(剪切)
|
||||||
|
- <kbd>MOD</kbd>+<kbd>v</kbd> 注入 `PASTE`(黏贴)(在电脑到设备的剪贴板同步完成之后)
|
||||||
|
|
||||||
|
另外,<kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>可以将电脑的剪贴板内容转换为一串按键事件输入到设备。
|
||||||
|
在应用程序不接受黏贴时(比如 _Termux_ ),这项功能可以排上一定的用场。
|
||||||
|
需要注意的是,这项功能可能会导致非ASCII编码的内容出现错误。
|
||||||
|
|
||||||
|
**警告:** 将电脑剪贴板的内容黏贴至设备(无论是通过<kbd>Ctrl</kbd>+<kbd>v</kbd>还是<kbd>MOD</kbd>+<kbd>v</kbd>)
|
||||||
|
都需要将内容保存至设备的剪贴板。如此,任何一个应用程序都可以读取它。
|
||||||
|
您应当避免将敏感内容通过这种方式传输(如密码)。
|
||||||
|
|
||||||
|
|
||||||
|
#### 捏拉缩放
|
||||||
|
|
||||||
|
模拟 “捏拉缩放”:<kbd>Ctrl</kbd>+_按住并移动鼠标_。
|
||||||
|
|
||||||
|
更准确的说,您需要在按住<kbd>Ctrl</kbd>的同时按住并移动鼠标。
|
||||||
|
在鼠标左键松开之后,光标的任何操作都会相对于屏幕的中央进行。
|
||||||
|
|
||||||
|
具体来说, _scrcpy_ 使用“虚拟手指”以在相对于屏幕中央相反的位置产生触摸事件。
|
||||||
|
|
||||||
|
|
||||||
|
#### 文字注入偏好
|
||||||
|
|
||||||
|
打字的时候,系统会产生两种[事件][textevents]:
|
||||||
|
- _按键事件_ ,代表一个按键被按下/松开。
|
||||||
|
- _文本事件_ ,代表一个文本被输入。
|
||||||
|
|
||||||
|
程序默认使用按键事件来输入字母。只有这样,键盘才会在游戏中正常运作(尤其WASD键)。
|
||||||
|
|
||||||
|
但这也有可能[造成问题][prefertext]。如果您遇到了这样的问题,您可以通过下列操作避免它:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --prefer-text
|
||||||
|
```
|
||||||
|
|
||||||
|
(这会导致键盘在游戏中工作不正常)
|
||||||
|
|
||||||
|
[textevents]: https://blog.rom1v.com/2018/03/introducing-scrcpy/#handle-text-input
|
||||||
|
[prefertext]: https://github.com/Genymobile/scrcpy/issues/650#issuecomment-512945343
|
||||||
|
|
||||||
|
|
||||||
|
#### 按键重复
|
||||||
|
|
||||||
|
当你一直按着一个按键不放时,程序默认产生多个按键事件。
|
||||||
|
在某些游戏中这可能会导致性能问题。
|
||||||
|
|
||||||
|
避免转发重复按键事件:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --no-key-repeat
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### 文件传输
|
||||||
|
|
||||||
|
#### 安装APK
|
||||||
|
|
||||||
|
如果您要要安装APK,请拖放APK文件(文件名以`.apk`结尾)到 _scrcpy_ 窗口。
|
||||||
|
|
||||||
|
该操作在屏幕上不会出现任何变化,而会在控制台输出一条日志。
|
||||||
|
|
||||||
|
|
||||||
|
#### 将文件推送至设备
|
||||||
|
|
||||||
|
如果您要推送文件到设备的 `/sdcard/`,请拖放文件至(不能是APK文件)_scrcpy_ 窗口。
|
||||||
|
|
||||||
|
该操作没有可见的响应,只会在控制台输出日志。
|
||||||
|
|
||||||
|
在启动时可以修改目标目录:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --push-target /sdcard/foo/bar/
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### 音频转发
|
||||||
|
|
||||||
|
_scrcpy_ 不支持音频。请使用 [sndcpy].
|
||||||
|
|
||||||
|
另外请阅读 [issue #14]。
|
||||||
|
|
||||||
|
[sndcpy]: https://github.com/rom1v/sndcpy
|
||||||
|
[issue #14]: https://github.com/Genymobile/scrcpy/issues/14
|
||||||
|
|
||||||
|
|
||||||
|
## 热键
|
||||||
|
|
||||||
|
在下列表格中, <kbd>MOD</kbd> 是热键的修饰键。
|
||||||
|
默认是(左)<kbd>Alt</kbd>或者(左)<kbd>Super</kbd>。
|
||||||
|
|
||||||
|
您可以使用 `--shortcut-mod`后缀来修改它。可选的按键有`lctrl`、`rctrl`、
|
||||||
|
`lalt`、`ralt`、`lsuper`和`rsuper`。如下例:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 使用右侧的Ctrl键
|
||||||
|
scrcpy --shortcut-mod=rctrl
|
||||||
|
|
||||||
|
# 使用左侧的Ctrl键、Alt键或Super键
|
||||||
|
scrcpy --shortcut-mod=lctrl+lalt,lsuper
|
||||||
|
```
|
||||||
|
|
||||||
|
_一般来说,<kbd>[Super]</kbd>就是<kbd>Windows</kbd>或者<kbd>Cmd</kbd>。_
|
||||||
|
|
||||||
|
[Super]: https://en.wikipedia.org/wiki/Super_key_(keyboard_button)
|
||||||
|
|
||||||
|
| 操作 | 快捷键
|
||||||
|
| ------------------------------------------- |:-----------------------------
|
||||||
|
| 全屏 | <kbd>MOD</kbd>+<kbd>f</kbd>
|
||||||
|
| 向左旋转屏幕 | <kbd>MOD</kbd>+<kbd>←</kbd> _(左)_
|
||||||
|
| 向右旋转屏幕 | <kbd>MOD</kbd>+<kbd>→</kbd> _(右)_
|
||||||
|
| 将窗口大小重置为1:1 (像素优先) | <kbd>MOD</kbd>+<kbd>g</kbd>
|
||||||
|
| 将窗口大小重置为消除黑边 | <kbd>MOD</kbd>+<kbd>w</kbd> \| _双击¹_
|
||||||
|
| 点按 `主屏幕` | <kbd>MOD</kbd>+<kbd>h</kbd> \| _点击鼠标中键_
|
||||||
|
| 点按 `返回` | <kbd>MOD</kbd>+<kbd>b</kbd> \| _点击鼠标右键²_
|
||||||
|
| 点按 `切换应用` | <kbd>MOD</kbd>+<kbd>s</kbd>
|
||||||
|
| 点按 `菜单` (解锁屏幕) | <kbd>MOD</kbd>+<kbd>m</kbd>
|
||||||
|
| 点按 `音量+` | <kbd>MOD</kbd>+<kbd>↑</kbd> _(up)_
|
||||||
|
| 点按 `音量-` | <kbd>MOD</kbd>+<kbd>↓</kbd> _(down)_
|
||||||
|
| 点按 `电源` | <kbd>MOD</kbd>+<kbd>p</kbd>
|
||||||
|
| 打开屏幕 | _点击鼠标右键²_
|
||||||
|
| 关闭设备屏幕(但继续在电脑上显示) | <kbd>MOD</kbd>+<kbd>o</kbd>
|
||||||
|
| 打开设备屏幕 | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>
|
||||||
|
| 旋转设备屏幕 | <kbd>MOD</kbd>+<kbd>r</kbd>
|
||||||
|
| 展开通知面板 | <kbd>MOD</kbd>+<kbd>n</kbd>
|
||||||
|
| 展开快捷操作 | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>n</kbd>
|
||||||
|
| 复制到剪贴板³ | <kbd>MOD</kbd>+<kbd>c</kbd>
|
||||||
|
| 剪切到剪贴板³ | <kbd>MOD</kbd>+<kbd>x</kbd>
|
||||||
|
| 同步剪贴板并黏贴³ | <kbd>MOD</kbd>+<kbd>v</kbd>
|
||||||
|
| 导入电脑剪贴板文本 | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>
|
||||||
|
| 打开/关闭FPS显示(在 stdout) | <kbd>MOD</kbd>+<kbd>i</kbd>
|
||||||
|
| 捏拉缩放 | <kbd>Ctrl</kbd>+_点按并移动鼠标_
|
||||||
|
|
||||||
|
_¹双击黑色边界以关闭黑色边界_
|
||||||
|
_²点击鼠标右键将在屏幕熄灭时点亮屏幕,其余情况则视为按下 返回键 。_
|
||||||
|
_³需要安卓版本 Android >= 7。_
|
||||||
|
|
||||||
|
所有的 <kbd>Ctrl</kbd>+_按键_ 的热键都是被转发到设备进行处理的,所以实际上会由当前应用程序对其做出响应。
|
||||||
|
|
||||||
|
|
||||||
|
## 自定义路径
|
||||||
|
|
||||||
|
为了使用您想使用的 _adb_ ,您可以在环境变量
|
||||||
|
`ADB`中设置它的路径:
|
||||||
|
|
||||||
|
ADB=/path/to/adb scrcpy
|
||||||
|
|
||||||
|
如果需要覆盖`scrcpy-server`的路径,您可以在
|
||||||
|
`SCRCPY_SERVER_PATH`中设置它。
|
||||||
|
|
||||||
|
[useful]: https://github.com/Genymobile/scrcpy/issues/278#issuecomment-429330345
|
||||||
|
|
||||||
|
|
||||||
|
## 为什么叫 _scrcpy_ ?
|
||||||
|
|
||||||
|
一个同事让我找出一个和[gnirehtet]一样难以发音的名字。
|
||||||
|
|
||||||
|
[`strcpy`] 可以复制**str**ing; `scrcpy` 可以复制**scr**een。
|
||||||
|
|
||||||
|
[gnirehtet]: https://github.com/Genymobile/gnirehtet
|
||||||
|
[`strcpy`]: http://man7.org/linux/man-pages/man3/strcpy.3.html
|
||||||
|
|
||||||
|
|
||||||
|
## 如何编译?
|
||||||
|
|
||||||
|
请查看[编译]。
|
||||||
|
|
||||||
|
[编译]: BUILD.md
|
||||||
|
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
请查看[FAQ](FAQ.md).
|
||||||
|
|
||||||
|
|
||||||
|
## 开发者
|
||||||
|
|
||||||
|
请查看[开发者页面]。
|
||||||
|
|
||||||
|
[开发者页面]: DEVELOP.md
|
||||||
|
|
||||||
|
|
||||||
|
## 许可协议
|
||||||
|
|
||||||
|
Copyright (C) 2018 Genymobile
|
||||||
|
Copyright (C) 2018-2021 Romain Vimont
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
## 相关文章
|
||||||
|
|
||||||
|
- [Introducing scrcpy][article-intro]
|
||||||
|
- [Scrcpy now works wirelessly][article-tcpip]
|
||||||
|
|
||||||
|
[article-intro]: https://blog.rom1v.com/2018/03/introducing-scrcpy/
|
||||||
|
[article-tcpip]: https://www.genymotion.com/blog/open-source-project-scrcpy-now-works-wirelessly/
|
@ -682,7 +682,7 @@ _³只支援 Android 7+。_
|
|||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
Copyright (C) 2018 Genymobile
|
Copyright (C) 2018 Genymobile
|
||||||
Copyright (C) 2018-2020 Romain Vimont
|
Copyright (C) 2018-2021 Romain Vimont
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -119,9 +119,6 @@ conf.set('DEFAULT_BIT_RATE', '8000000') # 8Mbps
|
|||||||
# enable High DPI support
|
# enable High DPI support
|
||||||
conf.set('HIDPI_SUPPORT', get_option('hidpi_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
|
# run a server debugger and wait for a client to be attached
|
||||||
conf.set('SERVER_DEBUGGER', get_option('server_debugger'))
|
conf.set('SERVER_DEBUGGER', get_option('server_debugger'))
|
||||||
|
|
||||||
@ -132,18 +129,11 @@ configure_file(configuration: conf, output: 'config.h')
|
|||||||
|
|
||||||
src_dir = include_directories('src')
|
src_dir = include_directories('src')
|
||||||
|
|
||||||
if get_option('windows_noconsole')
|
|
||||||
link_args = [ '-Wl,--subsystem,windows' ]
|
|
||||||
else
|
|
||||||
link_args = []
|
|
||||||
endif
|
|
||||||
|
|
||||||
executable('scrcpy', src,
|
executable('scrcpy', src,
|
||||||
dependencies: dependencies,
|
dependencies: dependencies,
|
||||||
include_directories: src_dir,
|
include_directories: src_dir,
|
||||||
install: true,
|
install: true,
|
||||||
c_args: [],
|
c_args: [])
|
||||||
link_args: link_args)
|
|
||||||
|
|
||||||
install_man('scrcpy.1')
|
install_man('scrcpy.1')
|
||||||
|
|
||||||
|
@ -12,11 +12,7 @@
|
|||||||
# define PATH_SEPARATOR '\\'
|
# define PATH_SEPARATOR '\\'
|
||||||
# define PRIexitcode "lu"
|
# define PRIexitcode "lu"
|
||||||
// <https://stackoverflow.com/a/44383330/1987178>
|
// <https://stackoverflow.com/a/44383330/1987178>
|
||||||
# ifdef _WIN64
|
# define PRIsizet "Iu"
|
||||||
# define PRIsizet PRIu64
|
|
||||||
# else
|
|
||||||
# define PRIsizet PRIu32
|
|
||||||
# endif
|
|
||||||
# define PROCESS_NONE NULL
|
# define PROCESS_NONE NULL
|
||||||
# define NO_EXIT_CODE -1u // max value as unsigned
|
# define NO_EXIT_CODE -1u // max value as unsigned
|
||||||
typedef HANDLE process_t;
|
typedef HANDLE process_t;
|
||||||
|
@ -98,11 +98,5 @@ main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
avformat_network_deinit(); // ignore failure
|
avformat_network_deinit(); // ignore failure
|
||||||
|
|
||||||
#if defined (__WINDOWS__) && ! defined (WINDOWS_NOCONSOLE)
|
|
||||||
if (res != 0) {
|
|
||||||
fprintf(stderr, "Press Enter to continue...\n");
|
|
||||||
getchar();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "util/net.h"
|
#include "util/net.h"
|
||||||
|
|
||||||
static struct server server = SERVER_INITIALIZER;
|
static struct server server;
|
||||||
static struct screen screen = SCREEN_INITIALIZER;
|
static struct screen screen = SCREEN_INITIALIZER;
|
||||||
static struct fps_counter fps_counter;
|
static struct fps_counter fps_counter;
|
||||||
static struct video_buffer video_buffer;
|
static struct video_buffer video_buffer;
|
||||||
@ -304,6 +304,19 @@ av_log_callback(void *avcl, int level, const char *fmt, va_list vl) {
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
scrcpy(const struct scrcpy_options *options) {
|
scrcpy(const struct scrcpy_options *options) {
|
||||||
|
if (!server_init(&server)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool server_started = false;
|
||||||
|
bool fps_counter_initialized = false;
|
||||||
|
bool video_buffer_initialized = false;
|
||||||
|
bool file_handler_initialized = false;
|
||||||
|
bool recorder_initialized = false;
|
||||||
|
bool stream_started = false;
|
||||||
|
bool controller_initialized = false;
|
||||||
|
bool controller_started = false;
|
||||||
|
|
||||||
bool record = !!options->record_filename;
|
bool record = !!options->record_filename;
|
||||||
struct server_params params = {
|
struct server_params params = {
|
||||||
.log_level = options->log_level,
|
.log_level = options->log_level,
|
||||||
@ -322,18 +335,10 @@ scrcpy(const struct scrcpy_options *options) {
|
|||||||
.force_adb_forward = options->force_adb_forward,
|
.force_adb_forward = options->force_adb_forward,
|
||||||
};
|
};
|
||||||
if (!server_start(&server, options->serial, ¶ms)) {
|
if (!server_start(&server, options->serial, ¶ms)) {
|
||||||
return false;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ret = false;
|
server_started = true;
|
||||||
|
|
||||||
bool fps_counter_initialized = false;
|
|
||||||
bool video_buffer_initialized = false;
|
|
||||||
bool file_handler_initialized = false;
|
|
||||||
bool recorder_initialized = false;
|
|
||||||
bool stream_started = false;
|
|
||||||
bool controller_initialized = false;
|
|
||||||
bool controller_started = false;
|
|
||||||
|
|
||||||
if (!sdl_init_and_configure(options->display, options->render_driver,
|
if (!sdl_init_and_configure(options->display, options->render_driver,
|
||||||
options->disable_screensaver)) {
|
options->disable_screensaver)) {
|
||||||
@ -444,7 +449,7 @@ scrcpy(const struct scrcpy_options *options) {
|
|||||||
|
|
||||||
input_manager_init(&input_manager, options);
|
input_manager_init(&input_manager, options);
|
||||||
|
|
||||||
ret = event_loop(options);
|
bool ret = event_loop(options);
|
||||||
LOGD("quit...");
|
LOGD("quit...");
|
||||||
|
|
||||||
screen_destroy(&screen);
|
screen_destroy(&screen);
|
||||||
@ -465,8 +470,10 @@ end:
|
|||||||
fps_counter_interrupt(&fps_counter);
|
fps_counter_interrupt(&fps_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// shutdown the sockets and kill the server
|
if (server_started) {
|
||||||
server_stop(&server);
|
// shutdown the sockets and kill the server
|
||||||
|
server_stop(&server);
|
||||||
|
}
|
||||||
|
|
||||||
// now that the sockets are shutdown, the stream and controller are
|
// now that the sockets are shutdown, the stream and controller are
|
||||||
// interrupted, we can join them
|
// interrupted, we can join them
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
#include "util/lock.h"
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "util/net.h"
|
#include "util/net.h"
|
||||||
#include "util/str_util.h"
|
#include "util/str_util.h"
|
||||||
@ -353,15 +354,51 @@ close_socket(socket_t socket) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
server_init(struct server *server) {
|
server_init(struct server *server) {
|
||||||
*server = (struct server) SERVER_INITIALIZER;
|
server->serial = NULL;
|
||||||
|
server->process = PROCESS_NONE;
|
||||||
|
server->wait_server_thread = NULL;
|
||||||
|
atomic_flag_clear_explicit(&server->server_socket_closed,
|
||||||
|
memory_order_relaxed);
|
||||||
|
|
||||||
|
server->mutex = SDL_CreateMutex();
|
||||||
|
if (!server->mutex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
server->process_terminated_cond = SDL_CreateCond();
|
||||||
|
if (!server->process_terminated_cond) {
|
||||||
|
SDL_DestroyMutex(server->mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
server->process_terminated = false;
|
||||||
|
|
||||||
|
server->server_socket = INVALID_SOCKET;
|
||||||
|
server->video_socket = INVALID_SOCKET;
|
||||||
|
server->control_socket = INVALID_SOCKET;
|
||||||
|
|
||||||
|
server->port_range.first = 0;
|
||||||
|
server->port_range.last = 0;
|
||||||
|
server->local_port = 0;
|
||||||
|
|
||||||
|
server->tunnel_enabled = false;
|
||||||
|
server->tunnel_forward = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
run_wait_server(void *data) {
|
run_wait_server(void *data) {
|
||||||
struct server *server = data;
|
struct server *server = data;
|
||||||
cmd_simple_wait(server->process, NULL); // ignore exit code
|
cmd_simple_wait(server->process, NULL); // ignore exit code
|
||||||
|
|
||||||
|
mutex_lock(server->mutex);
|
||||||
|
server->process_terminated = true;
|
||||||
|
cond_signal(server->process_terminated_cond);
|
||||||
|
mutex_unlock(server->mutex);
|
||||||
|
|
||||||
// no need for synchronization, server_socket is initialized before this
|
// no need for synchronization, server_socket is initialized before this
|
||||||
// thread was created
|
// thread was created
|
||||||
if (server->server_socket != INVALID_SOCKET
|
if (server->server_socket != INVALID_SOCKET
|
||||||
@ -493,17 +530,39 @@ server_stop(struct server *server) {
|
|||||||
|
|
||||||
assert(server->process != PROCESS_NONE);
|
assert(server->process != PROCESS_NONE);
|
||||||
|
|
||||||
cmd_terminate(server->process);
|
|
||||||
|
|
||||||
if (server->tunnel_enabled) {
|
if (server->tunnel_enabled) {
|
||||||
// ignore failure
|
// ignore failure
|
||||||
disable_tunnel(server);
|
disable_tunnel(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Give some delay for the server to terminate properly
|
||||||
|
mutex_lock(server->mutex);
|
||||||
|
int r = 0;
|
||||||
|
if (!server->process_terminated) {
|
||||||
|
#define WATCHDOG_DELAY_MS 1000
|
||||||
|
r = cond_wait_timeout(server->process_terminated_cond,
|
||||||
|
server->mutex,
|
||||||
|
WATCHDOG_DELAY_MS);
|
||||||
|
}
|
||||||
|
mutex_unlock(server->mutex);
|
||||||
|
|
||||||
|
// After this delay, kill the server if it's not dead already.
|
||||||
|
// On some devices, closing the sockets is not sufficient to wake up the
|
||||||
|
// blocking calls while the device is asleep.
|
||||||
|
if (r == SDL_MUTEX_TIMEDOUT) {
|
||||||
|
// FIXME There is a race condition here: there is a small chance that
|
||||||
|
// the process is already terminated, and the PID assigned to a new
|
||||||
|
// process.
|
||||||
|
LOGW("Killing the server...");
|
||||||
|
cmd_terminate(server->process);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_WaitThread(server->wait_server_thread, NULL);
|
SDL_WaitThread(server->wait_server_thread, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
server_destroy(struct server *server) {
|
server_destroy(struct server *server) {
|
||||||
SDL_free(server->serial);
|
SDL_free(server->serial);
|
||||||
|
SDL_DestroyCond(server->process_terminated_cond);
|
||||||
|
SDL_DestroyMutex(server->mutex);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,11 @@ struct server {
|
|||||||
process_t process;
|
process_t process;
|
||||||
SDL_Thread *wait_server_thread;
|
SDL_Thread *wait_server_thread;
|
||||||
atomic_flag server_socket_closed;
|
atomic_flag server_socket_closed;
|
||||||
|
|
||||||
|
SDL_mutex *mutex;
|
||||||
|
SDL_cond *process_terminated_cond;
|
||||||
|
bool process_terminated;
|
||||||
|
|
||||||
socket_t server_socket; // only used if !tunnel_forward
|
socket_t server_socket; // only used if !tunnel_forward
|
||||||
socket_t video_socket;
|
socket_t video_socket;
|
||||||
socket_t control_socket;
|
socket_t control_socket;
|
||||||
@ -27,23 +32,6 @@ struct server {
|
|||||||
bool tunnel_forward; // use "adb forward" instead of "adb reverse"
|
bool tunnel_forward; // use "adb forward" instead of "adb reverse"
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SERVER_INITIALIZER { \
|
|
||||||
.serial = NULL, \
|
|
||||||
.process = PROCESS_NONE, \
|
|
||||||
.wait_server_thread = NULL, \
|
|
||||||
.server_socket_closed = ATOMIC_FLAG_INIT, \
|
|
||||||
.server_socket = INVALID_SOCKET, \
|
|
||||||
.video_socket = INVALID_SOCKET, \
|
|
||||||
.control_socket = INVALID_SOCKET, \
|
|
||||||
.port_range = { \
|
|
||||||
.first = 0, \
|
|
||||||
.last = 0, \
|
|
||||||
}, \
|
|
||||||
.local_port = 0, \
|
|
||||||
.tunnel_enabled = false, \
|
|
||||||
.tunnel_forward = false, \
|
|
||||||
}
|
|
||||||
|
|
||||||
struct server_params {
|
struct server_params {
|
||||||
enum sc_log_level log_level;
|
enum sc_log_level log_level;
|
||||||
const char *crop;
|
const char *crop;
|
||||||
@ -62,7 +50,7 @@ struct server_params {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// init default values
|
// init default values
|
||||||
void
|
bool
|
||||||
server_init(struct server *server);
|
server_init(struct server *server);
|
||||||
|
|
||||||
// push, enable tunnel et start the server
|
// push, enable tunnel et start the server
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
// modern glibc will complain without this
|
// modern glibc will complain without this
|
||||||
#define _DEFAULT_SOURCE
|
#define _DEFAULT_SOURCE
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
# define _DARWIN_C_SOURCE // for strdup(), strtok_r(), memset_pattern4()
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -17,7 +21,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
@ -39,12 +39,7 @@ cmd_execute(const char *const argv[], HANDLE *handle) {
|
|||||||
return PROCESS_ERROR_GENERIC;
|
return PROCESS_ERROR_GENERIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WINDOWS_NOCONSOLE
|
if (!CreateProcessW(NULL, wide, NULL, NULL, FALSE, 0, NULL, NULL, &si,
|
||||||
int flags = CREATE_NO_WINDOW;
|
|
||||||
#else
|
|
||||||
int flags = 0;
|
|
||||||
#endif
|
|
||||||
if (!CreateProcessW(NULL, wide, NULL, NULL, FALSE, flags, NULL, NULL, &si,
|
|
||||||
&pi)) {
|
&pi)) {
|
||||||
SDL_free(wide);
|
SDL_free(wide);
|
||||||
*handle = NULL;
|
*handle = NULL;
|
||||||
@ -61,7 +56,7 @@ cmd_execute(const char *const argv[], HANDLE *handle) {
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
cmd_terminate(HANDLE handle) {
|
cmd_terminate(HANDLE handle) {
|
||||||
return TerminateProcess(handle, 1) && CloseHandle(handle);
|
return TerminateProcess(handle, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -75,6 +70,7 @@ cmd_simple_wait(HANDLE handle, DWORD *exit_code) {
|
|||||||
if (exit_code) {
|
if (exit_code) {
|
||||||
*exit_code = code;
|
*exit_code = code;
|
||||||
}
|
}
|
||||||
|
CloseHandle(handle);
|
||||||
return !code;
|
return !code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.6.2'
|
classpath 'com.android.tools.build:gradle:4.0.1'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
@ -17,4 +17,4 @@ endian = 'little'
|
|||||||
[properties]
|
[properties]
|
||||||
prebuilt_ffmpeg_shared = 'ffmpeg-4.3.1-win32-shared'
|
prebuilt_ffmpeg_shared = 'ffmpeg-4.3.1-win32-shared'
|
||||||
prebuilt_ffmpeg_dev = 'ffmpeg-4.3.1-win32-dev'
|
prebuilt_ffmpeg_dev = 'ffmpeg-4.3.1-win32-dev'
|
||||||
prebuilt_sdl2 = 'SDL2-2.0.12/i686-w64-mingw32'
|
prebuilt_sdl2 = 'SDL2-2.0.14/i686-w64-mingw32'
|
||||||
|
@ -17,4 +17,4 @@ endian = 'little'
|
|||||||
[properties]
|
[properties]
|
||||||
prebuilt_ffmpeg_shared = 'ffmpeg-4.3.1-win64-shared'
|
prebuilt_ffmpeg_shared = 'ffmpeg-4.3.1-win64-shared'
|
||||||
prebuilt_ffmpeg_dev = 'ffmpeg-4.3.1-win64-dev'
|
prebuilt_ffmpeg_dev = 'ffmpeg-4.3.1-win64-dev'
|
||||||
prebuilt_sdl2 = 'SDL2-2.0.12/x86_64-w64-mingw32'
|
prebuilt_sdl2 = 'SDL2-2.0.14/x86_64-w64-mingw32'
|
||||||
|
4
data/scrcpy-console.bat
Normal file
4
data/scrcpy-console.bat
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@echo off
|
||||||
|
scrcpy.exe %*
|
||||||
|
:: if the exit code is >= 1, then pause
|
||||||
|
if errorlevel 1 pause
|
1
data/scrcpy-noconsole.vbs
Normal file
1
data/scrcpy-noconsole.vbs
Normal file
@ -0,0 +1 @@
|
|||||||
|
CreateObject("Wscript.Shell").Run "cmd /c scrcpy.exe", 0, false
|
@ -1,5 +1,5 @@
|
|||||||
project('scrcpy', 'c',
|
project('scrcpy', 'c',
|
||||||
version: '1.16',
|
version: '1.17',
|
||||||
meson_version: '>= 0.48',
|
meson_version: '>= 0.48',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c11',
|
'c_std=c11',
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
option('compile_app', type: 'boolean', value: true, description: 'Build the client')
|
option('compile_app', type: 'boolean', value: true, description: 'Build the client')
|
||||||
option('compile_server', type: 'boolean', value: true, description: 'Build the server')
|
option('compile_server', type: 'boolean', value: true, description: 'Build the server')
|
||||||
option('crossbuild_windows', type: 'boolean', value: false, description: 'Build for Windows from Linux')
|
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('prebuilt_server', type: 'string', description: 'Path of the prebuilt server')
|
||||||
option('portable', type: 'boolean', value: false, description: 'Use scrcpy-server from the same directory as the scrcpy executable')
|
option('portable', type: 'boolean', value: false, description: 'Use scrcpy-server from the same directory as the scrcpy executable')
|
||||||
option('hidpi_support', type: 'boolean', value: true, description: 'Enable High DPI support')
|
option('hidpi_support', type: 'boolean', value: true, description: 'Enable High DPI support')
|
||||||
|
@ -10,31 +10,31 @@ prepare-win32: prepare-sdl2 prepare-ffmpeg-shared-win32 prepare-ffmpeg-dev-win32
|
|||||||
prepare-win64: prepare-sdl2 prepare-ffmpeg-shared-win64 prepare-ffmpeg-dev-win64 prepare-adb
|
prepare-win64: prepare-sdl2 prepare-ffmpeg-shared-win64 prepare-ffmpeg-dev-win64 prepare-adb
|
||||||
|
|
||||||
prepare-ffmpeg-shared-win32:
|
prepare-ffmpeg-shared-win32:
|
||||||
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win32/shared/ffmpeg-4.3.1-win32-shared.zip \
|
@./prepare-dep https://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win32-shared.zip \
|
||||||
357af9901a456f4dcbacd107e83a934d344c9cb07ddad8aaf80612eeab7d26d2 \
|
357af9901a456f4dcbacd107e83a934d344c9cb07ddad8aaf80612eeab7d26d2 \
|
||||||
ffmpeg-4.3.1-win32-shared
|
ffmpeg-4.3.1-win32-shared
|
||||||
|
|
||||||
prepare-ffmpeg-dev-win32:
|
prepare-ffmpeg-dev-win32:
|
||||||
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win32/dev/ffmpeg-4.3.1-win32-dev.zip \
|
@./prepare-dep https://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win32-dev.zip \
|
||||||
230efb08e9bcf225bd474da29676c70e591fc94d8790a740ca801408fddcb78b \
|
230efb08e9bcf225bd474da29676c70e591fc94d8790a740ca801408fddcb78b \
|
||||||
ffmpeg-4.3.1-win32-dev
|
ffmpeg-4.3.1-win32-dev
|
||||||
|
|
||||||
prepare-ffmpeg-shared-win64:
|
prepare-ffmpeg-shared-win64:
|
||||||
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win64/shared/ffmpeg-4.3.1-win64-shared.zip \
|
@./prepare-dep https://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win64-shared.zip \
|
||||||
dd29b7f92f48dead4dd940492c7509138c0f99db445076d0a597007298a79940 \
|
dd29b7f92f48dead4dd940492c7509138c0f99db445076d0a597007298a79940 \
|
||||||
ffmpeg-4.3.1-win64-shared
|
ffmpeg-4.3.1-win64-shared
|
||||||
|
|
||||||
prepare-ffmpeg-dev-win64:
|
prepare-ffmpeg-dev-win64:
|
||||||
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win64/dev/ffmpeg-4.3.1-win64-dev.zip \
|
@./prepare-dep https://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win64-dev.zip \
|
||||||
2e8038242cf8e1bd095c2978f196ff0462b122cc6ef7e74626a6af15459d8b81 \
|
2e8038242cf8e1bd095c2978f196ff0462b122cc6ef7e74626a6af15459d8b81 \
|
||||||
ffmpeg-4.3.1-win64-dev
|
ffmpeg-4.3.1-win64-dev
|
||||||
|
|
||||||
prepare-sdl2:
|
prepare-sdl2:
|
||||||
@./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.12-mingw.tar.gz \
|
@./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.14-mingw.tar.gz \
|
||||||
e614a60f797e35ef9f3f96aef3dc6a1d786de3cc7ca6216f97e435c0b6aafc46 \
|
405eaff3eb18f2e08fe669ef9e63bc9a8710b7d343756f238619761e9b60407d \
|
||||||
SDL2-2.0.12
|
SDL2-2.0.14
|
||||||
|
|
||||||
prepare-adb:
|
prepare-adb:
|
||||||
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r30.0.4-windows.zip \
|
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r30.0.5-windows.zip \
|
||||||
413182fff6c5957911e231b9e97e6be4fc6a539035e3dfb580b5c54bd5950fee \
|
549ba2bdc31f335eb8a504f005f77606a479cc216d6b64a3e8b64c780003661f \
|
||||||
platform-tools
|
platform-tools
|
||||||
|
@ -9,21 +9,20 @@
|
|||||||
# the server to the device.
|
# the server to the device.
|
||||||
|
|
||||||
.PHONY: default clean \
|
.PHONY: default clean \
|
||||||
|
test \
|
||||||
build-server \
|
build-server \
|
||||||
prepare-deps-win32 prepare-deps-win64 \
|
prepare-deps-win32 prepare-deps-win64 \
|
||||||
build-win32 build-win32-noconsole \
|
build-win32 build-win64 \
|
||||||
build-win64 build-win64-noconsole \
|
|
||||||
dist-win32 dist-win64 \
|
dist-win32 dist-win64 \
|
||||||
zip-win32 zip-win64 \
|
zip-win32 zip-win64 \
|
||||||
sums release
|
release
|
||||||
|
|
||||||
GRADLE ?= ./gradlew
|
GRADLE ?= ./gradlew
|
||||||
|
|
||||||
|
TEST_BUILD_DIR := build-test
|
||||||
SERVER_BUILD_DIR := build-server
|
SERVER_BUILD_DIR := build-server
|
||||||
WIN32_BUILD_DIR := build-win32
|
WIN32_BUILD_DIR := build-win32
|
||||||
WIN32_NOCONSOLE_BUILD_DIR := build-win32-noconsole
|
|
||||||
WIN64_BUILD_DIR := build-win64
|
WIN64_BUILD_DIR := build-win64
|
||||||
WIN64_NOCONSOLE_BUILD_DIR := build-win64-noconsole
|
|
||||||
|
|
||||||
DIST := dist
|
DIST := dist
|
||||||
WIN32_TARGET_DIR := scrcpy-win32
|
WIN32_TARGET_DIR := scrcpy-win32
|
||||||
@ -33,19 +32,35 @@ VERSION := $(shell git describe --tags --always)
|
|||||||
WIN32_TARGET := $(WIN32_TARGET_DIR)-$(VERSION).zip
|
WIN32_TARGET := $(WIN32_TARGET_DIR)-$(VERSION).zip
|
||||||
WIN64_TARGET := $(WIN64_TARGET_DIR)-$(VERSION).zip
|
WIN64_TARGET := $(WIN64_TARGET_DIR)-$(VERSION).zip
|
||||||
|
|
||||||
release: clean zip-win32 zip-win64 sums
|
RELEASE_DIR := release-$(VERSION)
|
||||||
@echo "Windows archives generated in $(DIST)/"
|
|
||||||
|
release: clean test build-server zip-win32 zip-win64
|
||||||
|
mkdir -p "$(RELEASE_DIR)"
|
||||||
|
cp "$(SERVER_BUILD_DIR)/server/scrcpy-server" \
|
||||||
|
"$(RELEASE_DIR)/scrcpy-server-$(VERSION)"
|
||||||
|
cp "$(DIST)/$(WIN32_TARGET)" "$(RELEASE_DIR)"
|
||||||
|
cp "$(DIST)/$(WIN64_TARGET)" "$(RELEASE_DIR)"
|
||||||
|
cd "$(RELEASE_DIR)" && \
|
||||||
|
sha256sum "scrcpy-server-$(VERSION)" \
|
||||||
|
"scrcpy-win32-$(VERSION).zip" \
|
||||||
|
"scrcpy-win64-$(VERSION).zip" > SHA256SUMS.txt
|
||||||
|
@echo "Release generated in $(RELEASE_DIR)/"
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(GRADLE) clean
|
$(GRADLE) clean
|
||||||
rm -rf "$(SERVER_BUILD_DIR)" "$(WIN32_BUILD_DIR)" "$(WIN64_BUILD_DIR)" \
|
rm -rf "$(DIST)" "$(TEST_BUILD_DIR)" "$(SERVER_BUILD_DIR)" \
|
||||||
"$(WIN32_NOCONSOLE_BUILD_DIR)" "$(WIN64_NOCONSOLE_BUILD_DIR)" "$(DIST)"
|
"$(WIN32_BUILD_DIR)" "$(WIN64_BUILD_DIR)"
|
||||||
|
|
||||||
|
test:
|
||||||
|
[ -d "$(TEST_BUILD_DIR)" ] || ( mkdir "$(TEST_BUILD_DIR)" && \
|
||||||
|
meson "$(TEST_BUILD_DIR)" -Db_sanitize=address )
|
||||||
|
ninja -C "$(TEST_BUILD_DIR)"
|
||||||
|
$(GRADLE) -p server check
|
||||||
|
|
||||||
build-server:
|
build-server:
|
||||||
[ -d "$(SERVER_BUILD_DIR)" ] || ( mkdir "$(SERVER_BUILD_DIR)" && \
|
[ -d "$(SERVER_BUILD_DIR)" ] || ( mkdir "$(SERVER_BUILD_DIR)" && \
|
||||||
meson "$(SERVER_BUILD_DIR)" \
|
meson "$(SERVER_BUILD_DIR)" --buildtype release -Dcompile_app=false )
|
||||||
--buildtype release -Dcompile_app=false )
|
ninja -C "$(SERVER_BUILD_DIR)"
|
||||||
ninja -C "$(SERVER_BUILD_DIR)"
|
|
||||||
|
|
||||||
prepare-deps-win32:
|
prepare-deps-win32:
|
||||||
-$(MAKE) -C prebuilt-deps prepare-win32
|
-$(MAKE) -C prebuilt-deps prepare-win32
|
||||||
@ -60,17 +75,6 @@ build-win32: prepare-deps-win32
|
|||||||
-Dportable=true )
|
-Dportable=true )
|
||||||
ninja -C "$(WIN32_BUILD_DIR)"
|
ninja -C "$(WIN32_BUILD_DIR)"
|
||||||
|
|
||||||
build-win32-noconsole: prepare-deps-win32
|
|
||||||
[ -d "$(WIN32_NOCONSOLE_BUILD_DIR)" ] || ( mkdir "$(WIN32_NOCONSOLE_BUILD_DIR)" && \
|
|
||||||
meson "$(WIN32_NOCONSOLE_BUILD_DIR)" \
|
|
||||||
--cross-file cross_win32.txt \
|
|
||||||
--buildtype release --strip -Db_lto=true \
|
|
||||||
-Dcrossbuild_windows=true \
|
|
||||||
-Dcompile_server=false \
|
|
||||||
-Dwindows_noconsole=true \
|
|
||||||
-Dportable=true )
|
|
||||||
ninja -C "$(WIN32_NOCONSOLE_BUILD_DIR)"
|
|
||||||
|
|
||||||
prepare-deps-win64:
|
prepare-deps-win64:
|
||||||
-$(MAKE) -C prebuilt-deps prepare-win64
|
-$(MAKE) -C prebuilt-deps prepare-win64
|
||||||
|
|
||||||
@ -84,22 +88,12 @@ build-win64: prepare-deps-win64
|
|||||||
-Dportable=true )
|
-Dportable=true )
|
||||||
ninja -C "$(WIN64_BUILD_DIR)"
|
ninja -C "$(WIN64_BUILD_DIR)"
|
||||||
|
|
||||||
build-win64-noconsole: prepare-deps-win64
|
dist-win32: build-server build-win32
|
||||||
[ -d "$(WIN64_NOCONSOLE_BUILD_DIR)" ] || ( mkdir "$(WIN64_NOCONSOLE_BUILD_DIR)" && \
|
|
||||||
meson "$(WIN64_NOCONSOLE_BUILD_DIR)" \
|
|
||||||
--cross-file cross_win64.txt \
|
|
||||||
--buildtype release --strip -Db_lto=true \
|
|
||||||
-Dcrossbuild_windows=true \
|
|
||||||
-Dcompile_server=false \
|
|
||||||
-Dwindows_noconsole=true \
|
|
||||||
-Dportable=true )
|
|
||||||
ninja -C "$(WIN64_NOCONSOLE_BUILD_DIR)"
|
|
||||||
|
|
||||||
dist-win32: build-server build-win32 build-win32-noconsole
|
|
||||||
mkdir -p "$(DIST)/$(WIN32_TARGET_DIR)"
|
mkdir -p "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||||
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server "$(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_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 data/scrcpy-console.bat "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||||
|
cp data/scrcpy-noconsole.vbs "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win32-shared/bin/avutil-56.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.3.1-win32-shared/bin/avutil-56.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win32-shared/bin/avcodec-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.3.1-win32-shared/bin/avcodec-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win32-shared/bin/avformat-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.3.1-win32-shared/bin/avformat-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
@ -108,13 +102,14 @@ dist-win32: build-server build-win32 build-win32-noconsole
|
|||||||
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/SDL2-2.0.12/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/SDL2-2.0.14/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
|
|
||||||
dist-win64: build-server build-win64 build-win64-noconsole
|
dist-win64: build-server build-win64
|
||||||
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
|
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||||
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server "$(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_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 data/scrcpy-console.bat "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||||
|
cp data/scrcpy-noconsole.vbs "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win64-shared/bin/avutil-56.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.3.1-win64-shared/bin/avutil-56.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win64-shared/bin/avcodec-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.3.1-win64-shared/bin/avcodec-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win64-shared/bin/avformat-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.3.1-win64-shared/bin/avformat-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
@ -123,7 +118,7 @@ dist-win64: build-server build-win64 build-win64-noconsole
|
|||||||
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/SDL2-2.0.12/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/SDL2-2.0.14/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
|
|
||||||
zip-win32: dist-win32
|
zip-win32: dist-win32
|
||||||
cd "$(DIST)/$(WIN32_TARGET_DIR)"; \
|
cd "$(DIST)/$(WIN32_TARGET_DIR)"; \
|
||||||
@ -132,7 +127,3 @@ zip-win32: dist-win32
|
|||||||
zip-win64: dist-win64
|
zip-win64: dist-win64
|
||||||
cd "$(DIST)/$(WIN64_TARGET_DIR)"; \
|
cd "$(DIST)/$(WIN64_TARGET_DIR)"; \
|
||||||
zip -r "../$(WIN64_TARGET)" .
|
zip -r "../$(WIN64_TARGET)" .
|
||||||
|
|
||||||
sums:
|
|
||||||
cd "$(DIST)"; \
|
|
||||||
sha256sum *.zip > SHA256SUMS.txt
|
|
44
release.sh
44
release.sh
@ -1,44 +1,2 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
make -f release.mk
|
||||||
|
|
||||||
# test locally
|
|
||||||
TESTDIR=build_test
|
|
||||||
rm -rf "$TESTDIR"
|
|
||||||
# run client tests with ASAN enabled
|
|
||||||
meson "$TESTDIR" -Db_sanitize=address
|
|
||||||
ninja -C"$TESTDIR" test
|
|
||||||
|
|
||||||
# test server
|
|
||||||
GRADLE=${GRADLE:-./gradlew}
|
|
||||||
$GRADLE -p server check
|
|
||||||
|
|
||||||
BUILDDIR=build_release
|
|
||||||
rm -rf "$BUILDDIR"
|
|
||||||
meson "$BUILDDIR" --buildtype release --strip -Db_lto=true
|
|
||||||
cd "$BUILDDIR"
|
|
||||||
ninja
|
|
||||||
cd -
|
|
||||||
|
|
||||||
# build Windows releases
|
|
||||||
make -f Makefile.CrossWindows
|
|
||||||
|
|
||||||
# the generated server must be the same everywhere
|
|
||||||
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" "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" \
|
|
||||||
"scrcpy-win32-$TAG.zip" \
|
|
||||||
"scrcpy-win64-$TAG.zip" > SHA256SUMS.txt
|
|
||||||
|
|
||||||
echo "Release generated in release-$TAG/"
|
|
||||||
|
@ -6,8 +6,8 @@ android {
|
|||||||
applicationId "com.genymobile.scrcpy"
|
applicationId "com.genymobile.scrcpy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 19
|
versionCode 20
|
||||||
versionName "1.16"
|
versionName "1.17"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@ -20,7 +20,7 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.13'
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$project.rootDir/config/android-checkstyle.gradle"
|
apply from: "$project.rootDir/config/android-checkstyle.gradle"
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
SCRCPY_DEBUG=false
|
SCRCPY_DEBUG=false
|
||||||
SCRCPY_VERSION_NAME=1.16
|
SCRCPY_VERSION_NAME=1.17
|
||||||
|
|
||||||
PLATFORM=${ANDROID_PLATFORM:-30}
|
PLATFORM=${ANDROID_PLATFORM:-30}
|
||||||
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-30.0.0}
|
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-30.0.0}
|
||||||
|
@ -58,12 +58,14 @@ public final class Server {
|
|||||||
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions,
|
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions,
|
||||||
options.getEncoderName());
|
options.getEncoderName());
|
||||||
|
|
||||||
|
Thread controllerThread = null;
|
||||||
|
Thread deviceMessageSenderThread = null;
|
||||||
if (options.getControl()) {
|
if (options.getControl()) {
|
||||||
final Controller controller = new Controller(device, connection);
|
final Controller controller = new Controller(device, connection);
|
||||||
|
|
||||||
// asynchronous
|
// asynchronous
|
||||||
startController(controller);
|
controllerThread = startController(controller);
|
||||||
startDeviceMessageSender(controller.getSender());
|
deviceMessageSenderThread = startDeviceMessageSender(controller.getSender());
|
||||||
|
|
||||||
device.setClipboardListener(new Device.ClipboardListener() {
|
device.setClipboardListener(new Device.ClipboardListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -79,12 +81,19 @@ public final class Server {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// this is expected on close
|
// this is expected on close
|
||||||
Ln.d("Screen streaming stopped");
|
Ln.d("Screen streaming stopped");
|
||||||
|
} finally {
|
||||||
|
if (controllerThread != null) {
|
||||||
|
controllerThread.interrupt();
|
||||||
|
}
|
||||||
|
if (deviceMessageSenderThread != null) {
|
||||||
|
deviceMessageSenderThread.interrupt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void startController(final Controller controller) {
|
private static Thread startController(final Controller controller) {
|
||||||
new Thread(new Runnable() {
|
Thread thread = new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@ -94,11 +103,13 @@ public final class Server {
|
|||||||
Ln.d("Controller stopped");
|
Ln.d("Controller stopped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
});
|
||||||
|
thread.start();
|
||||||
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void startDeviceMessageSender(final DeviceMessageSender sender) {
|
private static Thread startDeviceMessageSender(final DeviceMessageSender sender) {
|
||||||
new Thread(new Runnable() {
|
Thread thread = new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@ -108,7 +119,9 @@ public final class Server {
|
|||||||
Ln.d("Device message sender stopped");
|
Ln.d("Device message sender stopped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
});
|
||||||
|
thread.start();
|
||||||
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Options createOptions(String... args) {
|
private static Options createOptions(String... args) {
|
||||||
|
Reference in New Issue
Block a user