Compare commits
1 Commits
doc-rotate
...
legacy_pas
Author | SHA1 | Date | |
---|---|---|---|
206abdb2c5 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,4 +6,3 @@ build/
|
|||||||
.idea/
|
.idea/
|
||||||
.gradle/
|
.gradle/
|
||||||
/x/
|
/x/
|
||||||
local.properties
|
|
||||||
|
@ -3,16 +3,16 @@
|
|||||||
다음은 자주 제보되는 문제들과 그들의 현황입니다.
|
다음은 자주 제보되는 문제들과 그들의 현황입니다.
|
||||||
|
|
||||||
|
|
||||||
### Windows 운영체제에서, 디바이스가 발견되지 않습니다.
|
### Window 운영체제에서, 디바이스가 발견되지 않습니다.
|
||||||
|
|
||||||
가장 흔한 제보는 `adb`에 발견되지 않는 디바이스 혹은 권한 관련 문제입니다.
|
가장 흔한 제보는 `adb`에 발견되지 않는 디바이스 혹은 권한 관련 문제입니다.
|
||||||
다음 명령어를 호출하여 모든 것들에 이상이 없는지 확인하세요:
|
다음 명령어를 호출하여 모든 것들에 이상이 없는지 확인하세요:
|
||||||
|
|
||||||
adb devices
|
adb devices
|
||||||
|
|
||||||
Windows는 당신의 디바이스를 감지하기 위해 [드라이버]가 필요할 수도 있습니다.
|
Window는 당신의 디바이스를 감지하기 위해 [drivers]가 필요할 수도 있습니다.
|
||||||
|
|
||||||
[드라이버]: https://developer.android.com/studio/run/oem-usb.html
|
[drivers]: https://developer.android.com/studio/run/oem-usb.html
|
||||||
|
|
||||||
|
|
||||||
### 내 디바이스의 미러링만 가능하고, 디바이스와 상호작용을 할 수 없습니다.
|
### 내 디바이스의 미러링만 가능하고, 디바이스와 상호작용을 할 수 없습니다.
|
||||||
|
2
FAQ.md
2
FAQ.md
@ -199,5 +199,3 @@ scrcpy -m 1920
|
|||||||
scrcpy -m 1024
|
scrcpy -m 1024
|
||||||
scrcpy -m 800
|
scrcpy -m 800
|
||||||
```
|
```
|
||||||
|
|
||||||
You could also try another [encoder](README.md#encoder).
|
|
||||||
|
@ -100,7 +100,6 @@ dist-win32: build-server build-win32 build-win32-noconsole
|
|||||||
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 "$(WIN32_NOCONSOLE_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN32_TARGET_DIR)/scrcpy-noconsole.exe"
|
||||||
cp data/scrcpy-console.bat "$(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)/"
|
||||||
@ -116,7 +115,6 @@ dist-win64: build-server build-win64 build-win64-noconsole
|
|||||||
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 "$(WIN64_NOCONSOLE_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN64_TARGET_DIR)/scrcpy-noconsole.exe"
|
||||||
cp data/scrcpy-console.bat "$(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)/"
|
||||||
|
699
README.id.md
699
README.id.md
@ -1,699 +0,0 @@
|
|||||||
_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-2020 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/
|
|
||||||
|
|
57
README.md
57
README.md
@ -202,24 +202,6 @@ scrcpy --lock-video-orientation 3 # 90° clockwise
|
|||||||
|
|
||||||
This affects recording orientation.
|
This affects recording orientation.
|
||||||
|
|
||||||
The [window may also be rotated](#rotation) independently.
|
|
||||||
|
|
||||||
|
|
||||||
#### Encoder
|
|
||||||
|
|
||||||
Some devices have more than one encoder, and some of them may cause issues or
|
|
||||||
crash. It is possible to select a different encoder:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --encoder OMX.qcom.video.encoder.avc
|
|
||||||
```
|
|
||||||
|
|
||||||
To list the available encoders, you could pass an invalid encoder name, the
|
|
||||||
error will give the available encoders:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --encoder _
|
|
||||||
```
|
|
||||||
|
|
||||||
### Recording
|
### Recording
|
||||||
|
|
||||||
@ -253,13 +235,7 @@ _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, or by
|
2. Get your device IP address (in Settings → About phone → Status).
|
||||||
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`)_.
|
||||||
@ -406,12 +382,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
|
- <kbd>MOD</kbd>+<kbd>r</kbd> requests the device to switch between portrait and
|
||||||
and landscape (the current running app may refuse, if it does support the
|
landscape (the current running app may refuse, if it does support the
|
||||||
requested orientation).
|
requested orientation).
|
||||||
- [`--lock-video-orientation`](#lock-video-orientation) changes the mirroring
|
- `--lock-video-orientation` changes the mirroring orientation (the orientation
|
||||||
orientation (the orientation of the video sent from the device to the
|
of the video sent from the device to the computer). This affects the
|
||||||
computer). This affects the recording.
|
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.
|
||||||
@ -574,9 +550,8 @@ way.
|
|||||||
|
|
||||||
Some devices do not behave as expected when setting the device clipboard
|
Some devices do not behave as expected when setting the device clipboard
|
||||||
programmatically. An option `--legacy-paste` is provided to change the behavior
|
programmatically. An option `--legacy-paste` is provided to change the behavior
|
||||||
of <kbd>Ctrl</kbd>+<kbd>v</kbd> and <kbd>MOD</kbd>+<kbd>v</kbd> so that they
|
of <kbd>Ctrl</kbd>+<kbd>v</kbd> and <kbd>MOD</kbd>+<kbd>v</kbd> to also inject
|
||||||
also inject the computer clipboard text as a sequence of key events (the same
|
the computer clipboard text as a sequence of key events.
|
||||||
way as <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>).
|
|
||||||
|
|
||||||
#### Pinch-to-zoom
|
#### Pinch-to-zoom
|
||||||
|
|
||||||
@ -624,16 +599,6 @@ scrcpy --no-key-repeat
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#### Right-click and middle-click
|
|
||||||
|
|
||||||
By default, right-click triggers BACK (or POWER on) and middle-click triggers
|
|
||||||
HOME. To disable these shortcuts and forward the clicks to the device instead:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --forward-all-clicks
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### File drop
|
### File drop
|
||||||
|
|
||||||
#### Install APK
|
#### Install APK
|
||||||
@ -794,10 +759,8 @@ Read the [developers page].
|
|||||||
|
|
||||||
This README is available in other languages:
|
This README is available in other languages:
|
||||||
|
|
||||||
- [Indonesian (Indonesia, `id`) - v1.16](README.id.md)
|
- [繁體中文 (Traditional Chinese, `zh-Hant`) - v1.15](README.zh-Hant.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.
|
||||||
|
@ -1,726 +0,0 @@
|
|||||||
_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-2020 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/
|
|
@ -56,18 +56,10 @@ The list of possible display ids can be listed by "adb shell dumpsys display"
|
|||||||
|
|
||||||
Default is 0.
|
Default is 0.
|
||||||
|
|
||||||
.TP
|
|
||||||
.BI "\-\-encoder " name
|
|
||||||
Use a specific MediaCodec encoder (must be a H.264 encoder).
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B \-\-force\-adb\-forward
|
.B \-\-force\-adb\-forward
|
||||||
Do not attempt to use "adb reverse" to connect to the device.
|
Do not attempt to use "adb reverse" to connect to the device.
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-\-forward\-all\-clicks
|
|
||||||
By default, right-click triggers BACK (or POWER on) and middle-click triggers HOME. This option disables these shortcuts and forward the clicks to the device instead.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B \-f, \-\-fullscreen
|
.B \-f, \-\-fullscreen
|
||||||
Start in fullscreen.
|
Start in fullscreen.
|
||||||
|
@ -53,18 +53,10 @@ scrcpy_print_usage(const char *arg0) {
|
|||||||
"\n"
|
"\n"
|
||||||
" Default is 0.\n"
|
" Default is 0.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" --encoder name\n"
|
|
||||||
" Use a specific MediaCodec encoder (must be a H.264 encoder).\n"
|
|
||||||
"\n"
|
|
||||||
" --force-adb-forward\n"
|
" --force-adb-forward\n"
|
||||||
" Do not attempt to use \"adb reverse\" to connect to the\n"
|
" Do not attempt to use \"adb reverse\" to connect to the\n"
|
||||||
" the device.\n"
|
" the device.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" --forward-all-clicks\n"
|
|
||||||
" By default, right-click triggers BACK (or POWER on) and\n"
|
|
||||||
" middle-click triggers HOME. This option disables these\n"
|
|
||||||
" shortcuts and forward the clicks to the device instead.\n"
|
|
||||||
"\n"
|
|
||||||
" -f, --fullscreen\n"
|
" -f, --fullscreen\n"
|
||||||
" Start in fullscreen.\n"
|
" Start in fullscreen.\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -665,9 +657,7 @@ guess_record_format(const char *filename) {
|
|||||||
#define OPT_DISABLE_SCREENSAVER 1020
|
#define OPT_DISABLE_SCREENSAVER 1020
|
||||||
#define OPT_SHORTCUT_MOD 1021
|
#define OPT_SHORTCUT_MOD 1021
|
||||||
#define OPT_NO_KEY_REPEAT 1022
|
#define OPT_NO_KEY_REPEAT 1022
|
||||||
#define OPT_FORWARD_ALL_CLICKS 1023
|
#define OPT_LEGACY_PASTE 1023
|
||||||
#define OPT_LEGACY_PASTE 1024
|
|
||||||
#define OPT_ENCODER_NAME 1025
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
||||||
@ -679,11 +669,8 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||||||
{"disable-screensaver", no_argument, NULL,
|
{"disable-screensaver", no_argument, NULL,
|
||||||
OPT_DISABLE_SCREENSAVER},
|
OPT_DISABLE_SCREENSAVER},
|
||||||
{"display", required_argument, NULL, OPT_DISPLAY_ID},
|
{"display", required_argument, NULL, OPT_DISPLAY_ID},
|
||||||
{"encoder", required_argument, NULL, OPT_ENCODER_NAME},
|
|
||||||
{"force-adb-forward", no_argument, NULL,
|
{"force-adb-forward", no_argument, NULL,
|
||||||
OPT_FORCE_ADB_FORWARD},
|
OPT_FORCE_ADB_FORWARD},
|
||||||
{"forward-all-clicks", no_argument, NULL,
|
|
||||||
OPT_FORWARD_ALL_CLICKS},
|
|
||||||
{"fullscreen", no_argument, NULL, 'f'},
|
{"fullscreen", no_argument, NULL, 'f'},
|
||||||
{"help", no_argument, NULL, 'h'},
|
{"help", no_argument, NULL, 'h'},
|
||||||
{"legacy-paste", no_argument, NULL, OPT_LEGACY_PASTE},
|
{"legacy-paste", no_argument, NULL, OPT_LEGACY_PASTE},
|
||||||
@ -866,9 +853,6 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||||||
case OPT_CODEC_OPTIONS:
|
case OPT_CODEC_OPTIONS:
|
||||||
opts->codec_options = optarg;
|
opts->codec_options = optarg;
|
||||||
break;
|
break;
|
||||||
case OPT_ENCODER_NAME:
|
|
||||||
opts->encoder_name = optarg;
|
|
||||||
break;
|
|
||||||
case OPT_FORCE_ADB_FORWARD:
|
case OPT_FORCE_ADB_FORWARD:
|
||||||
opts->force_adb_forward = true;
|
opts->force_adb_forward = true;
|
||||||
break;
|
break;
|
||||||
@ -880,9 +864,6 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_FORWARD_ALL_CLICKS:
|
|
||||||
opts->forward_all_clicks = true;
|
|
||||||
break;
|
|
||||||
case OPT_LEGACY_PASTE:
|
case OPT_LEGACY_PASTE:
|
||||||
opts->legacy_paste = true;
|
opts->legacy_paste = true;
|
||||||
break;
|
break;
|
||||||
|
@ -12,7 +12,11 @@
|
|||||||
# define PATH_SEPARATOR '\\'
|
# define PATH_SEPARATOR '\\'
|
||||||
# define PRIexitcode "lu"
|
# define PRIexitcode "lu"
|
||||||
// <https://stackoverflow.com/a/44383330/1987178>
|
// <https://stackoverflow.com/a/44383330/1987178>
|
||||||
# define PRIsizet "Iu"
|
# ifdef _WIN64
|
||||||
|
# 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;
|
||||||
|
@ -60,7 +60,6 @@ input_manager_init(struct input_manager *im,
|
|||||||
im->control = options->control;
|
im->control = options->control;
|
||||||
im->forward_key_repeat = options->forward_key_repeat;
|
im->forward_key_repeat = options->forward_key_repeat;
|
||||||
im->prefer_text = options->prefer_text;
|
im->prefer_text = options->prefer_text;
|
||||||
im->forward_all_clicks = options->forward_all_clicks;
|
|
||||||
im->legacy_paste = options->legacy_paste;
|
im->legacy_paste = options->legacy_paste;
|
||||||
|
|
||||||
const struct sc_shortcut_mods *shortcut_mods = &options->shortcut_mods;
|
const struct sc_shortcut_mods *shortcut_mods = &options->shortcut_mods;
|
||||||
@ -636,7 +635,7 @@ input_manager_process_mouse_button(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool down = event->type == SDL_MOUSEBUTTONDOWN;
|
bool down = event->type == SDL_MOUSEBUTTONDOWN;
|
||||||
if (!im->forward_all_clicks && down) {
|
if (down) {
|
||||||
if (control && event->button == SDL_BUTTON_RIGHT) {
|
if (control && event->button == SDL_BUTTON_RIGHT) {
|
||||||
press_back_or_turn_screen_on(im->controller);
|
press_back_or_turn_screen_on(im->controller);
|
||||||
return;
|
return;
|
||||||
|
@ -25,7 +25,6 @@ struct input_manager {
|
|||||||
bool control;
|
bool control;
|
||||||
bool forward_key_repeat;
|
bool forward_key_repeat;
|
||||||
bool prefer_text;
|
bool prefer_text;
|
||||||
bool forward_all_clicks;
|
|
||||||
bool legacy_paste;
|
bool legacy_paste;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -98,5 +98,11 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,6 @@ scrcpy(const struct scrcpy_options *options) {
|
|||||||
.show_touches = options->show_touches,
|
.show_touches = options->show_touches,
|
||||||
.stay_awake = options->stay_awake,
|
.stay_awake = options->stay_awake,
|
||||||
.codec_options = options->codec_options,
|
.codec_options = options->codec_options,
|
||||||
.encoder_name = options->encoder_name,
|
|
||||||
.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)) {
|
||||||
@ -423,7 +422,7 @@ scrcpy(const struct scrcpy_options *options) {
|
|||||||
options->window_y, options->window_width,
|
options->window_y, options->window_width,
|
||||||
options->window_height,
|
options->window_height,
|
||||||
options->window_borderless,
|
options->window_borderless,
|
||||||
options->rotation, options->mipmaps)) {
|
options->rotation, options-> mipmaps)) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,6 @@ struct scrcpy_options {
|
|||||||
const char *push_target;
|
const char *push_target;
|
||||||
const char *render_driver;
|
const char *render_driver;
|
||||||
const char *codec_options;
|
const char *codec_options;
|
||||||
const char *encoder_name;
|
|
||||||
enum sc_log_level log_level;
|
enum sc_log_level log_level;
|
||||||
enum sc_record_format record_format;
|
enum sc_record_format record_format;
|
||||||
struct sc_port_range port_range;
|
struct sc_port_range port_range;
|
||||||
@ -80,7 +79,6 @@ struct scrcpy_options {
|
|||||||
bool force_adb_forward;
|
bool force_adb_forward;
|
||||||
bool disable_screensaver;
|
bool disable_screensaver;
|
||||||
bool forward_key_repeat;
|
bool forward_key_repeat;
|
||||||
bool forward_all_clicks;
|
|
||||||
bool legacy_paste;
|
bool legacy_paste;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -92,7 +90,6 @@ struct scrcpy_options {
|
|||||||
.push_target = NULL, \
|
.push_target = NULL, \
|
||||||
.render_driver = NULL, \
|
.render_driver = NULL, \
|
||||||
.codec_options = NULL, \
|
.codec_options = NULL, \
|
||||||
.encoder_name = NULL, \
|
|
||||||
.log_level = SC_LOG_LEVEL_INFO, \
|
.log_level = SC_LOG_LEVEL_INFO, \
|
||||||
.record_format = SC_RECORD_FORMAT_AUTO, \
|
.record_format = SC_RECORD_FORMAT_AUTO, \
|
||||||
.port_range = { \
|
.port_range = { \
|
||||||
@ -127,7 +124,6 @@ struct scrcpy_options {
|
|||||||
.force_adb_forward = false, \
|
.force_adb_forward = false, \
|
||||||
.disable_screensaver = false, \
|
.disable_screensaver = false, \
|
||||||
.forward_key_repeat = true, \
|
.forward_key_repeat = true, \
|
||||||
.forward_all_clicks = false, \
|
|
||||||
.legacy_paste = false, \
|
.legacy_paste = false, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +294,6 @@ execute_server(struct server *server, const struct server_params *params) {
|
|||||||
params->show_touches ? "true" : "false",
|
params->show_touches ? "true" : "false",
|
||||||
params->stay_awake ? "true" : "false",
|
params->stay_awake ? "true" : "false",
|
||||||
params->codec_options ? params->codec_options : "-",
|
params->codec_options ? params->codec_options : "-",
|
||||||
params->encoder_name ? params->encoder_name : "-",
|
|
||||||
};
|
};
|
||||||
#ifdef SERVER_DEBUGGER
|
#ifdef SERVER_DEBUGGER
|
||||||
LOGI("Server debugger waiting for a client on device port "
|
LOGI("Server debugger waiting for a client on device port "
|
||||||
|
@ -48,7 +48,6 @@ struct server_params {
|
|||||||
enum sc_log_level log_level;
|
enum sc_log_level log_level;
|
||||||
const char *crop;
|
const char *crop;
|
||||||
const char *codec_options;
|
const char *codec_options;
|
||||||
const char *encoder_name;
|
|
||||||
struct sc_port_range port_range;
|
struct sc_port_range port_range;
|
||||||
uint16_t max_size;
|
uint16_t max_size;
|
||||||
uint32_t bit_rate;
|
uint32_t bit_rate;
|
||||||
|
@ -5,10 +5,6 @@
|
|||||||
// 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"
|
||||||
|
@ -7,7 +7,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
classpath 'com.android.tools.build:gradle:3.6.2'
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
@echo off
|
|
||||||
scrcpy.exe %*
|
|
||||||
:: if the exit code is >= 1, then pause
|
|
||||||
if errorlevel 1 pause
|
|
@ -10,22 +10,22 @@ 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://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win32-shared.zip \
|
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win32/shared/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://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win32-dev.zip \
|
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win32/dev/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://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win64-shared.zip \
|
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win64/shared/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://github.com/Genymobile/scrcpy/releases/download/v1.16/ffmpeg-4.3.1-win64-dev.zip \
|
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win64/dev/ffmpeg-4.3.1-win64-dev.zip \
|
||||||
2e8038242cf8e1bd095c2978f196ff0462b122cc6ef7e74626a6af15459d8b81 \
|
2e8038242cf8e1bd095c2978f196ff0462b122cc6ef7e74626a6af15459d8b81 \
|
||||||
ffmpeg-4.3.1-win64-dev
|
ffmpeg-4.3.1-win64-dev
|
||||||
|
|
||||||
@ -35,6 +35,6 @@ prepare-sdl2:
|
|||||||
SDL2-2.0.12
|
SDL2-2.0.12
|
||||||
|
|
||||||
prepare-adb:
|
prepare-adb:
|
||||||
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r30.0.5-windows.zip \
|
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r30.0.4-windows.zip \
|
||||||
549ba2bdc31f335eb8a504f005f77606a479cc216d6b64a3e8b64c780003661f \
|
413182fff6c5957911e231b9e97e6be4fc6a539035e3dfb580b5c54bd5950fee \
|
||||||
platform-tools
|
platform-tools
|
||||||
|
@ -20,7 +20,7 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
testImplementation 'junit:junit:4.13'
|
testImplementation 'junit:junit:4.12'
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$project.rootDir/config/android-checkstyle.gradle"
|
apply from: "$project.rootDir/config/android-checkstyle.gradle"
|
||||||
|
@ -205,13 +205,9 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right-click and middle-click only work if the source is a mouse
|
|
||||||
boolean nonPrimaryButtonPressed = (buttons & ~MotionEvent.BUTTON_PRIMARY) != 0;
|
|
||||||
int source = nonPrimaryButtonPressed ? InputDevice.SOURCE_MOUSE : InputDevice.SOURCE_TOUCHSCREEN;
|
|
||||||
|
|
||||||
MotionEvent event = MotionEvent
|
MotionEvent event = MotionEvent
|
||||||
.obtain(lastTouchDown, now, action, pointerCount, pointerProperties, pointerCoords, 0, buttons, 1f, 1f, DEVICE_ID_VIRTUAL, 0, source,
|
.obtain(lastTouchDown, now, action, pointerCount, pointerProperties, pointerCoords, 0, buttons, 1f, 1f, DEVICE_ID_VIRTUAL, 0,
|
||||||
0);
|
InputDevice.SOURCE_TOUCHSCREEN, 0);
|
||||||
return device.injectEvent(event);
|
return device.injectEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
package com.genymobile.scrcpy;
|
|
||||||
|
|
||||||
import android.media.MediaCodecInfo;
|
|
||||||
|
|
||||||
public class InvalidEncoderException extends RuntimeException {
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
private final MediaCodecInfo[] availableEncoders;
|
|
||||||
|
|
||||||
public InvalidEncoderException(String name, MediaCodecInfo[] availableEncoders) {
|
|
||||||
super("There is no encoder having name '" + name + '"');
|
|
||||||
this.name = name;
|
|
||||||
this.availableEncoders = availableEncoders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MediaCodecInfo[] getAvailableEncoders() {
|
|
||||||
return availableEncoders;
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,7 +16,6 @@ public class Options {
|
|||||||
private boolean showTouches;
|
private boolean showTouches;
|
||||||
private boolean stayAwake;
|
private boolean stayAwake;
|
||||||
private String codecOptions;
|
private String codecOptions;
|
||||||
private String encoderName;
|
|
||||||
|
|
||||||
public Ln.Level getLogLevel() {
|
public Ln.Level getLogLevel() {
|
||||||
return logLevel;
|
return logLevel;
|
||||||
@ -121,12 +120,4 @@ public class Options {
|
|||||||
public void setCodecOptions(String codecOptions) {
|
public void setCodecOptions(String codecOptions) {
|
||||||
this.codecOptions = codecOptions;
|
this.codecOptions = codecOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEncoderName() {
|
|
||||||
return encoderName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEncoderName(String encoderName) {
|
|
||||||
this.encoderName = encoderName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import com.genymobile.scrcpy.wrappers.SurfaceControl;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
import android.media.MediaCodecInfo;
|
import android.media.MediaCodecInfo;
|
||||||
import android.media.MediaCodecList;
|
|
||||||
import android.media.MediaFormat;
|
import android.media.MediaFormat;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
@ -13,8 +12,6 @@ import android.view.Surface;
|
|||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
@ -29,19 +26,17 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||||||
private final AtomicBoolean rotationChanged = new AtomicBoolean();
|
private final AtomicBoolean rotationChanged = new AtomicBoolean();
|
||||||
private final ByteBuffer headerBuffer = ByteBuffer.allocate(12);
|
private final ByteBuffer headerBuffer = ByteBuffer.allocate(12);
|
||||||
|
|
||||||
private String encoderName;
|
|
||||||
private List<CodecOption> codecOptions;
|
private List<CodecOption> codecOptions;
|
||||||
private int bitRate;
|
private int bitRate;
|
||||||
private int maxFps;
|
private int maxFps;
|
||||||
private boolean sendFrameMeta;
|
private boolean sendFrameMeta;
|
||||||
private long ptsOrigin;
|
private long ptsOrigin;
|
||||||
|
|
||||||
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, List<CodecOption> codecOptions, String encoderName) {
|
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, List<CodecOption> codecOptions) {
|
||||||
this.sendFrameMeta = sendFrameMeta;
|
this.sendFrameMeta = sendFrameMeta;
|
||||||
this.bitRate = bitRate;
|
this.bitRate = bitRate;
|
||||||
this.maxFps = maxFps;
|
this.maxFps = maxFps;
|
||||||
this.codecOptions = codecOptions;
|
this.codecOptions = codecOptions;
|
||||||
this.encoderName = encoderName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -74,7 +69,7 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||||||
boolean alive;
|
boolean alive;
|
||||||
try {
|
try {
|
||||||
do {
|
do {
|
||||||
MediaCodec codec = createCodec(encoderName);
|
MediaCodec codec = createCodec();
|
||||||
IBinder display = createDisplay();
|
IBinder display = createDisplay();
|
||||||
ScreenInfo screenInfo = device.getScreenInfo();
|
ScreenInfo screenInfo = device.getScreenInfo();
|
||||||
Rect contentRect = screenInfo.getContentRect();
|
Rect contentRect = screenInfo.getContentRect();
|
||||||
@ -155,30 +150,8 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||||||
IO.writeFully(fd, headerBuffer);
|
IO.writeFully(fd, headerBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MediaCodecInfo[] listEncoders() {
|
private static MediaCodec createCodec() throws IOException {
|
||||||
List<MediaCodecInfo> result = new ArrayList<>();
|
return MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
|
||||||
MediaCodecList list = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
|
||||||
for (MediaCodecInfo codecInfo : list.getCodecInfos()) {
|
|
||||||
if (codecInfo.isEncoder() && Arrays.asList(codecInfo.getSupportedTypes()).contains(MediaFormat.MIMETYPE_VIDEO_AVC)) {
|
|
||||||
result.add(codecInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result.toArray(new MediaCodecInfo[result.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MediaCodec createCodec(String encoderName) throws IOException {
|
|
||||||
if (encoderName != null) {
|
|
||||||
Ln.d("Creating encoder by name: '" + encoderName + "'");
|
|
||||||
try {
|
|
||||||
return MediaCodec.createByCodecName(encoderName);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
MediaCodecInfo[] encoders = listEncoders();
|
|
||||||
throw new InvalidEncoderException(encoderName, encoders);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MediaCodec codec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
|
|
||||||
Ln.d("Using encoder: '" + codec.getName() + "'");
|
|
||||||
return codec;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setCodecOption(MediaFormat format, CodecOption codecOption) {
|
private static void setCodecOption(MediaFormat format, CodecOption codecOption) {
|
||||||
|
@ -4,7 +4,6 @@ import com.genymobile.scrcpy.wrappers.ContentProvider;
|
|||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
import android.media.MediaCodecInfo;
|
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
@ -55,8 +54,7 @@ public final class Server {
|
|||||||
boolean tunnelForward = options.isTunnelForward();
|
boolean tunnelForward = options.isTunnelForward();
|
||||||
|
|
||||||
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) {
|
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) {
|
||||||
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions,
|
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions);
|
||||||
options.getEncoderName());
|
|
||||||
|
|
||||||
if (options.getControl()) {
|
if (options.getControl()) {
|
||||||
final Controller controller = new Controller(device, connection);
|
final Controller controller = new Controller(device, connection);
|
||||||
@ -122,7 +120,7 @@ public final class Server {
|
|||||||
"The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")");
|
"The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
final int expectedParameters = 15;
|
final int expectedParameters = 14;
|
||||||
if (args.length != expectedParameters) {
|
if (args.length != expectedParameters) {
|
||||||
throw new IllegalArgumentException("Expecting " + expectedParameters + " parameters");
|
throw new IllegalArgumentException("Expecting " + expectedParameters + " parameters");
|
||||||
}
|
}
|
||||||
@ -169,9 +167,6 @@ public final class Server {
|
|||||||
String codecOptions = args[13];
|
String codecOptions = args[13];
|
||||||
options.setCodecOptions(codecOptions);
|
options.setCodecOptions(codecOptions);
|
||||||
|
|
||||||
String encoderName = "-".equals(args[14]) ? null : args[14];
|
|
||||||
options.setEncoderName(encoderName);
|
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,15 +206,6 @@ public final class Server {
|
|||||||
Ln.e(" scrcpy --display " + id);
|
Ln.e(" scrcpy --display " + id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (e instanceof InvalidEncoderException) {
|
|
||||||
InvalidEncoderException iee = (InvalidEncoderException) e;
|
|
||||||
MediaCodecInfo[] encoders = iee.getAvailableEncoders();
|
|
||||||
if (encoders != null && encoders.length > 0) {
|
|
||||||
Ln.e("Try to use one of the available encoders:");
|
|
||||||
for (MediaCodecInfo encoder : encoders) {
|
|
||||||
Ln.e(" scrcpy --encoder-name '" + encoder.getName() + "'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user