Full Code of Genymobile/scrcpy for AI

master 3fcc177da5b6 cached
353 files
1.5 MB
393.9k tokens
2212 symbols
4 requests
Download .txt
Showing preview only (1,638K chars total). Download the full file or copy to clipboard to get everything.
Repository: Genymobile/scrcpy
Branch: master
Commit: 3fcc177da5b6
Files: 353
Total size: 1.5 MB

Directory structure:
gitextract_ouc_2c7j/

├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── feature_request.md
│   │   └── question.md
│   └── workflows/
│       └── release.yml
├── .gitignore
├── FAQ.md
├── LICENSE
├── README.md
├── app/
│   ├── data/
│   │   ├── bash-completion/
│   │   │   └── scrcpy
│   │   ├── open_a_terminal_here.bat
│   │   ├── scrcpy-console.bat
│   │   ├── scrcpy-console.desktop
│   │   ├── scrcpy-noconsole.vbs
│   │   ├── scrcpy.desktop
│   │   └── zsh-completion/
│   │       └── _scrcpy
│   ├── deps/
│   │   ├── .gitignore
│   │   ├── README
│   │   ├── _init
│   │   ├── adb_linux.sh
│   │   ├── adb_macos.sh
│   │   ├── adb_windows.sh
│   │   ├── dav1d.sh
│   │   ├── ffmpeg.sh
│   │   ├── libusb.sh
│   │   └── sdl.sh
│   ├── meson.build
│   ├── scrcpy-windows.manifest
│   ├── scrcpy-windows.rc
│   ├── scrcpy.1
│   ├── src/
│   │   ├── adb/
│   │   │   ├── adb.c
│   │   │   ├── adb.h
│   │   │   ├── adb_device.c
│   │   │   ├── adb_device.h
│   │   │   ├── adb_parser.c
│   │   │   ├── adb_parser.h
│   │   │   ├── adb_tunnel.c
│   │   │   └── adb_tunnel.h
│   │   ├── android/
│   │   │   ├── input.h
│   │   │   └── keycodes.h
│   │   ├── audio_player.c
│   │   ├── audio_player.h
│   │   ├── audio_regulator.c
│   │   ├── audio_regulator.h
│   │   ├── cli.c
│   │   ├── cli.h
│   │   ├── clock.c
│   │   ├── clock.h
│   │   ├── common.h
│   │   ├── compat.c
│   │   ├── compat.h
│   │   ├── control_msg.c
│   │   ├── control_msg.h
│   │   ├── controller.c
│   │   ├── controller.h
│   │   ├── coords.h
│   │   ├── decoder.c
│   │   ├── decoder.h
│   │   ├── delay_buffer.c
│   │   ├── delay_buffer.h
│   │   ├── demuxer.c
│   │   ├── demuxer.h
│   │   ├── device_msg.c
│   │   ├── device_msg.h
│   │   ├── display.c
│   │   ├── display.h
│   │   ├── events.c
│   │   ├── events.h
│   │   ├── file_pusher.c
│   │   ├── file_pusher.h
│   │   ├── fps_counter.c
│   │   ├── fps_counter.h
│   │   ├── frame_buffer.c
│   │   ├── frame_buffer.h
│   │   ├── hid/
│   │   │   ├── hid_event.h
│   │   │   ├── hid_gamepad.c
│   │   │   ├── hid_gamepad.h
│   │   │   ├── hid_keyboard.c
│   │   │   ├── hid_keyboard.h
│   │   │   ├── hid_mouse.c
│   │   │   └── hid_mouse.h
│   │   ├── icon.c
│   │   ├── icon.h
│   │   ├── input_events.h
│   │   ├── input_manager.c
│   │   ├── input_manager.h
│   │   ├── keyboard_sdk.c
│   │   ├── keyboard_sdk.h
│   │   ├── main.c
│   │   ├── mouse_capture.c
│   │   ├── mouse_capture.h
│   │   ├── mouse_sdk.c
│   │   ├── mouse_sdk.h
│   │   ├── opengl.c
│   │   ├── opengl.h
│   │   ├── options.c
│   │   ├── options.h
│   │   ├── packet_merger.c
│   │   ├── packet_merger.h
│   │   ├── receiver.c
│   │   ├── receiver.h
│   │   ├── recorder.c
│   │   ├── recorder.h
│   │   ├── scrcpy.c
│   │   ├── scrcpy.h
│   │   ├── screen.c
│   │   ├── screen.h
│   │   ├── server.c
│   │   ├── server.h
│   │   ├── shortcut_mod.h
│   │   ├── sys/
│   │   │   ├── unix/
│   │   │   │   ├── file.c
│   │   │   │   └── process.c
│   │   │   └── win/
│   │   │       ├── file.c
│   │   │       └── process.c
│   │   ├── trait/
│   │   │   ├── frame_sink.h
│   │   │   ├── frame_source.c
│   │   │   ├── frame_source.h
│   │   │   ├── gamepad_processor.h
│   │   │   ├── key_processor.h
│   │   │   ├── mouse_processor.h
│   │   │   ├── packet_sink.h
│   │   │   ├── packet_source.c
│   │   │   └── packet_source.h
│   │   ├── uhid/
│   │   │   ├── gamepad_uhid.c
│   │   │   ├── gamepad_uhid.h
│   │   │   ├── keyboard_uhid.c
│   │   │   ├── keyboard_uhid.h
│   │   │   ├── mouse_uhid.c
│   │   │   ├── mouse_uhid.h
│   │   │   ├── uhid_output.c
│   │   │   └── uhid_output.h
│   │   ├── usb/
│   │   │   ├── aoa_hid.c
│   │   │   ├── aoa_hid.h
│   │   │   ├── gamepad_aoa.c
│   │   │   ├── gamepad_aoa.h
│   │   │   ├── keyboard_aoa.c
│   │   │   ├── keyboard_aoa.h
│   │   │   ├── mouse_aoa.c
│   │   │   ├── mouse_aoa.h
│   │   │   ├── scrcpy_otg.c
│   │   │   ├── scrcpy_otg.h
│   │   │   ├── screen_otg.c
│   │   │   ├── screen_otg.h
│   │   │   ├── usb.c
│   │   │   └── usb.h
│   │   ├── util/
│   │   │   ├── acksync.c
│   │   │   ├── acksync.h
│   │   │   ├── audiobuf.c
│   │   │   ├── audiobuf.h
│   │   │   ├── average.c
│   │   │   ├── average.h
│   │   │   ├── binary.h
│   │   │   ├── env.c
│   │   │   ├── env.h
│   │   │   ├── file.c
│   │   │   ├── file.h
│   │   │   ├── intmap.c
│   │   │   ├── intmap.h
│   │   │   ├── intr.c
│   │   │   ├── intr.h
│   │   │   ├── log.c
│   │   │   ├── log.h
│   │   │   ├── memory.c
│   │   │   ├── memory.h
│   │   │   ├── net.c
│   │   │   ├── net.h
│   │   │   ├── net_intr.c
│   │   │   ├── net_intr.h
│   │   │   ├── process.c
│   │   │   ├── process.h
│   │   │   ├── process_intr.c
│   │   │   ├── process_intr.h
│   │   │   ├── rand.c
│   │   │   ├── rand.h
│   │   │   ├── str.c
│   │   │   ├── str.h
│   │   │   ├── strbuf.c
│   │   │   ├── strbuf.h
│   │   │   ├── term.c
│   │   │   ├── term.h
│   │   │   ├── thread.c
│   │   │   ├── thread.h
│   │   │   ├── tick.c
│   │   │   ├── tick.h
│   │   │   ├── timeout.c
│   │   │   ├── timeout.h
│   │   │   ├── vecdeque.h
│   │   │   └── vector.h
│   │   ├── v4l2_sink.c
│   │   ├── v4l2_sink.h
│   │   ├── version.c
│   │   └── version.h
│   └── tests/
│       ├── test_adb_parser.c
│       ├── test_audiobuf.c
│       ├── test_binary.c
│       ├── test_cli.c
│       ├── test_control_msg_serialize.c
│       ├── test_device_msg_deserialize.c
│       ├── test_orientation.c
│       ├── test_str.c
│       ├── test_strbuf.c
│       ├── test_vecdeque.c
│       └── test_vector.c
├── build.gradle
├── bump_version
├── config/
│   ├── android-checkstyle.gradle
│   └── checkstyle/
│       └── checkstyle.xml
├── cross_win32.txt
├── cross_win64.txt
├── doc/
│   ├── audio.md
│   ├── build.md
│   ├── camera.md
│   ├── connection.md
│   ├── control.md
│   ├── develop.md
│   ├── device.md
│   ├── gamepad.md
│   ├── keyboard.md
│   ├── linux.md
│   ├── macos.md
│   ├── mouse.md
│   ├── otg.md
│   ├── recording.md
│   ├── shortcuts.md
│   ├── tunnels.md
│   ├── v4l2.md
│   ├── video.md
│   ├── virtual_display.md
│   ├── window.md
│   └── windows.md
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── install_release.sh
├── meson.build
├── meson_options.txt
├── release/
│   ├── .gitignore
│   ├── build_common
│   ├── build_linux.sh
│   ├── build_macos.sh
│   ├── build_server.sh
│   ├── build_windows.sh
│   ├── generate_checksums.sh
│   ├── package_client.sh
│   ├── package_server.sh
│   ├── release.sh
│   ├── test_client.sh
│   └── test_server.sh
├── run
├── server/
│   ├── .gitignore
│   ├── build.gradle
│   ├── build_without_gradle.sh
│   ├── meson.build
│   ├── proguard-rules.pro
│   ├── scripts/
│   │   └── build-wrapper.sh
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── aidl/
│       │   │   └── android/
│       │   │       ├── content/
│       │   │       │   └── IOnPrimaryClipChangedListener.aidl
│       │   │       └── view/
│       │   │           └── IDisplayWindowListener.aidl
│       │   └── java/
│       │       ├── android/
│       │       │   └── content/
│       │       │       └── IContentProvider.java
│       │       └── com/
│       │           └── genymobile/
│       │               └── scrcpy/
│       │                   ├── AndroidVersions.java
│       │                   ├── AsyncProcessor.java
│       │                   ├── CleanUp.java
│       │                   ├── FakeContext.java
│       │                   ├── Options.java
│       │                   ├── Server.java
│       │                   ├── Workarounds.java
│       │                   ├── audio/
│       │                   │   ├── AudioCapture.java
│       │                   │   ├── AudioCaptureException.java
│       │                   │   ├── AudioCodec.java
│       │                   │   ├── AudioConfig.java
│       │                   │   ├── AudioDirectCapture.java
│       │                   │   ├── AudioEncoder.java
│       │                   │   ├── AudioPlaybackCapture.java
│       │                   │   ├── AudioRawRecorder.java
│       │                   │   ├── AudioRecordReader.java
│       │                   │   └── AudioSource.java
│       │                   ├── control/
│       │                   │   ├── ControlChannel.java
│       │                   │   ├── ControlMessage.java
│       │                   │   ├── ControlMessageReader.java
│       │                   │   ├── ControlProtocolException.java
│       │                   │   ├── Controller.java
│       │                   │   ├── DeviceMessage.java
│       │                   │   ├── DeviceMessageSender.java
│       │                   │   ├── DeviceMessageWriter.java
│       │                   │   ├── KeyComposition.java
│       │                   │   ├── Pointer.java
│       │                   │   ├── PointersState.java
│       │                   │   ├── PositionMapper.java
│       │                   │   └── UhidManager.java
│       │                   ├── device/
│       │                   │   ├── ConfigurationException.java
│       │                   │   ├── DesktopConnection.java
│       │                   │   ├── Device.java
│       │                   │   ├── DeviceApp.java
│       │                   │   ├── DisplayInfo.java
│       │                   │   ├── NewDisplay.java
│       │                   │   ├── Orientation.java
│       │                   │   ├── Point.java
│       │                   │   ├── Position.java
│       │                   │   ├── Size.java
│       │                   │   └── Streamer.java
│       │                   ├── opengl/
│       │                   │   ├── AffineOpenGLFilter.java
│       │                   │   ├── GLUtils.java
│       │                   │   ├── OpenGLException.java
│       │                   │   ├── OpenGLFilter.java
│       │                   │   └── OpenGLRunner.java
│       │                   ├── util/
│       │                   │   ├── AffineMatrix.java
│       │                   │   ├── Binary.java
│       │                   │   ├── Codec.java
│       │                   │   ├── CodecOption.java
│       │                   │   ├── CodecUtils.java
│       │                   │   ├── Command.java
│       │                   │   ├── HandlerExecutor.java
│       │                   │   ├── IO.java
│       │                   │   ├── Ln.java
│       │                   │   ├── LogUtils.java
│       │                   │   ├── Settings.java
│       │                   │   ├── SettingsException.java
│       │                   │   ├── StringUtils.java
│       │                   │   └── Threads.java
│       │                   ├── video/
│       │                   │   ├── CameraAspectRatio.java
│       │                   │   ├── CameraCapture.java
│       │                   │   ├── CameraFacing.java
│       │                   │   ├── CaptureReset.java
│       │                   │   ├── DisplaySizeMonitor.java
│       │                   │   ├── NewDisplayCapture.java
│       │                   │   ├── ScreenCapture.java
│       │                   │   ├── SurfaceCapture.java
│       │                   │   ├── SurfaceEncoder.java
│       │                   │   ├── VideoCodec.java
│       │                   │   ├── VideoFilter.java
│       │                   │   ├── VideoSource.java
│       │                   │   └── VirtualDisplayListener.java
│       │                   └── wrappers/
│       │                       ├── ActivityManager.java
│       │                       ├── ClipboardManager.java
│       │                       ├── ContentProvider.java
│       │                       ├── DisplayControl.java
│       │                       ├── DisplayManager.java
│       │                       ├── DisplayWindowListener.java
│       │                       ├── InputManager.java
│       │                       ├── PowerManager.java
│       │                       ├── ServiceManager.java
│       │                       ├── StatusBarManager.java
│       │                       ├── SurfaceControl.java
│       │                       └── WindowManager.java
│       └── test/
│           └── java/
│               └── com/
│                   └── genymobile/
│                       └── scrcpy/
│                           ├── control/
│                           │   ├── ControlMessageReaderTest.java
│                           │   └── DeviceMessageWriterTest.java
│                           └── util/
│                               ├── BinaryTest.java
│                               ├── CodecOptionsTest.java
│                               ├── CommandParserTest.java
│                               └── StringUtilsTest.java
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
github: [rom1v]
liberapay: rom1v
custom: ["https://paypal.me/rom2v"]


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

_Please read the [prerequisites] to run scrcpy._

[prerequisites]: https://github.com/Genymobile/scrcpy#prerequisites

_Also read the [FAQ] and check if your [issue][issues] already exists._

[FAQ]: https://github.com/Genymobile/scrcpy/blob/master/FAQ.md
[issues]: https://github.com/Genymobile/scrcpy/issues

## Environment

 - **OS:** [e.g. Debian, Windows, macOS...]
 - **Scrcpy version:** [e.g. 2.5]
 - **Installation method:** [e.g. manual build, apt, snap, brew, Windows release...]
 - **Device model:**
 - **Android version:** [e.g. 14]

## Describe the bug

A clear and concise description of what the bug is.

On errors, please provide the output of the console (and `adb logcat` if relevant).

```
Please paste terminal output in a code block.
```

Please do not post screenshots of your terminal, just post the content as text instead.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

 - [ ] I have checked that a similar [feature request](https://github.com/Genymobile/scrcpy/issues?q=is%3Aopen+is%3Aissue+label%3A%22feature+request%22) does not already exist.

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/ISSUE_TEMPLATE/question.md
================================================
---
name: Question
about: Ask a question about scrcpy
title: ''
labels: ''
assignees: ''

---


================================================
FILE: .github/workflows/release.yml
================================================
name: Build

on:
  workflow_dispatch:
    inputs:
      name:
        description: 'Version name (default is ref name)'

env:
  # $VERSION is used by release scripts
  VERSION: ${{ github.event.inputs.name || github.ref_name }}

jobs:
  test-scrcpy-server:
    runs-on: ubuntu-latest
    env:
      GRADLE: gradle  # use native gradle instead of ./gradlew in scripts
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup JDK
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: '17'

      - name: Test scrcpy-server
        run: release/test_server.sh

  build-scrcpy-server:
    runs-on: ubuntu-latest
    env:
      GRADLE: gradle  # use native gradle instead of ./gradlew in scripts
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup JDK
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: '17'

      - name: Build
        run: release/build_server.sh

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: scrcpy-server
          path: release/work/build-server/server/scrcpy-server

  test-build-scrcpy-server-without-gradle:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup JDK
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: '17'

      - name: Build without gradle
        run: server/build_without_gradle.sh

  test-client:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install dependencies
        run: |
          sudo apt update
          sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
             libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
             libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
             libv4l-dev

      - name: Test
        run: release/test_client.sh

  build-linux-x86_64:
    runs-on: ubuntu-22.04
    steps:
      - name: Check architecture
        run: |
            arch=$(uname -m)
            if [[ "$arch" != x86_64 ]]
            then
                echo "Unexpected architecture: $arch" >&2
                exit 1
            fi

      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install dependencies
        run: |
          sudo apt update
          sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
             libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
             libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
             libv4l-dev

      - name: Build
        run: release/build_linux.sh x86_64

      # upload-artifact does not preserve permissions
      - name: Tar
        run: |
            cd release/work/build-linux-x86_64
            mkdir dist-tar
            cd dist-tar
            tar -C .. -cvf dist.tar.gz dist/

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: build-linux-x86_64-intermediate
          path: release/work/build-linux-x86_64/dist-tar/

  build-win32:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install dependencies
        run: |
          sudo apt update
          sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
             libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
             libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
             mingw-w64 mingw-w64-tools libz-mingw-w64-dev

      - name: Build
        run: release/build_windows.sh 32

      # upload-artifact does not preserve permissions
      - name: Tar
        run: |
            cd release/work/build-win32
            mkdir dist-tar
            cd dist-tar
            tar -C .. -cvf dist.tar.gz dist/

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: build-win32-intermediate
          path: release/work/build-win32/dist-tar/

  build-win64:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install dependencies
        run: |
          sudo apt update
          sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
             libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
             libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
             mingw-w64 mingw-w64-tools libz-mingw-w64-dev

      - name: Build
        run: release/build_windows.sh 64

      # upload-artifact does not preserve permissions
      - name: Tar
        run: |
            cd release/work/build-win64
            mkdir dist-tar
            cd dist-tar
            tar -C .. -cvf dist.tar.gz dist/

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: build-win64-intermediate
          path: release/work/build-win64/dist-tar/

  build-macos-aarch64:
    runs-on: macos-latest
    steps:
      - name: Check architecture
        run: |
            arch=$(uname -m)
            if [[ "$arch" != arm64 ]]
            then
                echo "Unexpected architecture: $arch" >&2
                exit 1
            fi

      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install dependencies
        run: |
            brew install meson nasm libiconv zlib automake autoconf libtool

      - name: Build
        env:
          # the default Xcode (and macOS SDK) version can be found at
          # <https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md#xcode>
          #
          # then the minimal supported deployment target of that macOS SDK can be found at
          # <https://developer.apple.com/support/xcode/#minimum-requirements>
          MACOSX_DEPLOYMENT_TARGET: 10.13
        run: release/build_macos.sh aarch64

      # upload-artifact does not preserve permissions
      - name: Tar
        run: |
            cd release/work/build-macos-aarch64
            mkdir dist-tar
            cd dist-tar
            tar -C .. -cvf dist.tar.gz dist/

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: build-macos-aarch64-intermediate
          path: release/work/build-macos-aarch64/dist-tar/

  build-macos-x86_64:
    runs-on: macos-15-intel
    steps:
      - name: Check architecture
        run: |
            arch=$(uname -m)
            if [[ "$arch" != x86_64 ]]
            then
                echo "Unexpected architecture: $arch" >&2
                exit 1
            fi

      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install dependencies
        run: brew install meson nasm libiconv zlib automake
             # autoconf and libtool are already installed on macos-13

      - name: Build
        env:
          # the default Xcode (and macOS SDK) version can be found at
          # <https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#xcode>
          #
          # then the minimal supported deployment target of that macOS SDK can be found at
          # <https://developer.apple.com/support/xcode/#minimum-requirements>
          MACOSX_DEPLOYMENT_TARGET: 10.13
        run: release/build_macos.sh x86_64

      # upload-artifact does not preserve permissions
      - name: Tar
        run: |
            cd release/work/build-macos-x86_64
            mkdir dist-tar
            cd dist-tar
            tar -C .. -cvf dist.tar.gz dist/

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: build-macos-x86_64-intermediate
          path: release/work/build-macos-x86_64/dist-tar/

  package-linux-x86_64:
    needs:
      - build-scrcpy-server
      - build-linux-x86_64
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download scrcpy-server
        uses: actions/download-artifact@v4
        with:
          name: scrcpy-server
          path: release/work/build-server/server/

      - name: Download build-linux-x86_64
        uses: actions/download-artifact@v4
        with:
          name: build-linux-x86_64-intermediate
          path: release/work/build-linux-x86_64/dist-tar/

      # upload-artifact does not preserve permissions
      - name: Detar
        run: |
            cd release/work/build-linux-x86_64
            tar xf dist-tar/dist.tar.gz

      - name: Package
        run: release/package_client.sh linux-x86_64 tar.gz

      - name: Upload release
        uses: actions/upload-artifact@v4
        with:
          name: release-linux-x86_64
          path: release/output/

  package-win32:
    needs:
      - build-scrcpy-server
      - build-win32
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download scrcpy-server
        uses: actions/download-artifact@v4
        with:
          name: scrcpy-server
          path: release/work/build-server/server/

      - name: Download build-win32
        uses: actions/download-artifact@v4
        with:
          name: build-win32-intermediate
          path: release/work/build-win32/dist-tar/

      # upload-artifact does not preserve permissions
      - name: Detar
        run: |
            cd release/work/build-win32
            tar xf dist-tar/dist.tar.gz

      - name: Package
        run: release/package_client.sh win32 zip

      - name: Upload release
        uses: actions/upload-artifact@v4
        with:
          name: release-win32
          path: release/output/

  package-win64:
    needs:
      - build-scrcpy-server
      - build-win64
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download scrcpy-server
        uses: actions/download-artifact@v4
        with:
          name: scrcpy-server
          path: release/work/build-server/server/

      - name: Download build-win64
        uses: actions/download-artifact@v4
        with:
          name: build-win64-intermediate
          path: release/work/build-win64/dist-tar/

      # upload-artifact does not preserve permissions
      - name: Detar
        run: |
            cd release/work/build-win64
            tar xf dist-tar/dist.tar.gz

      - name: Package
        run: release/package_client.sh win64 zip

      - name: Upload release
        uses: actions/upload-artifact@v4
        with:
          name: release-win64
          path: release/output

  package-macos-aarch64:
    needs:
      - build-scrcpy-server
      - build-macos-aarch64
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download scrcpy-server
        uses: actions/download-artifact@v4
        with:
          name: scrcpy-server
          path: release/work/build-server/server/

      - name: Download build-macos-aarch64
        uses: actions/download-artifact@v4
        with:
          name: build-macos-aarch64-intermediate
          path: release/work/build-macos-aarch64/dist-tar/

      # upload-artifact does not preserve permissions
      - name: Detar
        run: |
            cd release/work/build-macos-aarch64
            tar xf dist-tar/dist.tar.gz

      - name: Package
        run: release/package_client.sh macos-aarch64 tar.gz

      - name: Upload release
        uses: actions/upload-artifact@v4
        with:
          name: release-macos-aarch64
          path: release/output/

  package-macos-x86_64:
    needs:
      - build-scrcpy-server
      - build-macos-x86_64
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download scrcpy-server
        uses: actions/download-artifact@v4
        with:
          name: scrcpy-server
          path: release/work/build-server/server/

      - name: Download build-macos
        uses: actions/download-artifact@v4
        with:
          name: build-macos-x86_64-intermediate
          path: release/work/build-macos-x86_64/dist-tar/

      # upload-artifact does not preserve permissions
      - name: Detar
        run: |
            cd release/work/build-macos-x86_64
            tar xf dist-tar/dist.tar.gz

      - name: Package
        run: release/package_client.sh macos-x86_64 tar.gz

      - name: Upload release
        uses: actions/upload-artifact@v4
        with:
          name: release-macos-x86_64
          path: release/output/

  release:
    needs:
      - build-scrcpy-server
      - package-linux-x86_64
      - package-win32
      - package-win64
      - package-macos-aarch64
      - package-macos-x86_64
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download scrcpy-server
        uses: actions/download-artifact@v4
        with:
          name: scrcpy-server
          path: release/work/build-server/server/

      - name: Download release-linux-x86_64
        uses: actions/download-artifact@v4
        with:
          name: release-linux-x86_64
          path: release/output/

      - name: Download release-win32
        uses: actions/download-artifact@v4
        with:
          name: release-win32
          path: release/output/

      - name: Download release-win64
        uses: actions/download-artifact@v4
        with:
          name: release-win64
          path: release/output/

      - name: Download release-macos-aarch64
        uses: actions/download-artifact@v4
        with:
          name: release-macos-aarch64
          path: release/output/

      - name: Download release-macos-x86_64
        uses: actions/download-artifact@v4
        with:
          name: release-macos-x86_64
          path: release/output/

      - name: Package server
        run: release/package_server.sh

      - name: Generate checksums
        run: release/generate_checksums.sh

      - name: Upload release artifact
        uses: actions/upload-artifact@v4
        with:
          name: scrcpy-release-${{ env.VERSION }}
          path: release/output


================================================
FILE: .gitignore
================================================
build/
/dist/
/build-*/
/build_*/
/release-*/
.idea/
.gradle/
/x/
local.properties
/scrcpy-server


================================================
FILE: FAQ.md
================================================
# Frequently Asked Questions

[Read in another language](#translations)

Here are the common reported problems and their status.

If you encounter any error, the first step is to upgrade to the latest version.


## `adb` and USB issues

`scrcpy` execute `adb` commands to initialize the connection with the device. If
`adb` fails, then scrcpy will not work.

This is typically not a bug in _scrcpy_, but a problem in your environment.


### `adb` not found

You need `adb` accessible from your `PATH`.

On Windows, the current directory is in your `PATH`, and `adb.exe` is included
in the release, so it should work out-of-the-box.


### Device not detected

>     ERROR: Could not find any ADB device

Check that you correctly enabled [adb debugging][enable-adb].

Your device must be detected by `adb`:

```
adb devices
```

If your device is not detected, you may need some [drivers] (on Windows). There is a separate [USB driver for Google devices][google-usb-driver].

[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
[drivers]: https://developer.android.com/studio/run/oem-usb.html
[google-usb-driver]: https://developer.android.com/studio/run/win-usb


### Device unauthorized

>     ERROR: Device is unauthorized:
>     ERROR:     -->   (usb)  0123456789abcdef          unauthorized
>     ERROR: A popup should open on the device to request authorization.

When connecting, a popup should open on the device. You must authorize USB
debugging.

If it does not open, check [stackoverflow][device-unauthorized].

[device-unauthorized]: https://stackoverflow.com/questions/23081263/adb-android-device-unauthorized


### Several devices connected

If several devices are connected, you will encounter this error:

>     ERROR: Multiple (2) ADB devices:
>     ERROR:     -->   (usb)  0123456789abcdef                device  Nexus_5
>     ERROR:     --> (tcpip)  192.168.1.5:5555                device  GM1913
>     ERROR: Select a device via -s (--serial), -d (--select-usb) or -e (--select-tcpip)

In that case, you can either provide the identifier of the device you want to
mirror:

```bash
scrcpy -s 0123456789abcdef
```

Or request the single USB (or TCP/IP) device:

```bash
scrcpy -d  # USB device
scrcpy -e  # TCP/IP device
```

Note that if your device is connected over TCP/IP, you might get this message:

>     adb: error: more than one device/emulator
>     ERROR: "adb reverse" returned with value 1
>     WARN: 'adb reverse' failed, fallback to 'adb forward'

This is expected (due to a bug on old Android versions, see [#5]), but in that
case, scrcpy fallbacks to a different method, which should work.

[#5]: https://github.com/Genymobile/scrcpy/issues/5


### Conflicts between adb versions

>     adb server version (41) doesn't match this client (39); killing...

This error occurs when you use several `adb` versions simultaneously. You must
find the program using a different `adb` version, and use the same `adb` version
everywhere.

You could overwrite the `adb` binary in the other program, or ask _scrcpy_ to
use a specific `adb` binary, by setting the `ADB` environment variable:

```bash
# in bash
export ADB=/path/to/your/adb
scrcpy
```

```cmd
:: in cmd
set ADB=C:\path\to\your\adb.exe
scrcpy
```

```powershell
# in PowerShell
$env:ADB = 'C:\path\to\your\adb.exe'
scrcpy
```


### Device disconnected

If _scrcpy_ stops itself with the warning "Device disconnected", then the
`adb` connection has been closed.

Try with another USB cable or plug it into another USB port. See [#281] and
[#283].

[#281]: https://github.com/Genymobile/scrcpy/issues/281
[#283]: https://github.com/Genymobile/scrcpy/issues/283


## OTG issues on Windows

On Windows, if `scrcpy --otg` (or `--keyboard=aoa`/`--mouse=aoa`) results in:

>     ERROR: Could not find any USB device

(or if only unrelated USB devices are detected), there might be drivers issues.

Please read [#3654], in particular [this comment][#3654-comment1] and [the next
one][#3654-comment2].

[#3654]: https://github.com/Genymobile/scrcpy/issues/3654
[#3654-comment1]: https://github.com/Genymobile/scrcpy/issues/3654#issuecomment-1369278232
[#3654-comment2]: https://github.com/Genymobile/scrcpy/issues/3654#issuecomment-1369295011


## Control issues

### Mouse and keyboard do not work

On some devices, you may need to enable an option to allow [simulating input].
In developer options, enable:

> **USB debugging (Security settings)**  
> _Allow granting permissions and simulating input via USB debugging_

Rebooting the device is necessary once this option is set.

[simulating input]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323


### Special characters do not work

The default text injection method is limited to ASCII characters. A trick allows
to also inject some [accented characters][accented-characters],
but that's all. See [#37].

To avoid the problem, [change the keyboard mode to simulate a physical
keyboard][hid].

[accented-characters]: https://blog.rom1v.com/2018/03/introducing-scrcpy/#handle-accented-characters
[#37]: https://github.com/Genymobile/scrcpy/issues/37
[hid]: doc/keyboard.md#physical-keyboard-simulation


## Client issues

### Issue with Wayland

By default, SDL uses x11 on Linux. The [video driver] can be changed via the
`SDL_VIDEODRIVER` environment variable:

[video driver]: https://wiki.libsdl.org/FAQUsingSDL#how_do_i_choose_a_specific_video_driver

```bash
export SDL_VIDEODRIVER=wayland
scrcpy
```

On some distributions (at least Fedora), the package `libdecor` must be
installed manually.

See issues [#2554] and [#2559].

[#2554]: https://github.com/Genymobile/scrcpy/issues/2554
[#2559]: https://github.com/Genymobile/scrcpy/issues/2559


### KWin compositor crashes

On Plasma Desktop, compositor is disabled while _scrcpy_ is running.

As a workaround, [disable "Block compositing"][kwin].

[kwin]: https://github.com/Genymobile/scrcpy/issues/114#issuecomment-378778613


## Crashes

### Exception

If you get any exception related to `MediaCodec`:

```
ERROR: Exception on thread Thread[main,5,main]
java.lang.IllegalStateException
        at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)
```

then try with another [encoder](doc/video.md#encoder).


## Translations

Translations of this FAQ in other languages are available in the [wiki].

[wiki]: https://github.com/Genymobile/scrcpy/wiki

Only this FAQ file is guaranteed to be up-to-date.


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright (C) 2018 Genymobile
   Copyright (C) 2018-2026 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.



================================================
FILE: README.md
================================================
**This GitHub repo (<https://github.com/Genymobile/scrcpy>) is the only official
source for the project. Do not download releases from random websites, even if
their name contains `scrcpy`.**

# scrcpy (v3.3.4)

<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />

_pronounced "**scr**een **c**o**py**"_

This application mirrors Android devices (video and audio) connected via USB or
[TCP/IP](doc/connection.md#tcpip-wireless) and allows control using the
computer's keyboard and mouse. It does not require _root_ access or an app
installed on the device. It works on _Linux_, _Windows_, and _macOS_.

![screenshot](assets/screenshot-debian-600.jpg)

It focuses on:

 - **lightness**: native, displays only the device screen
 - **performance**: 30~120fps, depending on the device
 - **quality**: 1920×1080 or above
 - **low latency**: [35~70ms][lowlatency]
 - **low startup time**: ~1 second to display the first image
 - **non-intrusiveness**: nothing is left installed on the Android device
 - **user benefits**: no account, no ads, no internet required
 - **freedom**: free and open source software

[lowlatency]: https://github.com/Genymobile/scrcpy/pull/646

Its features include:
 - [audio forwarding](doc/audio.md) (Android 11+)
 - [recording](doc/recording.md)
 - [virtual display](doc/virtual_display.md)
 - mirroring with [Android device screen off](doc/device.md#turn-screen-off)
 - [copy-paste](doc/control.md#copy-paste) in both directions
 - [configurable quality](doc/video.md)
 - [camera mirroring](doc/camera.md) (Android 12+)
 - [mirroring as a webcam (V4L2)](doc/v4l2.md) (Linux-only)
 - physical [keyboard][hid-keyboard] and [mouse][hid-mouse] simulation (HID)
 - [gamepad](doc/gamepad.md) support
 - [OTG mode](doc/otg.md)
 - and more…

[hid-keyboard]: doc/keyboard.md#physical-keyboard-simulation
[hid-mouse]: doc/mouse.md#physical-mouse-simulation

## Prerequisites

The Android device requires at least API 21 (Android 5.0).

[Audio forwarding](doc/audio.md) is supported for API >= 30 (Android 11+).

Make sure you [enabled USB debugging][enable-adb] on your device(s).

[enable-adb]: https://developer.android.com/studio/debug/dev-options#enable

On some devices (especially Xiaomi), you might get the following error:

```
Injecting input events requires the caller (or the source of the instrumentation, if any) to have the INJECT_EVENTS permission.
```

In that case, you need to enable [an additional option][control] `USB debugging
(Security Settings)` (this is an item different from `USB debugging`) to control
it using a keyboard and mouse. Rebooting the device is necessary once this
option is set.

[control]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323

Note that USB debugging is not required to run scrcpy in [OTG mode](doc/otg.md).


## Get the app

 - [Linux](doc/linux.md)
 - [Windows](doc/windows.md) (read [how to run](doc/windows.md#run))
 - [macOS](doc/macos.md)


## Must-know tips

 - [Reducing resolution](doc/video.md#size) may greatly improve performance
   (`scrcpy -m1024`)
 - [_Right-click_](doc/mouse.md#mouse-bindings) triggers `BACK`
 - [_Middle-click_](doc/mouse.md#mouse-bindings) triggers `HOME`
 - <kbd>Alt</kbd>+<kbd>f</kbd> toggles [fullscreen](doc/window.md#fullscreen)
 - There are many other [shortcuts](doc/shortcuts.md)


## Usage examples

There are a lot of options, [documented](#user-documentation) in separate pages.
Here are just some common examples.

 - Capture the screen in H.265 (better quality), limit the size to 1920, limit
   the frame rate to 60fps, disable audio, and control the device by simulating
   a physical keyboard:

    ```bash
    scrcpy --video-codec=h265 --max-size=1920 --max-fps=60 --no-audio --keyboard=uhid
    scrcpy --video-codec=h265 -m1920 --max-fps=60 --no-audio -K  # short version
    ```

 - Start VLC in a new virtual display (separate from the device display):

    ```bash
    scrcpy --new-display=1920x1080 --start-app=org.videolan.vlc
    ```

 - Record the device camera in H.265 at 1920x1080 (and microphone) to an MP4
   file:

    ```bash
    scrcpy --video-source=camera --video-codec=h265 --camera-size=1920x1080 --record=file.mp4
    ```

 - Capture the device front camera and expose it as a webcam on the computer (on
   Linux):

    ```bash
    scrcpy --video-source=camera --camera-size=1920x1080 --camera-facing=front --v4l2-sink=/dev/video2 --no-playback
    ```

 - Control the device without mirroring by simulating a physical keyboard and
   mouse (USB debugging not required):

    ```bash
    scrcpy --otg
    ```

 - Control the device using gamepad controllers plugged into the computer:

    ```bash
    scrcpy --gamepad=uhid
    scrcpy -G  # short version
    ```

## User documentation

The application provides a lot of features and configuration options. They are
documented in the following pages:

 - [Connection](doc/connection.md)
 - [Video](doc/video.md)
 - [Audio](doc/audio.md)
 - [Control](doc/control.md)
 - [Keyboard](doc/keyboard.md)
 - [Mouse](doc/mouse.md)
 - [Gamepad](doc/gamepad.md)
 - [Device](doc/device.md)
 - [Window](doc/window.md)
 - [Recording](doc/recording.md)
 - [Virtual display](doc/virtual_display.md)
 - [Tunnels](doc/tunnels.md)
 - [OTG](doc/otg.md)
 - [Camera](doc/camera.md)
 - [Video4Linux](doc/v4l2.md)
 - [Shortcuts](doc/shortcuts.md)


## Resources

 - [FAQ](FAQ.md)
 - [Translations][wiki] (not necessarily up to date)
 - [Build instructions](doc/build.md)
 - [Developers](doc/develop.md)

[wiki]: https://github.com/Genymobile/scrcpy/wiki


## Articles

- [Introducing scrcpy][article-intro]
- [Scrcpy now works wirelessly][article-tcpip]
- [Scrcpy 2.0, with audio][article-scrcpy2]

[article-intro]: https://blog.rom1v.com/2018/03/introducing-scrcpy/
[article-tcpip]: https://www.genymotion.com/blog/open-source-project-scrcpy-now-works-wirelessly/
[article-scrcpy2]: https://blog.rom1v.com/2023/03/scrcpy-2-0-with-audio/

## Contact

You can open an [issue] for bug reports, feature requests or general questions.

For bug reports, please read the [FAQ](FAQ.md) first, you might find a solution
to your problem immediately.

[issue]: https://github.com/Genymobile/scrcpy/issues

You can also use:

 - Reddit: [`r/scrcpy`](https://www.reddit.com/r/scrcpy)
 - BlueSky: [`@scrcpy.bsky.social`](https://bsky.app/profile/scrcpy.bsky.social)
 - Twitter: [`@scrcpy_app`](https://twitter.com/scrcpy_app)


## Donate

I'm [@rom1v](https://github.com/rom1v), the author and maintainer of _scrcpy_.

If you appreciate this application, you can [support my open source
work][donate]:
 - [GitHub Sponsors](https://github.com/sponsors/rom1v)
 - [Liberapay](https://liberapay.com/rom1v/)
 - [PayPal](https://paypal.me/rom2v)

[donate]: https://blog.rom1v.com/about/#support-my-open-source-work

## License

    Copyright (C) 2018 Genymobile
    Copyright (C) 2018-2026 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.


================================================
FILE: app/data/bash-completion/scrcpy
================================================
_scrcpy() {
    local cur prev words cword
    local opts="
        --always-on-top
        --angle
        --audio-bit-rate=
        --audio-buffer=
        --audio-codec=
        --audio-codec-options=
        --audio-dup
        --audio-encoder=
        --audio-source=
        --audio-output-buffer=
        -b --video-bit-rate=
        --camera-ar=
        --camera-id=
        --camera-facing=
        --camera-fps=
        --camera-high-speed
        --camera-size=
        --capture-orientation=
        --crop=
        -d --select-usb
        --disable-screensaver
        --display-id=
        --display-ime-policy=
        --display-orientation=
        -e --select-tcpip
        -f --fullscreen
        --force-adb-forward
        -G
        --gamepad=
        -h --help
        -K
        --keyboard=
        --kill-adb-on-close
        --legacy-paste
        --list-apps
        --list-camera-sizes
        --list-cameras
        --list-displays
        --list-encoders
        -m --max-size=
        -M
        --max-fps=
        --mouse=
        --mouse-bind=
        -n --no-control
        -N --no-playback
        --new-display
        --new-display=
        --no-audio
        --no-audio-playback
        --no-cleanup
        --no-clipboard-autosync
        --no-downsize-on-error
        --no-key-repeat
        --no-mipmaps
        --no-mouse-hover
        --no-power-on
        --no-vd-destroy-content
        --no-vd-system-decorations
        --no-video
        --no-video-playback
        --orientation=
        --otg
        -p --port=
        --pause-on-exit
        --pause-on-exit=
        --power-off-on-close
        --prefer-text
        --print-fps
        --push-target=
        -r --record=
        --raw-key-events
        --record-format=
        --record-orientation=
        --render-driver=
        --require-audio
        --rotation=
        -s --serial=
        -S --turn-screen-off
        --screen-off-timeout=
        --shortcut-mod=
        --start-app=
        -t --show-touches
        --tcpip
        --tcpip=
        --time-limit=
        --tunnel-host=
        --tunnel-port=
        --v4l2-buffer=
        --v4l2-sink=
        -v --version
        -V --verbosity=
        --video-buffer=
        --video-codec=
        --video-codec-options=
        --video-encoder=
        --video-source=
        -w --stay-awake
        --window-borderless
        --window-title=
        --window-x=
        --window-y=
        --window-width=
        --window-height="

    _init_completion -s || return

    case "$prev" in
        --video-codec)
            COMPREPLY=($(compgen -W 'h264 h265 av1' -- "$cur"))
            return
            ;;
        --audio-codec)
            COMPREPLY=($(compgen -W 'opus aac flac raw' -- "$cur"))
            return
            ;;
        --video-source)
            COMPREPLY=($(compgen -W 'display camera' -- "$cur"))
            return
            ;;
        --audio-source)
            COMPREPLY=($(compgen -W 'output playback mic mic-unprocessed mic-camcorder mic-voice-recognition mic-voice-communication voice-call voice-call-uplink voice-call-downlink voice-performance' -- "$cur"))
            return
            ;;
        --camera-facing)
            COMPREPLY=($(compgen -W 'front back external' -- "$cur"))
            return
            ;;
        --keyboard)
            COMPREPLY=($(compgen -W 'disabled sdk uhid aoa' -- "$cur"))
            return
            ;;
        --mouse)
            COMPREPLY=($(compgen -W 'disabled sdk uhid aoa' -- "$cur"))
            return
            ;;
        --gamepad)
            COMPREPLY=($(compgen -W 'disabled uhid aoa' -- "$cur"))
            return
            ;;
        --capture-orientation)
            COMPREPLY=($(compgen -W '0 90 180 270 flip0 flip90 flip180 flip270 @0 @90 @180 @270 @flip0 @flip90 @flip180 @flip270' -- "$cur"))
            return
            ;;
        --orientation|--display-orientation)
            COMPREPLY=($(compgen -W '0 90 180 270 flip0 flip90 flip180 flip270' -- "$cur"))
            return
            ;;
        --display-ime-policy)
            COMPREPLY=($(compgen -W 'local fallback hide' -- "$cur"))
            return
            ;;
        --record-orientation)
            COMPREPLY=($(compgen -W '0 90 180 270' -- "$cur"))
            return
            ;;
        --pause-on-exit)
            COMPREPLY=($(compgen -W 'true false if-error' -- "$cur"))
            return
            ;;
        -r|--record)
            COMPREPLY=($(compgen -f -- "$cur"))
            return
            ;;
        --record-format)
            COMPREPLY=($(compgen -W 'mp4 mkv m4a mka opus aac flac wav' -- "$cur"))
            return
            ;;
        --render-driver)
            COMPREPLY=($(compgen -W 'direct3d opengl opengles2 opengles metal software' -- "$cur"))
            return
            ;;
        --shortcut-mod)
            # Only auto-complete a single key
            COMPREPLY=($(compgen -W 'lctrl rctrl lalt ralt lsuper rsuper' -- "$cur"))
            return
            ;;
        -V|--verbosity)
            COMPREPLY=($(compgen -W 'verbose debug info warn error' -- "$cur"))
            return
            ;;
        -s|--serial)
            # Use 'adb devices' to list serial numbers
            COMPREPLY=($(compgen -W "$("${ADB:-adb}" devices | awk '$2 == "device" {print $1}')" -- ${cur}))
            return
            ;;
        --audio-bit-rate \
        |--audio-buffer \
        |-b|--video-bit-rate \
        |--audio-codec-options \
        |--audio-encoder \
        |--audio-output-buffer \
        |--camera-ar \
        |--camera-id \
        |--camera-fps \
        |--camera-size \
        |--crop \
        |--display-id \
        |--max-fps \
        |-m|--max-size \
        |--new-display \
        |-p|--port \
        |--push-target \
        |--rotation \
        |--screen-off-timeout \
        |--tunnel-host \
        |--tunnel-port \
        |--v4l2-buffer \
        |--v4l2-sink \
        |--video-buffer \
        |--video-codec-options \
        |--video-encoder \
        |--tcpip \
        |--window-*)
            # Option accepting an argument, but nothing to auto-complete
            return
            ;;
    esac

    COMPREPLY=($(compgen -W "$opts" -- "$cur"))
    [[ $COMPREPLY == *= ]] && compopt -o nospace
}

complete -F _scrcpy scrcpy


================================================
FILE: app/data/open_a_terminal_here.bat
================================================
@cmd


================================================
FILE: app/data/scrcpy-console.bat
================================================
@echo off
scrcpy.exe --pause-on-exit=if-error %*


================================================
FILE: app/data/scrcpy-console.desktop
================================================
[Desktop Entry]
Name=scrcpy (console)
GenericName=Android Remote Control
Comment=Display and control your Android device
# For some users, the PATH or ADB environment variables are set from the shell
# startup file, like .bashrc or .zshrc… Run an interactive shell to get
# environment correctly initialized.
Exec=/bin/sh -c "\\$SHELL -i -c 'scrcpy --pause-on-exit=if-error'"
Icon=scrcpy
Terminal=true
Type=Application
Categories=Utility;RemoteAccess;
StartupNotify=false


================================================
FILE: app/data/scrcpy-noconsole.vbs
================================================
strCommand = "cmd /c scrcpy.exe"

For Each Arg In WScript.Arguments
    strCommand = strCommand & " """ & replace(Arg, """", """""""""") & """"
Next

CreateObject("Wscript.Shell").Run strCommand, 0, false


================================================
FILE: app/data/scrcpy.desktop
================================================
[Desktop Entry]
Name=scrcpy
GenericName=Android Remote Control
Comment=Display and control your Android device
# For some users, the PATH or ADB environment variables are set from the shell
# startup file, like .bashrc or .zshrc… Run an interactive shell to get
# environment correctly initialized.
Exec=/bin/sh -c "\\$SHELL -i -c scrcpy"
Icon=scrcpy
Terminal=false
Type=Application
Categories=Utility;RemoteAccess;
StartupNotify=false


================================================
FILE: app/data/zsh-completion/_scrcpy
================================================
#compdef scrcpy scrcpy.exe
#
# name: scrcpy
# auth: hltdev [hltdev8642@gmail.com]
# desc: completion file for scrcpy (all OSes)
#

local arguments

arguments=(
    '--always-on-top[Make scrcpy window always on top \(above other windows\)]'
    '--angle=[Rotate the video content by a custom angle, in degrees]'
    '--audio-bit-rate=[Encode the audio at the given bit-rate]'
    '--audio-buffer=[Configure the audio buffering delay \(in milliseconds\)]'
    '--audio-codec=[Select the audio codec]:codec:(opus aac flac raw)'
    '--audio-codec-options=[Set a list of comma-separated key\:type=value options for the device audio encoder]'
    '--audio-dup=[Duplicate audio]'
    '--audio-encoder=[Use a specific MediaCodec audio encoder]'
    '--audio-source=[Select the audio source]:source:(output playback mic mic-unprocessed mic-camcorder mic-voice-recognition mic-voice-communication voice-call voice-call-uplink voice-call-downlink voice-performance)'
    '--audio-output-buffer=[Configure the size of the SDL audio output buffer (in milliseconds)]'
    {-b,--video-bit-rate=}'[Encode the video at the given bit-rate]'
    '--camera-ar=[Select the camera size by its aspect ratio]'
    '--camera-high-speed=[Enable high-speed camera capture mode]'
    '--camera-id=[Specify the camera id to mirror]'
    '--camera-facing=[Select the device camera by its facing direction]:facing:(front back external)'
    '--camera-fps=[Specify the camera capture frame rate]'
    '--camera-size=[Specify an explicit camera capture size]'
    '--capture-orientation=[Set the capture video orientation]:orientation:(0 90 180 270 flip0 flip90 flip180 flip270 @0 @90 @180 @270 @flip0 @flip90 @flip180 @flip270)'
    '--crop=[\[width\:height\:x\:y\] Crop the device screen on the server]'
    {-d,--select-usb}'[Use USB device]'
    '--disable-screensaver[Disable screensaver while scrcpy is running]'
    '--display-id=[Specify the display id to mirror]'
    '--display-ime-policy[Set the policy for selecting where the IME should be displayed]'
    '--display-orientation=[Set the initial display orientation]:orientation values:(0 90 180 270 flip0 flip90 flip180 flip270)'
    {-e,--select-tcpip}'[Use TCP/IP device]'
    {-f,--fullscreen}'[Start in fullscreen]'
    '--force-adb-forward[Do not attempt to use \"adb reverse\" to connect to the device]'
    '-G[Use UHID/AOA gamepad \(same as --gamepad=uhid or --gamepad=aoa, depending on OTG mode\)]'
    '--gamepad=[Set the gamepad input mode]:mode:(disabled uhid aoa)'
    {-h,--help}'[Print the help]'
    '-K[Use UHID/AOA keyboard \(same as --keyboard=uhid or --keyboard=aoa, depending on OTG mode\)]'
    '--keyboard=[Set the keyboard input mode]:mode:(disabled sdk uhid aoa)'
    '--kill-adb-on-close[Kill adb when scrcpy terminates]'
    '--legacy-paste[Inject computer clipboard text as a sequence of key events on Ctrl+v]'
    '--list-apps[List Android apps installed on the device]'
    '--list-camera-sizes[List the valid camera capture sizes]'
    '--list-cameras[List cameras available on the device]'
    '--list-displays[List displays available on the device]'
    '--list-encoders[List video and audio encoders available on the device]'
    {-m,--max-size=}'[Limit both the width and height of the video to value]'
    '-M[Use UHID/AOA mouse \(same as --mouse=uhid or --mouse=aoa, depending on OTG mode\)]'
    '--max-fps=[Limit the frame rate of screen capture]'
    '--mouse=[Set the mouse input mode]:mode:(disabled sdk uhid aoa)'
    '--mouse-bind=[Configure bindings of secondary clicks]'
    {-n,--no-control}'[Disable device control \(mirror the device in read only\)]'
    {-N,--no-playback}'[Disable video and audio playback]'
    '--new-display=[Create a new display]'
    '--no-audio[Disable audio forwarding]'
    '--no-audio-playback[Disable audio playback]'
    '--no-cleanup[Disable device cleanup actions on exit]'
    '--no-clipboard-autosync[Disable automatic clipboard synchronization]'
    '--no-downsize-on-error[Disable lowering definition on MediaCodec error]'
    '--no-key-repeat[Do not forward repeated key events when a key is held down]'
    '--no-mipmaps[Disable the generation of mipmaps]'
    '--no-mouse-hover[Do not forward mouse hover events]'
    '--no-power-on[Do not power on the device on start]'
    '--no-vd-destroy-content[Disable virtual display "destroy content on removal" flag]'
    '--no-vd-system-decorations[Disable virtual display system decorations flag]'
    '--no-video[Disable video forwarding]'
    '--no-video-playback[Disable video playback]'
    '--orientation=[Set the video orientation]:orientation values:(0 90 180 270 flip0 flip90 flip180 flip270)'
    '--otg[Run in OTG mode \(simulating physical keyboard and mouse\)]'
    {-p,--port=}'[\[port\[\:port\]\] Set the TCP port \(range\) used by the client to listen]'
    '--pause-on-exit=[Make scrcpy pause before exiting]:mode:(true false if-error)'
    '--power-off-on-close[Turn the device screen off when closing scrcpy]'
    '--prefer-text[Inject alpha characters and space as text events instead of key events]'
    '--print-fps[Start FPS counter, to print frame logs to the console]'
    '--push-target=[Set the target directory for pushing files to the device by drag and drop]'
    {-r,--record=}'[Record screen to file]:record file:_files'
    '--raw-key-events[Inject key events for all input keys, and ignore text events]'
    '--record-format=[Force recording format]:format:(mp4 mkv m4a mka opus aac flac wav)'
    '--record-orientation=[Set the record orientation]:orientation values:(0 90 180 270)'
    '--render-driver=[Request SDL to use the given render driver]:driver name:(direct3d opengl opengles2 opengles metal software)'
    '--require-audio=[Make scrcpy fail if audio is enabled but does not work]'
    {-s,--serial=}'[The device serial number \(mandatory for multiple devices only\)]:serial:($("${ADB-adb}" devices | awk '\''$2 == "device" {print $1}'\''))'
    {-S,--turn-screen-off}'[Turn the device screen off immediately]'
    '--screen-off-timeout=[Set the screen off timeout in seconds]'
    '--shortcut-mod=[\[key1,key2+key3,...\] Specify the modifiers to use for scrcpy shortcuts]:shortcut mod:(lctrl rctrl lalt ralt lsuper rsuper)'
    '--start-app=[Start an Android app]'
    {-t,--show-touches}'[Show physical touches]'
    '--tcpip[\(optional \[ip\:port\]\) Configure and connect the device over TCP/IP]'
    '--time-limit=[Set the maximum mirroring time, in seconds]'
    '--tunnel-host=[Set the IP address of the adb tunnel to reach the scrcpy server]'
    '--tunnel-port=[Set the TCP port of the adb tunnel to reach the scrcpy server]'
    '--v4l2-buffer=[Add a buffering delay \(in milliseconds\) before pushing frames]'
    '--v4l2-sink=[\[\/dev\/videoN\] Output to v4l2loopback device]'
    {-v,--version}'[Print the version of scrcpy]'
    {-V,--verbosity=}'[Set the log level]:verbosity:(verbose debug info warn error)'
    '--video-buffer=[Add a buffering delay \(in milliseconds\) before displaying video frames]'
    '--video-codec=[Select the video codec]:codec:(h264 h265 av1)'
    '--video-codec-options=[Set a list of comma-separated key\:type=value options for the device video encoder]'
    '--video-encoder=[Use a specific MediaCodec video encoder]'
    '--video-source=[Select the video source]:source:(display camera)'
    {-w,--stay-awake}'[Keep the device on while scrcpy is running, when the device is plugged in]'
    '--window-borderless[Disable window decorations \(display borderless window\)]'
    '--window-title=[Set a custom window title]'
    '--window-x=[Set the initial window horizontal position]'
    '--window-y=[Set the initial window vertical position]'
    '--window-width=[Set the initial window width]'
    '--window-height=[Set the initial window height]'
)

_arguments -s $arguments


================================================
FILE: app/deps/.gitignore
================================================
/work


================================================
FILE: app/deps/README
================================================
This directory (app/deps/) contains:

*.sh          : shell scripts to download and build dependencies

patches/      : patches to fix dependencies (used by scripts)

work/sources/ : downloaded tarballs and extracted folders
                    ffmpeg-6.1.1.tar.xz
                    ffmpeg-6.1.1/
                    libusb-1.0.27.tar.gz
                    libusb-1.0.27/
                    ...
work/build/   : build dirs for each dependency/version/architecture
                    ffmpeg-6.1.1/win32/
                    ffmpeg-6.1.1/win64/
                    libusb-1.0.27/win32/
                    libusb-1.0.27/win64/
                    ...
work/install/ : install dirs for each architexture
                    win32/bin/
                    win32/include/
                    win32/lib/
                    win32/share/
                    win64/bin/
                    win64/include/
                    win64/lib/
                    win64/share/


================================================
FILE: app/deps/_init
================================================
# This file is intended to be sourced by other scripts, not executed

process_args() {
    if [[ $# != 3 ]]
    then
        # <host>: linux, macos, win32 or win64
        # <build_type>: native or cross
        # <link_type>: static or shared
        echo "Syntax: $0 <host> <build_type> <link_type>" >&2
        exit 1
    fi

    HOST="$1"
    BUILD_TYPE="$2"
    LINK_TYPE="$3"
    DIRNAME="$HOST-$BUILD_TYPE-$LINK_TYPE"

    if [[ "$BUILD_TYPE" != native && "$BUILD_TYPE" != cross ]]
    then
        echo "Unsupported build type (expected native or cross): $BUILD_TYPE" >&2
        exit 1
    fi

    if [[ "$LINK_TYPE" != static && "$LINK_TYPE" != shared ]]
    then
        echo "Unsupported link type (expected static or shared): $LINK_TYPE" >&2
        exit 1
    fi

    if [[ "$BUILD_TYPE" == cross ]]
    then
        if [[ "$HOST" = win32 ]]
        then
            HOST_TRIPLET=i686-w64-mingw32
        elif [[ "$HOST" = win64 ]]
        then
            HOST_TRIPLET=x86_64-w64-mingw32
        else
            echo "Unsupported cross-build to host: $HOST" >&2
            exit 1
        fi
    fi
}

DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
cd "$DEPS_DIR"

PATCHES_DIR="$PWD/patches"

WORK_DIR="$PWD/work"
SOURCES_DIR="$WORK_DIR/sources"
BUILD_DIR="$WORK_DIR/build"
INSTALL_DIR="$WORK_DIR/install"

mkdir -p "$INSTALL_DIR" "$SOURCES_DIR" "$WORK_DIR"

checksum() {
    local file="$1"
    local sum="$2"
    echo "$file: verifying checksum..."
    echo "$sum  $file" | shasum -a256 -c
}

get_file() {
    local url="$1"
    local file="$2"
    local sum="$3"
    if [[ -f "$file" ]]
    then
        echo "$file: found"
    else
        echo "$file: not found, downloading..."
        wget "$url" -O "$file"
    fi
    checksum "$file" "$sum"
}


================================================
FILE: app/deps/adb_linux.sh
================================================
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init "$@"

VERSION=36.0.0
URL="https://dl.google.com/android/repository/platform-tools_r$VERSION-linux.zip"
SHA256SUM=0ead642c943ffe79701fccca8f5f1c69c4ce4f43df2eefee553f6ccb27cbfbe8

PROJECT_DIR="platform-tools-$VERSION-linux"
FILENAME="$PROJECT_DIR.zip"

cd "$SOURCES_DIR"

if [[ -d "$PROJECT_DIR" ]]
then
    echo "$PWD/$PROJECT_DIR" found
else
    get_file "$URL" "$FILENAME" "$SHA256SUM"
    mkdir -p "$PROJECT_DIR"
    cd "$PROJECT_DIR"
    ZIP_PREFIX=platform-tools
    unzip "../$FILENAME" "$ZIP_PREFIX"/adb
    mv "$ZIP_PREFIX"/* .
    rmdir "$ZIP_PREFIX"
fi

mkdir -p "$INSTALL_DIR/adb-linux"
cd "$INSTALL_DIR/adb-linux"
cp -r "$SOURCES_DIR/$PROJECT_DIR"/. "$INSTALL_DIR/adb-linux/"


================================================
FILE: app/deps/adb_macos.sh
================================================
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init "$@"

VERSION=36.0.0
URL="https://dl.google.com/android/repository/platform-tools_r$VERSION-darwin.zip"
SHA256SUM=d3e9fa1df3345cf728586908426615a60863d2632f73f1ce14f0f1349ef000fd

PROJECT_DIR="platform-tools-$VERSION-darwin"
FILENAME="$PROJECT_DIR.zip"

cd "$SOURCES_DIR"

if [[ -d "$PROJECT_DIR" ]]
then
    echo "$PWD/$PROJECT_DIR" found
else
    get_file "$URL" "$FILENAME" "$SHA256SUM"
    mkdir -p "$PROJECT_DIR"
    cd "$PROJECT_DIR"
    ZIP_PREFIX=platform-tools
    unzip "../$FILENAME" "$ZIP_PREFIX"/adb
    mv "$ZIP_PREFIX"/* .
    rmdir "$ZIP_PREFIX"
fi

mkdir -p "$INSTALL_DIR/adb-macos"
cd "$INSTALL_DIR/adb-macos"
cp -r "$SOURCES_DIR/$PROJECT_DIR"/. "$INSTALL_DIR/adb-macos/"


================================================
FILE: app/deps/adb_windows.sh
================================================
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init "$@"

VERSION=36.0.0
URL="https://dl.google.com/android/repository/platform-tools_r$VERSION-win.zip"
SHA256SUM=12c2841f354e92a0eb2fd7bf6f0f9bf8538abce7bd6b060ac8349d6f6a61107c

PROJECT_DIR="platform-tools-$VERSION-windows"
FILENAME="$PROJECT_DIR.zip"

cd "$SOURCES_DIR"

if [[ -d "$PROJECT_DIR" ]]
then
    echo "$PWD/$PROJECT_DIR" found
else
    get_file "$URL" "$FILENAME" "$SHA256SUM"
    mkdir -p "$PROJECT_DIR"
    cd "$PROJECT_DIR"
    ZIP_PREFIX=platform-tools
    unzip "../$FILENAME" \
        "$ZIP_PREFIX"/AdbWinApi.dll \
        "$ZIP_PREFIX"/AdbWinUsbApi.dll \
        "$ZIP_PREFIX"/adb.exe
    mv "$ZIP_PREFIX"/* .
    rmdir "$ZIP_PREFIX"
fi

mkdir -p "$INSTALL_DIR/adb-windows"
cd "$INSTALL_DIR/adb-windows"
cp -r "$SOURCES_DIR/$PROJECT_DIR"/. "$INSTALL_DIR/adb-windows/"


================================================
FILE: app/deps/dav1d.sh
================================================
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init
process_args "$@"

VERSION=1.5.0
URL="https://code.videolan.org/videolan/dav1d/-/archive/$VERSION/dav1d-$VERSION.tar.gz"
SHA256SUM=78b15d9954b513ea92d27f39362535ded2243e1b0924fde39f37a31ebed5f76b

PROJECT_DIR="dav1d-$VERSION"
FILENAME="$PROJECT_DIR.tar.gz"

cd "$SOURCES_DIR"

if [[ -d "$PROJECT_DIR" ]]
then
    echo "$PWD/$PROJECT_DIR" found
else
    get_file "$URL" "$FILENAME" "$SHA256SUM"
    tar xf "$FILENAME"  # First level directory is "$PROJECT_DIR"
fi

mkdir -p "$BUILD_DIR/$PROJECT_DIR"
cd "$BUILD_DIR/$PROJECT_DIR"

if [[ -d "$DIRNAME" ]]
then
    echo "'$PWD/$DIRNAME' already exists, not reconfigured"
    cd "$DIRNAME"
else
    mkdir "$DIRNAME"
    cd "$DIRNAME"

    conf=(
        --prefix="$INSTALL_DIR/$DIRNAME"
        --libdir=lib
        -Denable_tests=false
        -Denable_tools=false
        # Always build dav1d statically
        --default-library=static
    )

    if [[ "$BUILD_TYPE" == cross ]]
    then
        case "$HOST" in
            win32)
                conf+=(
                    --cross-file="$SOURCES_DIR/$PROJECT_DIR/package/crossfiles/i686-w64-mingw32.meson"
                )
                ;;

            win64)
                conf+=(
                    --cross-file="$SOURCES_DIR/$PROJECT_DIR/package/crossfiles/x86_64-w64-mingw32.meson"
                )
                ;;

            *)
                echo "Unsupported host: $HOST" >&2
                exit 1
        esac
    fi

    meson setup . "$SOURCES_DIR/$PROJECT_DIR" "${conf[@]}"
fi

ninja
ninja install


================================================
FILE: app/deps/ffmpeg.sh
================================================
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init
process_args "$@"

VERSION=7.1.1
URL="https://ffmpeg.org/releases/ffmpeg-$VERSION.tar.xz"
SHA256SUM=733984395e0dbbe5c046abda2dc49a5544e7e0e1e2366bba849222ae9e3a03b1

PROJECT_DIR="ffmpeg-$VERSION"
FILENAME="$PROJECT_DIR.tar.xz"

cd "$SOURCES_DIR"

if [[ -d "$PROJECT_DIR" ]]
then
    echo "$PWD/$PROJECT_DIR" found
else
    get_file "$URL" "$FILENAME" "$SHA256SUM"
    tar xf "$FILENAME"  # First level directory is "$PROJECT_DIR"
fi

mkdir -p "$BUILD_DIR/$PROJECT_DIR"
cd "$BUILD_DIR/$PROJECT_DIR"

if [[ -d "$DIRNAME" ]]
then
    echo "'$PWD/$DIRNAME' already exists, not reconfigured"
    cd "$DIRNAME"
else
    mkdir "$DIRNAME"
    cd "$DIRNAME"

    if [[ "$HOST" == win* ]]
    then
        # -static-libgcc to avoid missing libgcc_s_dw2-1.dll
        # -static to avoid dynamic dependency to zlib
        export CFLAGS='-static-libgcc -static'
        export CXXFLAGS="$CFLAGS"
        export LDFLAGS='-static-libgcc -static'
    elif [[ "$HOST" == "macos" ]]
    then
        export PKG_CONFIG_PATH="/opt/homebrew/opt/zlib/lib/pkgconfig"
    fi

    export PKG_CONFIG_PATH="$INSTALL_DIR/$DIRNAME/lib/pkgconfig:$PKG_CONFIG_PATH"

    conf=(
        --prefix="$INSTALL_DIR/$DIRNAME"
        --pkg-config-flags="--static"
        --extra-cflags="-O2 -fPIC"
        --disable-programs
        --disable-doc
        --disable-swscale
        --disable-postproc
        --disable-avfilter
        --disable-network
        --disable-everything
        --disable-vulkan
        --disable-vaapi
        --disable-vdpau
        --enable-swresample
        --enable-libdav1d
        --enable-decoder=h264
        --enable-decoder=hevc
        --enable-decoder=av1
        --enable-decoder=libdav1d
        --enable-decoder=pcm_s16le
        --enable-decoder=opus
        --enable-decoder=aac
        --enable-decoder=flac
        --enable-decoder=png
        --enable-protocol=file
        --enable-demuxer=image2
        --enable-parser=png
        --enable-zlib
        --enable-muxer=matroska
        --enable-muxer=mp4
        --enable-muxer=opus
        --enable-muxer=flac
        --enable-muxer=wav
    )

    if [[ "$HOST" == linux ]]
    then
        conf+=(
            --enable-libv4l2
            --enable-outdev=v4l2
            --enable-encoder=rawvideo
        )
    else
        # libavdevice is only used for V4L2 on Linux
        conf+=(
            --disable-avdevice
        )
    fi

    if [[ "$LINK_TYPE" == static ]]
    then
        conf+=(
            --enable-static
            --disable-shared
        )
    else
        conf+=(
            --disable-static
            --enable-shared
        )
    fi

    if [[ "$BUILD_TYPE" == cross ]]
    then
        conf+=(
            --enable-cross-compile
            --cross-prefix="${HOST_TRIPLET}-"
            --cc="${HOST_TRIPLET}-gcc"
        )

        case "$HOST" in
            win32)
                conf+=(
                    --target-os=mingw32
                    --arch=x86
                )
                ;;

            win64)
                conf+=(
                    --target-os=mingw32
                    --arch=x86_64
                )
                ;;

            *)
                echo "Unsupported host: $HOST" >&2
                exit 1
        esac
    fi

    "$SOURCES_DIR/$PROJECT_DIR"/configure "${conf[@]}"
fi

make -j
make install


================================================
FILE: app/deps/libusb.sh
================================================
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init
process_args "$@"

VERSION=1.0.29
URL="https://github.com/libusb/libusb/archive/refs/tags/v$VERSION.tar.gz"
SHA256SUM=7c2dd39c0b2589236e48c93247c986ae272e27570942b4163cb00a060fcf1b74

PROJECT_DIR="libusb-$VERSION"
FILENAME="$PROJECT_DIR.tar.gz"

cd "$SOURCES_DIR"

if [[ -d "$PROJECT_DIR" ]]
then
    echo "$PWD/$PROJECT_DIR" found
else
    get_file "$URL" "$FILENAME" "$SHA256SUM"
    tar xf "$FILENAME"  # First level directory is "$PROJECT_DIR"
fi

mkdir -p "$BUILD_DIR/$PROJECT_DIR"
cd "$BUILD_DIR/$PROJECT_DIR"

export CFLAGS='-O2'
export CXXFLAGS="$CFLAGS"

if [[ -d "$DIRNAME" ]]
then
    echo "'$PWD/$DIRNAME' already exists, not reconfigured"
    cd "$DIRNAME"
else
    mkdir "$DIRNAME"
    cd "$DIRNAME"

    conf=(
        --prefix="$INSTALL_DIR/$DIRNAME"
    )

    if [[ "$LINK_TYPE" == static ]]
    then
        conf+=(
            --enable-static
            --disable-shared
        )
    else
        conf+=(
            --disable-static
            --enable-shared
        )
    fi

    if [[ "$BUILD_TYPE" == cross ]]
    then
        conf+=(
            --host="$HOST_TRIPLET"
        )
    fi

    "$SOURCES_DIR/$PROJECT_DIR"/bootstrap.sh
    "$SOURCES_DIR/$PROJECT_DIR"/configure "${conf[@]}"
fi

make -j
make install-strip


================================================
FILE: app/deps/sdl.sh
================================================
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init
process_args "$@"

VERSION=2.32.8
URL="https://github.com/libsdl-org/SDL/archive/refs/tags/release-$VERSION.tar.gz"
SHA256SUM=dd35e05644ae527848d02433bec24dd0ea65db59faecf1a0e5d1880c533dac2c

PROJECT_DIR="sdl-$VERSION"
FILENAME="$PROJECT_DIR.tar.gz"

cd "$SOURCES_DIR"

if [[ -d "$PROJECT_DIR" ]]
then
    echo "$PWD/$PROJECT_DIR" found
else
    get_file "$URL" "$FILENAME" "$SHA256SUM"
    tar xf "$FILENAME"  # First level directory is "SDL-release-$VERSION"
    mv "SDL-release-$VERSION" "$PROJECT_DIR"
fi

mkdir -p "$BUILD_DIR/$PROJECT_DIR"
cd "$BUILD_DIR/$PROJECT_DIR"

export CFLAGS='-O2'
export CXXFLAGS="$CFLAGS"

if [[ -d "$DIRNAME" ]]
then
    echo "'$PWD/$DIRNAME' already exists, not reconfigured"
    cd "$DIRNAME"
else
    mkdir "$DIRNAME"
    cd "$DIRNAME"

    conf=(
        --prefix="$INSTALL_DIR/$DIRNAME"
    )

    if [[ "$HOST" == linux ]]
    then
        conf+=(
            --enable-video-wayland
            --enable-video-x11
        )
    fi

    if [[ "$LINK_TYPE" == static ]]
    then
        conf+=(
            --enable-static
            --disable-shared
        )
    else
        conf+=(
            --disable-static
            --enable-shared
        )
    fi

    if [[ "$BUILD_TYPE" == cross ]]
    then
        conf+=(
            --host="$HOST_TRIPLET"
        )
    fi

    "$SOURCES_DIR/$PROJECT_DIR"/configure "${conf[@]}"
fi

make -j
# There is no "make install-strip"
make install
# Strip manually
if [[ "$LINK_TYPE" == shared && "$HOST" == win* ]]
then
    ${HOST_TRIPLET}-strip "$INSTALL_DIR/$DIRNAME/bin/SDL2.dll"
fi


================================================
FILE: app/meson.build
================================================
src = [
    'src/main.c',
    'src/adb/adb.c',
    'src/adb/adb_device.c',
    'src/adb/adb_parser.c',
    'src/adb/adb_tunnel.c',
    'src/audio_player.c',
    'src/audio_regulator.c',
    'src/cli.c',
    'src/clock.c',
    'src/compat.c',
    'src/control_msg.c',
    'src/controller.c',
    'src/decoder.c',
    'src/delay_buffer.c',
    'src/demuxer.c',
    'src/device_msg.c',
    'src/display.c',
    'src/events.c',
    'src/icon.c',
    'src/file_pusher.c',
    'src/fps_counter.c',
    'src/frame_buffer.c',
    'src/input_manager.c',
    'src/keyboard_sdk.c',
    'src/mouse_capture.c',
    'src/mouse_sdk.c',
    'src/opengl.c',
    'src/options.c',
    'src/packet_merger.c',
    'src/receiver.c',
    'src/recorder.c',
    'src/scrcpy.c',
    'src/screen.c',
    'src/server.c',
    'src/version.c',
    'src/hid/hid_gamepad.c',
    'src/hid/hid_keyboard.c',
    'src/hid/hid_mouse.c',
    'src/trait/frame_source.c',
    'src/trait/packet_source.c',
    'src/uhid/gamepad_uhid.c',
    'src/uhid/keyboard_uhid.c',
    'src/uhid/mouse_uhid.c',
    'src/uhid/uhid_output.c',
    'src/util/acksync.c',
    'src/util/audiobuf.c',
    'src/util/average.c',
    'src/util/env.c',
    'src/util/file.c',
    'src/util/intmap.c',
    'src/util/intr.c',
    'src/util/log.c',
    'src/util/memory.c',
    'src/util/net.c',
    'src/util/net_intr.c',
    'src/util/process.c',
    'src/util/process_intr.c',
    'src/util/rand.c',
    'src/util/strbuf.c',
    'src/util/str.c',
    'src/util/term.c',
    'src/util/thread.c',
    'src/util/tick.c',
    'src/util/timeout.c',
]

conf = configuration_data()

conf.set('_POSIX_C_SOURCE', '200809L')
conf.set('_XOPEN_SOURCE', '700')
conf.set('_GNU_SOURCE', true)

if host_machine.system() == 'windows'
    windows = import('windows')
    src += [
        'src/sys/win/file.c',
        'src/sys/win/process.c',
        windows.compile_resources('scrcpy-windows.rc'),
    ]
    conf.set('_WIN32_WINNT', '0x0600')
    conf.set('WINVER', '0x0600')
else
    src += [
        'src/sys/unix/file.c',
        'src/sys/unix/process.c',
    ]
    if host_machine.system() == 'darwin'
        conf.set('_DARWIN_C_SOURCE', true)
    endif
endif

v4l2_support = get_option('v4l2') and host_machine.system() == 'linux'
if v4l2_support
    src += [ 'src/v4l2_sink.c' ]
endif

usb_support = get_option('usb')
if usb_support
    src += [
        'src/usb/aoa_hid.c',
        'src/usb/gamepad_aoa.c',
        'src/usb/keyboard_aoa.c',
        'src/usb/mouse_aoa.c',
        'src/usb/scrcpy_otg.c',
        'src/usb/screen_otg.c',
        'src/usb/usb.c',
    ]
endif

cc = meson.get_compiler('c')

static = get_option('static')

dependencies = [
    dependency('libavformat', version: '>= 57.33', static: static),
    dependency('libavcodec', version: '>= 57.37', static: static),
    dependency('libavutil', static: static),
    dependency('libswresample', static: static),
    dependency('sdl2', version: '>= 2.0.5', static: static),
]

if v4l2_support
    dependencies += dependency('libavdevice', static: static)
endif

if usb_support
    dependencies += dependency('libusb-1.0', static: static)
endif

if host_machine.system() == 'windows'
    dependencies += cc.find_library('mingw32')
    dependencies += cc.find_library('ws2_32')
endif

check_functions = [
    'strdup',
    'asprintf',
    'vasprintf',
    'nrand48',
    'jrand48',
    'reallocarray',
]

foreach f : check_functions
  if cc.has_function(f)
    define = 'HAVE_' + f.underscorify().to_upper()
    conf.set(define, true)
  endif
endforeach

conf.set('HAVE_SOCK_CLOEXEC', host_machine.system() != 'windows' and
                              cc.has_header_symbol('sys/socket.h', 'SOCK_CLOEXEC'))

# the version, updated on release
conf.set_quoted('SCRCPY_VERSION', meson.project_version())

# the prefix used during configuration (meson --prefix=PREFIX)
conf.set_quoted('PREFIX', get_option('prefix'))

# build a "portable" version (with scrcpy-server accessible from the same
# directory as the executable)
conf.set('PORTABLE', get_option('portable'))

# the default client TCP port range for the "adb reverse" tunnel
# overridden by option --port
conf.set('DEFAULT_LOCAL_PORT_RANGE_FIRST', '27183')
conf.set('DEFAULT_LOCAL_PORT_RANGE_LAST', '27199')

# run a server debugger and wait for a client to be attached
conf.set('SERVER_DEBUGGER', get_option('server_debugger'))

# enable V4L2 support (linux only)
conf.set('HAVE_V4L2', v4l2_support)

# enable HID over AOA support (linux only)
conf.set('HAVE_USB', usb_support)

configure_file(configuration: conf, output: 'config.h')

src_dir = include_directories('src')

executable('scrcpy', src,
           dependencies: dependencies,
           include_directories: src_dir,
           install: true,
           c_args: [])

# <https://mesonbuild.com/Builtin-options.html#directories>
datadir = get_option('datadir') # by default 'share'

install_man('scrcpy.1')
install_data('data/icon.png',
             rename: 'scrcpy.png',
             install_dir: datadir / 'icons/hicolor/256x256/apps')
install_data('data/zsh-completion/_scrcpy',
             install_dir: datadir / 'zsh/site-functions')
install_data('data/bash-completion/scrcpy',
             install_dir: datadir / 'bash-completion/completions')

# Desktop entry file for application launchers
if host_machine.system() == 'linux'
    # Install a launcher (ex: /usr/local/share/applications/scrcpy.desktop)
    install_data('data/scrcpy.desktop',
                 install_dir: datadir / 'applications')
    install_data('data/scrcpy-console.desktop',
                 install_dir: datadir / 'applications')
endif


### TESTS

# do not build tests in release (assertions would not be executed at all)
if get_option('buildtype') == 'debug'
    tests = [
        ['test_adb_parser', [
            'tests/test_adb_parser.c',
            'src/adb/adb_device.c',
            'src/adb/adb_parser.c',
            'src/util/str.c',
            'src/util/strbuf.c',
        ]],
        ['test_binary', [
            'tests/test_binary.c',
        ]],
        ['test_audiobuf', [
            'tests/test_audiobuf.c',
            'src/util/audiobuf.c',
            'src/util/memory.c',
        ]],
        ['test_cli', [
            'tests/test_cli.c',
            'src/cli.c',
            'src/options.c',
            'src/util/log.c',
            'src/util/net.c',
            'src/util/str.c',
            'src/util/strbuf.c',
            'src/util/term.c',
        ]],
        ['test_control_msg_serialize', [
            'tests/test_control_msg_serialize.c',
            'src/control_msg.c',
            'src/util/str.c',
            'src/util/strbuf.c',
        ]],
        ['test_device_msg_deserialize', [
            'tests/test_device_msg_deserialize.c',
            'src/device_msg.c',
        ]],
        ['test_orientation', [
            'tests/test_orientation.c',
            'src/options.c',
        ]],
        ['test_strbuf', [
            'tests/test_strbuf.c',
            'src/util/strbuf.c',
        ]],
        ['test_str', [
            'tests/test_str.c',
            'src/util/str.c',
            'src/util/strbuf.c',
        ]],
        ['test_vecdeque', [
            'tests/test_vecdeque.c',
            'src/util/memory.c',
        ]],
        ['test_vector', [
            'tests/test_vector.c',
        ]],
    ]

    foreach t : tests
        sources = t[1] + ['src/compat.c']
        exe = executable(t[0], sources,
                         include_directories: src_dir,
                         dependencies: dependencies,
                         c_args: ['-DSDL_MAIN_HANDLED', '-DSC_TEST'])
        test(t[0], exe)
    endforeach
endif

if meson.version().version_compare('>= 0.58.0')
       devenv = environment()
       devenv.set('SCRCPY_ICON_PATH', meson.current_source_dir() / 'data/icon.png')
       meson.add_devenv(devenv)
endif


================================================
FILE: app/scrcpy-windows.manifest
================================================
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
  <asmv3:application>
    <asmv3:windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>


================================================
FILE: app/scrcpy-windows.rc
================================================
#include <winuser.h>

0 ICON "data/icon.ico"
1 RT_MANIFEST "scrcpy-windows.manifest"
2 VERSIONINFO
BEGIN
  BLOCK "StringFileInfo"
  BEGIN
    BLOCK "040904E4"
    BEGIN
      VALUE "FileDescription", "Display and control your Android device"
      VALUE "InternalName", "scrcpy"
      VALUE "LegalCopyright", "Romain Vimont, Genymobile"
      VALUE "OriginalFilename", "scrcpy.exe"
      VALUE "ProductName", "scrcpy"
      VALUE "ProductVersion", "3.3.4"
    END
  END
  BLOCK "VarFileInfo"
  BEGIN
    VALUE "Translation", 0x409, 1252
  END
END


================================================
FILE: app/scrcpy.1
================================================
.TH "scrcpy" "1"
.SH NAME
scrcpy \- Display and control your Android device


.SH SYNOPSIS
.B scrcpy
.RI [ options ]


.SH DESCRIPTION
.B scrcpy
provides display and control of Android devices connected on USB (or over TCP/IP). It does not require any root access.


.SH OPTIONS

.TP
.B \-\-always\-on\-top
Make scrcpy window always on top (above other windows).

.TP
.BI "\-\-angle " degrees
Rotate the video content by a custom angle, in degrees (clockwise).

.TP
.BI "\-\-audio\-bit\-rate " value
Encode the audio at the given bit rate, expressed in bits/s. Unit suffixes are supported: '\fBK\fR' (x1000) and '\fBM\fR' (x1000000).

Default is 128K (128000).

.TP
.BI "\-\-audio\-buffer " ms
Configure the audio buffering delay (in milliseconds).

Lower values decrease the latency, but increase the likelihood of buffer underrun (causing audio glitches).

Default is 50.

.TP
.BI "\-\-audio\-codec " name
Select an audio codec (opus, aac, flac or raw).

Default is opus.

.TP
.BI "\-\-audio\-codec\-options " key\fR[:\fItype\fR]=\fIvalue\fR[,...]
Set a list of comma-separated key:type=value options for the device audio encoder.

The possible values for 'type' are 'int' (default), 'long', 'float' and 'string'.

The list of possible codec options is available in the Android documentation:

<https://d.android.com/reference/android/media/MediaFormat>

.TP
.B \-\-audio\-dup
Duplicate audio (capture and keep playing on the device).

This feature is only available with --audio-source=playback.

.TP
.BI "\-\-audio\-encoder " name
Use a specific MediaCodec audio encoder (depending on the codec provided by \fB\-\-audio\-codec\fR).

The available encoders can be listed by \fB\-\-list\-encoders\fR.

.TP
.BI "\-\-audio\-source " source
Select the audio source. Possible values are:

 - "output": forwards the whole audio output, and disables playback on the device.
 - "playback": captures the audio playback (Android apps can opt-out, so the whole output is not necessarily captured).
 - "mic": captures the microphone.
 - "mic-unprocessed": captures the microphone unprocessed (raw) sound.
 - "mic-camcorder": captures the microphone tuned for video recording, with the same orientation as the camera if available.
 - "mic-voice-recognition": captures the microphone tuned for voice recognition.
 - "mic-voice-communication": captures the microphone tuned for voice communications (it will for instance take advantage of echo cancellation or automatic gain control if available).
 - "voice-call": captures voice call.
 - "voice-call-uplink": captures voice call uplink only.
 - "voice-call-downlink": captures voice call downlink only.
 - "voice-performance": captures audio meant to be processed for live performance (karaoke), includes both the microphone and the device playback.

Default is output.

.TP
.BI "\-\-audio\-output\-buffer " ms
Configure the size of the SDL audio output buffer (in milliseconds).

If you get "robotic" audio playback, you should test with a higher value (10). Do not change this setting otherwise.

Default is 5.

.TP
.BI "\-b, \-\-video\-bit\-rate " value
Encode the video at the given bit rate, expressed in bits/s. Unit suffixes are supported: '\fBK\fR' (x1000) and '\fBM\fR' (x1000000).

Default is 8M (8000000).

.TP
.BI "\-\-camera\-ar " ar
Select the camera size by its aspect ratio (+/- 10%).

Possible values are "sensor" (use the camera sensor aspect ratio), "\fInum\fR:\fIden\fR" (e.g. "4:3") and "\fIvalue\fR" (e.g. "1.6").

.TP
.BI "\-\-camera\-facing " facing
Select the device camera by its facing direction.

Possible values are "front", "back" and "external".

.TP
.BI "\-\-camera\-fps " fps
Specify the camera capture frame rate.

If not specified, Android's default frame rate (30 fps) is used.

.TP
.B \-\-camera\-high\-speed
Enable high-speed camera capture mode.

This mode is restricted to specific resolutions and frame rates, listed by \fB\-\-list\-camera\-sizes\fR.

.TP
.BI "\-\-camera\-id " id
Specify the device camera id to mirror.

The available camera ids can be listed by \fB\-\-list\-cameras\fR.

.TP
.BI "\-\-camera\-size " width\fRx\fIheight
Specify an explicit camera capture size.

.TP
.BI "\-\-capture\-orientation " value
Possible values are 0, 90, 180, 270, flip0, flip90, flip180 and flip270, possibly prefixed by '@'.

The number represents the clockwise rotation in degrees; the "flip" keyword applies a horizontal flip before the rotation.

If a leading '@' is passed (@90) for display capture, then the rotation is locked, and is relative to the natural device orientation.

If '@' is passed alone, then the rotation is locked to the initial device orientation.

Default is 0.

.TP
.BI "\-\-crop " width\fR:\fIheight\fR:\fIx\fR:\fIy
Crop the device screen on the server.

The values are expressed in the device natural orientation (typically, portrait for a phone, landscape for a tablet).

.TP
.B \-d, \-\-select\-usb
Use USB device (if there is exactly one, like adb -d).

Also see \fB\-e\fR (\fB\-\-select\-tcpip\fR).

.TP
.BI "\-\-disable\-screensaver"
Disable screensaver while scrcpy is running.

.TP
.BI "\-\-display\-id " id
Specify the device display id to mirror.

The available display ids can be listed by \fB\-\-list\-displays\fR.

Default is 0.

.TP
.BI "\-\-display\-ime\-policy " value
Set the policy for selecting where the IME should be displayed.

Possible values are "local", "fallback" and "hide":

 - "local" means that the IME should appear on the local display.
 - "fallback" means that the IME should appear on a fallback display (the default display).
 - "hide" means that the IME should be hidden.

By default, the IME policy is left unchanged.


.TP
.BI "\-\-display\-orientation " value
Set the initial display orientation.

Possible values are 0, 90, 180, 270, flip0, flip90, flip180 and flip270. The number represents the clockwise rotation in degrees; the "flip" keyword applies a horizontal flip before the rotation.

Default is 0.

.TP
.B \-e, \-\-select\-tcpip
Use TCP/IP device (if there is exactly one, like adb -e).

Also see \fB\-d\fR (\fB\-\-select\-usb\fR).

.TP
.B \-f, \-\-fullscreen
Start in fullscreen.

.TP
.B \-\-force\-adb\-forward
Do not attempt to use "adb reverse" to connect to the device.

.TP
.B \-G
Same as \fB\-\-gamepad=uhid\fR, or \fB\-\-keyboard=aoa\fR if \fB\-\-otg\fR is set.

.TP
.BI "\-\-gamepad " mode
Select how to send gamepad inputs to the device.

Possible values are "disabled", "uhid" and "aoa":

 - "disabled" does not send gamepad inputs to the device.
 - "uhid" simulates physical HID gamepads using the Linux HID kernel module on the device.
 - "aoa" simulates physical HID gamepads using the AOAv2 protocol. It may only work over USB.

Also see \fB\-\-keyboard\f and R\fB\-\-mouse\fR.
.TP
.B \-h, \-\-help
Print this help.

.TP
.B \-K
Same as \fB\-\-keyboard=uhid\fR, or \fB\-\-keyboard=aoa\fR if \fB\-\-otg\fR is set.

.TP
.BI "\-\-keyboard " mode
Select how to send keyboard inputs to the device.

Possible values are "disabled", "sdk", "uhid" and "aoa":

 - "disabled" does not send keyboard inputs to the device.
 - "sdk" uses the Android system API to deliver keyboard events to applications.
 - "uhid" simulates a physical HID keyboard using the Linux HID kernel module on the device.
 - "aoa" simulates a physical HID keyboard using the AOAv2 protocol. It may only work over USB.

For "uhid" and "aoa", the keyboard layout must be configured (once and for all) on the device, via Settings -> System -> Languages and input -> Physical keyboard. This settings page can be started directly using the shortcut MOD+k (except in OTG mode), or by executing:

    adb shell am start -a android.settings.HARD_KEYBOARD_SETTINGS

This option is only available when the HID keyboard is enabled (or a physical keyboard is connected).

Also see \fB\-\-mouse\fR and \fB\-\-gamepad\fR.

.TP
.B \-\-kill\-adb\-on\-close
Kill adb when scrcpy terminates.

.TP
.B \-\-legacy\-paste
Inject computer clipboard text as a sequence of key events on Ctrl+v (like MOD+Shift+v).

This is a workaround for some devices not behaving as expected when setting the device clipboard programmatically.

.TP
.B \-\-list\-apps
List Android apps installed on the device.

.TP
.B \-\-list\-camera\-sizes
List the valid camera capture sizes.

.TP
.B \-\-list\-cameras
List cameras available on the device.

.TP
.B \-\-list\-encoders
List video and audio encoders available on the device.

.TP
.B \-\-list\-displays
List displays available on the device.

.TP
.BI "\-m, \-\-max\-size " value
Limit both the width and height of the video to \fIvalue\fR. The other dimension is computed so that the device aspect\-ratio is preserved.

Default is 0 (unlimited).

.TP
.B \-M
Same as \fB\-\-mouse=uhid\fR, or \fB\-\-mouse=aoa\fR if \fB\-\-otg\fR is set.

.TP
.BI "\-\-max\-fps " value
Limit the framerate of screen capture (officially supported since Android 10, but may work on earlier versions).

.TP
.BI "\-\-mouse " mode
Select how to send mouse inputs to the device.

Possible values are "disabled", "sdk", "uhid" and "aoa":

 - "disabled" does not send mouse inputs to the device.
 - "sdk" uses the Android system API to deliver mouse events to applications.
 - "uhid" simulates a physical HID mouse using the Linux HID kernel module on the device.
 - "aoa" simulates a physical mouse using the AOAv2 protocol. It may only work over USB.

In "uhid" and "aoa" modes, the computer mouse is captured to control the device directly (relative mouse mode).

LAlt, LSuper or RSuper toggle the capture mode, to give control of the mouse back to the computer.

Also see \fB\-\-keyboard\fR and \fB\-\-gamepad\fR.

.TP
.BI "\-\-mouse\-bind " xxxx[:xxxx]
Configure bindings of secondary clicks.

The argument must be one or two sequences (separated by ':') of exactly 4 characters, one for each secondary click (in order: right click, middle click, 4th click, 5th click).

The first sequence defines the primary bindings, used when a mouse button is pressed alone. The second sequence defines the secondary bindings, used when a mouse button is pressed while the Shift key is held.

If the second sequence of bindings is omitted, then it is the same as the first one.

Each character must be one of the following:

 - '+': forward the click to the device
 - '-': ignore the click
 - 'b': trigger shortcut BACK (or turn screen on if off)
 - 'h': trigger shortcut HOME
 - 's': trigger shortcut APP_SWITCH
 - 'n': trigger shortcut "expand notification panel"

Default is 'bhsn:++++' for SDK mouse, and '++++:bhsn' for AOA and UHID.


.TP
.B \-n, \-\-no\-control
Disable device control (mirror the device in read\-only).

.TP
.B \-N, \-\-no\-playback
Disable video and audio playback on the computer (equivalent to \fB\-\-no\-video\-playback \-\-no\-audio\-playback\fR).

.TP
\fB\-\-new\-display\fR[=[\fIwidth\fRx\fIheight\fR][/\fIdpi\fR]]
Create a new display with the specified resolution and density. If not provided, they default to the main display dimensions and DPI.

Examples:

    \-\-new\-display=1920x1080
    \-\-new\-display=1920x1080/420
    \-\-new\-display         # main display size and density
    \-\-new\-display=/240    # main display size and 240 dpi

.TP
.B \-\-no\-audio
Disable audio forwarding.

.TP
.B \-\-no\-audio\-playback
Disable audio playback on the computer.

.TP
.B \-\-no\-cleanup
By default, scrcpy removes the server binary from the device and restores the device state (show touches, stay awake and power mode) on exit.

This option disables this cleanup.

.TP
.B \-\-no\-clipboard\-autosync
By default, scrcpy automatically synchronizes the computer clipboard to the device clipboard before injecting Ctrl+v, and the device clipboard to the computer clipboard whenever it changes.

This option disables this automatic synchronization.

.TP
.B \-\-no\-downsize\-on\-error
By default, on MediaCodec error, scrcpy automatically tries again with a lower definition.

This option disables this behavior.

.TP
.B \-\-no\-key\-repeat
Do not forward repeated key events when a key is held down.

.TP
.B \-\-no\-mipmaps
If the renderer is OpenGL 3.0+ or OpenGL ES 2.0+, then mipmaps are automatically generated to improve downscaling quality. This option disables the generation of mipmaps.

.TP
.B \-\-no\-mouse\-hover
Do not forward mouse hover (mouse motion without any clicks) events.

.TP
.B \-\-no\-power\-on
Do not power on the device on start.

.TP
.B \-\-no\-vd\-destroy\-content
Disable virtual display "destroy content on removal" flag.

With this option, when the virtual display is closed, the running apps are moved to the main display rather than being destroyed.

.TP
.B \-\-no\-vd\-system\-decorations
Disable virtual display system decorations flag.

.TP
.B \-\-no\-video
Disable video forwarding.

.TP
.B \-\-no\-video\-playback
Disable video playback on the computer.

.TP
.B \-\-no\-window
Disable scrcpy window. Implies --no-video-playback.

.TP
.BI "\-\-orientation " value
Same as --display-orientation=value --record-orientation=value.

.TP
.B \-\-otg
Run in OTG mode: simulate physical keyboard and mouse, as if the computer keyboard and mouse were plugged directly to the device via an OTG cable.

In this mode, adb (USB debugging) is not necessary, and mirroring is disabled.

LAlt, LSuper or RSuper toggle the mouse capture mode, to give control of the mouse back to the computer.

If any of \fB\-\-hid\-keyboard\fR or \fB\-\-hid\-mouse\fR is set, only enable keyboard or mouse respectively, otherwise enable both.

It may only work over USB.

See \fB\-\-keyboard\fR, \fB\-\-mouse\fR and \fB\-\-gamepad\fR.

.TP
.BI "\-p, \-\-port " port\fR[:\fIport\fR]
Set the TCP port (range) used by the client to listen.

Default is 27183:27199.

.TP
\fB\-\-pause\-on\-exit\fR[=\fImode\fR]
Configure pause on exit. Possible values are "true" (always pause on exit), "false" (never pause on exit) and "if-error" (pause only if an error occurred).

This is useful to prevent the terminal window from automatically closing, so that error messages can be read.

Default is "false".

Passing the option without argument is equivalent to passing "true".

.TP
.B \-\-power\-off\-on\-close
Turn the device screen off when closing scrcpy.

.TP
.B \-\-prefer\-text
Inject alpha characters and space as text events instead of key events.

This avoids issues when combining multiple keys to enter special characters,
but breaks the expected behavior of alpha keys in games (typically WASD).

.TP
.B "\-\-print\-fps
Start FPS counter, to print framerate logs to the console. It can be started or stopped at any time with MOD+i.

.TP
.BI "\-\-push\-target " path
Set the target directory for pushing files to the device by drag & drop. It is passed as\-is to "adb push".

Default is "/sdcard/Download/".

.TP
.BI "\-r, \-\-record " file
Record screen to
.IR file .

The format is determined by the
.B \-\-record\-format
option if set, or by the file extension.

.TP
.B \-\-raw\-key\-events
Inject key events for all input keys, and ignore text events.

.TP
.BI "\-\-record\-format " format
Force recording format (mp4, mkv, m4a, mka, opus, aac, flac or wav).

.TP
.BI "\-\-record\-orientation " value
Set the record orientation.

Possible values are 0, 90, 180 and 270. The number represents the clockwise rotation in degrees.

Default is 0.

.TP
.BI "\-\-render\-driver " name
Request SDL to use the given render driver (this is just a hint).

Supported names are currently "direct3d", "opengl", "opengles2", "opengles", "metal" and "software".

<https://wiki.libsdl.org/SDL_HINT_RENDER_DRIVER>

.TP
.B \-\-require\-audio
By default, scrcpy mirrors only the video if audio capture fails on the device. This option makes scrcpy fail if audio is enabled but does not work.

.TP
.BI "\-s, \-\-serial " number
The device serial number. Mandatory only if several devices are connected to adb.

.TP
.B \-S, \-\-turn\-screen\-off
Turn the device screen off immediately.

.TP
.B "\-\-screen\-off\-timeout " seconds
Set the screen off timeout while scrcpy is running (restore the initial value on exit).

.TP
.BI "\-\-shortcut\-mod " key\fR[+...]][,...]
Specify the modifiers to use for scrcpy shortcuts. Possible keys are "lctrl", "rctrl", "lalt", "ralt", "lsuper" and "rsuper".

Several shortcut modifiers can be specified, separated by ','.

For example, to use either LCtrl or LSuper for scrcpy shortcuts, pass "lctrl,lsuper".

Default is "lalt,lsuper" (left-Alt or left-Super).

.TP
.BI "\-\-start\-app " name
Start an Android app, by its exact package name.

Add a '?' prefix to select an app whose name starts with the given name, case-insensitive (retrieving app names on the device may take some time):

    scrcpy --start-app=?firefox

Add a '+' prefix to force-stop before starting the app:

    scrcpy --new-display --start-app=+org.mozilla.firefox

Both prefixes can be used, in that order:

    scrcpy --start-app=+?firefox

.TP
.B \-t, \-\-show\-touches
Enable "show touches" on start, restore the initial value on exit.

It only shows physical touches (not clicks from scrcpy).

.TP
.BI "\-\-tcpip\fR[=[+]\fIip\fR[:\fIport\fR]]
Configure and connect the device over TCP/IP.

If a destination address is provided, then scrcpy connects to this address before starting. The device must listen on the given TCP port (default is 5555).

If no destination address is provided, then scrcpy attempts to find the IP address and adb port of the current device (typically connected over USB), enables TCP/IP mode if necessary, then connects to this address before starting.

Prefix the address with a '+' to force a reconnection.

.TP
.BI "\-\-time\-limit " seconds
Set the maximum mirroring time, in seconds.

.TP
.BI "\-\-tunnel\-host " ip
Set the IP address of the adb tunnel to reach the scrcpy server. This option automatically enables \fB\-\-force\-adb\-forward\fR.

Default is localhost.

.TP
.BI "\-\-tunnel\-port " port
Set the TCP port of the adb tunnel to reach the scrcpy server. This option automatically enables \fB\-\-force\-adb\-forward\fR.

Default is 0 (not forced): the local port used for establishing the tunnel will be used.

.TP
.B \-v, \-\-version
Print the version of scrcpy.

.TP
.BI "\-V, \-\-verbosity " value
Set the log level ("verbose", "debug", "info", "warn" or "error").

Default is "info" for release builds, "debug" for debug builds.

.TP
.BI "\-\-v4l2-sink " /dev/videoN
Output to v4l2loopback device.

.TP
.BI "\-\-v4l2-buffer " ms
Add a buffering delay (in milliseconds) before pushing frames. This increases latency to compensate for jitter.

This option is similar to \fB\-\-video\-buffer\fR, but specific to V4L2 sink.

Default is 0 (no buffering).

.TP
.BI "\-\-video\-buffer " ms
Add a buffering delay (in milliseconds) before displaying video frames.

This increases latency to compensate for jitter.

Default is 0 (no buffering).

.TP
.BI "\-\-video\-codec " name
Select a video codec (h264, h265 or av1).

Default is h264.

.TP
.BI "\-\-video\-codec\-options " key\fR[:\fItype\fR]=\fIvalue\fR[,...]
Set a list of comma-separated key:type=value options for the device video encoder.

The possible values for 'type' are 'int' (default), 'long', 'float' and 'string'.

The list of possible codec options is available in the Android documentation:

<https://d.android.com/reference/android/media/MediaFormat>

.TP
.BI "\-\-video\-encoder " name
Use a specific MediaCodec video encoder (depending on the codec provided by \fB\-\-video\-codec\fR).

The available encoders can be listed by \fB\-\-list\-encoders\fR.

.TP
.BI "\-\-video\-source " source
Select the video source (display or camera).

Camera mirroring requires Android 12+.

Default is display.

.TP
.B \-w, \-\-stay-awake
Keep the device on while scrcpy is running, when the device is plugged in.

.TP
.B \-\-window\-borderless
Disable window decorations (display borderless window).

.TP
.BI "\-\-window\-title " text
Set a custom window title.

.TP
.BI "\-\-window\-x " value
Set the initial window horizontal position.

Default is "auto".

.TP
.BI "\-\-window\-y " value
Set the initial window vertical position.

Default is "auto".

.TP
.BI "\-\-window\-width " value
Set the initial window width.

Default is 0 (automatic).

.TP
.BI "\-\-window\-height " value
Set the initial window height.

Default is 0 (automatic).

.SH EXIT STATUS
.B scrcpy
will exit with code 0 on normal program termination. If an initial
connection cannot be established, the exit code 1 will be returned. If the
device disconnects while a session is active, exit code 2 will be returned.

.SH SHORTCUTS

In the following list, MOD is the shortcut modifier. By default, it's (left)
Alt or (left) Super, but it can be configured by \fB\-\-shortcut\-mod\fR (see above).

.TP
.B MOD+f
Switch fullscreen mode

.TP
.B MOD+Left
Rotate display left

.TP
.B MOD+Right
Rotate display right

.TP
.B MOD+Shift+Left, MOD+Shift+Right
Flip display horizontally

.TP
.B MOD+Shift+Up, MOD+Shift+Down
Flip display vertically

.TP
.B MOD+z
Pause or re-pause display

.TP
.B MOD+Shift+z
Unpause display

.TP
.B MOD+Shift+r
Reset video capture/encoding

.TP
.B MOD+g
Resize window to 1:1 (pixel\-perfect)

.TP
.B MOD+w, Double\-click on black borders
Resize window to remove black borders

.TP
.B MOD+h, Home, Middle\-click
Click on HOME

.TP
.B MOD+b, MOD+Backspace, Right\-click (when screen is on)
Click on BACK

.TP
.B MOD+s
Click on APP_SWITCH

.TP
.B MOD+m
Click on MENU

.TP
.B MOD+Up
Click on VOLUME_UP

.TP
.B MOD+Down
Click on VOLUME_DOWN

.TP
.B MOD+p
Click on POWER (turn screen on/off)

.TP
.B Right\-click (when screen is off)
Turn screen on

.TP
.B MOD+o
Turn device screen off (keep mirroring)

.TP
.B MOD+Shift+o
Turn device screen on

.TP
.B MOD+r
Rotate device screen

.TP
.B MOD+n
Expand notification panel

.TP
.B MOD+Shift+n
Collapse notification panel

.TP
.B Mod+c
Copy to clipboard (inject COPY keycode, Android >= 7 only)

.TP
.B Mod+x
Cut to clipboard (inject CUT keycode, Android >= 7 only)

.TP
.B MOD+v
Copy computer clipboard to device, then paste (inject PASTE keycode, Android >= 7 only)

.TP
.B MOD+Shift+v
Inject computer clipboard text as a sequence of key events

.TP
.B MOD+k
Open keyboard settings on the device (for HID keyboard only)

.TP
.B MOD+i
Enable/disable FPS counter (print frames/second in logs)

.TP
.B Ctrl+click-and-move
Pinch-to-zoom and rotate from the center of the screen

.TP
.B Shift+click-and-move
Tilt vertically (slide with 2 fingers)

.TP
.B Ctrl+Shift+click-and-move
Tilt horizontally (slide with 2 fingers)

.TP
.B Drag & drop APK file
Install APK from computer

.TP
.B Drag & drop non-APK file
Push file to device (see \fB\-\-push\-target\fR)


.SH Environment variables

.TP
.B ADB
Path to adb.

.TP
.B ANDROID_SERIAL
Device serial to use if no selector (\fB-s\fR, \fB-d\fR, \fB-e\fR or \fB\-\-tcpip=\fIaddr\fR) is specified.

.TP
.B SCRCPY_ICON_PATH
Path to the program icon.

.TP
.B SCRCPY_SERVER_PATH
Path to the server binary.


.SH AUTHORS
.B scrcpy
is written by Romain Vimont.

This manual page was written by
.MT mmyangfl@gmail.com
Yangfl
.ME
for the Debian Project (and may be used by others).


.SH "REPORTING BUGS"
Report bugs to <https://github.com/Genymobile/scrcpy/issues>.

.SH COPYRIGHT
Copyright \(co 2018 Genymobile <https://www.genymobile.com>

Copyright \(co 2018\-2026 Romain Vimont <rom@rom1v.com>

Licensed under the Apache License, Version 2.0.

.SH WWW
<https://github.com/Genymobile/scrcpy>


================================================
FILE: app/src/adb/adb.c
================================================
#include "adb.h"

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#include "adb/adb_device.h"
#include "adb/adb_parser.h"
#include "util/env.h"
#include "util/file.h"
#include "util/log.h"
#include "util/process_intr.h"
#include "util/str.h"

/* Convenience macro to expand:
 *
 *     const char *const argv[] =
 *         SC_ADB_COMMAND("shell", "echo", "hello");
 *
 * to:
 *
 *     const char *const argv[] =
 *         { sc_adb_get_executable(), "shell", "echo", "hello", NULL };
 */
#define SC_ADB_COMMAND(...) { sc_adb_get_executable(), __VA_ARGS__, NULL }

static char *adb_executable;

bool
sc_adb_init(void) {
    adb_executable = sc_get_env("ADB");
    if (adb_executable) {
        LOGD("Using adb: %s", adb_executable);
        return true;
    }

#if !defined(PORTABLE) || defined(_WIN32)
    adb_executable = strdup("adb");
    if (!adb_executable) {
        LOG_OOM();
        return false;
    }
#else
    // For portable builds, use the absolute path to the adb executable
    // in the same directory as scrcpy (except on Windows, where "adb"
    // is sufficient)
    adb_executable = sc_file_get_local_path("adb");
    if (!adb_executable) {
        // Error already logged
        return false;
    }

    LOGD("Using adb (portable): %s", adb_executable);
#endif

    return true;
}

void
sc_adb_destroy(void) {
    free(adb_executable);
}

const char *
sc_adb_get_executable(void) {
    return adb_executable;
}

// serialize argv to string "[arg1], [arg2], [arg3]"
static size_t
argv_to_string(const char *const *argv, char *buf, size_t bufsize) {
    size_t idx = 0;
    bool first = true;
    while (*argv) {
        const char *arg = *argv;
        size_t len = strlen(arg);
        // count space for "[], ...\0"
        if (idx + len + 8 >= bufsize) {
            // not enough space, truncate
            assert(idx < bufsize - 4);
            memcpy(&buf[idx], "...", 3);
            idx += 3;
            break;
        }
        if (first) {
            first = false;
        } else {
            buf[idx++] = ',';
            buf[idx++] = ' ';
        }
        buf[idx++] = '[';
        memcpy(&buf[idx], arg, len);
        idx += len;
        buf[idx++] = ']';
        argv++;
    }
    assert(idx < bufsize);
    buf[idx] = '\0';
    return idx;
}

static void
show_adb_installation_msg(void) {
#ifndef _WIN32
    static const struct {
        const char *binary;
        const char *command;
    } pkg_managers[] = {
        {"apt", "apt install adb"},
        {"apt-get", "apt-get install adb"},
        {"brew", "brew install --cask android-platform-tools"},
        {"dnf", "dnf install android-tools"},
        {"emerge", "emerge dev-util/android-tools"},
        {"pacman", "pacman -S android-tools"},
    };
    for (size_t i = 0; i < ARRAY_LEN(pkg_managers); ++i) {
        if (sc_file_executable_exists(pkg_managers[i].binary)) {
            LOGI("You may install 'adb' by \"%s\"", pkg_managers[i].command);
            return;
        }
    }
#endif
}

static void
show_adb_err_msg(enum sc_process_result err, const char *const argv[]) {
#define MAX_COMMAND_STRING_LEN 1024
    char *buf = malloc(MAX_COMMAND_STRING_LEN);
    if (!buf) {
        LOG_OOM();
        LOGE("Failed to execute");
        return;
    }

    switch (err) {
        case SC_PROCESS_ERROR_GENERIC:
            argv_to_string(argv, buf, MAX_COMMAND_STRING_LEN);
            LOGE("Failed to execute: %s", buf);
            break;
        case SC_PROCESS_ERROR_MISSING_BINARY:
            argv_to_string(argv, buf, MAX_COMMAND_STRING_LEN);
            LOGE("Command not found: %s", buf);
            LOGE("(make 'adb' accessible from your PATH or define its full"
                 "path in the ADB environment variable)");
            show_adb_installation_msg();
            break;
        case SC_PROCESS_SUCCESS:
            // do nothing
            break;
    }

    free(buf);
}

static bool
process_check_success_internal(sc_pid pid, const char *name, bool close,
                               unsigned flags) {
    bool log_errors = !(flags & SC_ADB_NO_LOGERR);

    if (pid == SC_PROCESS_NONE) {
        if (log_errors) {
            LOGE("Could not execute \"%s\"", name);
        }
        return false;
    }
    sc_exit_code exit_code = sc_process_wait(pid, close);
    if (exit_code) {
        if (log_errors) {
            if (exit_code != SC_EXIT_CODE_NONE) {
                LOGE("\"%s\" returned with value %" SC_PRIexitcode, name,
                     exit_code);
            } else {
                LOGE("\"%s\" exited unexpectedly", name);
            }
        }
        return false;
    }
    return true;
}

static bool
process_check_success_intr(struct sc_intr *intr, sc_pid pid, const char *name,
                           unsigned flags) {
    if (intr && !sc_intr_set_process(intr, pid)) {
        // Already interrupted
        return false;
    }

    // Always pass close=false, interrupting would be racy otherwise
    bool ret = process_check_success_internal(pid, name, false, flags);

    if (intr) {
        sc_intr_set_process(intr, SC_PROCESS_NONE);
    }

    // Close separately
    sc_process_close(pid);

    return ret;
}

static sc_pid
sc_adb_execute_p(const char *const argv[], unsigned flags, sc_pipe *pout) {
    unsigned process_flags = 0;
    if (flags & SC_ADB_NO_STDOUT) {
        process_flags |= SC_PROCESS_NO_STDOUT;
    }
    if (flags & SC_ADB_NO_STDERR) {
        process_flags |= SC_PROCESS_NO_STDERR;
    }

    sc_pid pid;
    enum sc_process_result r =
        sc_process_execute_p(argv, &pid, process_flags, NULL, pout, NULL);
    if (r != SC_PROCESS_SUCCESS) {
        // If the execution itself failed (not the command exit code), log the
        // error in all cases
        show_adb_err_msg(r, argv);
        pid = SC_PROCESS_NONE;
    }

    return pid;
}

sc_pid
sc_adb_execute(const char *const argv[], unsigned flags) {
    return sc_adb_execute_p(argv, flags, NULL);
}

bool
sc_adb_start_server(struct sc_intr *intr, unsigned flags) {
    const char *const argv[] = SC_ADB_COMMAND("start-server");

    sc_pid pid = sc_adb_execute(argv, flags);
    return process_check_success_intr(intr, pid, "adb start-server", flags);
}

bool
sc_adb_kill_server(struct sc_intr *intr, unsigned flags) {
    const char *const argv[] = SC_ADB_COMMAND("kill-server");

    sc_pid pid = sc_adb_execute(argv, flags);
    return process_check_success_intr(intr, pid, "adb kill-server", flags);
}

bool
sc_adb_forward(struct sc_intr *intr, const char *serial, uint16_t local_port,
               const char *device_socket_name, unsigned flags) {
    char local[4 + 5 + 1]; // tcp:PORT
    char remote[108 + 14 + 1]; // localabstract:NAME

    int r = snprintf(local, sizeof(local), "tcp:%" PRIu16, local_port);
    assert(r >= 0 && (size_t) r < sizeof(local));

    r = snprintf(remote, sizeof(remote), "localabstract:%s",
                 device_socket_name);
    if (r < 0 || (size_t) r >= sizeof(remote)) {
        LOGE("Could not write socket name");
        return false;
    }

    assert(serial);
    const char *const argv[] =
        SC_ADB_COMMAND("-s", serial, "forward", local, remote);

    sc_pid pid = sc_adb_execute(argv, flags);
    return process_check_success_intr(intr, pid, "adb forward", flags);
}

bool
sc_adb_forward_remove(struct sc_intr *intr, const char *serial,
                      uint16_t local_port, unsigned flags) {
    char local[4 + 5 + 1]; // tcp:PORT
    int r = snprintf(local, sizeof(local), "tcp:%" PRIu16, local_port);
    assert(r >= 0 && (size_t) r < sizeof(local));
    (void) r;

    assert(serial);
    const char *const argv[] =
        SC_ADB_COMMAND("-s", serial, "forward", "--remove", local);

    sc_pid pid = sc_adb_execute(argv, flags);
    return process_check_success_intr(intr, pid, "adb forward --remove", flags);
}

bool
sc_adb_reverse(struct sc_intr *intr, const char *serial,
               const char *device_socket_name, uint16_t local_port,
               unsigned flags) {
    char local[4 + 5 + 1]; // tcp:PORT
    char remote[108 + 14 + 1]; // localabstract:NAME
    int r = snprintf(local, sizeof(local), "tcp:%" PRIu16, local_port);
    assert(r >= 0 && (size_t) r < sizeof(local));

    r = snprintf(remote, sizeof(remote), "localabstract:%s",
                 device_socket_name);
    if (r < 0 || (size_t) r >= sizeof(remote)) {
        LOGE("Could not write socket name");
        return false;
    }

    assert(serial);
    const char *const argv[] =
        SC_ADB_COMMAND("-s", serial, "reverse", remote, local);

    sc_pid pid = sc_adb_execute(argv, flags);
    return process_check_success_intr(intr, pid, "adb reverse", flags);
}

bool
sc_adb_reverse_remove(struct sc_intr *intr, const char *serial,
                      const char *device_socket_name, unsigned flags) {
    char remote[108 + 14 + 1]; // localabstract:NAME
    int r = snprintf(remote, sizeof(remote), "localabstract:%s",
                     device_socket_name);
    if (r < 0 || (size_t) r >= sizeof(remote)) {
        LOGE("Device socket name too long");
        return false;
    }

    assert(serial);
    const char *const argv[] =
        SC_ADB_COMMAND("-s", serial, "reverse", "--remove", remote);

    sc_pid pid = sc_adb_execute(argv, flags);
    return process_check_success_intr(intr, pid, "adb reverse --remove", flags);
}

bool
sc_adb_push(struct sc_intr *intr, const char *serial, const char *local,
            const char *remote, unsigned flags) {
#ifdef _WIN32
    // Windows will parse the string, so the paths must be quoted
    // (see sys/win/command.c)
    local = sc_str_quote(local);
    if (!local) {
        return SC_PROCESS_NONE;
    }
    remote = sc_str_quote(remote);
    if (!remote) {
        free((void *) local);
        return SC_PROCESS_NONE;
    }
#endif

    assert(serial);
    const char *const argv[] =
        SC_ADB_COMMAND("-s", serial, "push", local, remote);

    sc_pid pid = sc_adb_execute(argv, flags);

#ifdef _WIN32
    free((void *) remote);
    free((void *) local);
#endif

    return process_check_success_intr(intr, pid, "adb push", flags);
}

bool
sc_adb_install(struct sc_intr *intr, const char *serial, const char *local,
               unsigned flags) {
#ifdef _WIN32
    // Windows will parse the string, so the local name must be quoted
    // (see sys/win/command.c)
    local = sc_str_quote(local);
    if (!local) {
        return SC_PROCESS_NONE;
    }
#endif

    assert(serial);
    const char *const argv[] =
        SC_ADB_COMMAND("-s", serial, "install", "-r", local);

    sc_pid pid = sc_adb_execute(argv, flags);

#ifdef _WIN32
    free((void *) local);
#endif

    return process_check_success_intr(intr, pid, "adb install", flags);
}

bool
sc_adb_tcpip(struct sc_intr *intr, const char *serial, uint16_t port,
             unsigned flags) {
    char port_string[5 + 1];
    int r = snprintf(port_string, sizeof(port_string), "%" PRIu16, port);
    assert(r >= 0 && (size_t) r < sizeof(port_string));
    (void) r;

    assert(serial);
    const char *const argv[] =
        SC_ADB_COMMAND("-s", serial, "tcpip", port_string);

    sc_pid pid = sc_adb_execute(argv, flags);
    return process_check_success_intr(intr, pid, "adb tcpip", flags);
}

bool
sc_adb_connect(struct sc_intr *intr, const char *ip_port, unsigned flags) {
    const char *const argv[] = SC_ADB_COMMAND("connect", ip_port);

    sc_pipe pout;
    sc_pid pid = sc_adb_execute_p(argv, flags, &pout);
    if (pid == SC_PROCESS_NONE) {
        LOGE("Could not execute \"adb connect\"");
        return false;
    }

    // "adb connect" always returns successfully (with exit code 0), even in
    // case of failure. As a workaround, check if its output starts with
    // "connected" or "already connected".
    char buf[128];
    ssize_t r = sc_pipe_read_all_intr(intr, pid, pout, buf, sizeof(buf) - 1);
    sc_pipe_close(pout);

    bool ok = process_check_success_intr(intr, pid, "adb connect", flags);
    if (!ok) {
        return false;
    }

    if (r == -1) {
        return false;
    }

    assert((size_t) r < sizeof(buf));
    buf[r] = '\0';

    ok = !strncmp("connected", buf, sizeof("connected") - 1)
        || !strncmp("already connected", buf, sizeof("already connected") - 1);
    if (!ok && !(flags & SC_ADB_NO_STDERR)) {
        // "adb connect" also prints errors to stdout. Since we capture it,
        // re-print the error to stderr.
        size_t len = strcspn(buf, "\r\n");
        buf[len] = '\0';
        fprintf(stderr, "%s\n", buf);
    }
    return ok;
}

bool
sc_adb_disconnect(struct sc_intr *intr, const char *ip_port, unsigned flags) {
    assert(ip_port);
    const char *const argv[] = SC_ADB_COMMAND("disconnect", ip_port);

    sc_pid pid = sc_adb_execute(argv, flags);
    return process_check_success_intr(intr, pid, "adb disconnect", flags);
}

static bool
sc_adb_list_devices(struct sc_intr *intr, unsigned flags,
                    struct sc_vec_adb_devices *out_vec) {
    const char *const argv[] = SC_ADB_COMMAND("devices", "-l");

#define BUFSIZE 65536
    char *buf = malloc(BUFSIZE);
    if (!buf) {
        LOG_OOM();
        return false;
    }

    sc_pipe pout;
    sc_pid pid = sc_adb_execute_p(argv, flags, &pout);
    if (pid == SC_PROCESS_NONE) {
        LOGE("Could not execute \"adb devices -l\"");
        free(buf);
        return false;
    }

    ssize_t r = sc_pipe_read_all_intr(intr, pid, pout, buf, BUFSIZE - 1);
    sc_pipe_close(pout);

    bool ok = process_check_success_intr(intr, pid, "adb devices -l", flags);
    if (!ok) {
        free(buf);
        return false;
    }

    if (r == -1) {
        free(buf);
        return false;
    }

    assert((size_t) r < BUFSIZE);
    if (r == BUFSIZE - 1)  {
        // The implementation assumes that the output of "adb devices -l" fits
        // in the buffer in a single pass
        LOGW("Result of \"adb devices -l\" does not fit in 64Kb. "
             "Please report an issue.");
        free(buf);
        return false;
    }

    // It is parsed as a NUL-terminated string
    buf[r] = '\0';

    // List all devices to the output list directly
    ok = sc_adb_parse_devices(buf, out_vec);
    free(buf);
    return ok;
}

static bool
sc_adb_accept_device(const struct sc_adb_device *device,
                     const struct sc_adb_device_selector *selector) {
    switch (selector->type) {
        case SC_ADB_DEVICE_SELECT_ALL:
            return true;
        case SC_ADB_DEVICE_SELECT_SERIAL:
            assert(selector->serial);
            char *device_serial_colon = strchr(device->serial, ':');
            if (device_serial_colon) {
                // The device serial is an IP:port...
                char *serial_colon = strchr(selector->serial, ':');
                if (!serial_colon) {
                    // But the requested serial has no ':', so only consider
                    // the IP part of the device serial. This allows to use
                    // "192.168.1.1" to match any "192.168.1.1:port".
                    size_t serial_len = strlen(selector->serial);
                    size_t device_ip_len = device_serial_colon - device->serial;
                    if (serial_len != device_ip_len) {
                        // They are not equal, they don't even have the same
                        // length
                        return false;
                    }
                    return !strncmp(selector->serial, device->serial,
                                    device_ip_len);
                }
            }
            return !strcmp(selector->serial, device->serial);
        case SC_ADB_DEVICE_SELECT_USB:
            return sc_adb_device_get_type(device->serial) ==
                    SC_ADB_DEVICE_TYPE_USB;
        case SC_ADB_DEVICE_SELECT_TCPIP:
            // Both emulators and TCP/IP devices are selected via -e
            return sc_adb_device_get_type(device->serial) !=
                    SC_ADB_DEVICE_TYPE_USB;
        default:
            assert(!"Missing SC_ADB_DEVICE_SELECT_* handling");
            break;
    }

    return false;
}

static size_t
sc_adb_devices_select(struct sc_adb_device *devices, size_t len,
                      const struct sc_adb_device_selector *selector,
                      size_t *idx_out) {
    size_t count = 0;
    for (size_t i = 0; i < len; ++i) {
        struct sc_adb_device *device = &devices[i];
        device->selected = sc_adb_accept_device(device, selector);
        if (device->selected) {
            if (idx_out && !count) {
                *idx_out = i;
            }
            ++count;
        }
    }

    return count;
}

static void
sc_adb_devices_log(enum sc_log_level level, struct sc_adb_device *devices,
                   size_t count) {
    for (size_t i = 0; i < count; ++i) {
        struct sc_adb_device *d = &devices[i];
        const char *selection = d->selected ? "-->" : "   ";
        bool is_usb =
            sc_adb_device_get_type(d->serial) == SC_ADB_DEVICE_TYPE_USB;
        const char *type = is_usb ? "  (usb)"
                                  : "(tcpip)";
        LOG(level, "    %s %s  %-20s  %16s  %s",
             selection, type, d->serial, d->state, d->model ? d->model : "");
    }
}

static bool
sc_adb_device_check_state(struct sc_adb_device *device,
                          struct sc_adb_device *devices, size_t count) {
    const char *state = device->state;

    if (!strcmp("device", state)) {
        return true;
    }

    if (!strcmp("unauthorized", state)) {
        LOGE("Device is unauthorized:");
        sc_adb_devices_log(SC_LOG_LEVEL_ERROR, devices, count);
        LOGE("A popup should open on the device to request authorization.");
        LOGE("Check the FAQ: "
             "<https://github.com/Genymobile/scrcpy/blob/master/FAQ.md>");
    } else {
        LOGE("Device could not be connected (state=%s)", state);
    }

    return false;
}

bool
sc_adb_select_device(struct sc_intr *intr,
                     const struct sc_adb_device_selector *selector,
                     unsigned flags, struct sc_adb_device *out_device) {
    struct sc_vec_adb_devices vec = SC_VECTOR_INITIALIZER;
    bool ok = sc_adb_list_devices(intr, flags, &vec);
    if (!ok) {
        LOGE("Could not list ADB devices");
        return false;
    }

    if (vec.size == 0) {
        LOGE("Could not find any ADB device");
        return false;
    }

    size_t sel_idx; // index of the single matching device if sel_count == 1
    size_t sel_count =
        sc_adb_devices_select(vec.data, vec.size, selector, &sel_idx);

    if (sel_count == 0) {
        // if count > 0 && sel_count == 0, then necessarily a selection is
        // requested
        assert(selector->type != SC_ADB_DEVICE_SELECT_ALL);

        switch (selector->type) {
            case SC_ADB_DEVICE_SELECT_SERIAL:
                assert(selector->serial);
                LOGE("Could not find ADB device %s:", selector->serial);
                break;
            case SC_ADB_DEVICE_SELECT_USB:
                LOGE("Could not find any ADB device over USB:");
                break;
            case SC_ADB_DEVICE_SELECT_TCPIP:
                LOGE("Could not find any ADB device over TCP/IP:");
                break;
            default:
                assert(!"Unexpected selector type");
                break;
        }

        sc_adb_devices_log(SC_LOG_LEVEL_ERROR, vec.data, vec.size);
        sc_adb_devices_destroy(&vec);
        return false;
    }

    if (sel_count > 1) {
        switch (selector->type) {
            case SC_ADB_DEVICE_SELECT_ALL:
                LOGE("Multiple (%" SC_PRIsizet ") ADB devices:", sel_count);
                break;
            case SC_ADB_DEVICE_SELECT_SERIAL:
                assert(selector->serial);
                LOGE("Multiple (%" SC_PRIsizet ") ADB devices with serial %s:",
                     sel_count, selector->serial);
                break;
            case SC_ADB_DEVICE_SELECT_USB:
                LOGE("Multiple (%" SC_PRIsizet ") ADB devices over USB:",
                     sel_count);
                break;
            case SC_ADB_DEVICE_SELECT_TCPIP:
                LOGE("Multiple (%" SC_PRIsizet ") ADB devices over TCP/IP:",
                     sel_count);
                break;
            default:
                assert(!"Unexpected selector type");
                break;
        }
        sc_adb_devices_log(SC_LOG_LEVEL_ERROR, vec.data, vec.size);
        LOGE("Select a device via -s (--serial), -d (--select-usb) or -e "
             "(--select-tcpip)");
        sc_adb_devices_destroy(&vec);
        return false;
    }

    assert(sel_count == 1); // sel_idx is valid only if sel_count == 1
    struct sc_adb_device *device = &vec.data[sel_idx];

    ok = sc_adb_device_check_state(device, vec.data, vec.size);
    if (!ok) {
        sc_adb_devices_destroy(&vec);
        return false;
    }

    LOGI("ADB device found:");
    sc_adb_devices_log(SC_LOG_LEVEL_INFO, vec.data, vec.size);

    // Move devics into out_device (do not destroy device)
    sc_adb_device_move(out_device, device);
    sc_adb_devices_destroy(&vec);
    return true;
}

char *
sc_adb_getprop(struct sc_intr *intr, const char *serial, const char *prop,
               unsigned flags) {
    assert(serial);
    const char *const argv[] =
        SC_ADB_COMMAND("-s", serial, "shell", "getprop", prop);

    sc_pipe pout;
    sc_pid pid = sc_adb_execute_p(argv, flags, &pout);
    if (pid == SC_PROCESS_NONE) {
        LOGE("Could not execute \"adb getprop\"");
        return NULL;
    }

    char buf[128];
    ssize_t r = sc_pipe_read_all_intr(intr, pid, pout, buf, sizeof(buf) - 1);
    sc_pipe_close(pout);

    bool ok = process_check_success_intr(intr, pid, "adb getprop", flags);
    if (!ok) {
        return NULL;
    }

    if (r == -1) {
        return NULL;
    }

    assert((size_t) r < sizeof(buf));
    buf[r] = '\0';
    size_t len = strcspn(buf, " \r\n");
    buf[len] = '\0';

    return strdup(buf);
}

char *
sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags) {
    assert(serial);
    const char *const argv[] =
        SC_ADB_COMMAND("-s", serial, "shell", "ip", "route");

    sc_pipe pout;
    sc_pid pid = sc_adb_execute_p(argv, flags, &pout);
    if (pid == SC_PROCESS_NONE) {
        LOGD("Could not execute \"ip route\"");
        return NULL;
    }

    // "adb shell ip route" output should contain only a few lines
    char buf[1024];
    ssize_t r = sc_pipe_read_all_intr(intr, pid, pout, buf, sizeof(buf) - 1);
    sc_pipe_close(pout);

    bool ok = process_check_success_intr(intr, pid, "ip route", flags);
    if (!ok) {
        return NULL;
    }

    if (r == -1) {
        return NULL;
    }

    assert((size_t) r < sizeof(buf));
    if (r == sizeof(buf) - 1)  {
        // The implementation assumes that the output of "ip route" fits in the
        // buffer in a single pass
        LOGW("Result of \"ip route\" does not fit in 1Kb. "
             "Please report an issue.");
        return NULL;
    }

    // It is parsed as a NUL-terminated string
    buf[r] = '\0';

    return sc_adb_parse_device_ip(buf);
}

uint16_t
sc_adb_get_device_sdk_version(struct sc_intr *intr, const char *serial) {
    char *sdk_version =
        sc_adb_getprop(intr, serial, "ro.build.version.sdk", SC_ADB_SILENT);
    if (!sdk_version) {
        return 0;
    }

    long value;
    bool ok = sc_str_parse_integer(sdk_version, &value);
    free(sdk_version);
    if (!ok || value < 0 || value > 0xFFFF) {
        return 0;
    }

    return value;
}


================================================
FILE: app/src/adb/adb.h
================================================
#ifndef SC_ADB_H
#define SC_ADB_H

#include "common.h"

#include <stdbool.h>
#include <inttypes.h>

#include "adb/adb_device.h"
#include "util/intr.h"

#define SC_ADB_NO_STDOUT (1 << 0)
#define SC_ADB_NO_STDERR (1 << 1)
#define SC_ADB_NO_LOGERR (1 << 2)

#define SC_ADB_SILENT (SC_ADB_NO_STDOUT | SC_ADB_NO_STDERR | SC_ADB_NO_LOGERR)

bool
sc_adb_init(void);

void
sc_adb_destroy(void);

const char *
sc_adb_get_executable(void);

enum sc_adb_device_selector_type {
    SC_ADB_DEVICE_SELECT_ALL,
    SC_ADB_DEVICE_SELECT_SERIAL,
    SC_ADB_DEVICE_SELECT_USB,
    SC_ADB_DEVICE_SELECT_TCPIP,
};

struct sc_adb_device_selector {
    enum sc_adb_device_selector_type type;
    const char *serial;
};

sc_pid
sc_adb_execute(const char *const argv[], unsigned flags);

bool
sc_adb_start_server(struct sc_intr *intr, unsigned flags);

bool
sc_adb_kill_server(struct sc_intr *intr, unsigned flags);

bool
sc_adb_forward(struct sc_intr *intr, const char *serial, uint16_t local_port,
               const char *device_socket_name, unsigned flags);

bool
sc_adb_forward_remove(struct sc_intr *intr, const char *serial,
                      uint16_t local_port, unsigned flags);

bool
sc_adb_reverse(struct sc_intr *intr, const char *serial,
               const char *device_socket_name, uint16_t local_port,
               unsigned flags);

bool
sc_adb_reverse_remove(struct sc_intr *intr, const char *serial,
                      const char *device_socket_name, unsigned flags);

bool
sc_adb_push(struct sc_intr *intr, const char *serial, const char *local,
            const char *remote, unsigned flags);

bool
sc_adb_install(struct sc_intr *intr, const char *serial, const char *local,
               unsigned flags);

/**
 * Execute `adb tcpip <port>`
 */
bool
sc_adb_tcpip(struct sc_intr *intr, const char *serial, uint16_t port,
             unsigned flags);

/**
 * Execute `adb connect <ip_port>`
 *
 * `ip_port` may not be NULL.
 */
bool
sc_adb_connect(struct sc_intr *intr, const char *ip_port, unsigned flags);

/**
 * Execute `adb disconnect [<ip_port>]`
 *
 * If `ip_port` is NULL, execute `adb disconnect`.
 * Otherwise, execute `adb disconnect <ip_port>`.
 */
bool
sc_adb_disconnect(struct sc_intr *intr, const char *ip_port, unsigned flags);

/**
 * Execute `adb devices` and parse the result to select a device
 *
 * Return true if a single matching device is found, and write it to out_device.
 */
bool
sc_adb_select_device(struct sc_intr *intr,
                     const struct sc_adb_device_selector *selector,
                     unsigned flags, struct sc_adb_device *out_device);

/**
 * Execute `adb getprop <prop>`
 */
char *
sc_adb_getprop(struct sc_intr *intr, const char *serial, const char *prop,
               unsigned flags);

/**
 * Attempt to retrieve the device IP
 *
 * Return the IP as a string of the form "xxx.xxx.xxx.xxx", to be freed by the
 * caller, or NULL on error.
 */
char *
sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags);

/**
 * Return the device SDK version.
 */
uint16_t
sc_adb_get_device_sdk_version(struct sc_intr *intr, const char *serial);

#endif


================================================
FILE: app/src/adb/adb_device.c
================================================
#include "adb_device.h"

#include <stdlib.h>
#include <string.h>

void
sc_adb_device_destroy(struct sc_adb_device *device) {
    free(device->serial);
    free(device->state);
    free(device->model);
}

void
sc_adb_device_move(struct sc_adb_device *dst, struct sc_adb_device *src) {
    *dst = *src;
    src->serial = NULL;
    src->state = NULL;
    src->model = NULL;
}

void
sc_adb_devices_destroy(struct sc_vec_adb_devices *devices) {
    for (size_t i = 0; i < devices->size; ++i) {
        sc_adb_device_destroy(&devices->data[i]);
    }
    sc_vector_destroy(devices);
}

enum sc_adb_device_type
sc_adb_device_get_type(const char *serial) {
    // Starts with "emulator-"
    if (!strncmp(serial, "emulator-", sizeof("emulator-") - 1)) {
        return SC_ADB_DEVICE_TYPE_EMULATOR;
    }

    // If the serial contains a ':', then it is a TCP/IP device (it is
    // sufficient to distinguish an ip:port from a real USB serial)
    if (strchr(serial, ':')) {
        return SC_ADB_DEVICE_TYPE_TCPIP;
    }

    return SC_ADB_DEVICE_TYPE_USB;
}


================================================
FILE: app/src/adb/adb_device.h
================================================
#ifndef SC_ADB_DEVICE_H
#define SC_ADB_DEVICE_H

#include "common.h"

#include <stdbool.h>

#include "util/vector.h"

struct sc_adb_device {
    char *serial;
    char *state;
    char *model;
    bool selected;
};

enum sc_adb_device_type {
    SC_ADB_DEVICE_TYPE_USB,
    SC_ADB_DEVICE_TYPE_TCPIP,
    SC_ADB_DEVICE_TYPE_EMULATOR,
};

struct sc_vec_adb_devices SC_VECTOR(struct sc_adb_device);

void
sc_adb_device_destroy(struct sc_adb_device *device);

/**
 * Move src to dst
 *
 * After this call, the content of src is undefined, except that
 * sc_adb_device_destroy() can be called.
 *
 * This is useful to take a device from a list that will be destroyed, without
 * making unnecessary copies.
 */
void
sc_adb_device_move(struct sc_adb_device *dst, struct sc_adb_device *src);

void
sc_adb_devices_destroy(struct sc_vec_adb_devices *devices);

/**
 * Deduce the device type from the serial
 */
enum sc_adb_device_type
sc_adb_device_get_type(const char *serial);

#endif


================================================
FILE: app/src/adb/adb_parser.c
================================================
#include "adb_parser.h"

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#include "util/log.h"
#include "util/str.h"

static bool
sc_adb_parse_device(char *line, struct sc_adb_device *device) {
    // One device line looks like:
    // "0123456789abcdef	device usb:2-1 product:MyProduct model:MyModel "
    //     "device:MyDevice transport_id:1"

    if (line[0] == '*') {
        // Garbage lines printed by adb daemon while starting start with a '*'
        return false;
    }

    if (!strncmp("adb server", line, sizeof("adb server") - 1)) {
        // Ignore lines starting with "adb server":
        //   adb server version (41) doesn't match this client (39); killing...
        return false;
    }

    char *s = line; // cursor in the line

    // After the serial:
    //  - "adb devices" writes a single '\t'
    //  - "adb devices -l" writes multiple spaces
    // For flexibility, accept both.
    size_t serial_len = strcspn(s, " \t");
    if (!serial_len) {
        // empty serial
        return false;
    }
    bool eol = s[serial_len] == '\0';
    if (eol) {
        // serial alone is unexpected
        return false;
    }
    s[serial_len] = '\0';
    char *serial = s;
    s += serial_len + 1;
    // After the serial, there might be several spaces
    s += strspn(s, " \t"); // consume all separators

    size_t state_len = strcspn(s, " ");
    if (!state_len) {
        // empty state
        return false;
    }
    eol = s[state_len] == '\0';
    s[state_len] = '\0';
    char *state = s;

    char *model = NULL;
    if (!eol) {
        s += state_len + 1;

        // Iterate over all properties "key:value key:value ..."
        for (;;) {
            size_t token_len = strcspn(s, " ");
            if (!token_len) {
                break;
            }
            eol = s[token_len] == '\0';
            s[token_len] = '\0';
            char *token = s;

            if (!strncmp("model:", token, sizeof("model:") - 1)) {
                model = &token[sizeof("model:") - 1];
                // We only need the model
                break;
            }

            if (eol) {
                break;
            } else {
                s+= token_len + 1;
            }
        }
    }

    device->serial = strdup(serial);
    if (!device->serial) {
        return false;
    }

    device->state = strdup(state);
    if (!device->state) {
        free(device->serial);
        return false;
    }

    if (model) {
        device->model = strdup(model);
        if (!device->model) {
            LOG_OOM();
            // model is optional, do not fail
        }
    } else {
        device->model = NULL;
    }

    device->selected = false;

    return true;
}

bool
sc_adb_parse_devices(char *str, struct sc_vec_adb_devices *out_vec) {
#define HEADER "List of devices attached"
#define HEADER_LEN (sizeof(HEADER) - 1)
    bool header_found = false;

    size_t idx_line = 0;
    while (str[idx_line] != '\0') {
        char *line = &str[idx_line];
        size_t len = strcspn(line, "\n");

        // The next line starts after the '\n' (replaced by `\0`)
        idx_line += len;

        if (str[idx_line] != '\0') {
            // The next line starts after the '\n'
            ++idx_line;
        }

        if (!header_found) {
            if (!strncmp(line, HEADER, HEADER_LEN)) {
                header_found = true;
            }
            // Skip everything until the header, there might be garbage lines
            // related to daemon starting before
            continue;
        }

        // The line, but without any trailing '\r'
        size_t line_len = sc_str_remove_trailing_cr(line, len);
        line[line_len] = '\0';

        struct sc_adb_device device;
        bool ok = sc_adb_parse_device(line, &device);
        if (!ok) {
            continue;
        }

        ok = sc_vector_push(out_vec, device);
        if (!ok) {
            LOG_OOM();
            LOGE("Could not push adb_device to vector");
            sc_adb_device_destroy(&device);
            // continue anyway
            continue;
        }
    }

    assert(header_found || out_vec->size == 0);
    return header_found;
}

static char *
sc_adb_parse_device_ip_from_line(char *line) {
    // One line from "ip route" looks like:
    // "192.168.1.0/24 dev wlan0  proto kernel  scope link  src 192.168.1.x"

    // Get the location of the device name (index of "wlan0" in the example)
    ssize_t idx_dev_name = sc_str_index_of_column(line, 2, " ");
    if (idx_dev_name == -1) {
        return NULL;
    }

    // Get the location of the ip address (column 8, but column 6 if we start
    // from column 2). Must be computed before truncating individual columns.
    ssize_t idx_ip = sc_str_index_of_column(&line[idx_dev_name], 6, " ");
    if (idx_ip == -1) {
        return NULL;
    }
    // idx_ip is searched from &line[idx_dev_name]
    idx_ip += idx_dev_name;

    char *dev_name = &line[idx_dev_name];
    size_t dev_name_len = strcspn(dev_name, " \t");
    dev_name[dev_name_len] = '\0';

    char *ip = &line[idx_ip];
    size_t ip_len = strcspn(ip, " \t");
    ip[ip_len] = '\0';

    // Only consider lines where the device name starts with "wlan"
    if (strncmp(dev_name, "wlan", sizeof("wlan") - 1)) {
        LOGD("Device ip lookup: ignoring %s (%s)", ip, dev_name);
        return NULL;
    }

    return strdup(ip);
}

char *
sc_adb_parse_device_ip(char *str) {
    size_t idx_line = 0;
    while (str[idx_line] != '\0') {
        char *line = &str[idx_line];
        size_t len = strcspn(line, "\n");
        bool is_last_line = line[len] == '\0';

        // The same, but without any trailing '\r'
        size_t line_len = sc_str_remove_trailing_cr(line, len);
        line[line_len] = '\0';

        char *ip = sc_adb_parse_device_ip_from_line(line);
        if (ip) {
            // Found
            return ip;
        }

        if (is_last_line) {
            break;
        }

        // The next line starts after the '\n'
        idx_line += len + 1;
    }

    return NULL;
}


================================================
FILE: app/src/adb/adb_parser.h
================================================
#ifndef SC_ADB_PARSER_H
#define SC_ADB_PARSER_H

#include "common.h"

#include <stdbool.h>

#include "adb/adb_device.h"

/**
 * Parse the available devices from the output of `adb devices`
 *
 * The parameter must be a NUL-terminated string.
 *
 * Warning: this function modifies the buffer for optimization purposes.
 */
bool
sc_adb_parse_devices(char *str, struct sc_vec_adb_devices *out_vec);

/**
 * Parse the ip from the output of `adb shell ip route`
 *
 * The parameter must be a NUL-terminated string.
 *
 * Warning: this function modifies the buffer for optimization purposes.
 */
char *
sc_adb_parse_device_ip(char *str);

#endif


================================================
FILE: app/src/adb/adb_tunnel.c
================================================
#include "adb_tunnel.h"

#include <assert.h>
#include <inttypes.h>

#include "adb/adb.h"
#include "util/log.h"
#include "util/net_intr.h"

static bool
listen_on_port(struct sc_intr *intr, sc_socket socket, uint16_t port) {
    return net_listen_intr(intr, socket, IPV4_LOCALHOST, port, 1);
}

static bool
enable_tunnel_reverse_any_port(struct sc_adb_tunnel *tunnel,
                               struct sc_intr *intr, const char *serial,
                               const char *device_socket_name,
                               struct sc_port_range port_range) {
    uint16_t port = port_range.first;
    for (;;) {
        if (!sc_adb_reverse(intr, serial, device_socket_name, port,
                            SC_ADB_NO_STDOUT)) {
            // the command itself failed, it will fail on any port
            return false;
        }

        // At the application level, the device part is "the server" because it
        // serves video stream and control. However, at the network level, the
        // client listens and the server connects to the client. That way, the
        // client can listen before starting the server app, so there is no
        // need to try to connect until the server socket is listening on the
        // device.
        sc_socket server_socket = net_socket();
        if (server_socket != SC_SOCKET_NONE) {
            bool ok = listen_on_port(intr, server_socket, port);
            if (ok) {
                // success
                tunnel->server_socket = server_socket;
                tunnel->local_port = port;
                tunnel->enabled = true;
                return true;
            }

            net_close(server_socket);
        }

        if (sc_intr_is_interrupted(intr)) {
            // Stop immediately
            return false;
        }

        // failure, disable tunnel and try another port
        if (!sc_adb_reverse_remove(intr, serial, device_socket_name,
                                SC_ADB_NO_STDOUT)) {
            LOGW("Could not remove reverse tunnel on port %" PRIu16, port);
        }

        // check before incrementing to avoid overflow on port 65535
        if (port < port_range.last) {
            LOGW("Could not listen on port %" PRIu16", retrying on %" PRIu16,
                 port, (uint16_t) (port + 1));
            port++;
            continue;
        }

        if (port_range.first == port_range.last) {
            LOGE("Could not listen on port %" PRIu16, port_range.first);
        } else {
            LOGE("Could not listen on any port in range %" PRIu16 ":%" PRIu16,
                 port_range.first, port_range.last);
        }
        return false;
    }
}

static bool
enable_tunnel_forward_any_port(struct sc_adb_tunnel *tunnel,
                               struct sc_intr *intr, const char *serial,
                               const char *device_socket_name,
                               struct sc_port_range port_range) {
    tunnel->forward = true;

    uint16_t port = port_range.first;
    for (;;) {
        if (sc_adb_forward(intr, serial, port, device_socket_name,
                           SC_ADB_NO_STDOUT)) {
            // success
            tunnel->local_port = port;
            tunnel->enabled = true;
            return true;
        }

        if (sc_intr_is_interrupted(intr)) {
            // Stop immediately
            return false;
        }

        if (port < port_range.last) {
            LOGW("Could not forward port %" PRIu16", retrying on %" PRIu16,
                 port, (uint16_t) (port + 1));
            port++;
            continue;
        }

        if (port_range.first == port_range.last) {
            LOGE("Could not forward port %" PRIu16, port_range.first);
        } else {
            LOGE("Could not forward any port in range %" PRIu16 ":%" PRIu16,
                 port_range.first, port_range.last);
        }
        return false;
    }
}

void
sc_adb_tunnel_init(struct sc_adb_tunnel *tunnel) {
    tunnel->enabled = false;
    tunnel->forward = false;
    tunnel->server_socket = SC_SOCKET_NONE;
    tunnel->local_port = 0;
}

bool
sc_adb_tunnel_open(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
                   const char *serial, const char *device_socket_name,
                   struct sc_port_range port_range, bool force_adb_forward) {
    assert(!tunnel->enabled);

    if (!force_adb_forward) {
        // Attempt to use "adb reverse"
        if (enable_tunnel_reverse_any_port(tunnel, intr, serial,
                                           device_socket_name, port_range)) {
            return true;
        }

        // if "adb reverse" does not work (e.g. over "adb connect"), it
        // fallbacks to "adb forward", so the app socket is the client

        LOGW("'adb reverse' failed, fallback to 'adb forward'");
    }

    return enable_tunnel_forward_any_port(tunnel, intr, serial,
                                          device_socket_name, port_range);
}

bool
sc_adb_tunnel_close(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
                    const char *serial, const char *device_socket_name) {
    assert(tunnel->enabled);

    bool ret;
    if (tunnel->forward) {
        ret = sc_adb_forward_remove(intr, serial, tunnel->local_port,
                                    SC_ADB_NO_STDOUT);
    } else {
        ret = sc_adb_reverse_remove(intr, serial, device_socket_name,
                                    SC_ADB_NO_STDOUT);

        assert(tunnel->server_socket != SC_SOCKET_NONE);
        if (!net_close(tunnel->server_socket)) {
            LOGW("Could not close server socket");
        }

        // server_socket is never used anymore
    }

    // Consider tunnel disabled even if the command failed
    tunnel->enabled = false;

    return ret;
}


================================================
FILE: app/src/adb/adb_tunnel.h
================================================
#ifndef SC_ADB_TUNNEL_H
#define SC_ADB_TUNNEL_H

#include "common.h"

#include <stdbool.h>
#include <stdint.h>

#include "options.h"
#include "util/intr.h"
#include "util/net.h"

struct sc_adb_tunnel {
    bool enabled;
    bool forward; // use "adb forward" instead of "adb reverse"
    sc_socket server_socket; // only used if !forward
    uint16_t local_port;
};

/**
 * Initialize the adb tunnel struct to default values
 */
void
sc_adb_tunnel_init(struct sc_adb_tunnel *tunnel);

/**
 * Open a tunnel
 *
 * Blocking calls may be interrupted asynchronously via `intr`.
 *
 * If `force_adb_forward` is not set, then attempts to set up an "adb reverse"
 * tunnel first. Only if it fails (typical on old Android version connected via
 * TCP/IP), use "adb forward".
 */
bool
sc_adb_tunnel_open(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
                   const char *serial, const char *device_socket_name,
                   struct sc_port_range port_range, bool force_adb_forward);

/**
 * Close the tunnel
 */
bool
sc_adb_tunnel_close(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
                    const char *serial, const char *device_socket_name);

#endif


================================================
FILE: app/src/android/input.h
================================================
// copied from <https://android.googlesource.com/platform/frameworks/native/+/master/include/android/input.h>
// blob 08299899b6305a0fe74d7d2b8471b7cd0af49dc7
// (and modified)
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * 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.
 */

#ifndef _ANDROID_INPUT_H
#define _ANDROID_INPUT_H

/**
 * Meta key / modifier state.
 */
enum android_metastate {
    /** No meta keys are pressed. */
    AMETA_NONE = 0,

    /** This mask is used to check whether one of the ALT meta keys is pressed. */
    AMETA_ALT_ON = 0x02,

    /** This mask is used to check whether the left ALT meta key is pressed. */
    AMETA_ALT_LEFT_ON = 0x10,

    /** This mask is used to check whether the right ALT meta key is pressed. */
    AMETA_ALT_RIGHT_ON = 0x20,

    /** This mask is used to check whether one of the SHIFT meta keys is pressed. */
    AMETA_SHIFT_ON = 0x01,

    /** This mask is used to check whether the left SHIFT meta key is pressed. */
    AMETA_SHIFT_LEFT_ON = 0x40,

    /** This mask is used to check whether the right SHIFT meta key is pressed. */
    AMETA_SHIFT_RIGHT_ON = 0x80,

    /** This mask is used to check whether the SYM meta key is pressed. */
    AMETA_SYM_ON = 0x04,

    /** This mask is used to check whether the FUNCTION meta key is pressed. */
    AMETA_FUNCTION_ON = 0x08,

    /** This mask is used to check whether one of the CTRL meta keys is pressed. */
    AMETA_CTRL_ON = 0x1000,

    /** This mask is used to check whether the left CTRL meta key is pressed. */
    AMETA_CTRL_LEFT_ON = 0x2000,

    /** This mask is used to check whether the right CTRL meta key is pressed. */
    AMETA_CTRL_RIGHT_ON = 0x4000,

    /** This mask is used to check whether one of the META meta keys is pressed. */
    AMETA_META_ON = 0x10000,

    /** This mask is used to check whether the left META meta key is pressed. */
    AMETA_META_LEFT_ON = 0x20000,

    /** This mask is used to check whether the right META meta key is pressed. */
    AMETA_META_RIGHT_ON = 0x40000,

    /** This mask is used to check whether the CAPS LOCK meta key is on. */
    AMETA_CAPS_LOCK_ON = 0x100000,

    /** This mask is used to check whether the NUM LOCK meta key is on. */
    AMETA_NUM_LOCK_ON = 0x200000,

    /** This mask is used to check whether the SCROLL LOCK meta key is on. */
    AMETA_SCROLL_LOCK_ON = 0x400000,
};

/**
 * Input event types.
 */
enum android_input_event_type {
    /** Indicates that the input event is a key event. */
    AINPUT_EVENT_TYPE_KEY = 1,
    /** Indicates that the input event is a motion event. */
    AINPUT_EVENT_TYPE_MOTION = 2
};

/**
 * Key event actions.
 */
enum android_keyevent_action {
    /** The key has been pressed down. */
    AKEY_EVENT_ACTION_DOWN = 0,

    /** The key has been released. */
    AKEY_EVENT_ACTION_UP = 1,

    /**
     * Multiple duplicate key events have occurred in a row, or a
     * complex string is being delivered.  The repeat_count property
     * of the key event contains the number of times the given key
     * code should be executed.
     */
    AKEY_EVENT_ACTION_MULTIPLE = 2
};

/**
 * Key event flags.
 */
enum android_keyevent_flags {
    /** This mask is set if the device woke because of this key event. */
    AKEY_EVENT_FLAG_WOKE_HERE = 0x1,

    /** This mask is set if the key event was generated by a software keyboard. */
    AKEY_EVENT_FLAG_SOFT_KEYBOARD = 0x2,

    /** This mask is set if we don't want the key event to cause us to leave touch mode. */
    AKEY_EVENT_FLAG_KEEP_TOUCH_MODE = 0x4,

    /**
     * This mask is set if an event was known to come from a trusted
     * part of the system.  That is, the event is known to come from
     * the user, and could not have been spoofed by a third party
     * component.
     */
    AKEY_EVENT_FLAG_FROM_SYSTEM = 0x8,

    /**
     * This mask is used for compatibility, to identify enter keys that are
     * coming from an IME whose enter key has been auto-labelled "next" or
     * "done".  This allows TextView to dispatch these as normal enter keys
     * for old applications, but still do the appropriate action when
     * receiving them.
     */
    AKEY_EVENT_FLAG_EDITOR_ACTION = 0x10,

    /**
     * When associated with up key events, this indicates that the key press
     * has been canceled.  Typically this is used with virtual touch screen
     * keys, where the user can slide from the virtual key area on to the
     * display: in that case, the application will receive a canceled up
     * event and should not perform the action normally associated with the
     * key.  Note that for this to work, the application can not perform an
     * action for a key until it receives an up or the long press timeout has
     * expired.
     */
    AKEY_EVENT_FLAG_CANCELED = 0x20,

    /**
     * This key event was generated by a virtual (on-screen) hard key area.
     * Typically this is an area of the touchscreen, outside of the regular
     * display, dedicated to "hardware" buttons.
     */
    AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY = 0x40,

    /**
     * This flag is set for the first key repeat that occurs after the
     * long press timeout.
     */
    AKEY_EVENT_FLAG_LONG_PRESS = 0x80,

    /**
     * Set when a key event has AKEY_EVENT_FLAG_CANCELED set because a long
     * press action was executed while it was down.
     */
    AKEY_EVENT_FLAG_CANCELED_LONG_PRESS = 0x100,

    /**
     * Set for AKEY_EVENT_ACTION_UP when this event's key code is still being
     * tracked from its initial down.  That is, somebody requested that tracking
     * started on the key down and a long press has not caused
     * the tracking to be canceled.
     */
    AKEY_EVENT_FLAG_TRACKING = 0x200,

    /**
     * Set when a key event has been synthesized to implement default behavior
     * for an event that the application did not handle.
     * Fallback key events are generated by unhandled trackball motions
     * (to emulate a directional keypad) and by certain unhandled key presses
     * that are declared in the key map (such as special function numeric keypad
     * keys when numlock is off).
     */
    AKEY_EVENT_FLAG_FALLBACK = 0x400,
};

/**
 * Bit shift for the action bits holding the pointer index as
 * defined by AMOTION_EVENT_ACTION_POINTER_INDEX_MASK.
 */
#define AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT 8

/** Motion event actions */
enum android_motionevent_action {
    /** Bit mask of the parts of the action code that are the action itself. */
    AMOTION_EVENT_ACTION_MASK = 0xff,

    /**
     * Bits in the action code that represent a pointer index, used with
     * AMOTION_EVENT_ACTION_POINTER_DOWN and AMOTION_EVENT_ACTION_POINTER_UP.  Shifting
     * down by AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT provides the actual pointer
     * index where the data for the pointer going up or down can be found.
     */
    AMOTION_EVENT_ACTION_POINTER_INDEX_MASK  = 0xff00,

    /** A pressed gesture has started, the motion contains the initial starting location. */
    AMOTION_EVENT_ACTION_DOWN = 0,

    /**
     * A pressed gesture has finished, the motion contains the final release location
     * as well as any intermediate points since the last down or move event.
     */
    AMOTION_EVENT_ACTION_UP = 1,

    /**
     * A change has happened during a press gesture (between AMOTION_EVENT_ACTION_DOWN and
     * AMOTION_EVENT_ACTION_UP).  The motion contains the most recent point, as well as
     * any intermediate points since the last down or move event.
     */
    AMOTION_EVENT_ACTION_MOVE = 2,

    /**
     * The current gesture has been aborted.
     * You will not receive any more points in it.  You should treat this as
     * an up event, but not perform any action that you normally would.
     */
    AMOTION_EVENT_ACTION_CANCEL = 3,

    /**
     * A movement has happened outside of the normal bounds of the UI element.
     * This does not provide a full gesture, but only the initial location of the movement/touch.
     */
    AMOTION_EVENT_ACTION_OUTSIDE = 4,

    /**
     * A non-primary pointer has gone down.
     * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed.
     */
    AMOTION_EVENT_ACTION_POINTER_DOWN = 5,

    /**
     * A non-primary pointer has gone up.
     * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed.
     */
    AMOTION_EVENT_ACTION_POINTER_UP = 6,

    /**
     * A change happened but the pointer is not down (unlike AMOTION_EVENT_ACTION_MOVE).
     * The motion contains the most recent point, as well as any intermediate points since
     * the last hover move event.
     */
    AMOTION_EVENT_ACTION_HOVER_MOVE = 7,

    /**
     * The motion event contains relative vertical and/or horizontal scroll offsets.
     * Use getAxisValue to retrieve the information from AMOTION_EVENT_AXIS_VSCROLL
     * and AMOTION_EVENT_AXIS_HSCROLL.
     * The pointer may or may not be down when this event is dispatched.
     * This action is always delivered to the winder under the pointer, which
     * may not be the window currently touched.
     */
    AMOTION_EVENT_ACTION_SCROLL = 8,

    /** The pointer is not down but has entered the boundaries of a window or view. */
    AMOTION_EVENT_ACTION_HOVER_ENTER = 9,

    /** The pointer is not down but has exited the boundaries of a window or view. */
    AMOTION_EVENT_ACTION_HOVER_EXIT = 10,

    /* One or more buttons have been pressed. */
    AMOTION_EVENT_ACTION_BUTTON_PRESS = 11,

    /* One or more buttons have been released. */
    AMOTION_EVENT_ACTION_BUTTON_RELEASE = 12,
};

/**
 * Motion event flags.
 */
enum android_motionevent_flags {
    /**
     * This flag indicates that the window that received this motion event is partly
     * or wholly obscured by another visible window above it.  This flag is set to true
     * even if the event did not directly pass through the obscured area.
     * A security sensitive application can check this flag to identify situations in which
     * a malicious application may have covered up part of its content for the purpose
     * of misleading the user or hijacking touches.  An appropriate response might be
     * to drop the suspect touches or to take additional precautions to confirm the user's
     * actual intent.
     */
    AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED = 0x1,
};

/**
 * Motion event edge touch flags.
 */
enum android_motionevent_edge_touch_flags {
    /** No edges intersected. */
    AMOTION_EVENT_EDGE_FLAG_NONE = 0,

    /** Flag indicating the motion event intersected the top edge of the screen. */
    AMOTION_EVENT_EDGE_FLAG_TOP = 0x01,

    /** Flag indicating the motion event intersected the bottom edge of the screen. */
    AMOTION_EVENT_EDGE_FLAG_BOTTOM = 0x02,

    /** Flag indicating the motion event intersected the left edge of the screen. */
    AMOTION_EVENT_EDGE_FLAG_LEFT = 0x04,

    /** Flag indicating the motion event intersected the right edge of the screen. */
    AMOTION_EVENT_EDGE_FLAG_RIGHT = 0x08
};

/**
 * Constants that identify each individual axis of a motion event.
 * @anchor AMOTION_EVENT_AXIS
 */
enum android_motionevent_axis {
    /**
     * Axis constant: X axis of a motion event.
     *
     * - For a touch screen, reports the absolute X screen position of the center of
     * the touch contact area.  The units are display pixels.
     * - For a touch pad, reports the absolute X surface position of the center of the touch
     * contact area. The units are device-dependent.
     * - For a mouse, reports the absolute X screen position of the mouse pointer.
     * The units are display pixels.
     * - For a trackball, reports the relative horizontal displacement of the trackball.
     * The value is normalized to a range from -1.0 (left) to 1.0 (right).
     * - For a joystick, reports the absolute X position of the joystick.
     * The value is normalized to a range from -1.0 (left) to 1.0 (right).
     */
    AMOTION_EVENT_AXIS_X = 0,
    /**
     * Axis constant: Y axis of a motion event.
     *
     * - For a touch screen, reports the absolute Y screen position of the center of
     * the touch contact area.  The units are display pixels.
     * - For a touch pad, reports the absolute Y surface position of the center of the touch
     * contact area. The units are device-dependent.
     * - For a mouse, reports the absolute Y screen position of the mouse pointer.
     * The units are display pixels.
     * - For a trackball, reports the relative vertical displacement of the trackball.
     * The value is normalized to a range from -1.0 (up) to 1.0 (down).
     * - For a joystick, reports the absolute Y position of the joystick.
     * The value is normalized to a range from -1.0 (up or far) to 1.0 (down or near).
     */
    AMOTION_EVENT_AXIS_Y = 1,
    /**
     * Axis constant: Pressure axis of a motion event.
     *
     * - For a touch screen or touch pad, reports the approximate pressure applied to the surface
     * by a finger or other tool.  The value is normalized to a range from
     * 0 (no pressure at all) to 1 (normal pressure), although values higher than 1
     * may be generated depending on the calibration of the input device.
     * - For a trackball, the value is set to 1 if the trackball button is pressed
     * or 0 otherwise.
     * - For a mouse, the value is set to 1 if the primary mouse button is pressed
     * or 0 otherwise.
     */
    AMOTION_EVENT_AXIS_PRESSURE = 2,
    /**
     * Axis constant: Size axis of a motion event.
     *
     * - For a touch screen or touch pad, reports the approximate size of the contact area in
     * relation to the maximum detectable size for the device.  The value is normalized
     * to a range from 0 (smallest detectable size) to 1 (largest detectable size),
     * although it is not a linear scale. This value is of limited use.
     * To obtain calibrated size information, see
     * {@link AMOTION_EVENT_AXIS_TOUCH_MAJOR} or {@link AMOTION_EVENT_AXIS_TOOL_MAJOR}.
     */
    AMOTION_EVENT_AXIS_SIZE = 3,
    /**
     * Axis constant: TouchMajor axis of a motion event.
     *
     * - For a touch screen, reports the length of the major axis of an ellipse that
     * represents the touch area at the point of contact.
     * The units are display pixels.
     * - For a touch pad, reports the length of the major axis of an ellipse that
     * represents the touch area at the point of contact.
     * The units are device-dependent.
     */
    AMOTION_EVENT_AXIS_TOUCH_MAJOR = 4,
    /**
     * Axis constant: TouchMinor axis of a motion event.
     *
     * - For a touch screen, reports the length of the minor axis of an ellipse that
     * represents the touch area at the point of contact.
     * The units are display pixels.
     * - For a touch pad, reports the length of the minor axis of an ellipse that
     * represents the touch area at the point of contact.
     * The units are device-dependent.
     *
     * When the touch is circular, the major and minor axis lengths will be equal to one another.
     */
    AMOTION_EVENT_AXIS_TOUCH_MINOR = 5,
    /**
     * Axis constant: ToolMajor axis of a motion event.
     *
     * - For a touch screen, reports the length of the major axis of an ellipse that
     * represents the size of the approaching finger or tool used to make contact.
     * - For a touch pad, reports the length of the major axis of an ellipse that
     * represents the size of the approaching finger or tool used to make contact.
     * The units are device-dependent.
     *
     * When the touch is circular, the major and minor axis lengths will be equal to one another.
     *
     * The tool size may be larger than the touch size since the tool may not be fully
     * in contact with the touch sensor.
     */
    AMOTION_EVENT_AXIS_TOOL_MAJOR = 6,
    /**
     * Axis constant: ToolMinor axis of a motion event.
     *
     * - For a touch screen, reports the length of the minor axis of an ellipse that
     * represents the size of the approaching finger or tool used to make contact.
     * - For a touch pad, reports the length of the minor axis of an ellipse that
     * represents the size of the approaching finger or tool used to make contact.
     * The units are device-dependent.
     *
     * When the touch is circular, the major and minor axis lengths will be equal to one another.
     *
     * The tool size may be larger than the touch size since the tool may not be fully
     * in contact with the touch sensor.
     */
    AMOTION_EVENT_AXIS_TOOL_MINOR = 7,
    /**
     * Axis constant: Orientation axis of a motion event.
     *
     * - For a touch screen or touch pad, reports the orientation of the finger
     * or tool in radians relative to the vertical plane of the device.
     * An angle of 0 radians indicates that the major axis of contact is oriented
     * upwards, is perfectly circular or is of unknown orientation.  A positive angle
     * indicates that the major axis of contact is oriented to the right.  A negative angle
     * indicates that the major axis of contact is oriented to the left.
     * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
     * (finger pointing fully right).
     * - For a stylus, the orientation indicates the direction in which the stylus
     * is pointing in relation to the vertical axis of the current orientation of the screen.
     * The range is from -PI radians to PI radians, where 0 is pointing up,
     * -PI/2 radians is pointing left, -PI or PI radians is pointing down, and PI/2 radians
     * is pointing right.  See also {@link AMOTION_EVENT_AXIS_TILT}.
     */
    AMOTION_EVENT_AXIS_ORIENTATION = 8,
    /**
     * Axis constant: Vertical Scroll axis of a motion event.
     *
     * - For a mouse, reports the relative movement of the vertical scroll wheel.
     * The value is normalized to a range from -1.0 (down) to 1.0 (up).
     *
     * This axis should be used to scroll views vertically.
     */
    AMOTION_EVENT_AXIS_VSCROLL = 9,
    /**
     * Axis constant: Horizontal Scroll axis of a motion event.
     *
     * - For a mouse, reports the relative movement of the horizontal scroll wheel.
     * The value is normalized to a range from -1.0 (left) to 1.0 (right).
     *
     * This axis should be used to scroll views horizontally.
     */
    AMOTION_EVENT_AXIS_HSCROLL = 10,
    /**
     * Axis constant: Z axis of a motion event.
     *
     * - For a joystick, reports the absolute Z position of the joystick.
     * The value is normalized to a range from -1.0 (high) to 1.0 (low).
     * <em>On game pads with two analog joysticks, this axis is often reinterpreted
     * to report the absolute X position of the second joystick instead.</em>
     */
    AMOTION_EVENT_AXIS_Z = 11,
    /**
     * Axis constant: X Rotation axis of a motion event.
     *
     * - For a joystick, reports the absolute rotation angle about the X axis.
     * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
     */
    AMOTION_EVENT_AXIS_RX = 12,
    /**
     * Axis constant: Y Rotation axis of a motion event.
     *
     * - For a joystick, reports the absolute rotation angle about the Y axis.
     * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
     */
    AMOTION_EVENT_AXIS_RY = 13,
    /**
     * Axis constant: Z Rotation axis of a motion event.
     *
     * - For a joystick, reports the absolute rotation angle about the Z axis.
     * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
     * On game pads with two analog joysticks, this axis is often reinterpreted
     * to report the absolute Y position of the second joystick instead.
     */
    AMOTION_EVENT_AXIS_RZ = 14,
    /**
     * Axis constant: Hat X axis of a motion event.
     *
     * - For a joystick, reports the absolute X position of the directional hat control.
     * The value is normalized to a range from -1.0 (left) to 1.0 (right).
     */
    AMOTION_EVENT_AXIS_HAT_X = 15,
    /**
     * Axis constant: Hat Y axis of a motion event.
     *
     * - For a joystick, reports the absolute Y position of the directional hat control.
     * The value is normalized to a range from -1.0 (up) to 1.0 (down).
     */
    AMOTION_EVENT_AXIS_HAT_Y = 16,
    /**
     * Axis constant: Left Trigger axis of a motion event.
     *
     * - For a joystick, reports the absolute position of the left trigger control.
     * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed).
     */
    AMOTION_EVENT_AXIS_LTRIGGER = 17,
    /**
     * Axis constant: Right Trigger axis of a motion event.
     *
     * - For a joystick, reports the absolute position of the right trigger control.
     * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed).
     */
    AMOTION_EVENT_AXIS_RTRIGGER = 18,
    /**
     * Axis constant: Throttle axis of a motion event.
     *
     * - For a joystick, reports the absolute position of the throttle control.
     * The value is normalized to a range from 0.0 (fully open) to 1.0 (fully closed).
     */
    AMOTION_EVENT_AXIS_THROTTLE = 19,
    /**
     * Axis constant: Rudder axis of a motion event.
     *
     * - For a joystick, reports the absolute position of the rudder control.
     * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
     */
    AMOTION_EVENT_AXIS_RUDDER = 20,
    /**
     * Axis constant: Wheel axis of a motion event.
     *
     * - For a joystick, reports the absolute position of the steering wheel control.
     * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
     */
    AMOTION_EVENT_AXIS_WHEEL = 21,
    /**
     * Axis constant: Gas axis of a motion event.
     *
     * - For a joystick, reports the absolute position of the gas (accelerator) control.
     * The value is normalized to a range from 0.0 (no acceleration)
     * to 1.0 (maximum acceleration).
     */
    AMOTION_EVENT_AXIS_GAS = 22,
    /**
     * Axis constant: Brake axis of a motion event.
     *
     * - For a joystick, reports the absolute position of the brake control.
     * The value is normalized to a range from 0.0 (no braking) to 1.0 (maximum braking).
     */
    AMOTION_EVENT_AXIS_BRAKE = 23,
    /**
     * Axis constant: Distance axis of a motion event.
     *
     * - For a stylus, reports the distance of the stylus from the screen.
     * A value of 0.0 indicates direct contact and larger values indicate increasing
     * distance from the surface.
     */
    AMOTION_EVENT_AXIS_DISTANCE = 24,
    /**
     * Axis constant: Tilt axis of a motion event.
     *
     * - For a stylus, reports the tilt angle of the stylus in radians where
     * 0 radians indicates that the stylus is being held perpendicular to the
     * surface, and PI/2 radians indicates that the stylus is being held flat
     * against the surface.
     */
    AMOTION_EVENT_AXIS_TILT = 25,
    /**
     * Axis constant:  Generic scroll axis of a motion event.
     *
     * - This is used for scroll axis motion events that can't be classified as strictly
     *   vertical or horizontal. The movement of a rotating scroller is an example of this.
     */
    AMOTION_EVENT_AXIS_SCROLL = 26,
    /**
     * Axis constant: The movement of x position of a motion event.
     *
     * - For a mouse, reports a difference of x position between the previous position.
     * This is useful when pointer is captured, in that case the mouse pointer doesn't
     * change the location but this axis reports the difference which allows the app
     * to see how the mouse is moved.
     */
    AMOTION_EVENT_AXIS_RELATIVE_X = 27,
    /**
     * Axis constant: The movement of y position of a motion event.
     *
     * Same as {@link RELATIVE_X}, but for y position.
     */
    AMOTION_EVENT_AXIS_RELATIVE_Y = 28,
    /**
     * Axis constant: Generic 1 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_1 = 32,
    /**
     * Axis constant: Generic 2 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_2 = 33,
    /**
     * Axis constant: Generic 3 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_3 = 34,
    /**
     * Axis constant: Generic 4 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_4 = 35,
    /**
     * Axis constant: Generic 5 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_5 = 36,
    /**
     * Axis constant: Generic 6 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_6 = 37,
    /**
     * Axis constant: Generic 7 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_7 = 38,
    /**
     * Axis constant: Generic 8 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_8 = 39,
    /**
     * Axis constant: Generic 9 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_9 = 40,
    /**
     * Axis constant: Generic 10 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_10 = 41,
    /**
     * Axis constant: Generic 11 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_11 = 42,
    /**
     * Axis constant: Generic 12 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_12 = 43,
    /**
     * Axis constant: Generic 13 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_13 = 44,
    /**
     * Axis constant: Generic 14 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_14 = 45,
    /**
     * Axis constant: Generic 15 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_15 = 46,
    /**
     * Axis constant: Generic 16 axis of a motion event.
     * The interpretation of a generic axis is device-specific.
     */
    AMOTION_EVENT_AXIS_GENERIC_16 = 47,

    // NOTE: If you add a new axis here you must also add it to several other files.
    //       Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
};

/**
 * Constants that identify buttons that are associated with motion events.
 * Refer to the documentation on the MotionEvent class for descriptions of each button.
 */
enum android_motionevent_buttons {
    /** primary */
    AMOTION_EVENT_BUTTON_PRIMARY = 1 << 0,
    /** secondary */
    AMOTION_EVENT_BUTTON_SECONDARY = 1 << 1,
    /** tertiary */
    AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2,
    /** back */
    AMOTION_EVENT_BUTTON_BACK = 1 << 3,
    /** forward */
    AMOTION_EVENT_BUTTON_FORWARD = 1 << 4,
    AMOTION_EVENT_BUTTON_STYLUS_PRIMARY = 1 << 5,
    AMOTION_EVENT_BUTTON_STYLUS_SECONDARY = 1 << 6,
};

/**
 * Constants that identify tool types.
 * Refer to the documentation on the MotionEvent class for descriptions of each tool type.
 */
enum android_motionevent_tool_type {
    /** unknown */
    AMOTION_EVENT_TOOL_TYPE_UNKNOWN = 0,
    /** finger */
    AMOTION_EVENT_TOOL_TYPE_FINGER = 1,
    /** stylus */
    AMOTION_EVENT_TOOL_TYPE_STYLUS = 2,
    /** mouse */
    AMOTION_EVENT_TOOL_TYPE_MOUSE = 3,
    /** eraser */
    AMOTION_EVENT_TOOL_TYPE_ERASER = 4,
};

/**
 * Input source masks.
 *
 * Refer to the documentation on android.view.InputDevice for more details about input sources
 * and their correct interpretation.
 */
enum android_input_source_class {
    /** mask */
    AINPUT_SOURCE_CLASS_MASK = 0x000000ff,

    /** none */
    AINPUT_SOURCE_CLASS_NONE = 0x00000000,
    /** button */
    AINPUT_SOURCE_CLASS_BUTTON = 0x00000001,
    /** pointer */
    AINPUT_SOURCE_CLASS_POINTER = 0x00000002,
    /** navigation */
    AINPUT_SOURCE_CLASS_NAVIGATION = 0x00000004,
    /** position */
    AINPUT_SOURCE_CLASS_POSITION = 0x00000008,
    /** joystick */
    AINPUT_SOURCE_CLASS_JOYSTICK = 0x00000010,
};

/**
 * Input sources.
 */
enum android_input_source {
    /** unknown */
    AINPUT_SOURCE_UNKNOWN = 0x00000000,

    /** keyboard */
    AINPUT_SOURCE_KEYBOARD = 0x00000100 | AINPUT_SOURCE_CLASS_BUTTON,
    /** dpad */
    AINPUT_SOURCE_DPAD = 0x00000200 | AINPUT_SOURCE_CLASS_BUTTON,
    /** gamepad */
    AINPUT_SOURCE_GAMEPAD = 0x00000400 | AINPUT_SOURCE_CLASS_BUTTON,
    /** touchscreen */
    AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER,
    /** mouse */
    AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER,
    /** stylus */
    AINPUT_SOURCE_STYLUS = 0x00004000 | AINPUT_SOURCE_CLASS_POINTER,
    /** bluetooth stylus */
    AINPUT_SOURCE_BLUETOOTH_STYLUS = 0x00008000 | AINPUT_SOURCE_STYLUS,
    /** trackball */
    AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION,
    /** mouse relative */
    AINPUT_SOURCE_MOUSE_RELATIVE = 0x00020000 | AINPUT_SOURCE_CLASS_NAVIGATION,
    /** touchpad */
    AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION,
    /** navigation */
    AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE,
    /** joystick */
    AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
    /** rotary encoder */
    AINPUT_SOURCE_ROTARY_ENCODER = 0x00400000 | AINPUT_SOURCE_CLASS_NONE,
};

/**
 * Keyboard types.
 *
 * Refer to the documentation on android.view.InputDevice for more details.
 */
enum android_keyboard_type {
    /** none */
    AINPUT_KEYBOARD_TYPE_NONE = 0,
    /** non alphabetic */
    AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC = 1,
    /** alphabetic */
    AINPUT_KEYBOARD_TYPE_ALPHABETIC = 2,
};

/**
 * Constants used to retrieve information about the range of motion for a particular
 * coordinate of a motion event.
 *
 * Refer to the documentation on android.view.InputDevice for more details about input sources
 * and their correct interpretation.
 *
 * @deprecated These constants are deprecated. Use {@link AMOTION_EVENT_AXIS AMOTION_EVENT_AXIS_*} constants instead.
 */
enum android_motion_range {
    /** x */
    AINPUT_MOTION_RANGE_X = AMOTION_EVENT_AXIS_X,
    /** y */
    AINPUT_MOTION_RANGE_Y = AMOTION_EVENT_AXIS_Y,
    /** pressure */
    AINPUT_MOTION_RANGE_PRESSURE = AMOTION_EVENT_AXIS_PRESSURE,
    /** size */
    AINPUT_MOTION_RANGE_SIZE = AMOTION_EVENT_AXIS_SIZE,
    /** touch major */
    AINPUT_MOTION_RANGE_TOUCH_MAJOR = AMOTION_EVENT_AXIS_TOUCH_MAJOR,
    /** touch minor */
    AINPUT_MOTION_RANGE_TOUCH_MINOR = AMOTION_EVENT_AXIS_TOUCH_MINOR,
    /** tool major */
    AINPUT_MOTION_RANGE_TOOL_MAJOR = AMOTION_EVENT_AXIS_TOOL_MAJOR,
    /** tool minor */
    AINPUT_MOTION_RANGE_TOOL_MINOR = AMOTION_EVENT_AXIS_TOOL_MINOR,
    /** orientation */
    AINPUT_MOTION_RANGE_ORIENTATION = AMOTION_EVENT_AXIS_ORIENTATION,
};

#endif // _ANDROID_INPUT_H


================================================
FILE: app/src/android/keycodes.h
================================================
// copied from <https://android.googlesource.com/platform/frameworks/native/+/master/include/android/keycodes.h>
// blob 2164d6163e1646c22825e364cad4f3c47638effd
// (and modified)
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * 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.
 */

#ifndef _ANDROID_KEYCODES_H
#define _ANDROID_KEYCODES_H

/**
 * Key codes.
 */
enum android_keycode {
    /** Unknown key code. */
    AKEYCODE_UNKNOWN         = 0,
    /** Soft Left key.
     * Usually situated below the display on phones and used as a multi-function
     * feature key for selecting a software defined function shown on the bottom left
     * of the display. */
    AKEYCODE_SOFT_LEFT       = 1,
    /** Soft Right key.
     * Usually situated below the display on phones and used as a multi-function
     * feature key for selecting a software defined function shown on the bottom right
     * of the display. */
    AKEYCODE_SOFT_RIGHT      = 2,
    /** Home key.
     * This key is handled by the framework and is never delivered to applications. */
    AKEYCODE_HOME            = 3,
    /** Back key. */
    AKEYCODE_BACK            = 4,
    /** Call key. */
    AKEYCODE_CALL            = 5,
    /** End Call key. */
    AKEYCODE_ENDCALL         = 6,
    /** '0' key. */
    AKEYCODE_0               = 7,
    /** '1' key. */
    AKEYCODE_1               = 8,
    /** '2' key. */
    AKEYCODE_2               = 9,
    /** '3' key. */
    AKEYCODE_3               = 10,
    /** '4' key. */
    AKEYCODE_4               = 11,
    /** '5' key. */
    AKEYCODE_5               = 12,
    /** '6' key. */
    AKEYCODE_6               = 13,
    /** '7' key. */
    AKEYCODE_7               = 14,
    /** '8' key. */
    AKEYCODE_8               = 15,
    /** '9' key. */
    AKEYCODE_9               = 16,
    /** '*' key. */
    AKEYCODE_STAR            = 17,
    /** '#' key. */
    AKEYCODE_POUND           = 18,
    /** Directional Pad Up key.
     * May also be synthesized from trackball motions. */
    AKEYCODE_DPAD_UP         = 19,
    /** Directional Pad Down key.
     * May also be synthesized from trackball motions. */
    AKEYCODE_DPAD_DOWN       = 20,
    /** Directional Pad Left key.
     * May also be synthesized from trackball motions. */
    AKEYCODE_DPAD_LEFT       = 21,
    /** Directional Pad Right key.
     * May also be synthesized from trackball motions. */
    AKEYCODE_DPAD_RIGHT      = 22,
    /** Directional Pad Center key.
     * May also be synthesized from trackball motions. */
    AKEYCODE_DPAD_CENTER     = 23,
    /** Volume Up key.
     * Adjusts the speaker volume up. */
    AKEYCODE_VOLUME_UP       = 24,
    /** Volume Down key.
     * Adjusts the speaker volume down. */
    AKEYCODE_VOLUME_DOWN     = 25,
    /** Power key. */
    AKEYCODE_POWER           = 26,
    /** Camera key.
     * Used to launch a camera application or take pictures. */
    AKEYCODE_CAMERA          = 27,
    /** Clear key. */
    AKEYCODE_CLEAR           = 28,
    /** 'A' key. */
    AKEYCODE_A               = 29,
    /** 'B' key. */
    AKEYCODE_B               = 30,
    /** 'C' key. */
    AKEYCODE_C               = 31,
    /** 'D' key. */
    AKEYCODE_D               = 32,
    /** 'E' key. */
    AKEYCODE_E               = 33,
    /** 'F' key. */
    AKEYCODE_F               = 34,
    /** 'G' key. */
    AKEYCODE_G               = 35,
    /** 'H' key. */
    AKEYCODE_H               = 36,
    /** 'I' key. */
    AKEYCODE_I               = 37,
    /** 'J' key. */
    AKEYCODE_J               = 38,
    /** 'K' key. */
    AKEYCODE_K               = 39,
    /** 'L' key. */
    AKEYCODE_L               = 40,
    /** 'M' key. */
    AKEYCODE_M               = 41,
    /** 'N' key. */
    AKEYCODE_N               = 42,
    /** 'O' key. */
    AKEYCODE_O               = 43,
    /** 'P' key. */
    AKEYCODE_P               = 44,
    /** 'Q' key. */
    AKEYCODE_Q               = 45,
    /** 'R' key. */
    AKEYCODE_R               = 46,
    /** 'S' key. */
    AKEYCODE_S               = 47,
    /** 'T' key. */
    AKEYCODE_T               = 48,
    /** 'U' key. */
    AKEYCODE_U               = 49,
    /** 'V' key. */
    AKEYCODE_V               = 50,
    /** 'W' key. */
    AKEYCODE_W               = 51,
    /** 'X' key. */
    AKEYCODE_X               = 52,
    /** 'Y' key. */
    AKEYCODE_Y               = 53,
    /** 'Z' key. */
    AKEYCODE_Z               = 54,
    /** ',' key. */
    AKEYCODE_COMMA           = 55,
    /** '.' key. */
    AKEYCODE_PERIOD          = 56,
    /** Left Alt modifier key. */
    AKEYCODE_ALT_LEFT        = 57,
    /** Right Alt modifier key. */
    AKEYCODE_ALT_RIGHT       = 58,
    /** Left Shift modifier key. */
    AKEYCODE_SHIFT_LEFT      = 59,
    /** Right Shift modifier key. */
    AKEYCODE_SHIFT_RIGHT     = 60,
    /** Tab key. */
    AKEYCODE_TAB             = 61,
    /** Space key. */
    AKEYCODE_SPACE           = 62,
    /** Symbol modifier key.
     * Used to enter alternate symbols. */
    AKEYCODE_SYM             = 63,
    /** Explorer special function key.
     * Used to launch a browser application. */
    AKEYCODE_EXPLORER        = 64,
    /** Envelope special function key.
     * Used to launch a mail application. */
    AKEYCODE_ENVELOPE        = 65,
    /** Enter key. */
    AKEYCODE_ENTER           = 66,
    /** Backspace key.
     * Deletes characters before the insertion point, unlike {@link AKEYCODE_FORWARD_DEL}. */
    AKEYCODE_DEL             = 67,
    /** '`' (backtick) key. */
    AKEYCODE_GRAVE           = 68,
    /** '-'. */
    AKEYCODE_MINUS           = 69,
    /** '=' key. */
    AKEYCODE_EQUALS          = 70,
    /** '[' key. */
    AKEYCODE_LEFT_BRACKET    = 71,
    /** ']' key. */
    AKEYCODE_RIGHT_BRACKET   = 72,
    /** '\' key. */
    AKEYCODE_BACKSLASH       = 73,
    /** ';' key. */
    AKEYCODE_SEMICOLON       = 74,
    /** ''' (apostrophe) key. */
    AKEYCODE_APOSTROPHE      = 75,
    /** '/' key. */
    AKEYCODE_SLASH           = 76,
    /** '@' key. */
    AKEYCODE_AT              = 77,
    /** Number modifier key.
     * Used to enter numeric symbols.
     * This key is not {@link AKEYCODE_NUM_LOCK}; it is more like {@link AKEYCODE_ALT_LEFT}. */
    AKEYCODE_NUM             = 78,
    /** Headset Hook key.
     * Used to hang up calls and stop media. */
    AKEYCODE_HEADSETHOOK     = 79,
    /** Camera Focus key.
     * Used to focus the camera. */
    AKEYCODE_FOCUS           = 80,
    /** '+' key. */
    AKEYCODE_PLUS            = 81,
    /** Menu key. */
    AKEYCODE_MENU            = 82,
    /** Notification key. */
    AKEYCODE_NOTIFICATION    = 83,
    /** Search key. */
    AKEYCODE_SEARCH          = 84,
    /** Play/Pause media key. */
    AKEYCODE_MEDIA_PLAY_PAUSE= 85,
    /** Stop media key. */
    AKEYCODE_MEDIA_STOP      = 86,
    /** Play Next media key. */
    AKEYCODE_MEDIA_NEXT      = 87,
    /** Play Previous media key. */
    AKEYCODE_MEDIA_PREVIOUS  = 88,
    /** Rewind media key. */
    AKEYCODE_MEDIA_REWIND    = 89,
    /** Fast Forward media key. */
    AKEYCODE_MEDIA_FAST_FORWARD = 90,
    /** Mute key.
     * Mutes the microphone, unlike {@link AKEYCODE_VOLUME_MUTE}. */
    AKEYCODE_MUTE            = 91,
    /** Page Up key. */
    AKEYCODE_PAGE_UP         = 92,
    /** Page Down key. */
    AKEYCODE_PAGE_DOWN       = 93,
    /** Picture Symbols modifier key.
     * Used to switch symbol sets (Emoji, Kao-moji). */
    AKEYCODE_PICTSYMBOLS     = 94,
    /** Switch Charset modifier key.
     * Used to switch character sets (Kanji, Katakana). */
    AKEYCODE_SWITCH_CHARSET  = 95,
    /** A Button key.
     * On a game controller, the A button should be either the button labeled A
     * or the first button on the bottom row of controller buttons. */
    AKEYCODE_BUTTON_A        = 96,
    /** B Button key.
     * On a game controller, the B button should be either the button labeled B
     * or the second button on the bottom row of controller buttons. */
    AKEYCODE_BUTTON_B        = 97,
    /** C Button key.
     * On a game controller, the C button should be either the button labeled C
     * or the third button on the bottom row of controller buttons. */
    AKEYCODE_BUTTON_C        = 98,
    /** X Button key.
     * On a game controller, the X button should be either the button labeled X
     * or the first button on the upper row of controller buttons. */
    AKEYCODE_BUTTON_X        = 99,
    /** Y Button key.
     * On a game controller, the Y button should be either the button labeled Y
     * or the second button on the upper row of controller buttons. */
    AKEYCODE_BUTTON_Y        = 100,
    /** Z Button key.
     * On a game controller, the Z button should be either the button labeled Z
     * or the third button on the upper row of controller buttons. */
    AKEYCODE_BUTTON_Z        = 101,
    /** L1 Button key.
     * On a game controller, the L1 button should be either the button labeled L1 (or L)
     * or the top left trigger button. */
    AKEYCODE_BUTTON_L1       = 102,
    /** R1 Button key.
     * On a game controller, the R1 button should be either the button labeled R1 (or R)
     * or the top right trigger button. */
    AKEYCODE_BUTTON_R1       = 103,
    /** L2 Button key.
     * On a game controller, the L2 button should be either the button labeled L2
     * or the bottom left trigger button. */
    AKEYCODE_BUTTON_L2       = 104,
    /** R2 Button key.
     * On a game controller, the R2 button should be either the button labeled R2
     * or the bottom right trigger button. */
    AKEYCODE_BUTTON_R2       = 105,
    /** Left Thumb Button key.
     * On a game controller, the left thumb button indicates that the left (or only)
     * joystick is pressed. */
    AKEYCODE_BUTTON_THUMBL   = 106,
    /** Right Thumb Button key.
     * On a game controller, the right thumb button indicates that the right
     * joystick is pressed. */
    AKEYCODE_BUTTON_THUMBR   = 107,
    /** Start Button key.
     * On a game controller, the button labeled Start. */
    AKEYCODE_BUTTON_START    = 108,
    /** Select Button key.
     * On a game controller, the button labeled Select. */
    AKEYCODE_BUTTON_SELECT   = 109,
    /** Mode Button key.
     * On a game controller, the button labeled Mode. */
    AKEYCODE_BUTTON_MODE     = 110,
    /** Escape key. */
    AKEYCODE_ESCAPE          = 111,
    /** Forward Delete key.
     * Deletes characters ahead of the insertion point, unlike {@link AKEYCODE_DEL}. */
    AKEYCODE_FORWARD_DEL     = 112,
    /** Left Control modifier key. */
    AKEYCODE_CTRL_LEFT       = 113,
    /** Right Control modifier key. */
    AKEYCODE_CTRL_RIGHT      = 114,
    /** Caps Lock key. */
    AKEYCODE_CAPS_LOCK       = 115,
    /** Scroll Lock key. */
    AKEYCODE_SCROLL_LOCK     = 116,
    /** Left Meta modifier key. */
    AKEYCODE_META_LEFT       = 117,
    /** Right Meta modifier key. */
    AKEYCODE_META_RIGHT      = 118,
    /** Function modifier key. */
    AKEYCODE_FUNCTION        = 119,
    /** System Request / Print Screen key. */
    AKEYCODE_SYSRQ           = 120,
    /** Break / Pause key. */
    AKEYCODE_BREAK           = 121,
    /** Home Movement key.
     * Used for scrolling or moving the cursor around to the start of a line
     * or to the top of a list. */
    AKEYCODE_MOVE_HOME       = 122,
    /** End Movement key.
     * Used for scrolling or moving the cursor around to the end of a line
     * or to the bottom of a list. */
    AKEYCODE_MOVE_END        = 123,
    /** Insert key.
     * Toggles insert / overwrite edit mode. */
    AKEYCODE_INSERT          = 124,
    /** Forward key.
     * Navigates forward in the history stack.  Complement of {@link AKEYCODE_BACK}. */
    AKEYCODE_FORWARD         = 125,
    /** Play media key. */
    AKEYCODE_MEDIA_PLAY      = 126,
    /** Pause media key. */
    AKEYCODE_MEDIA_PAUSE     = 127,
    /** Close media key.
     * May be used to close a CD tray, for example. */
    AKEYCODE_MEDIA_CLOSE     = 128,
    /** Eject media key.
     * May be used to eject a CD tray, for example. */
    AKEYCODE_MEDIA_EJECT     = 129,
    /** Record media key. */
    AKEYCODE_MEDIA_RECORD    = 130,
    /** F1 key. */
    AKEYCODE_F1              = 131,
    /** F2 key. */
    AKEYCODE_F2              = 132,
    /** F3 key. */
    AKEYCODE_F3              = 133,
    /** F4 key. */
    AKEYCODE_F4              = 134,
    /** F5 key. */
    AKEYCODE_F5              = 135,
    /** F6 key. */
    AKEYCODE_F6              = 136,
    /** F7 key. */
    AKEYCODE_F7              = 137,
    /** F8 key. */
    AKEYCODE_F8              = 138,
    /** F9 key. */
    AKEYCODE_F9              = 139,
    /** F10 key. */
    AKEYCODE_F10             = 140,
    /** F11 key. */
    AKEYCODE_F11             = 141,
    /** F12 key. */
    AKEYCODE_F12             = 142,
    /** Num Lock key.
     * This is the Num Lock key; it is different from {@link AKEYCODE_NUM}.
     * This key alters the behavior of other keys on the numeric keypad. */
    AKEYCODE_NUM_LOCK        = 143,
    /** Numeric keypad '0' key. */
    AKEYCODE_NUMPAD_0        = 144,
    /** Numeric keypad '1' key. */
    AKEYCODE_NUMPAD_1        = 145,
    /** Numeric keypad '2' key. */
    AKEYCODE_NUMPAD_2        = 146,
    /** Numeric keypad '3' key. */
    AKEYCODE_NUMPAD_3        = 147,
    /** Numeric keypad '4' key. */
    AKEYCODE_NUMPAD_4        = 148,
    /** Numeric keypad '5' key. */
    AKEYCODE_NUMPAD_5        = 149,
    /** Numeric keypad '6' key. */
    AKEYCODE_NUMPAD_6        = 150,
    /** Numeric keypad '7' key. */
    AKEYCODE_NUMPAD_7        = 151,
    /** Numeric keypad '8' key. */
    AKEYCODE_NUMPAD_8        = 152,
    /** Numeric keypad '9' key. */
    AKEYCODE_NUMPAD_9        = 153,
    /** Numeric keypad '/' key (for division). */
    AKEYCODE_NUMPAD_DIVIDE   = 154,
    /** Numeric keypad '*' key (for multiplication). */
    AKEYCODE_NUMPAD_MULTIPLY = 155,
    /** Numeric keypad '-' key (for subtraction). */
    AKEYCODE_NUMPAD_SUBTRACT = 156,
    /** Numeric keypad '+' key (for addition). */
    AKEYCODE_NUMPAD_ADD      = 157,
    /** Numeric keypad '.' key (for decimals or digit grouping). */
    AKEYCODE_NUMPAD_DOT      = 158,
    /** Numeric keypad ',' key (for decimals or digit grouping). */
    AKEYCODE_NUMPAD_COMMA    = 159,
    /** Numeric keypad Enter key. */
    AKEYCODE_NUMPAD_ENTER    = 160,
    /** Numeric keypad '=' key. */
    AKEYCODE_NUMPAD_EQUALS   = 161,
    /** Numeric keypad '(' key. */
    AKEYCODE_NUMPAD_LEFT_PAREN = 162,
    /** Numeric keypad ')' key. */
    AKEYCODE_NUMPAD_RIGHT_PAREN = 163,
    /** Volume Mute key.
     * Mutes the speaker, unlike {@link AKEYCODE_MUTE}.
     * This key should normally be implemented as a toggle such that the first press
     * mutes the speaker and the second press restores the original volume. */
    AKEYCODE_VOLUME_MUTE     = 164,
    /** Info key.
     * Common on TV remotes to show additional information related to what is
     * currently being viewed. */
    AKEYCODE_INFO            = 165,
    /** Channel up key.
     * On TV remotes, increments the television channel. */
    AKEYCODE_CHANNEL_UP      = 166,
    /** Channel down key.
     * On TV remotes, decrements the television channel. */
    AKEYCODE_CHANNEL_DOWN    = 167,
    /** Zoom in key. */
    AKEYCODE_ZOOM_IN         = 168,
    /** Zoom out key. */
    AKEYCODE_ZOOM_OUT        = 169,
    /** TV key.
     * On TV remotes, switches to viewing live TV. */
    AKEYCODE_TV              = 170,
    /** Window key.
     * On TV remotes, toggles picture-in-picture mode or other windowing functions. */
    AKEYCODE_WINDOW          = 171,
    /** Guide key.
     * On TV remotes, shows a programming guide. */
    AKEYCODE_GUIDE           = 172,
    /** DVR key.
     * On some TV remotes, switches to a DVR mode for recorded shows. */
    AKEYCODE_DVR             = 173,
    /** Bookmark key.
     * On some TV remotes, bookmarks content or web pages. */
    AKEYCODE_BOOKMARK        = 174,
    /** Toggle captions key.
     * Switches the mode for closed-captioning text, for example during television shows. */
    AKEYCODE_CAPTIONS        = 175,
    /** Settings key.
     * Starts the system settings activity. */
    AKEYCODE_SETTINGS        = 176,
    /** TV power key.
     * On TV remotes, toggles the power on a television screen. */
    AKEYCODE_TV_POWER        = 177,
    /** TV input key.
     * On TV remotes, switches the input on a television screen. */
    AKEYCODE_TV_INPUT        = 178,
    /** Set-top-box power key.
     * On TV remotes, toggles the power on an external Set-top-box. */
    AKEYCODE_STB_POWER       = 179,
    /** Set-top-box input key.
     * On TV remotes, switches the input mode on an external Set-top-box. */
    AKEYCODE_STB_INPUT       = 180,
    /** A/V Receiver power key.
     * On TV remotes, toggles the power on an external A/V Receiver. */
    AKEYCODE_AVR_POWER       = 181,
    /** A/V Receiver input key.
     * On TV remotes, switches the input mode on an external A/V Receiver. */
    AKEYCODE_AVR_INPUT       = 182,
    /** Red "programmable" key.
     * On TV remotes, acts as a contextual/programmable key. */
    AKEYCODE_PROG_RED        = 183,
    /** Green "programmable" key.
     * On TV remotes, actsas a contextual/progra
Download .txt
gitextract_ouc_2c7j/

├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── feature_request.md
│   │   └── question.md
│   └── workflows/
│       └── release.yml
├── .gitignore
├── FAQ.md
├── LICENSE
├── README.md
├── app/
│   ├── data/
│   │   ├── bash-completion/
│   │   │   └── scrcpy
│   │   ├── open_a_terminal_here.bat
│   │   ├── scrcpy-console.bat
│   │   ├── scrcpy-console.desktop
│   │   ├── scrcpy-noconsole.vbs
│   │   ├── scrcpy.desktop
│   │   └── zsh-completion/
│   │       └── _scrcpy
│   ├── deps/
│   │   ├── .gitignore
│   │   ├── README
│   │   ├── _init
│   │   ├── adb_linux.sh
│   │   ├── adb_macos.sh
│   │   ├── adb_windows.sh
│   │   ├── dav1d.sh
│   │   ├── ffmpeg.sh
│   │   ├── libusb.sh
│   │   └── sdl.sh
│   ├── meson.build
│   ├── scrcpy-windows.manifest
│   ├── scrcpy-windows.rc
│   ├── scrcpy.1
│   ├── src/
│   │   ├── adb/
│   │   │   ├── adb.c
│   │   │   ├── adb.h
│   │   │   ├── adb_device.c
│   │   │   ├── adb_device.h
│   │   │   ├── adb_parser.c
│   │   │   ├── adb_parser.h
│   │   │   ├── adb_tunnel.c
│   │   │   └── adb_tunnel.h
│   │   ├── android/
│   │   │   ├── input.h
│   │   │   └── keycodes.h
│   │   ├── audio_player.c
│   │   ├── audio_player.h
│   │   ├── audio_regulator.c
│   │   ├── audio_regulator.h
│   │   ├── cli.c
│   │   ├── cli.h
│   │   ├── clock.c
│   │   ├── clock.h
│   │   ├── common.h
│   │   ├── compat.c
│   │   ├── compat.h
│   │   ├── control_msg.c
│   │   ├── control_msg.h
│   │   ├── controller.c
│   │   ├── controller.h
│   │   ├── coords.h
│   │   ├── decoder.c
│   │   ├── decoder.h
│   │   ├── delay_buffer.c
│   │   ├── delay_buffer.h
│   │   ├── demuxer.c
│   │   ├── demuxer.h
│   │   ├── device_msg.c
│   │   ├── device_msg.h
│   │   ├── display.c
│   │   ├── display.h
│   │   ├── events.c
│   │   ├── events.h
│   │   ├── file_pusher.c
│   │   ├── file_pusher.h
│   │   ├── fps_counter.c
│   │   ├── fps_counter.h
│   │   ├── frame_buffer.c
│   │   ├── frame_buffer.h
│   │   ├── hid/
│   │   │   ├── hid_event.h
│   │   │   ├── hid_gamepad.c
│   │   │   ├── hid_gamepad.h
│   │   │   ├── hid_keyboard.c
│   │   │   ├── hid_keyboard.h
│   │   │   ├── hid_mouse.c
│   │   │   └── hid_mouse.h
│   │   ├── icon.c
│   │   ├── icon.h
│   │   ├── input_events.h
│   │   ├── input_manager.c
│   │   ├── input_manager.h
│   │   ├── keyboard_sdk.c
│   │   ├── keyboard_sdk.h
│   │   ├── main.c
│   │   ├── mouse_capture.c
│   │   ├── mouse_capture.h
│   │   ├── mouse_sdk.c
│   │   ├── mouse_sdk.h
│   │   ├── opengl.c
│   │   ├── opengl.h
│   │   ├── options.c
│   │   ├── options.h
│   │   ├── packet_merger.c
│   │   ├── packet_merger.h
│   │   ├── receiver.c
│   │   ├── receiver.h
│   │   ├── recorder.c
│   │   ├── recorder.h
│   │   ├── scrcpy.c
│   │   ├── scrcpy.h
│   │   ├── screen.c
│   │   ├── screen.h
│   │   ├── server.c
│   │   ├── server.h
│   │   ├── shortcut_mod.h
│   │   ├── sys/
│   │   │   ├── unix/
│   │   │   │   ├── file.c
│   │   │   │   └── process.c
│   │   │   └── win/
│   │   │       ├── file.c
│   │   │       └── process.c
│   │   ├── trait/
│   │   │   ├── frame_sink.h
│   │   │   ├── frame_source.c
│   │   │   ├── frame_source.h
│   │   │   ├── gamepad_processor.h
│   │   │   ├── key_processor.h
│   │   │   ├── mouse_processor.h
│   │   │   ├── packet_sink.h
│   │   │   ├── packet_source.c
│   │   │   └── packet_source.h
│   │   ├── uhid/
│   │   │   ├── gamepad_uhid.c
│   │   │   ├── gamepad_uhid.h
│   │   │   ├── keyboard_uhid.c
│   │   │   ├── keyboard_uhid.h
│   │   │   ├── mouse_uhid.c
│   │   │   ├── mouse_uhid.h
│   │   │   ├── uhid_output.c
│   │   │   └── uhid_output.h
│   │   ├── usb/
│   │   │   ├── aoa_hid.c
│   │   │   ├── aoa_hid.h
│   │   │   ├── gamepad_aoa.c
│   │   │   ├── gamepad_aoa.h
│   │   │   ├── keyboard_aoa.c
│   │   │   ├── keyboard_aoa.h
│   │   │   ├── mouse_aoa.c
│   │   │   ├── mouse_aoa.h
│   │   │   ├── scrcpy_otg.c
│   │   │   ├── scrcpy_otg.h
│   │   │   ├── screen_otg.c
│   │   │   ├── screen_otg.h
│   │   │   ├── usb.c
│   │   │   └── usb.h
│   │   ├── util/
│   │   │   ├── acksync.c
│   │   │   ├── acksync.h
│   │   │   ├── audiobuf.c
│   │   │   ├── audiobuf.h
│   │   │   ├── average.c
│   │   │   ├── average.h
│   │   │   ├── binary.h
│   │   │   ├── env.c
│   │   │   ├── env.h
│   │   │   ├── file.c
│   │   │   ├── file.h
│   │   │   ├── intmap.c
│   │   │   ├── intmap.h
│   │   │   ├── intr.c
│   │   │   ├── intr.h
│   │   │   ├── log.c
│   │   │   ├── log.h
│   │   │   ├── memory.c
│   │   │   ├── memory.h
│   │   │   ├── net.c
│   │   │   ├── net.h
│   │   │   ├── net_intr.c
│   │   │   ├── net_intr.h
│   │   │   ├── process.c
│   │   │   ├── process.h
│   │   │   ├── process_intr.c
│   │   │   ├── process_intr.h
│   │   │   ├── rand.c
│   │   │   ├── rand.h
│   │   │   ├── str.c
│   │   │   ├── str.h
│   │   │   ├── strbuf.c
│   │   │   ├── strbuf.h
│   │   │   ├── term.c
│   │   │   ├── term.h
│   │   │   ├── thread.c
│   │   │   ├── thread.h
│   │   │   ├── tick.c
│   │   │   ├── tick.h
│   │   │   ├── timeout.c
│   │   │   ├── timeout.h
│   │   │   ├── vecdeque.h
│   │   │   └── vector.h
│   │   ├── v4l2_sink.c
│   │   ├── v4l2_sink.h
│   │   ├── version.c
│   │   └── version.h
│   └── tests/
│       ├── test_adb_parser.c
│       ├── test_audiobuf.c
│       ├── test_binary.c
│       ├── test_cli.c
│       ├── test_control_msg_serialize.c
│       ├── test_device_msg_deserialize.c
│       ├── test_orientation.c
│       ├── test_str.c
│       ├── test_strbuf.c
│       ├── test_vecdeque.c
│       └── test_vector.c
├── build.gradle
├── bump_version
├── config/
│   ├── android-checkstyle.gradle
│   └── checkstyle/
│       └── checkstyle.xml
├── cross_win32.txt
├── cross_win64.txt
├── doc/
│   ├── audio.md
│   ├── build.md
│   ├── camera.md
│   ├── connection.md
│   ├── control.md
│   ├── develop.md
│   ├── device.md
│   ├── gamepad.md
│   ├── keyboard.md
│   ├── linux.md
│   ├── macos.md
│   ├── mouse.md
│   ├── otg.md
│   ├── recording.md
│   ├── shortcuts.md
│   ├── tunnels.md
│   ├── v4l2.md
│   ├── video.md
│   ├── virtual_display.md
│   ├── window.md
│   └── windows.md
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── install_release.sh
├── meson.build
├── meson_options.txt
├── release/
│   ├── .gitignore
│   ├── build_common
│   ├── build_linux.sh
│   ├── build_macos.sh
│   ├── build_server.sh
│   ├── build_windows.sh
│   ├── generate_checksums.sh
│   ├── package_client.sh
│   ├── package_server.sh
│   ├── release.sh
│   ├── test_client.sh
│   └── test_server.sh
├── run
├── server/
│   ├── .gitignore
│   ├── build.gradle
│   ├── build_without_gradle.sh
│   ├── meson.build
│   ├── proguard-rules.pro
│   ├── scripts/
│   │   └── build-wrapper.sh
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── aidl/
│       │   │   └── android/
│       │   │       ├── content/
│       │   │       │   └── IOnPrimaryClipChangedListener.aidl
│       │   │       └── view/
│       │   │           └── IDisplayWindowListener.aidl
│       │   └── java/
│       │       ├── android/
│       │       │   └── content/
│       │       │       └── IContentProvider.java
│       │       └── com/
│       │           └── genymobile/
│       │               └── scrcpy/
│       │                   ├── AndroidVersions.java
│       │                   ├── AsyncProcessor.java
│       │                   ├── CleanUp.java
│       │                   ├── FakeContext.java
│       │                   ├── Options.java
│       │                   ├── Server.java
│       │                   ├── Workarounds.java
│       │                   ├── audio/
│       │                   │   ├── AudioCapture.java
│       │                   │   ├── AudioCaptureException.java
│       │                   │   ├── AudioCodec.java
│       │                   │   ├── AudioConfig.java
│       │                   │   ├── AudioDirectCapture.java
│       │                   │   ├── AudioEncoder.java
│       │                   │   ├── AudioPlaybackCapture.java
│       │                   │   ├── AudioRawRecorder.java
│       │                   │   ├── AudioRecordReader.java
│       │                   │   └── AudioSource.java
│       │                   ├── control/
│       │                   │   ├── ControlChannel.java
│       │                   │   ├── ControlMessage.java
│       │                   │   ├── ControlMessageReader.java
│       │                   │   ├── ControlProtocolException.java
│       │                   │   ├── Controller.java
│       │                   │   ├── DeviceMessage.java
│       │                   │   ├── DeviceMessageSender.java
│       │                   │   ├── DeviceMessageWriter.java
│       │                   │   ├── KeyComposition.java
│       │                   │   ├── Pointer.java
│       │                   │   ├── PointersState.java
│       │                   │   ├── PositionMapper.java
│       │                   │   └── UhidManager.java
│       │                   ├── device/
│       │                   │   ├── ConfigurationException.java
│       │                   │   ├── DesktopConnection.java
│       │                   │   ├── Device.java
│       │                   │   ├── DeviceApp.java
│       │                   │   ├── DisplayInfo.java
│       │                   │   ├── NewDisplay.java
│       │                   │   ├── Orientation.java
│       │                   │   ├── Point.java
│       │                   │   ├── Position.java
│       │                   │   ├── Size.java
│       │                   │   └── Streamer.java
│       │                   ├── opengl/
│       │                   │   ├── AffineOpenGLFilter.java
│       │                   │   ├── GLUtils.java
│       │                   │   ├── OpenGLException.java
│       │                   │   ├── OpenGLFilter.java
│       │                   │   └── OpenGLRunner.java
│       │                   ├── util/
│       │                   │   ├── AffineMatrix.java
│       │                   │   ├── Binary.java
│       │                   │   ├── Codec.java
│       │                   │   ├── CodecOption.java
│       │                   │   ├── CodecUtils.java
│       │                   │   ├── Command.java
│       │                   │   ├── HandlerExecutor.java
│       │                   │   ├── IO.java
│       │                   │   ├── Ln.java
│       │                   │   ├── LogUtils.java
│       │                   │   ├── Settings.java
│       │                   │   ├── SettingsException.java
│       │                   │   ├── StringUtils.java
│       │                   │   └── Threads.java
│       │                   ├── video/
│       │                   │   ├── CameraAspectRatio.java
│       │                   │   ├── CameraCapture.java
│       │                   │   ├── CameraFacing.java
│       │                   │   ├── CaptureReset.java
│       │                   │   ├── DisplaySizeMonitor.java
│       │                   │   ├── NewDisplayCapture.java
│       │                   │   ├── ScreenCapture.java
│       │                   │   ├── SurfaceCapture.java
│       │                   │   ├── SurfaceEncoder.java
│       │                   │   ├── VideoCodec.java
│       │                   │   ├── VideoFilter.java
│       │                   │   ├── VideoSource.java
│       │                   │   └── VirtualDisplayListener.java
│       │                   └── wrappers/
│       │                       ├── ActivityManager.java
│       │                       ├── ClipboardManager.java
│       │                       ├── ContentProvider.java
│       │                       ├── DisplayControl.java
│       │                       ├── DisplayManager.java
│       │                       ├── DisplayWindowListener.java
│       │                       ├── InputManager.java
│       │                       ├── PowerManager.java
│       │                       ├── ServiceManager.java
│       │                       ├── StatusBarManager.java
│       │                       ├── SurfaceControl.java
│       │                       └── WindowManager.java
│       └── test/
│           └── java/
│               └── com/
│                   └── genymobile/
│                       └── scrcpy/
│                           ├── control/
│                           │   ├── ControlMessageReaderTest.java
│                           │   └── DeviceMessageWriterTest.java
│                           └── util/
│                               ├── BinaryTest.java
│                               ├── CodecOptionsTest.java
│                               ├── CommandParserTest.java
│                               └── StringUtilsTest.java
└── settings.gradle
Download .txt
SYMBOL INDEX (2212 symbols across 252 files)

FILE: app/src/adb/adb.c
  function sc_adb_init (line 31) | bool
  function sc_adb_destroy (line 61) | void
  function argv_to_string (line 72) | static size_t
  function show_adb_installation_msg (line 104) | static void
  function show_adb_err_msg (line 127) | static void
  function process_check_success_internal (line 157) | static bool
  function process_check_success_intr (line 183) | static bool
  function sc_pid (line 204) | static sc_pid
  function sc_pid (line 227) | sc_pid
  function sc_adb_start_server (line 232) | bool
  function sc_adb_kill_server (line 240) | bool
  function sc_adb_forward (line 248) | bool
  function sc_adb_forward_remove (line 272) | bool
  function sc_adb_reverse (line 288) | bool
  function sc_adb_reverse_remove (line 312) | bool
  function sc_adb_push (line 331) | bool
  function sc_adb_install (line 362) | bool
  function sc_adb_tcpip (line 387) | bool
  function sc_adb_connect (line 403) | bool
  function sc_adb_disconnect (line 445) | bool
  function sc_adb_list_devices (line 454) | static bool
  function sc_adb_accept_device (line 507) | static bool
  function sc_adb_devices_select (line 550) | static size_t
  function sc_adb_devices_log (line 569) | static void
  function sc_adb_device_check_state (line 584) | static bool
  function sc_adb_select_device (line 606) | bool
  type sc_intr (line 700) | struct sc_intr
  type sc_intr (line 735) | struct sc_intr
  function sc_adb_get_device_sdk_version (line 776) | uint16_t

FILE: app/src/adb/adb.h
  type sc_adb_device_selector_type (line 27) | enum sc_adb_device_selector_type {
  type sc_adb_device_selector (line 34) | struct sc_adb_device_selector {
  type sc_intr (line 43) | struct sc_intr
  type sc_intr (line 46) | struct sc_intr
  type sc_intr (line 49) | struct sc_intr
  type sc_intr (line 53) | struct sc_intr
  type sc_intr (line 57) | struct sc_intr
  type sc_intr (line 62) | struct sc_intr
  type sc_intr (line 66) | struct sc_intr
  type sc_intr (line 70) | struct sc_intr
  type sc_intr (line 77) | struct sc_intr
  type sc_intr (line 86) | struct sc_intr
  type sc_intr (line 95) | struct sc_intr
  type sc_intr (line 103) | struct sc_intr
  type sc_adb_device_selector (line 104) | struct sc_adb_device_selector
  type sc_adb_device (line 105) | struct sc_adb_device
  type sc_intr (line 111) | struct sc_intr
  type sc_intr (line 121) | struct sc_intr
  type sc_intr (line 127) | struct sc_intr

FILE: app/src/adb/adb_device.c
  function sc_adb_device_destroy (line 6) | void
  function sc_adb_device_move (line 13) | void
  function sc_adb_devices_destroy (line 21) | void
  function sc_adb_device_get_type (line 29) | enum sc_adb_device_type

FILE: app/src/adb/adb_device.h
  type sc_adb_device (line 10) | struct sc_adb_device {
  type sc_adb_device_type (line 17) | enum sc_adb_device_type {
  type sc_vec_adb_devices (line 23) | struct sc_vec_adb_devices
  type sc_adb_device (line 23) | struct sc_adb_device
  type sc_adb_device (line 26) | struct sc_adb_device
  type sc_adb_device (line 38) | struct sc_adb_device
  type sc_adb_device (line 38) | struct sc_adb_device
  type sc_vec_adb_devices (line 41) | struct sc_vec_adb_devices
  type sc_adb_device_type (line 46) | enum sc_adb_device_type

FILE: app/src/adb/adb_parser.c
  function sc_adb_parse_device (line 11) | static bool
  function sc_adb_parse_devices (line 113) | bool

FILE: app/src/adb/adb_parser.h
  type sc_vec_adb_devices (line 18) | struct sc_vec_adb_devices

FILE: app/src/adb/adb_tunnel.c
  function listen_on_port (line 10) | static bool
  function enable_tunnel_reverse_any_port (line 15) | static bool
  function enable_tunnel_forward_any_port (line 77) | static bool
  function sc_adb_tunnel_init (line 116) | void
  function sc_adb_tunnel_open (line 124) | bool
  function sc_adb_tunnel_close (line 147) | bool

FILE: app/src/adb/adb_tunnel.h
  type sc_adb_tunnel (line 13) | struct sc_adb_tunnel {
  type sc_adb_tunnel (line 24) | struct sc_adb_tunnel
  type sc_adb_tunnel (line 36) | struct sc_adb_tunnel
  type sc_intr (line 36) | struct sc_intr
  type sc_port_range (line 38) | struct sc_port_range
  type sc_adb_tunnel (line 44) | struct sc_adb_tunnel
  type sc_intr (line 44) | struct sc_intr

FILE: app/src/android/input.h
  type android_metastate (line 26) | enum android_metastate {
  type android_input_event_type (line 85) | enum android_input_event_type {
  type android_keyevent_action (line 95) | enum android_keyevent_action {
  type android_keyevent_flags (line 114) | enum android_keyevent_flags {
  type android_motionevent_action (line 198) | enum android_motionevent_action {
  type android_motionevent_flags (line 284) | enum android_motionevent_flags {
  type android_motionevent_edge_touch_flags (line 301) | enum android_motionevent_edge_touch_flags {
  type android_motionevent_axis (line 322) | enum android_motionevent_axis {
  type android_motionevent_buttons (line 691) | enum android_motionevent_buttons {
  type android_motionevent_tool_type (line 710) | enum android_motionevent_tool_type {
  type android_input_source_class (line 729) | enum android_input_source_class {
  type android_input_source (line 750) | enum android_input_source {
  type android_keyboard_type (line 787) | enum android_keyboard_type {
  type android_motion_range (line 805) | enum android_motion_range {

FILE: app/src/android/keycodes.h
  type android_keycode (line 26) | enum android_keycode {

FILE: app/src/audio_player.c
  function sc_audio_player_sdl_callback (line 10) | static void SDLCALL
  function sc_audio_player_frame_sink_push (line 23) | static bool
  function sc_audio_player_frame_sink_open (line 31) | static bool
  function sc_audio_player_frame_sink_close (line 94) | static void
  function sc_audio_player_init (line 105) | void

FILE: app/src/audio_player.h
  type sc_audio_player (line 12) | struct sc_audio_player {
  type sc_audio_player (line 30) | struct sc_audio_player

FILE: app/src/audio_regulator.c
  function sc_audio_regulator_pull (line 62) | void
  type sc_audio_regulator (line 122) | struct sc_audio_regulator
  function sc_audio_regulator_push (line 140) | bool
  function sc_audio_regulator_init (line 365) | bool
  function sc_audio_regulator_destroy (line 450) | void

FILE: app/src/audio_regulator.h
  type sc_audio_regulator (line 18) | struct sc_audio_regulator {
  type sc_audio_regulator (line 66) | struct sc_audio_regulator
  type sc_audio_regulator (line 70) | struct sc_audio_regulator
  type sc_audio_regulator (line 73) | struct sc_audio_regulator
  type sc_audio_regulator (line 76) | struct sc_audio_regulator

FILE: app/src/cli.c
  type sc_option (line 119) | struct sc_option {
  type sc_shortcut (line 132) | struct sc_shortcut {
  type sc_envvar (line 137) | struct sc_envvar {
  type sc_exit_status (line 142) | struct sc_exit_status {
  type sc_getopt_adapter (line 147) | struct sc_getopt_adapter {
  type sc_option (line 152) | struct sc_option
  type sc_shortcut (line 1068) | struct sc_shortcut
  type sc_envvar (line 1212) | struct sc_envvar
  type sc_exit_status (line 1232) | struct sc_exit_status
  type sc_strbuf (line 1249) | struct sc_strbuf
  type sc_option (line 1255) | struct sc_option
  type option (line 1280) | struct option
  type option (line 1282) | struct option
  type sc_option (line 1291) | struct sc_option
  type option (line 1300) | struct option
  type option (line 1321) | struct option
  function sc_getopt_adapter_init (line 1326) | static bool
  function sc_getopt_adapter_destroy (line 1342) | static void
  function print_option_usage_header (line 1348) | static void
  function print_option_usage (line 1406) | static void
  function print_shortcuts_intro (line 1427) | static void
  function print_shortcut (line 1442) | static void
  function print_envvar (line 1466) | static void
  function print_exit_status (line 1483) | static void
  function scrcpy_print_usage (line 1502) | void
  function parse_integer_arg (line 1547) | static bool
  function parse_integers_arg (line 1572) | static size_t
  function parse_bit_rate (line 1593) | static bool
  function parse_max_size (line 1607) | static bool
  function parse_buffering_time (line 1619) | static bool
  function parse_audio_output_buffer (line 1636) | static bool
  function parse_display_ime_policy (line 1649) | static bool
  function parse_orientation (line 1668) | static bool
  function parse_capture_orientation (line 1707) | static bool
  function parse_window_position (line 1733) | static bool
  function parse_window_dimension (line 1754) | static bool
  function parse_port_range (line 1767) | static bool
  function parse_display_id (line 1795) | static bool
  function parse_log_level (line 1807) | static bool
  function parse_shortcut_mods_item (line 1838) | static enum sc_shortcut_mod
  function parse_shortcut_mods (line 1877) | static bool
  function sc_parse_shortcut_mods (line 1909) | bool
  function get_record_format (line 1915) | static enum sc_record_format
  function parse_record_format (line 1944) | static bool
  function parse_ip (line 1957) | static bool
  function parse_port (line 1962) | static bool
  function guess_record_format (line 1972) | static enum sc_record_format
  function parse_video_codec (line 1983) | static bool
  function parse_audio_codec (line 2001) | static bool
  function parse_video_source (line 2024) | static bool
  function parse_audio_source (line 2040) | static bool
  function parse_camera_facing (line 2104) | static bool
  function parse_camera_fps (line 2132) | static bool
  function parse_keyboard (line 2144) | static bool
  function parse_mouse (line 2176) | static bool
  function parse_gamepad (line 2207) | static bool
  function parse_time_limit (line 2233) | static bool
  function parse_screen_off_timeout (line 2245) | static bool
  function parse_pause_on_exit (line 2259) | static bool
  function parse_mouse_binding (line 2282) | static bool
  function parse_mouse_binding_set (line 2310) | static bool
  function parse_mouse_bindings (line 2330) | static bool
  function parse_args_with_getopt (line 2356) | static bool
  function sc_get_pause_on_exit (line 3323) | static enum sc_pause_on_exit
  function scrcpy_parse_args (line 3354) | bool

FILE: app/src/cli.h
  type sc_pause_on_exit (line 10) | enum sc_pause_on_exit {
  type scrcpy_cli_args (line 16) | struct scrcpy_cli_args {
  type scrcpy_cli_args (line 27) | struct scrcpy_cli_args

FILE: app/src/clock.c
  function sc_clock_init (line 11) | void
  function sc_clock_update (line 17) | void
  function sc_tick (line 34) | sc_tick

FILE: app/src/clock.h
  type sc_clock_point (line 8) | struct sc_clock_point {
  type sc_clock (line 29) | struct sc_clock {
  type sc_clock (line 35) | struct sc_clock
  type sc_clock (line 38) | struct sc_clock
  type sc_clock (line 41) | struct sc_clock

FILE: app/src/compat.c
  function asprintf (line 26) | int asprintf(char **strp, const char *fmt, ...) {
  function vasprintf (line 36) | int vasprintf(char **strp, const char *fmt, va_list ap) {
  function rand_iter48 (line 62) | static inline uint64_t rand_iter48(uint64_t x) {
  function rand_iter48_xsubi (line 67) | static uint64_t rand_iter48_xsubi(unsigned short xsubi[3]) {
  function nrand48 (line 82) | long nrand48(unsigned short xsubi[3]) {
  function jrand48 (line 89) | long jrand48(unsigned short xsubi[3]) {

FILE: app/src/control_msg.c
  function write_position (line 67) | static void
  function write_string_payload (line 76) | static size_t
  function write_string (line 87) | static size_t
  function write_string_tiny (line 95) | static size_t
  function sc_control_msg_serialize (line 103) | size_t
  function sc_control_msg_log (line 199) | void
  function sc_control_msg_is_droppable (line 327) | bool
  function sc_control_msg_destroy (line 337) | void

FILE: app/src/control_msg.h
  type sc_control_msg_type (line 27) | enum sc_control_msg_type {
  type sc_copy_key (line 48) | enum sc_copy_key {
  type sc_control_msg (line 54) | struct sc_control_msg {
  type sc_control_msg (line 120) | struct sc_control_msg
  type sc_control_msg (line 123) | struct sc_control_msg
  type sc_control_msg (line 128) | struct sc_control_msg
  type sc_control_msg (line 131) | struct sc_control_msg

FILE: app/src/controller.c
  function sc_controller_receiver_on_ended (line 10) | static void
  function sc_controller_init (line 20) | bool
  function sc_controller_configure (line 69) | void
  function sc_controller_destroy (line 77) | void
  function sc_controller_push_msg (line 92) | bool
  function process_msg (line 126) | static bool
  function run_controller (line 146) | static int
  function sc_controller_start (line 186) | bool
  function sc_controller_stop (line 206) | void
  function sc_controller_join (line 214) | void

FILE: app/src/controller.h
  type sc_control_msg_queue (line 15) | struct sc_control_msg_queue
  type sc_control_msg (line 15) | struct sc_control_msg
  type sc_controller (line 17) | struct sc_controller {
  type sc_controller_callbacks (line 30) | struct sc_controller_callbacks {
  type sc_controller (line 36) | struct sc_controller
  type sc_controller_callbacks (line 37) | struct sc_controller_callbacks
  type sc_controller (line 41) | struct sc_controller
  type sc_acksync (line 42) | struct sc_acksync
  type sc_uhid_devices (line 43) | struct sc_uhid_devices
  type sc_controller (line 46) | struct sc_controller
  type sc_controller (line 49) | struct sc_controller
  type sc_controller (line 52) | struct sc_controller
  type sc_controller (line 55) | struct sc_controller
  type sc_controller (line 58) | struct sc_controller
  type sc_control_msg (line 59) | struct sc_control_msg

FILE: app/src/coords.h
  type sc_size (line 6) | struct sc_size {
  type sc_point (line 11) | struct sc_point {
  type sc_position (line 16) | struct sc_position {

FILE: app/src/decoder.c
  function sc_decoder_open (line 12) | static bool
  function sc_decoder_close (line 30) | static void
  function sc_decoder_push (line 36) | static bool
  function sc_decoder_packet_sink_open (line 76) | static bool
  function sc_decoder_packet_sink_close (line 82) | static void
  function sc_decoder_packet_sink_push (line 88) | static bool
  function sc_decoder_init (line 95) | void

FILE: app/src/decoder.h
  type sc_decoder (line 11) | struct sc_decoder {
  type sc_decoder (line 23) | struct sc_decoder

FILE: app/src/delay_buffer.c
  function sc_delayed_frame_init (line 12) | static bool
  function sc_delayed_frame_destroy (line 29) | static void
  function run_buffering (line 35) | static int
  function sc_delay_buffer_frame_sink_open (line 110) | static bool
  function sc_delay_buffer_frame_sink_close (line 159) | static void
  function sc_delay_buffer_frame_sink_push (line 178) | static bool
  function sc_delay_buffer_init (line 224) | void

FILE: app/src/delay_buffer.h
  type AVFrame (line 19) | typedef struct AVFrame AVFrame;
  type sc_delayed_frame (line 21) | struct sc_delayed_frame {
  type sc_delayed_frame_queue (line 28) | struct sc_delayed_frame_queue
  type sc_delayed_frame (line 28) | struct sc_delayed_frame
  type sc_delay_buffer (line 30) | struct sc_delay_buffer {
  type sc_delay_buffer_callbacks (line 47) | struct sc_delay_buffer_callbacks {
  type sc_delay_buffer (line 60) | struct sc_delay_buffer

FILE: app/src/demuxer.c
  function sc_demuxer_to_avcodec_id (line 19) | static enum AVCodecID
  function sc_demuxer_recv_codec_id (line 54) | static bool
  function sc_demuxer_recv_video_size (line 66) | static bool
  function sc_demuxer_recv_packet (line 80) | static bool
  function run_demuxer (line 137) | static int
  function sc_demuxer_init (line 285) | void
  function sc_demuxer_start (line 300) | bool
  function sc_demuxer_join (line 313) | void

FILE: app/src/demuxer.h
  type sc_demuxer (line 12) | struct sc_demuxer {
  type sc_demuxer_status (line 24) | enum sc_demuxer_status {
  type sc_demuxer_callbacks (line 30) | struct sc_demuxer_callbacks {
  type sc_demuxer (line 37) | struct sc_demuxer
  type sc_demuxer_callbacks (line 38) | struct sc_demuxer_callbacks
  type sc_demuxer (line 41) | struct sc_demuxer
  type sc_demuxer (line 44) | struct sc_demuxer

FILE: app/src/device_msg.c
  function sc_device_msg_deserialize (line 10) | ssize_t
  function sc_device_msg_destroy (line 80) | void

FILE: app/src/device_msg.h
  type sc_device_msg_type (line 14) | enum sc_device_msg_type {
  type sc_device_msg (line 20) | struct sc_device_msg {
  type sc_device_msg (line 40) | struct sc_device_msg
  type sc_device_msg (line 43) | struct sc_device_msg

FILE: app/src/display.c
  function sc_display_init_novideo_icon (line 10) | static bool
  function sc_display_init (line 31) | bool
  function sc_display_destroy (line 114) | void
  function SDL_Texture (line 128) | static SDL_Texture *
  function sc_display_set_pending_size (line 156) | static inline void
  function sc_display_set_pending_frame (line 163) | static bool
  type sc_display (line 187) | struct sc_display
  function sc_display_apply_pending (line 190) | static bool
  function sc_display_set_texture_size_internal (line 218) | static bool
  function sc_display_set_texture_size (line 236) | enum sc_display_result
  function SDL_YUV_CONVERSION_MODE (line 248) | static SDL_YUV_CONVERSION_MODE
  function sc_display_update_texture_internal (line 254) | static bool
  function sc_display_update_texture (line 285) | enum sc_display_result
  function sc_display_render (line 301) | enum sc_display_result

FILE: app/src/display.h
  type sc_display (line 19) | struct sc_display {
  type sc_display_result (line 41) | enum sc_display_result {
  type sc_display (line 48) | struct sc_display
  type sc_display (line 52) | struct sc_display
  type sc_display_result (line 54) | enum sc_display_result
  type sc_display (line 55) | struct sc_display
  type sc_size (line 55) | struct sc_size
  type sc_display_result (line 57) | enum sc_display_result
  type sc_display (line 58) | struct sc_display
  type sc_display_result (line 60) | enum sc_display_result
  type sc_display (line 61) | struct sc_display
  type sc_orientation (line 62) | enum sc_orientation

FILE: app/src/events.c
  function sc_push_event_impl (line 8) | bool
  function sc_post_to_main_thread (line 24) | bool
  function task_event_filter (line 51) | static int SDLCALL
  function sc_reject_new_runnables (line 63) | void

FILE: app/src/file_pusher.c
  function sc_file_pusher_request_destroy (line 12) | static void
  function sc_file_pusher_init (line 17) | bool
  function sc_file_pusher_destroy (line 61) | void
  function sc_file_pusher_request (line 75) | bool
  function run_file_pusher (line 111) | static int
  function sc_file_pusher_start (line 160) | bool
  function sc_file_pusher_stop (line 173) | void
  function sc_file_pusher_join (line 184) | void

FILE: app/src/file_pusher.h
  type sc_file_pusher_action (line 12) | enum sc_file_pusher_action {
  type sc_file_pusher_request (line 17) | struct sc_file_pusher_request {
  type sc_file_pusher_request_queue (line 22) | struct sc_file_pusher_request_queue
  type sc_file_pusher_request (line 22) | struct sc_file_pusher_request
  type sc_file_pusher (line 24) | struct sc_file_pusher {
  type sc_file_pusher (line 38) | struct sc_file_pusher
  type sc_file_pusher (line 42) | struct sc_file_pusher
  type sc_file_pusher (line 45) | struct sc_file_pusher
  type sc_file_pusher (line 48) | struct sc_file_pusher
  type sc_file_pusher (line 51) | struct sc_file_pusher
  type sc_file_pusher (line 55) | struct sc_file_pusher
  type sc_file_pusher_action (line 56) | enum sc_file_pusher_action

FILE: app/src/fps_counter.c
  function sc_fps_counter_init (line 10) | bool
  function sc_fps_counter_destroy (line 30) | void
  function is_started (line 36) | static inline bool
  function set_started (line 41) | static inline void
  function display_fps (line 47) | static void
  function check_interval_expired (line 60) | static void
  function run_fps_counter (line 75) | static int
  function sc_fps_counter_start (line 97) | bool
  function sc_fps_counter_stop (line 126) | void
  function sc_fps_counter_is_started (line 133) | bool
  function sc_fps_counter_interrupt (line 138) | void
  function sc_fps_counter_join (line 151) | void
  function sc_fps_counter_add_rendered_frame (line 162) | void
  function sc_fps_counter_add_skipped_frame (line 175) | void

FILE: app/src/fps_counter.h
  type sc_fps_counter (line 12) | struct sc_fps_counter {
  type sc_fps_counter (line 31) | struct sc_fps_counter
  type sc_fps_counter (line 34) | struct sc_fps_counter
  type sc_fps_counter (line 37) | struct sc_fps_counter
  type sc_fps_counter (line 40) | struct sc_fps_counter
  type sc_fps_counter (line 43) | struct sc_fps_counter
  type sc_fps_counter (line 48) | struct sc_fps_counter
  type sc_fps_counter (line 51) | struct sc_fps_counter
  type sc_fps_counter (line 54) | struct sc_fps_counter
  type sc_fps_counter (line 57) | struct sc_fps_counter

FILE: app/src/frame_buffer.c
  function sc_frame_buffer_init (line 7) | bool
  function sc_frame_buffer_destroy (line 35) | void
  function swap_frames (line 42) | static inline void
  function sc_frame_buffer_push (line 49) | bool
  function sc_frame_buffer_consume (line 77) | void

FILE: app/src/frame_buffer.h
  type AVFrame (line 12) | typedef struct AVFrame AVFrame;
  type sc_frame_buffer (line 23) | struct sc_frame_buffer {
  type sc_frame_buffer (line 33) | struct sc_frame_buffer
  type sc_frame_buffer (line 36) | struct sc_frame_buffer
  type sc_frame_buffer (line 39) | struct sc_frame_buffer
  type sc_frame_buffer (line 43) | struct sc_frame_buffer

FILE: app/src/hid/hid_event.h
  type sc_hid_input (line 11) | struct sc_hid_input {
  type sc_hid_open (line 17) | struct sc_hid_open {
  type sc_hid_close (line 23) | struct sc_hid_close {

FILE: app/src/hid/hid_gamepad.c
  function sc_hid_gamepad_slot_init (line 199) | static void
  function sc_hid_gamepad_slot_find (line 213) | static ssize_t
  function sc_hid_gamepad_init (line 225) | void
  function sc_hid_gamepad_slot_get_id (line 232) | static inline uint16_t
  function sc_hid_gamepad_generate_open (line 238) | bool
  function sc_hid_gamepad_generate_close (line 259) | bool
  function sc_hid_gamepad_get_dpad_value (line 278) | static uint8_t
  function sc_hid_gamepad_event_from_slot (line 312) | static void
  function sc_hid_gamepad_get_button_id (line 331) | static uint32_t
  function sc_hid_gamepad_generate_input_from_button (line 370) | bool
  function sc_hid_gamepad_generate_input_from_axis (line 409) | bool

FILE: app/src/hid/hid_gamepad.h
  type sc_hid_gamepad_slot (line 16) | struct sc_hid_gamepad_slot {
  type sc_hid_gamepad (line 27) | struct sc_hid_gamepad {
  type sc_hid_gamepad (line 32) | struct sc_hid_gamepad
  type sc_hid_gamepad (line 35) | struct sc_hid_gamepad
  type sc_hid_open (line 36) | struct sc_hid_open
  type sc_hid_gamepad (line 40) | struct sc_hid_gamepad
  type sc_hid_close (line 41) | struct sc_hid_close
  type sc_hid_gamepad (line 45) | struct sc_hid_gamepad
  type sc_hid_input (line 46) | struct sc_hid_input
  type sc_gamepad_button_event (line 47) | struct sc_gamepad_button_event
  type sc_hid_gamepad (line 50) | struct sc_hid_gamepad
  type sc_hid_input (line 51) | struct sc_hid_input
  type sc_gamepad_axis_event (line 52) | struct sc_gamepad_axis_event

FILE: app/src/hid/hid_keyboard.c
  function sc_hid_keyboard_input_init (line 202) | static void
  function sc_hid_mod_from_sdl_keymod (line 214) | static uint16_t
  function sc_hid_keyboard_init (line 244) | void
  function scancode_is_modifier (line 249) | static inline bool
  function sc_hid_keyboard_generate_input_from_key (line 254) | bool
  function sc_hid_keyboard_generate_input_from_mods (line 312) | bool
  function sc_hid_keyboard_generate_open (line 337) | void sc_hid_keyboard_generate_open(struct sc_hid_open *hid_open) {
  function sc_hid_keyboard_generate_close (line 343) | void sc_hid_keyboard_generate_close(struct sc_hid_close *hid_close) {

FILE: app/src/hid/hid_keyboard.h
  type sc_hid_keyboard (line 32) | struct sc_hid_keyboard {
  type sc_hid_keyboard (line 37) | struct sc_hid_keyboard
  type sc_hid_open (line 40) | struct sc_hid_open
  type sc_hid_close (line 43) | struct sc_hid_close
  type sc_hid_keyboard (line 46) | struct sc_hid_keyboard
  type sc_hid_input (line 47) | struct sc_hid_input
  type sc_key_event (line 48) | struct sc_key_event
  type sc_hid_input (line 51) | struct sc_hid_input

FILE: app/src/hid/hid_mouse.c
  function sc_hid_mouse_input_init (line 141) | static void
  function sc_hid_buttons_from_buttons_state (line 148) | static uint8_t
  function sc_hid_mouse_generate_input_from_motion (line 169) | void
  function sc_hid_mouse_generate_input_from_click (line 182) | void
  function sc_hid_mouse_generate_input_from_scroll (line 195) | bool
  function sc_hid_mouse_generate_open (line 214) | void sc_hid_mouse_generate_open(struct sc_hid_open *hid_open) {
  function sc_hid_mouse_generate_close (line 220) | void sc_hid_mouse_generate_close(struct sc_hid_close *hid_close) {

FILE: app/src/hid/hid_mouse.h
  type sc_hid_open (line 12) | struct sc_hid_open
  type sc_hid_close (line 15) | struct sc_hid_close
  type sc_hid_input (line 18) | struct sc_hid_input
  type sc_mouse_motion_event (line 19) | struct sc_mouse_motion_event
  type sc_hid_input (line 22) | struct sc_hid_input
  type sc_mouse_click_event (line 23) | struct sc_mouse_click_event
  type sc_hid_input (line 26) | struct sc_hid_input
  type sc_mouse_scroll_event (line 27) | struct sc_mouse_scroll_event

FILE: app/src/icon.c
  function AVFrame (line 54) | static AVFrame *
  type SDL_PixelFormatEnum (line 162) | typedef int SDL_PixelFormatEnum;
  function SDL_PixelFormatEnum (line 165) | static SDL_PixelFormatEnum
  function SDL_Surface (line 187) | static SDL_Surface *
  function SDL_Surface (line 270) | SDL_Surface *
  function scrcpy_icon_destroy (line 282) | void

FILE: app/src/input_events.h
  type sc_mod (line 45) | enum sc_mod {
  type sc_action (line 59) | enum sc_action {
  type sc_keycode (line 64) | enum sc_keycode {
  type sc_scancode (line 197) | enum sc_scancode {
  type sc_mouse_button (line 316) | enum sc_mouse_button {
  type sc_gamepad_axis (line 328) | enum sc_gamepad_axis {
  type sc_gamepad_button (line 338) | enum sc_gamepad_button {
  type sc_mod (line 357) | enum sc_mod
  type sc_keycode (line 360) | enum sc_keycode
  type sc_scancode (line 363) | enum sc_scancode
  type sc_touch_action (line 366) | enum sc_touch_action {
  type sc_key_event (line 372) | struct sc_key_event {
  type sc_text_event (line 380) | struct sc_text_event {
  type sc_mouse_click_event (line 384) | struct sc_mouse_click_event {
  type sc_mouse_scroll_event (line 392) | struct sc_mouse_scroll_event {
  type sc_mouse_motion_event (line 401) | struct sc_mouse_motion_event {
  type sc_touch_event (line 409) | struct sc_touch_event {
  type sc_gamepad_device_event (line 421) | struct sc_gamepad_device_event {
  type sc_gamepad_button_event (line 425) | struct sc_gamepad_button_event {
  type sc_gamepad_axis_event (line 431) | struct sc_gamepad_axis_event {
  function sc_mods_state_from_sdl (line 437) | static inline uint16_t
  function sc_keycode_from_sdl (line 442) | static inline enum sc_keycode
  function sc_scancode_from_sdl (line 447) | static inline enum sc_scancode
  function sc_action_from_sdl_keyboard_type (line 452) | static inline enum sc_action
  function sc_action_from_sdl_mousebutton_type (line 461) | static inline enum sc_action
  function sc_touch_action_from_sdl (line 470) | static inline enum sc_touch_action
  function sc_mouse_button_from_sdl (line 483) | static inline enum sc_mouse_button
  function sc_mouse_buttons_state_from_sdl (line 493) | static inline uint8_t
  function sc_gamepad_axis_from_sdl (line 501) | static inline enum sc_gamepad_axis
  function sc_gamepad_button_from_sdl (line 511) | static inline enum sc_gamepad_button
  function sc_action_from_sdl_controllerbutton_type (line 521) | static inline enum sc_action

FILE: app/src/input_manager.c
  function sc_input_manager_init (line 15) | void
  function send_keycode (line 51) | static void
  function action_home (line 71) | static inline void
  function action_back (line 76) | static inline void
  function action_app_switch (line 81) | static inline void
  function action_power (line 86) | static inline void
  function action_volume_up (line 91) | static inline void
  function action_volume_down (line 96) | static inline void
  function action_menu (line 101) | static inline void
  function press_back_or_turn_screen_on (line 108) | static void
  function expand_notification_panel (line 124) | static void
  function expand_settings_panel (line 136) | static void
  function collapse_panels (line 148) | static void
  function get_device_clipboard (line 160) | static bool
  function set_device_clipboard (line 176) | static bool
  function set_display_power (line 209) | static void
  function switch_fps_counter_state (line 222) | static void
  function clipboard_paste (line 236) | static void
  function rotate_device (line 267) | static void
  function open_hard_keyboard_settings (line 279) | static void
  function reset_video (line 291) | static void
  function apply_orientation_transform (line 303) | static void
  function sc_input_manager_process_text_input (line 312) | static void
  function simulate_virtual_finger (line 333) | static bool
  function inverse_point (line 357) | static struct sc_point
  function sc_input_manager_process_key (line 369) | static void
  function sc_input_manager_get_position (line 615) | static struct sc_position
  function sc_input_manager_process_mouse_motion (line 632) | static void
  function sc_input_manager_process_touch (line 667) | static void
  function sc_input_manager_get_binding (line 697) | static enum sc_mouse_binding
  function sc_input_manager_process_mouse_button (line 716) | static void
  function sc_input_manager_process_mouse_wheel (line 883) | static void
  function sc_input_manager_process_gamepad_device (line 914) | static void
  function sc_input_manager_process_gamepad_axis (line 955) | static void
  function sc_input_manager_process_gamepad_button (line 971) | static void
  function is_apk (line 987) | static bool
  function sc_input_manager_process_file (line 993) | static void
  function sc_input_manager_handle_event (line 1015) | void

FILE: app/src/input_manager.h
  type sc_input_manager (line 18) | struct sc_input_manager {
  type sc_input_manager_params (line 49) | struct sc_input_manager_params {
  type sc_input_manager (line 64) | struct sc_input_manager
  type sc_input_manager_params (line 65) | struct sc_input_manager_params
  type sc_input_manager (line 68) | struct sc_input_manager

FILE: app/src/keyboard_sdk.c
  function convert_keycode_action (line 20) | static enum android_keyevent_action
  function convert_keycode (line 29) | static bool
  function autocomplete_metastate (line 196) | static enum android_metastate
  function convert_meta_state (line 215) | static enum android_metastate
  function convert_input_key (line 253) | static bool
  function sc_key_processor_process_key (line 270) | static void
  function sc_key_processor_process_text (line 298) | static void
  function sc_keyboard_sdk_init (line 330) | void

FILE: app/src/keyboard_sdk.h
  type sc_keyboard_sdk (line 12) | struct sc_keyboard_sdk {
  type sc_keyboard_sdk (line 26) | struct sc_keyboard_sdk
  type sc_controller (line 27) | struct sc_controller
  type sc_key_inject_mode (line 28) | enum sc_key_inject_mode

FILE: app/src/main.c
  function main_scrcpy (line 25) | static int
  function main (line 106) | int

FILE: app/src/mouse_capture.c
  function sc_mouse_capture_init (line 6) | void
  function sc_mouse_capture_is_capture_key (line 14) | static inline bool
  function sc_mouse_capture_handle_event (line 19) | bool
  function sc_mouse_capture_set_active (line 85) | void
  function sc_mouse_capture_is_active (line 113) | bool
  function sc_mouse_capture_toggle (line 119) | void

FILE: app/src/mouse_capture.h
  type sc_mouse_capture (line 10) | struct sc_mouse_capture {
  type sc_mouse_capture (line 21) | struct sc_mouse_capture
  type sc_mouse_capture (line 25) | struct sc_mouse_capture
  type sc_mouse_capture (line 28) | struct sc_mouse_capture
  type sc_mouse_capture (line 31) | struct sc_mouse_capture
  type sc_mouse_capture (line 35) | struct sc_mouse_capture

FILE: app/src/mouse_sdk.c
  function convert_mouse_buttons (line 15) | static enum android_motionevent_buttons
  function convert_mouse_action (line 36) | static enum android_motionevent_action
  function convert_touch_action (line 45) | static enum android_motionevent_action
  function sc_mouse_processor_process_mouse_motion (line 58) | static void
  function sc_mouse_processor_process_mouse_click (line 85) | static void
  function sc_mouse_processor_process_mouse_scroll (line 107) | static void
  function sc_mouse_processor_process_touch (line 127) | static void
  function sc_mouse_sdk_init (line 148) | void

FILE: app/src/mouse_sdk.h
  type sc_mouse_sdk (line 11) | struct sc_mouse_sdk {
  type sc_mouse_sdk (line 19) | struct sc_mouse_sdk
  type sc_controller (line 19) | struct sc_controller

FILE: app/src/opengl.c
  function sc_opengl_init (line 8) | void
  function sc_opengl_version_at_least (line 43) | bool

FILE: app/src/opengl.h
  type sc_opengl (line 9) | struct sc_opengl {
  type sc_opengl (line 29) | struct sc_opengl
  type sc_opengl (line 32) | struct sc_opengl

FILE: app/src/options.c
  type scrcpy_options (line 5) | struct scrcpy_options
  function sc_orientation_apply (line 118) | enum sc_orientation

FILE: app/src/options.h
  type sc_log_level (line 12) | enum sc_log_level {
  type sc_record_format (line 20) | enum sc_record_format {
  function sc_record_format_is_audio_only (line 32) | static inline bool
  type sc_codec (line 42) | enum sc_codec {
  type sc_video_source (line 52) | enum sc_video_source {
  type sc_audio_source (line 57) | enum sc_audio_source {
  type sc_camera_facing (line 72) | enum sc_camera_facing {
  type sc_orientation (line 83) | enum sc_orientation {         // v v v
  type sc_orientation_lock (line 94) | enum sc_orientation_lock {
  type sc_display_ime_policy (line 100) | enum sc_display_ime_policy {
  function sc_orientation_is_mirror (line 107) | static inline bool
  function sc_orientation_is_swap (line 114) | static inline bool
  function sc_orientation_get_rotation (line 120) | static inline enum sc_orientation
  type sc_orientation (line 126) | enum sc_orientation
  type sc_orientation (line 127) | enum sc_orientation
  type sc_orientation (line 127) | enum sc_orientation
  type sc_orientation (line 130) | enum sc_orientation
  type sc_keyboard_input_mode (line 153) | enum sc_keyboard_input_mode {
  type sc_mouse_input_mode (line 162) | enum sc_mouse_input_mode {
  type sc_gamepad_input_mode (line 171) | enum sc_gamepad_input_mode {
  type sc_mouse_binding (line 178) | enum sc_mouse_binding {
  type sc_mouse_binding_set (line 188) | struct sc_mouse_binding_set {
  type sc_mouse_bindings (line 195) | struct sc_mouse_bindings {
  type sc_key_inject_mode (line 200) | enum sc_key_inject_mode {
  type sc_shortcut_mod (line 214) | enum sc_shortcut_mod {
  type sc_port_range (line 223) | struct sc_port_range {
  type scrcpy_options (line 230) | struct scrcpy_options {
  type scrcpy_options (line 332) | struct scrcpy_options

FILE: app/src/packet_merger.c
  function sc_packet_merger_init (line 9) | void
  function sc_packet_merger_destroy (line 14) | void
  function sc_packet_merger_merge (line 19) | bool

FILE: app/src/packet_merger.h
  type sc_packet_merger (line 23) | struct sc_packet_merger {
  type sc_packet_merger (line 29) | struct sc_packet_merger
  type sc_packet_merger (line 32) | struct sc_packet_merger
  type sc_packet_merger (line 41) | struct sc_packet_merger

FILE: app/src/receiver.c
  type sc_uhid_output_task_data (line 13) | struct sc_uhid_output_task_data {
  function sc_receiver_init (line 20) | bool
  function sc_receiver_destroy (line 39) | void
  function task_set_clipboard (line 44) | static void
  function task_uhid_output (line 63) | static void
  function process_msg (line 76) | static void
  function process_msgs (line 156) | static ssize_t
  function run_receiver (line 180) | static int
  function sc_receiver_start (line 219) | bool
  function sc_receiver_join (line 233) | void

FILE: app/src/receiver.h
  type sc_receiver (line 15) | struct sc_receiver {
  type sc_receiver_callbacks (line 27) | struct sc_receiver_callbacks {
  type sc_receiver (line 32) | struct sc_receiver
  type sc_receiver_callbacks (line 33) | struct sc_receiver_callbacks
  type sc_receiver (line 36) | struct sc_receiver
  type sc_receiver (line 39) | struct sc_receiver
  type sc_receiver (line 44) | struct sc_receiver

FILE: app/src/recorder.c
  function AVOutputFormat (line 23) | static const AVOutputFormat *
  function AVPacket (line 40) | static AVPacket *
  function sc_recorder_queue_clear (line 56) | static void
  type sc_record_format (line 65) | enum sc_record_format
  function sc_recorder_set_extradata (line 85) | static bool
  function sc_recorder_rescale_packet (line 101) | static inline void
  function sc_recorder_write_stream (line 106) | static bool
  function sc_recorder_write_video (line 123) | static inline bool
  function sc_recorder_write_audio (line 128) | static inline bool
  function sc_recorder_open_output_file (line 133) | static bool
  function sc_recorder_close_output_file (line 176) | static void
  function sc_recorder_must_wait_for_config_packets (line 182) | static inline bool
  function sc_recorder_process_header (line 199) | static bool
  function sc_recorder_process_packets (line 284) | static bool
  function sc_recorder_record (line 461) | static bool
  function run_recorder (line 473) | static int
  function sc_recorder_set_orientation (line 506) | static bool
  function sc_recorder_video_packet_sink_open (line 542) | static bool
  function sc_recorder_video_packet_sink_close (line 586) | static void
  function sc_recorder_video_packet_sink_push (line 599) | static bool
  function sc_recorder_audio_packet_sink_open (line 636) | static bool
  function sc_recorder_audio_packet_sink_close (line 671) | static void
  function sc_recorder_audio_packet_sink_push (line 685) | static bool
  function sc_recorder_audio_packet_sink_disable (line 723) | static void
  function sc_recorder_stream_init (line 739) | static void
  function sc_recorder_init (line 745) | bool
  function sc_recorder_start (line 823) | bool
  function sc_recorder_stop (line 835) | void
  function sc_recorder_join (line 843) | void
  function sc_recorder_destroy (line 848) | void

FILE: app/src/recorder.h
  type sc_recorder_queue (line 16) | struct sc_recorder_queue
  type sc_recorder_stream (line 18) | struct sc_recorder_stream {
  type sc_recorder (line 23) | struct sc_recorder {
  type sc_recorder_callbacks (line 65) | struct sc_recorder_callbacks {
  type sc_recorder (line 71) | struct sc_recorder
  type sc_record_format (line 72) | enum sc_record_format
  type sc_orientation (line 73) | enum sc_orientation
  type sc_recorder_callbacks (line 74) | struct sc_recorder_callbacks
  type sc_recorder (line 77) | struct sc_recorder
  type sc_recorder (line 80) | struct sc_recorder
  type sc_recorder (line 83) | struct sc_recorder
  type sc_recorder (line 86) | struct sc_recorder

FILE: app/src/scrcpy.c
  type scrcpy (line 48) | struct scrcpy {
  function BOOL (line 95) | static BOOL WINAPI windows_ctrl_handler(DWORD ctrl_type) {
  function sdl_set_hints (line 104) | static void
  function sdl_configure (line 157) | static void
  function event_loop (line 178) | static enum scrcpy_exit_code
  function terminate_event_loop (line 220) | static void
  function await_for_server (line 236) | static bool
  function sc_recorder_on_ended (line 262) | static void
  function sc_video_demuxer_on_ended (line 273) | static void
  function sc_audio_demuxer_on_ended (line 289) | static void
  function sc_controller_on_ended (line 307) | static void
  function sc_server_on_connection_failed (line 322) | static void
  function sc_server_on_connected (line 330) | static void
  function sc_server_on_disconnected (line 338) | static void
  function sc_timeout_on_timeout (line 348) | static void
  function scrcpy_generate_scid (line 357) | static uint32_t
  function init_sdl_gamepads (line 365) | static void
  function scrcpy (line 380) | enum scrcpy_exit_code

FILE: app/src/scrcpy.h
  type scrcpy_exit_code (line 8) | enum scrcpy_exit_code {
  type scrcpy_exit_code (line 19) | enum scrcpy_exit_code
  type scrcpy_options (line 20) | struct scrcpy_options

FILE: app/src/screen.c
  function get_oriented_size (line 16) | static inline struct sc_size
  function get_window_size (line 30) | static struct sc_size
  function get_window_position (line 42) | static struct sc_point
  function set_window_size (line 55) | static void
  function get_preferred_display_bounds (line 64) | static bool
  function is_optimal_size (line 77) | static bool
  function get_optimal_size (line 92) | static struct sc_size
  function get_initial_optimal_size (line 134) | static inline struct sc_size
  function sc_screen_is_relative_mode (line 159) | static inline bool
  function sc_screen_update_content_rect (line 165) | static void
  function sc_screen_render (line 208) | static void
  function sc_screen_render_novideo (line 221) | static void
  function event_watcher (line 238) | static int
  function sc_screen_frame_sink_open (line 253) | static bool
  function sc_screen_frame_sink_close (line 288) | static void
  function sc_screen_frame_sink_push (line 299) | static bool
  function sc_screen_init (line 325) | bool
  function sc_screen_show_initial_window (line 487) | static void
  function sc_screen_hide_window (line 513) | void
  function sc_screen_interrupt (line 518) | void
  function sc_screen_join (line 523) | void
  function sc_screen_destroy (line 528) | void
  function resize_for_content (line 540) | static void
  function set_content_size (line 556) | static void
  function apply_pending_resize (line 572) | static void
  function sc_screen_set_orientation (line 586) | void
  function sc_screen_init_size (line 606) | static bool
  function prepare_for_frame (line 623) | static enum sc_display_result
  function sc_screen_apply_frame (line 644) | static bool
  function sc_screen_update_frame (line 685) | static bool
  function sc_screen_set_paused (line 708) | void
  function sc_screen_toggle_fullscreen (line 737) | void
  function sc_screen_resize_to_fit (line 756) | void
  function sc_screen_resize_to_pixel_perfect (line 782) | void
  function sc_screen_handle_event (line 801) | bool
  function sc_screen_convert_drawable_to_frame_coords (line 874) | struct sc_point
  function sc_screen_convert_window_to_frame_coords (line 930) | struct sc_point
  function sc_screen_hidpi_scale_coords (line 937) | void

FILE: app/src/screen.h
  type sc_screen (line 25) | struct sc_screen {
  type sc_screen_params (line 74) | struct sc_screen_params {
  type sc_screen (line 107) | struct sc_screen
  type sc_screen_params (line 107) | struct sc_screen_params
  type sc_screen (line 112) | struct sc_screen
  type sc_screen (line 116) | struct sc_screen
  type sc_screen (line 120) | struct sc_screen
  type sc_screen (line 127) | struct sc_screen
  type sc_screen (line 131) | struct sc_screen
  type sc_screen (line 135) | struct sc_screen
  type sc_screen (line 139) | struct sc_screen
  type sc_screen (line 143) | struct sc_screen
  type sc_orientation (line 144) | enum sc_orientation
  type sc_screen (line 148) | struct sc_screen
  type sc_screen (line 153) | struct sc_screen
  type sc_point (line 157) | struct sc_point
  type sc_screen (line 158) | struct sc_screen
  type sc_point (line 163) | struct sc_point
  type sc_screen (line 164) | struct sc_screen
  type sc_screen (line 172) | struct sc_screen

FILE: app/src/server.c
  function push_server (line 56) | static bool
  type sc_log_level (line 73) | enum sc_log_level
  function sc_server_sleep (line 91) | static bool
  type sc_codec (line 106) | enum sc_codec
  type sc_camera_facing (line 129) | enum sc_camera_facing
  type sc_audio_source (line 144) | enum sc_audio_source
  type sc_display_ime_policy (line 175) | enum sc_display_ime_policy
  function validate_string (line 189) | static bool
  function sc_pid (line 204) | static sc_pid
  function connect_and_read_byte (line 466) | static bool
  function sc_socket (line 485) | static sc_socket
  function sc_server_init (line 518) | bool
  function device_read_info (line 572) | static bool
  function sc_server_connect_to (line 588) | static bool
  function sc_server_on_terminated (line 744) | static void
  function get_adb_tcp_port (line 759) | static uint16_t
  function wait_tcpip_mode_enabled (line 783) | static bool
  type sc_server (line 823) | struct sc_server
  type sc_intr (line 826) | struct sc_intr
  function sc_server_connect_to_tcpip (line 868) | static bool
  function sc_server_configure_tcpip_known_address (line 890) | static bool
  function sc_server_configure_tcpip_unknown_address (line 906) | static bool
  function sc_server_kill_adb_if_requested (line 931) | static void
  function run_server (line 940) | static int
  function sc_server_start (line 1155) | bool
  function sc_server_stop (line 1167) | void
  function sc_server_join (line 1176) | void
  function sc_server_destroy (line 1181) | void

FILE: app/src/server.h
  type sc_server_info (line 17) | struct sc_server_info {
  type sc_server_params (line 21) | struct sc_server_params {
  type sc_server (line 76) | struct sc_server {
  type sc_server_callbacks (line 100) | struct sc_server_callbacks {
  type sc_server (line 122) | struct sc_server
  type sc_server_params (line 122) | struct sc_server_params
  type sc_server_callbacks (line 123) | struct sc_server_callbacks
  type sc_server (line 127) | struct sc_server
  type sc_server (line 131) | struct sc_server
  type sc_server (line 135) | struct sc_server
  type sc_server (line 139) | struct sc_server

FILE: app/src/shortcut_mod.h
  function sc_shortcut_mods_to_sdl (line 17) | static inline uint16_t
  function sc_shortcut_mods_is_shortcut_mod (line 41) | static inline bool
  function sc_shortcut_mods_is_shortcut_key (line 50) | static inline bool

FILE: app/src/sys/unix/file.c
  function sc_file_executable_exists (line 16) | bool
  function sc_file_is_regular (line 86) | bool

FILE: app/src/sys/unix/process.c
  function sc_process_execute_p (line 15) | enum sc_process_result
  function sc_process_terminate (line 192) | bool
  function sc_exit_code (line 202) | sc_exit_code
  function sc_process_close (line 221) | void
  function sc_pipe_read (line 226) | ssize_t
  function sc_pipe_close (line 231) | void

FILE: app/src/sys/win/file.c
  function sc_file_is_regular (line 25) | bool

FILE: app/src/sys/win/process.c
  function build_cmd (line 12) | static bool
  function sc_process_execute_p (line 26) | enum sc_process_result
  function sc_process_terminate (line 220) | bool
  function sc_exit_code (line 225) | sc_exit_code
  function sc_process_close (line 239) | void
  function sc_pipe_read (line 246) | ssize_t
  function sc_pipe_close (line 255) | void

FILE: app/src/trait/frame_sink.h
  type sc_frame_sink (line 14) | struct sc_frame_sink {
  type sc_frame_sink_ops (line 18) | struct sc_frame_sink_ops {

FILE: app/src/trait/frame_source.c
  function sc_frame_source_init (line 5) | void
  function sc_frame_source_add_sink (line 10) | void
  function sc_frame_source_sinks_close_firsts (line 19) | static void
  function sc_frame_source_sinks_open (line 28) | bool
  function sc_frame_source_sinks_close (line 43) | void
  function sc_frame_source_sinks_push (line 49) | bool

FILE: app/src/trait/frame_source.h
  type sc_frame_source (line 17) | struct sc_frame_source {
  type sc_frame_source (line 23) | struct sc_frame_source
  type sc_frame_source (line 26) | struct sc_frame_source
  type sc_frame_sink (line 27) | struct sc_frame_sink
  type sc_frame_source (line 30) | struct sc_frame_source
  type sc_frame_source (line 34) | struct sc_frame_source
  type sc_frame_source (line 37) | struct sc_frame_source

FILE: app/src/trait/gamepad_processor.h
  type sc_gamepad_processor (line 13) | struct sc_gamepad_processor {
  type sc_gamepad_processor_ops (line 17) | struct sc_gamepad_processor_ops {

FILE: app/src/trait/key_processor.h
  type sc_key_processor (line 15) | struct sc_key_processor {
  type sc_key_processor_ops (line 35) | struct sc_key_processor_ops {

FILE: app/src/trait/mouse_processor.h
  type sc_mouse_processor (line 16) | struct sc_mouse_processor {
  type sc_mouse_processor_ops (line 27) | struct sc_mouse_processor_ops {

FILE: app/src/trait/packet_sink.h
  type sc_packet_sink (line 14) | struct sc_packet_sink {
  type sc_packet_sink_ops (line 18) | struct sc_packet_sink_ops {

FILE: app/src/trait/packet_source.c
  function sc_packet_source_init (line 5) | void
  function sc_packet_source_add_sink (line 10) | void
  function sc_packet_source_sinks_close_firsts (line 19) | static void
  function sc_packet_source_sinks_open (line 28) | bool
  function sc_packet_source_sinks_close (line 43) | void
  function sc_packet_source_sinks_push (line 49) | bool
  function sc_packet_source_sinks_disable (line 63) | void

FILE: app/src/trait/packet_source.h
  type sc_packet_source (line 17) | struct sc_packet_source {
  type sc_packet_source (line 23) | struct sc_packet_source
  type sc_packet_source (line 26) | struct sc_packet_source
  type sc_packet_sink (line 27) | struct sc_packet_sink
  type sc_packet_source (line 30) | struct sc_packet_source
  type sc_packet_source (line 34) | struct sc_packet_source
  type sc_packet_source (line 37) | struct sc_packet_source
  type sc_packet_source (line 41) | struct sc_packet_source

FILE: app/src/uhid/gamepad_uhid.c
  function sc_gamepad_uhid_send_input (line 20) | static void
  function sc_gamepad_uhid_send_open (line 37) | static void
  function sc_gamepad_uhid_send_close (line 54) | static void
  function sc_gamepad_processor_process_gamepad_added (line 66) | static void
  function sc_gamepad_processor_process_gamepad_removed (line 86) | static void
  function sc_gamepad_processor_process_gamepad_axis (line 102) | static void
  function sc_gamepad_processor_process_gamepad_button (line 116) | static void
  function sc_gamepad_uhid_init (line 131) | void

FILE: app/src/uhid/gamepad_uhid.h
  type sc_gamepad_uhid (line 10) | struct sc_gamepad_uhid {
  type sc_gamepad_uhid (line 18) | struct sc_gamepad_uhid
  type sc_controller (line 19) | struct sc_controller

FILE: app/src/uhid/keyboard_uhid.c
  function sc_keyboard_uhid_send_input (line 18) | static void
  function sc_keyboard_uhid_synchronize_mod (line 34) | static void
  function sc_key_processor_process_key (line 57) | static void
  function sc_keyboard_uhid_to_sc_mod (line 90) | static unsigned
  function sc_keyboard_uhid_process_hid_output (line 104) | void
  function sc_keyboard_uhid_init (line 122) | bool

FILE: app/src/uhid/keyboard_uhid.h
  type sc_keyboard_uhid (line 12) | struct sc_keyboard_uhid {
  type sc_keyboard_uhid (line 21) | struct sc_keyboard_uhid
  type sc_controller (line 22) | struct sc_controller
  type sc_keyboard_uhid (line 25) | struct sc_keyboard_uhid

FILE: app/src/uhid/mouse_uhid.c
  function sc_mouse_uhid_send_input (line 13) | static void
  function sc_mouse_processor_process_mouse_motion (line 30) | static void
  function sc_mouse_processor_process_mouse_click (line 41) | static void
  function sc_mouse_processor_process_mouse_scroll (line 52) | static void
  function sc_mouse_uhid_init (line 65) | bool

FILE: app/src/uhid/mouse_uhid.h
  type sc_mouse_uhid (line 9) | struct sc_mouse_uhid {
  type sc_mouse_uhid (line 16) | struct sc_mouse_uhid
  type sc_controller (line 17) | struct sc_controller

FILE: app/src/uhid/uhid_output.c
  function sc_uhid_devices_init (line 8) | void
  function sc_uhid_devices_process_hid_output (line 14) | void

FILE: app/src/uhid/uhid_output.h
  type sc_uhid_devices (line 15) | struct sc_uhid_devices {
  type sc_uhid_devices (line 20) | struct sc_uhid_devices
  type sc_keyboard_uhid (line 21) | struct sc_keyboard_uhid
  type sc_uhid_devices (line 24) | struct sc_uhid_devices

FILE: app/src/usb/aoa_hid.c
  type sc_vec_hid_ids (line 27) | struct sc_vec_hid_ids
  function sc_hid_input_log (line 29) | static void
  function sc_hid_open_log (line 41) | static void
  function sc_hid_close_log (line 54) | static void
  function sc_aoa_init (line 60) | bool
  function sc_aoa_destroy (line 88) | void
  function sc_aoa_register_hid (line 96) | static bool
  function sc_aoa_set_hid_report_desc (line 120) | static bool
  function sc_aoa_send_hid_event (line 157) | static bool
  function sc_aoa_unregister_hid (line 181) | static bool
  function sc_aoa_setup_hid (line 204) | static bool
  function sc_aoa_push_input_with_ack_to_wait (line 224) | bool
  function sc_aoa_push_open (line 258) | bool
  function sc_aoa_push_close (line 290) | bool
  function sc_aoa_process_event (line 320) | static bool
  function run_aoa_thread (line 404) | static int
  function sc_aoa_start (line 447) | bool
  function sc_aoa_stop (line 460) | void
  function sc_aoa_join (line 472) | void

FILE: app/src/usb/aoa_hid.h
  type sc_aoa_event_type (line 15) | enum sc_aoa_event_type {
  type sc_aoa_event (line 21) | struct sc_aoa_event {
  type sc_aoa_event_queue (line 38) | struct sc_aoa_event_queue
  type sc_aoa_event (line 38) | struct sc_aoa_event
  type sc_aoa (line 40) | struct sc_aoa {
  type sc_aoa (line 52) | struct sc_aoa
  type sc_usb (line 52) | struct sc_usb
  type sc_acksync (line 52) | struct sc_acksync
  type sc_aoa (line 55) | struct sc_aoa
  type sc_aoa (line 58) | struct sc_aoa
  type sc_aoa (line 61) | struct sc_aoa
  type sc_aoa (line 64) | struct sc_aoa
  type sc_aoa (line 76) | struct sc_aoa
  type sc_hid_open (line 76) | struct sc_hid_open
  type sc_aoa (line 80) | struct sc_aoa
  type sc_hid_close (line 80) | struct sc_hid_close
  type sc_aoa (line 83) | struct sc_aoa
  type sc_hid_input (line 84) | struct sc_hid_input
  function sc_aoa_push_input (line 87) | static inline bool

FILE: app/src/usb/gamepad_aoa.c
  function sc_gamepad_processor_process_gamepad_added (line 11) | static void
  function sc_gamepad_processor_process_gamepad_removed (line 28) | static void
  function sc_gamepad_processor_process_gamepad_axis (line 44) | static void
  function sc_gamepad_processor_process_gamepad_button (line 60) | static void
  function sc_gamepad_aoa_init (line 76) | void
  function sc_gamepad_aoa_destroy (line 92) | void

FILE: app/src/usb/gamepad_aoa.h
  type sc_gamepad_aoa (line 10) | struct sc_gamepad_aoa {
  type sc_gamepad_aoa (line 18) | struct sc_gamepad_aoa
  type sc_aoa (line 18) | struct sc_aoa
  type sc_gamepad_aoa (line 21) | struct sc_gamepad_aoa

FILE: app/src/usb/keyboard_aoa.c
  function push_mod_lock_state (line 11) | static bool
  function sc_key_processor_process_key (line 29) | static void
  function sc_keyboard_aoa_init (line 65) | bool
  function sc_keyboard_aoa_destroy (line 99) | void

FILE: app/src/usb/keyboard_aoa.h
  type sc_keyboard_aoa (line 12) | struct sc_keyboard_aoa {
  type sc_keyboard_aoa (line 22) | struct sc_keyboard_aoa
  type sc_aoa (line 22) | struct sc_aoa
  type sc_keyboard_aoa (line 25) | struct sc_keyboard_aoa

FILE: app/src/usb/mouse_aoa.c
  function sc_mouse_processor_process_mouse_motion (line 13) | static void
  function sc_mouse_processor_process_mouse_click (line 26) | static void
  function sc_mouse_processor_process_mouse_scroll (line 39) | static void
  function sc_mouse_aoa_init (line 54) | bool
  function sc_mouse_aoa_destroy (line 82) | void

FILE: app/src/usb/mouse_aoa.h
  type sc_mouse_aoa (line 11) | struct sc_mouse_aoa {
  type sc_mouse_aoa (line 18) | struct sc_mouse_aoa
  type sc_aoa (line 18) | struct sc_aoa
  type sc_mouse_aoa (line 21) | struct sc_mouse_aoa

FILE: app/src/usb/scrcpy_otg.c
  type scrcpy_otg (line 19) | struct scrcpy_otg {
  function sc_usb_on_disconnected (line 29) | static void
  function event_loop (line 37) | static enum scrcpy_exit_code
  function scrcpy_otg (line 59) | enum scrcpy_exit_code

FILE: app/src/usb/scrcpy_otg.h
  type scrcpy_exit_code (line 9) | enum scrcpy_exit_code
  type scrcpy_options (line 10) | struct scrcpy_options

FILE: app/src/usb/screen_otg.c
  function sc_screen_otg_render (line 11) | static void
  function sc_screen_otg_init (line 20) | bool
  function sc_screen_otg_destroy (line 94) | void
  function sc_screen_otg_process_key (line 103) | static void
  function sc_screen_otg_process_mouse_motion (line 121) | static void
  function sc_screen_otg_process_mouse_button (line 138) | static void
  function sc_screen_otg_process_mouse_wheel (line 157) | static void
  function sc_screen_otg_process_gamepad_device (line 183) | static void
  function sc_screen_otg_process_gamepad_axis (line 224) | static void
  function sc_screen_otg_process_gamepad_button (line 243) | static void
  function sc_screen_otg_handle_event (line 262) | void

FILE: app/src/usb/screen_otg.h
  type sc_screen_otg (line 15) | struct sc_screen_otg {
  type sc_screen_otg_params (line 27) | struct sc_screen_otg_params {
  type sc_screen_otg (line 43) | struct sc_screen_otg
  type sc_screen_otg_params (line 44) | struct sc_screen_otg_params
  type sc_screen_otg (line 47) | struct sc_screen_otg
  type sc_screen_otg (line 50) | struct sc_screen_otg

FILE: app/src/usb/usb.c
  type sc_vec_usb_devices (line 8) | struct sc_vec_usb_devices
  type sc_usb_device (line 8) | struct sc_usb_device
  function sc_usb_read_device (line 36) | static bool
  function sc_usb_device_destroy (line 77) | void
  function sc_usb_device_move (line 87) | void
  function sc_usb_devices_destroy (line 96) | static void
  function sc_usb_list_devices (line 104) | static bool
  function sc_usb_accept_device (line 132) | static bool
  function sc_usb_devices_select (line 141) | static size_t
  function sc_usb_devices_log (line 159) | static void
  function sc_usb_select_device (line 172) | bool
  function sc_usb_init (line 225) | bool
  function sc_usb_destroy (line 231) | void
  function sc_usb_report_disconnected (line 236) | static void
  function sc_usb_check_disconnected (line 244) | bool
  function LIBUSB_CALL (line 254) | static LIBUSB_CALL int
  function run_libusb_event_handler (line 278) | static int
  function sc_usb_register_callback (line 288) | static bool
  function sc_usb_connect (line 325) | bool
  function sc_usb_disconnect (line 361) | void
  function sc_usb_stop (line 366) | void
  function sc_usb_join (line 374) | void

FILE: app/src/usb/usb.h
  type sc_usb (line 11) | struct sc_usb {
  type sc_usb_callbacks (line 28) | struct sc_usb_callbacks {
  type sc_usb_device (line 32) | struct sc_usb_device {
  type sc_usb_device (line 43) | struct sc_usb_device
  type sc_usb_device (line 55) | struct sc_usb_device
  type sc_usb_device (line 55) | struct sc_usb_device
  type sc_usb_device (line 58) | struct sc_usb_device
  type sc_usb (line 61) | struct sc_usb
  type sc_usb (line 64) | struct sc_usb
  type sc_usb (line 67) | struct sc_usb
  type sc_usb_device (line 68) | struct sc_usb_device
  type sc_usb (line 71) | struct sc_usb
  type sc_usb_callbacks (line 72) | struct sc_usb_callbacks
  type sc_usb (line 75) | struct sc_usb
  type sc_usb (line 80) | struct sc_usb
  type sc_usb (line 83) | struct sc_usb
  type sc_usb (line 86) | struct sc_usb

FILE: app/src/util/acksync.c
  function sc_acksync_init (line 5) | bool
  function sc_acksync_destroy (line 24) | void
  function sc_acksync_ack (line 30) | void
  function sc_acksync_wait (line 43) | enum sc_acksync_wait_result
  function sc_acksync_interrupt (line 69) | void

FILE: app/src/util/acksync.h
  type sc_acksync (line 21) | struct sc_acksync {
  type sc_acksync_wait_result (line 31) | enum sc_acksync_wait_result {
  type sc_acksync (line 43) | struct sc_acksync
  type sc_acksync (line 46) | struct sc_acksync
  type sc_acksync (line 55) | struct sc_acksync
  type sc_acksync_wait_result (line 60) | enum sc_acksync_wait_result
  type sc_acksync (line 61) | struct sc_acksync
  type sc_acksync (line 67) | struct sc_acksync

FILE: app/src/util/audiobuf.c
  function sc_audiobuf_init (line 8) | bool
  function sc_audiobuf_destroy (line 30) | void
  function sc_audiobuf_read (line 35) | uint32_t
  function sc_audiobuf_write (line 79) | uint32_t
  function sc_audiobuf_write_silence (line 120) | uint32_t

FILE: app/src/util/audiobuf.h
  type sc_audiobuf (line 17) | struct sc_audiobuf {
  function sc_audiobuf_to_samples (line 28) | static inline uint32_t
  function sc_audiobuf_to_bytes (line 34) | static inline size_t
  type sc_audiobuf (line 40) | struct sc_audiobuf
  type sc_audiobuf (line 44) | struct sc_audiobuf
  type sc_audiobuf (line 47) | struct sc_audiobuf
  type sc_audiobuf (line 50) | struct sc_audiobuf
  type sc_audiobuf (line 54) | struct sc_audiobuf
  function sc_audiobuf_capacity (line 56) | static inline uint32_t
  function sc_audiobuf_can_read (line 62) | static inline uint32_t

FILE: app/src/util/average.c
  function sc_average_init (line 5) | void
  function sc_average_push (line 12) | void
  function sc_average_get (line 22) | float

FILE: app/src/util/average.h
  type sc_average (line 6) | struct sc_average {
  type sc_average (line 20) | struct sc_average
  type sc_average (line 26) | struct sc_average
  type sc_average (line 35) | struct sc_average

FILE: app/src/util/binary.h
  function sc_write16be (line 9) | static inline void
  function sc_write16le (line 15) | static inline void
  function sc_write32be (line 21) | static inline void
  function sc_write32le (line 29) | static inline void
  function sc_write64be (line 37) | static inline void
  function sc_write64le (line 43) | static inline void
  function sc_read16be (line 49) | static inline uint16_t
  function sc_read32be (line 54) | static inline uint32_t
  function sc_read64be (line 59) | static inline uint64_t
  function sc_float_to_u16fp (line 69) | static inline uint16_t
  function sc_float_to_i16fp (line 83) | static inline int16_t

FILE: app/src/util/intmap.c
  type sc_intmap_entry (line 3) | struct sc_intmap_entry
  type sc_intmap_entry (line 4) | struct sc_intmap_entry
  type sc_intmap_entry (line 7) | struct sc_intmap_entry

FILE: app/src/util/intmap.h
  type sc_intmap_entry (line 9) | struct sc_intmap_entry {
  type sc_intmap_entry (line 14) | struct sc_intmap_entry
  type sc_intmap_entry (line 15) | struct sc_intmap_entry

FILE: app/src/util/intr.c
  function sc_intr_init (line 7) | bool
  function sc_intr_set_socket (line 23) | bool
  function sc_intr_set_process (line 38) | bool
  function sc_intr_interrupt (line 53) | void
  function sc_intr_destroy (line 77) | void

FILE: app/src/util/intr.h
  type sc_intr (line 19) | struct sc_intr {
  type sc_intr (line 35) | struct sc_intr
  type sc_intr (line 43) | struct sc_intr
  type sc_intr (line 51) | struct sc_intr
  type sc_intr (line 59) | struct sc_intr
  function sc_intr_is_interrupted (line 67) | static inline bool
  type sc_intr (line 76) | struct sc_intr

FILE: app/src/util/log.c
  function SDL_LogPriority (line 12) | static SDL_LogPriority
  function log_level_sdl_to_sc (line 31) | static enum sc_log_level
  function sc_set_log_level (line 50) | void
  function sc_get_log_level (line 57) | enum sc_log_level
  function sc_log (line 63) | void
  function sc_log_windows_error (line 74) | bool
  function SDL_LogPriority (line 94) | static SDL_LogPriority
  function sc_av_log_callback (line 111) | static void
  function sc_sdl_log_print (line 140) | static void SDLCALL
  function sc_log_configure (line 152) | void

FILE: app/src/util/log.h
  type sc_log_level (line 23) | enum sc_log_level
  type sc_log_level (line 25) | enum sc_log_level
  type sc_log_level (line 29) | enum sc_log_level

FILE: app/src/util/net.c
  type socklen_t (line 9) | typedef int socklen_t;
  type SOCKADDR_IN (line 19) | typedef struct sockaddr_in SOCKADDR_IN;
  type SOCKADDR (line 20) | typedef struct sockaddr SOCKADDR;
  type IN_ADDR (line 21) | typedef struct in_addr IN_ADDR;
  function net_init (line 26) | bool
  function net_cleanup (line 39) | void
  function sc_raw_socket_close (line 46) | static inline bool
  function sc_socket (line 55) | static inline sc_socket
  function sc_raw_socket (line 78) | static inline sc_raw_socket
  function set_cloexec_flag (line 94) | static bool
  function net_perror (line 111) | static void
  function sc_socket (line 120) | sc_socket
  function net_connect (line 139) | bool
  function net_listen (line 156) | bool
  function sc_socket (line 184) | sc_socket
  function net_recv (line 206) | ssize_t
  function net_recv_all (line 212) | ssize_t
  function net_send (line 218) | ssize_t
  function net_send_all (line 224) | ssize_t
  function net_interrupt (line 239) | bool
  function net_close (line 255) | bool
  function net_set_tcp_nodelay (line 271) | bool
  function net_parse_ipv4 (line 287) | bool

FILE: app/src/util/net.h
  type SOCKET (line 13) | typedef SOCKET sc_raw_socket;
  type sc_raw_socket (line 16) | typedef int sc_raw_socket;
  type sc_socket_wrapper (line 34) | struct sc_socket_wrapper {
  type sc_raw_socket (line 40) | typedef sc_raw_socket sc_socket;

FILE: app/src/util/net_intr.c
  function net_connect_intr (line 3) | bool
  function net_listen_intr (line 17) | bool
  function sc_socket (line 31) | sc_socket
  function net_recv_intr (line 44) | ssize_t
  function net_recv_all_intr (line 57) | ssize_t
  function net_send_intr (line 71) | ssize_t
  function net_send_all_intr (line 85) | ssize_t

FILE: app/src/util/net_intr.h
  type sc_intr (line 15) | struct sc_intr
  type sc_intr (line 19) | struct sc_intr
  type sc_intr (line 23) | struct sc_intr
  type sc_intr (line 26) | struct sc_intr
  type sc_intr (line 29) | struct sc_intr
  type sc_intr (line 33) | struct sc_intr
  type sc_intr (line 37) | struct sc_intr

FILE: app/src/util/process.c
  function sc_process_execute (line 5) | enum sc_process_result
  function sc_pipe_read_all (line 10) | ssize_t
  function run_observer (line 25) | static int
  function sc_process_observer_init (line 42) | bool
  function sc_process_observer_timedwait (line 76) | bool
  function sc_process_observer_join (line 91) | void
  function sc_process_observer_destroy (line 96) | void

FILE: app/src/util/process.h
  type HANDLE (line 19) | typedef HANDLE sc_pid;
  type DWORD (line 20) | typedef DWORD sc_exit_code;
  type HANDLE (line 21) | typedef HANDLE sc_pipe;
  type pid_t (line 29) | typedef pid_t sc_pid;
  type sc_exit_code (line 30) | typedef int sc_exit_code;
  type sc_pipe (line 31) | typedef int sc_pipe;
  type sc_process_listener (line 35) | struct sc_process_listener {
  type sc_process_observer (line 51) | struct sc_process_observer {
  type sc_process_result (line 63) | enum sc_process_result {
  type sc_process_result (line 82) | enum sc_process_result
  type sc_process_result (line 93) | enum sc_process_result
  type sc_process_observer (line 148) | struct sc_process_observer
  type sc_process_listener (line 149) | struct sc_process_listener
  type sc_process_observer (line 162) | struct sc_process_observer
  type sc_process_observer (line 169) | struct sc_process_observer
  type sc_process_observer (line 177) | struct sc_process_observer

FILE: app/src/util/process_intr.c
  function sc_pipe_read_intr (line 3) | ssize_t
  function sc_pipe_read_all_intr (line 20) | ssize_t

FILE: app/src/util/process_intr.h
  type sc_intr (line 10) | struct sc_intr
  type sc_intr (line 14) | struct sc_intr

FILE: app/src/util/rand.c
  function sc_rand_init (line 7) | void sc_rand_init(struct sc_rand *rand) {
  function sc_rand_u32 (line 14) | uint32_t sc_rand_u32(struct sc_rand *rand) {
  function sc_rand_u64 (line 20) | uint64_t sc_rand_u64(struct sc_rand *rand) {

FILE: app/src/util/rand.h
  type sc_rand (line 8) | struct sc_rand {
  type sc_rand (line 12) | struct sc_rand
  type sc_rand (line 13) | struct sc_rand
  type sc_rand (line 14) | struct sc_rand

FILE: app/src/util/str.c
  function sc_strncpy (line 18) | size_t
  function sc_str_join (line 28) | size_t
  function sc_str_parse_integer (line 87) | bool
  function sc_str_parse_integers (line 106) | size_t
  function sc_str_parse_integer_with_suffix (line 136) | bool
  function sc_str_list_contains (line 170) | bool
  function sc_str_utf8_truncation_index (line 188) | size_t
  function wchar_t (line 206) | wchar_t *
  type sc_strbuf (line 246) | struct sc_strbuf
  function sc_str_index_of_column (line 321) | ssize_t
  function sc_str_remove_trailing_cr (line 347) | size_t

FILE: app/src/util/strbuf.c
  function sc_strbuf_init (line 9) | bool
  function sc_strbuf_reserve (line 22) | static bool
  function sc_strbuf_append (line 38) | bool
  function sc_strbuf_append_char (line 54) | bool
  function sc_strbuf_append_n (line 67) | bool
  function sc_strbuf_shrink (line 80) | void

FILE: app/src/util/strbuf.h
  type sc_strbuf (line 10) | struct sc_strbuf {
  type sc_strbuf (line 22) | struct sc_strbuf
  type sc_strbuf (line 30) | struct sc_strbuf
  type sc_strbuf (line 38) | struct sc_strbuf
  type sc_strbuf (line 46) | struct sc_strbuf
  function sc_strbuf_append_str (line 51) | static inline bool
  type sc_strbuf (line 71) | struct sc_strbuf

FILE: app/src/util/term.c
  function sc_term_get_size (line 12) | bool

FILE: app/src/util/thread.c
  function sc_thread_create (line 13) | bool
  function SDL_ThreadPriority (line 30) | static SDL_ThreadPriority
  function sc_thread_set_priority (line 51) | bool
  function sc_thread_join (line 63) | void
  function sc_mutex_init (line 68) | bool
  function sc_mutex_destroy (line 83) | void
  function sc_mutex_lock (line 88) | void
  function sc_mutex_unlock (line 106) | void
  function sc_thread_id (line 123) | sc_thread_id
  function sc_mutex_held (line 129) | bool
  function sc_cond_init (line 137) | bool
  function sc_cond_destroy (line 149) | void
  function sc_cond_wait (line 154) | void
  function sc_cond_timedwait (line 170) | bool
  function sc_cond_signal (line 196) | void
  function sc_cond_broadcast (line 209) | void

FILE: app/src/util/thread.h
  type SDL_Thread (line 12) | typedef struct SDL_Thread SDL_Thread;
  type SDL_mutex (line 13) | typedef struct SDL_mutex SDL_mutex;
  type SDL_cond (line 14) | typedef struct SDL_cond SDL_cond;
  type sc_thread_id (line 17) | typedef unsigned sc_thread_id;
  type atomic_uint (line 18) | typedef atomic_uint sc_atomic_thread_id;
  type sc_thread (line 20) | typedef struct sc_thread {
  type sc_thread_priority (line 24) | enum sc_thread_priority {
  type sc_mutex (line 31) | typedef struct sc_mutex {
  type sc_cond (line 38) | typedef struct sc_cond {
  type sc_thread_priority (line 52) | enum sc_thread_priority
  type sc_mutex (line 71) | struct sc_mutex

FILE: app/src/util/tick.c
  function sc_tick (line 10) | sc_tick

FILE: app/src/util/tick.h
  type sc_tick (line 8) | typedef int64_t sc_tick;

FILE: app/src/util/timeout.c
  function sc_timeout_init (line 8) | bool
  function run_timeout (line 25) | static int
  function sc_timeout_start (line 43) | bool
  function sc_timeout_stop (line 62) | void
  function sc_timeout_join (line 70) | void
  function sc_timeout_destroy (line 75) | void

FILE: app/src/util/timeout.h
  type sc_timeout (line 11) | struct sc_timeout {
  type sc_timeout_callbacks (line 23) | struct sc_timeout_callbacks {
  type sc_timeout (line 28) | struct sc_timeout
  type sc_timeout (line 31) | struct sc_timeout
  type sc_timeout (line 34) | struct sc_timeout
  type sc_timeout_callbacks (line 35) | struct sc_timeout_callbacks
  type sc_timeout (line 38) | struct sc_timeout
  type sc_timeout (line 41) | struct sc_timeout

FILE: app/src/util/vecdeque.h
  function sc_vecdeque_growsize_ (line 228) | static inline size_t

FILE: app/src/util/vector.h
  function sc_vector_min_ (line 82) | static inline size_t
  function sc_vector_max_ (line 88) | static inline size_t
  function sc_vector_clamp_ (line 94) | static inline size_t
  function sc_vector_growsize_ (line 155) | static inline size_t
  function sc_char_array_reverse (line 339) | static inline void
  function sc_char_array_rotate_left (line 358) | static inline void
  function sc_char_array_rotate_right (line 374) | static inline void
  function sc_char_array_move (line 385) | static inline void

FILE: app/src/v4l2_sink.c
  function AVOutputFormat (line 17) | static const AVOutputFormat *
  function write_header (line 34) | static bool
  function rescale_packet (line 59) | static void
  function write_packet (line 65) | static bool
  function encode_and_write_frame (line 87) | static bool
  function run_v4l2_sink (line 114) | static int
  function sc_v4l2_sink_open (line 148) | static bool
  function sc_v4l2_sink_close (line 291) | static void
  function sc_v4l2_sink_push (line 310) | static bool
  function sc_v4l2_frame_sink_open (line 328) | static bool
  function sc_v4l2_frame_sink_close (line 334) | static void
  function sc_v4l2_frame_sink_push (line 340) | static bool
  function sc_v4l2_sink_init (line 346) | bool
  function sc_v4l2_sink_destroy (line 365) | void

FILE: app/src/v4l2_sink.h
  type sc_v4l2_sink (line 14) | struct sc_v4l2_sink {
  type sc_v4l2_sink (line 35) | struct sc_v4l2_sink
  type sc_v4l2_sink (line 38) | struct sc_v4l2_sink

FILE: app/src/version.c
  function scrcpy_print_version (line 15) | void

FILE: app/tests/test_adb_parser.c
  function test_adb_devices (line 8) | static void test_adb_devices(void) {
  function test_adb_devices_cr (line 34) | static void test_adb_devices_cr(void) {
  function test_adb_devices_daemon_start (line 60) | static void test_adb_devices_daemon_start(void) {
  function test_adb_devices_daemon_start_mixed (line 81) | static void test_adb_devices_daemon_start_mixed(void) {
  function test_adb_devices_without_eol (line 108) | static void test_adb_devices_without_eol(void) {
  function test_adb_devices_without_header (line 127) | static void test_adb_devices_without_header(void) {
  function test_adb_devices_corrupted (line 137) | static void test_adb_devices_corrupted(void) {
  function test_adb_devices_spaces (line 148) | static void test_adb_devices_spaces(void) {
  function test_get_ip_single_line (line 166) | static void test_get_ip_single_line(void) {
  function test_get_ip_single_line_without_eol (line 176) | static void test_get_ip_single_line_without_eol(void) {
  function test_get_ip_single_line_with_trailing_space (line 186) | static void test_get_ip_single_line_with_trailing_space(void) {
  function test_get_ip_multiline_first_ok (line 196) | static void test_get_ip_multiline_first_ok(void) {
  function test_get_ip_multiline_second_ok (line 208) | static void test_get_ip_multiline_second_ok(void) {
  function test_get_ip_multiline_second_ok_without_cr (line 220) | static void test_get_ip_multiline_second_ok_without_cr(void) {
  function test_get_ip_no_wlan (line 232) | static void test_get_ip_no_wlan(void) {
  function test_get_ip_no_wlan_without_eol (line 240) | static void test_get_ip_no_wlan_without_eol(void) {
  function test_get_ip_truncated (line 248) | static void test_get_ip_truncated(void) {
  function main (line 256) | int main(int argc, char *argv[]) {

FILE: app/tests/test_audiobuf.c
  function test_audiobuf_simple (line 8) | static void test_audiobuf_simple(void) {
  function test_audiobuf_boundaries (line 40) | static void test_audiobuf_boundaries(void) {
  function test_audiobuf_partial_read_write (line 85) | static void test_audiobuf_partial_read_write(void) {
  function main (line 127) | int main(int argc, char *argv[]) {

FILE: app/tests/test_binary.c
  function test_write16be (line 7) | static void test_write16be(void) {
  function test_write32be (line 17) | static void test_write32be(void) {
  function test_write64be (line 29) | static void test_write64be(void) {
  function test_write16le (line 45) | static void test_write16le(void) {
  function test_write32le (line 55) | static void test_write32le(void) {
  function test_write64le (line 67) | static void test_write64le(void) {
  function test_read16be (line 83) | static void test_read16be(void) {
  function test_read32be (line 91) | static void test_read32be(void) {
  function test_read64be (line 99) | static void test_read64be(void) {
  function test_float_to_u16fp (line 108) | static void test_float_to_u16fp(void) {
  function test_float_to_i16fp (line 119) | static void test_float_to_i16fp(void) {
  function main (line 138) | int main(int argc, char *argv[]) {

FILE: app/tests/test_cli.c
  function test_flag_version (line 9) | static void test_flag_version(void) {
  function test_flag_help (line 24) | static void test_flag_help(void) {
  function test_options (line 39) | static void test_options(void) {
  function test_options2 (line 99) | static void test_options2(void) {
  function test_parse_shortcut_mods (line 124) | static void test_parse_shortcut_mods(void) {
  function main (line 152) | int main(int argc, char *argv[]) {

FILE: app/tests/test_control_msg_serialize.c
  function test_serialize_inject_keycode (line 9) | static void test_serialize_inject_keycode(void) {
  function test_serialize_inject_text (line 34) | static void test_serialize_inject_text(void) {
  function test_serialize_inject_text_long (line 54) | static void test_serialize_inject_text_long(void) {
  function test_serialize_inject_touch_event (line 77) | static void test_serialize_inject_touch_event(void) {
  function test_serialize_inject_scroll_event (line 116) | static void test_serialize_inject_scroll_event(void) {
  function test_serialize_back_or_screen_on (line 151) | static void test_serialize_back_or_screen_on(void) {
  function test_serialize_expand_notification_panel (line 170) | static void test_serialize_expand_notification_panel(void) {
  function test_serialize_expand_settings_panel (line 185) | static void test_serialize_expand_settings_panel(void) {
  function test_serialize_collapse_panels (line 200) | static void test_serialize_collapse_panels(void) {
  function test_serialize_get_clipboard (line 215) | static void test_serialize_get_clipboard(void) {
  function test_serialize_set_clipboard (line 234) | static void test_serialize_set_clipboard(void) {
  function test_serialize_set_clipboard_long (line 258) | static void test_serialize_set_clipboard_long(void) {
  function test_serialize_set_display_power (line 292) | static void test_serialize_set_display_power(void) {
  function test_serialize_rotate_device (line 311) | static void test_serialize_rotate_device(void) {
  function test_serialize_uhid_create (line 326) | static void test_serialize_uhid_create(void) {
  function test_serialize_uhid_input (line 357) | static void test_serialize_uhid_input(void) {
  function test_serialize_uhid_destroy (line 380) | static void test_serialize_uhid_destroy(void) {
  function test_serialize_open_hard_keyboard (line 399) | static void test_serialize_open_hard_keyboard(void) {
  function test_serialize_start_app (line 414) | static void test_serialize_start_app(void) {
  function test_serialize_reset_video (line 434) | static void test_serialize_reset_video(void) {
  function main (line 449) | int main(int argc, char *argv[]) {

FILE: app/tests/test_device_msg_deserialize.c
  function test_deserialize_clipboard (line 10) | static void test_deserialize_clipboard(void) {
  function test_deserialize_clipboard_big (line 28) | static void test_deserialize_clipboard_big(void) {
  function test_deserialize_ack_set_clipboard (line 50) | static void test_deserialize_ack_set_clipboard(void) {
  function test_deserialize_uhid_output (line 64) | static void test_deserialize_uhid_output(void) {
  function main (line 86) | int main(int argc, char *argv[]) {

FILE: app/tests/test_orientation.c
  function test_transforms (line 7) | static void test_transforms(void) {
  function main (line 85) | int main(int argc, char *argv[]) {

FILE: app/tests/test_str.c
  function test_strncpy_simple (line 11) | static void test_strncpy_simple(void) {
  function test_strncpy_just_fit (line 28) | static void test_strncpy_just_fit(void) {
  function test_strncpy_truncated (line 42) | static void test_strncpy_truncated(void) {
  function test_join_simple (line 56) | static void test_join_simple(void) {
  function test_join_just_fit (line 74) | static void test_join_just_fit(void) {
  function test_join_truncated_in_token (line 89) | static void test_join_truncated_in_token(void) {
  function test_join_truncated_before_sep (line 104) | static void test_join_truncated_before_sep(void) {
  function test_join_truncated_after_sep (line 119) | static void test_join_truncated_after_sep(void) {
  function test_quote (line 134) | static void test_quote(void) {
  function test_concat (line 144) | static void test_concat(void) {
  function test_utf8_truncate (line 154) | static void test_utf8_truncate(void) {
  function test_parse_integer (line 185) | static void test_parse_integer(void) {
  function test_parse_integers (line 202) | static void test_parse_integers(void) {
  function test_parse_integer_with_suffix (line 251) | static void test_parse_integer_with_suffix(void) {
  function test_strlist_contains (line 305) | static void test_strlist_contains(void) {
  function test_wrap_lines (line 317) | static void test_wrap_lines(void) {
  function test_index_of_column (line 355) | static void test_index_of_column(void) {
  function test_remove_trailing_cr (line 375) | static void test_remove_trailing_cr(void) {
  function main (line 389) | int main(int argc, char *argv[]) {

FILE: app/tests/test_strbuf.c
  function test_strbuf_simple (line 10) | static void test_strbuf_simple(void) {
  function main (line 42) | int main(int argc, char *argv[]) {

FILE: app/tests/test_vecdeque.c
  function test_vecdeque_push_pop (line 15) | static void test_vecdeque_push_pop(void) {
  function test_vecdeque_reserve (line 50) | static void test_vecdeque_reserve(void) {
  function test_vecdeque_grow (line 105) | static void test_vecdeque_grow(void) {
  function test_vecdeque_push_hole (line 145) | static void test_vecdeque_push_hole(void) {
  function main (line 187) | int main(int argc, char *argv[]) {

FILE: app/tests/test_vector.c
  function test_vector_insert_remove (line 7) | static void test_vector_insert_remove(void) {
  function test_vector_push_array (line 50) | static void test_vector_push_array(void) {
  function test_vector_insert_array (line 83) | static void test_vector_insert_array(void) {
  function test_vector_remove_slice (line 115) | static void test_vector_remove_slice(void) {
  function test_vector_swap_remove (line 136) | static void test_vector_swap_remove(void) {
  function test_vector_index_of (line 158) | static void test_vector_index_of(void) {
  function test_vector_grow (line 190) | static void test_vector_grow(void) {
  function test_vector_exp_growth (line 242) | static void test_vector_exp_growth(void) {
  function test_vector_reserve (line 280) | static void test_vector_reserve(void) {
  function test_vector_shrink_to_fit (line 302) | static void test_vector_shrink_to_fit(void) {
  function test_vector_move (line 325) | static void test_vector_move(void) {
  function test_vector_move_slice_forward (line 349) | static void test_vector_move_slice_forward(void) {
  function test_vector_move_slice_backward (line 376) | static void test_vector_move_slice_backward(void) {
  function main (line 403) | int main(int argc, char *argv[]) {

FILE: server/src/main/java/android/content/IContentProvider.java
  type IContentProvider (line 3) | public interface IContentProvider {

FILE: server/src/main/java/com/genymobile/scrcpy/AndroidVersions.java
  class AndroidVersions (line 10) | public final class AndroidVersions {
    method AndroidVersions (line 12) | private AndroidVersions() {

FILE: server/src/main/java/com/genymobile/scrcpy/AsyncProcessor.java
  type AsyncProcessor (line 3) | public interface AsyncProcessor {
    type TerminationListener (line 4) | interface TerminationListener {
      method onTerminated (line 10) | void onTerminated(boolean fatalError);
    method start (line 13) | void start(TerminationListener listener);
    method stop (line 15) | void stop();
    method join (line 17) | void join() throws InterruptedException;

FILE: server/src/main/java/com/genymobile/scrcpy/CleanUp.java
  class CleanUp (line 23) | public final class CleanUp {
    method CleanUp (line 33) | private CleanUp(Options options) {
    method start (line 38) | public static CleanUp start(Options options) {
    method interrupt (line 42) | public synchronized void interrupt() {
    method join (line 48) | public void join() throws InterruptedException {
    method runCleanUp (line 52) | private void runCleanUp(Options options) {
    method run (line 125) | private void run(int displayId, int restoreStayOn, boolean disableShow...
    method setRestoreDisplayPower (line 169) | public synchronized void setRestoreDisplayPower(boolean restoreDisplay...
    method unlinkSelf (line 175) | public static void unlinkSelf() {
    method prepareMainLooper (line 183) | @SuppressWarnings("deprecation")
    method main (line 188) | public static void main(String... args) {

FILE: server/src/main/java/com/genymobile/scrcpy/FakeContext.java
  class FakeContext (line 17) | public final class FakeContext extends ContextWrapper {
    method get (line 24) | public static FakeContext get() {
    method acquireProvider (line 29) | @SuppressWarnings({"unused", "ProtectedMemberInFinalClass"})
    method releaseProvider (line 35) | @SuppressWarnings("unused")
    method acquireUnstableProvider (line 41) | @SuppressWarnings({"unused", "ProtectedMemberInFinalClass"})
    method releaseUnstableProvider (line 47) | @SuppressWarnings("unused")
    method unstableProviderDied (line 53) | @SuppressWarnings("unused")
    method FakeContext (line 60) | private FakeContext() {
    method getPackageName (line 64) | @Override
    method getOpPackageName (line 69) | @Override
    method getAttributionSource (line 74) | @TargetApi(AndroidVersions.API_31_ANDROID_12)
    method getDeviceId (line 83) | @SuppressWarnings("unused")
    method getApplicationContext (line 88) | @Override
    method createPackageContext (line 93) | @Override
    method getContentResolver (line 98) | @Override
    method getSystemService (line 103) | @SuppressLint("SoonBlockedPrivateApi")

FILE: server/src/main/java/com/genymobile/scrcpy/Options.java
  class Options (line 23) | public class Options {
    method getLogLevel (line 83) | public Ln.Level getLogLevel() {
    method getScid (line 87) | public int getScid() {
    method getVideo (line 91) | public boolean getVideo() {
    method getAudio (line 95) | public boolean getAudio() {
    method getMaxSize (line 99) | public int getMaxSize() {
    method getVideoCodec (line 103) | public VideoCodec getVideoCodec() {
    method getAudioCodec (line 107) | public AudioCodec getAudioCodec() {
    method getVideoSource (line 111) | public VideoSource getVideoSource() {
    method getAudioSource (line 115) | public AudioSource getAudioSource() {
    method getAudioDup (line 119) | public boolean getAudioDup() {
    method getVideoBitRate (line 123) | public int getVideoBitRate() {
    method getAudioBitRate (line 127) | public int getAudioBitRate() {
    method getMaxFps (line 131) | public float getMaxFps() {
    method getAngle (line 135) | public float getAngle() {
    method isTunnelForward (line 139) | public boolean isTunnelForward() {
    method getCrop (line 143) | public Rect getCrop() {
    method getControl (line 147) | public boolean getControl() {
    method getDisplayId (line 151) | public int getDisplayId() {
    method getCameraId (line 155) | public String getCameraId() {
    method getCameraSize (line 159) | public Size getCameraSize() {
    method getCameraFacing (line 163) | public CameraFacing getCameraFacing() {
    method getCameraAspectRatio (line 167) | public CameraAspectRatio getCameraAspectRatio() {
    method getCameraFps (line 171) | public int getCameraFps() {
    method getCameraHighSpeed (line 175) | public boolean getCameraHighSpeed() {
    method getShowTouches (line 179) | public boolean getShowTouches() {
    method getStayAwake (line 183) | public boolean getStayAwake() {
    method getScreenOffTimeout (line 187) | public int getScreenOffTimeout() {
    method getDisplayImePolicy (line 191) | public int getDisplayImePolicy() {
    method getVideoCodecOptions (line 195) | public List<CodecOption> getVideoCodecOptions() {
    method getAudioCodecOptions (line 199) | public List<CodecOption> getAudioCodecOptions() {
    method getVideoEncoder (line 203) | public String getVideoEncoder() {
    method getAudioEncoder (line 207) | public String getAudioEncoder() {
    method getPowerOffScreenOnClose (line 211) | public boolean getPowerOffScreenOnClose() {
    method getClipboardAutosync (line 215) | public boolean getClipboardAutosync() {
    method getDownsizeOnError (line 219) | public boolean getDownsizeOnError() {
    method getCleanup (line 223) | public boolean getCleanup() {
    method getPowerOn (line 227) | public boolean getPowerOn() {
    method getNewDisplay (line 231) | public NewDisplay getNewDisplay() {
    method getCaptureOrientation (line 235) | public Orientation getCaptureOrientation() {
    method getCaptureOrientationLock (line 239) | public Orientation.Lock getCaptureOrientationLock() {
    method getVDDestroyContent (line 243) | public boolean getVDDestroyContent() {
    method getVDSystemDecorations (line 247) | public boolean getVDSystemDecorations() {
    method getList (line 251) | public boolean getList() {
    method getListEncoders (line 255) | public boolean getListEncoders() {
    method getListDisplays (line 259) | public boolean getListDisplays() {
    method getListCameras (line 263) | public boolean getListCameras() {
    method getListCameraSizes (line 267) | public boolean getListCameraSizes() {
    method getListApps (line 271) | public boolean getListApps() {
    method getSendDeviceMeta (line 275) | public boolean getSendDeviceMeta() {
    method getSendFrameMeta (line 279) | public boolean getSendFrameMeta() {
    method getSendDummyByte (line 283) | public boolean getSendDummyByte() {
    method getSendCodecMeta (line 287) | public boolean getSendCodecMeta() {
    method parse (line 291) | @SuppressWarnings("MethodLength")
    method parseCrop (line 529) | private static Rect parseCrop(String crop) {
    method parseSize (line 548) | private static Size parseSize(String size) {
    method parseCameraAspectRatio (line 562) | private static CameraAspectRatio parseCameraAspectRatio(String ar) {
    method parseFloat (line 578) | private static float parseFloat(String key, String value) {
    method parseNewDisplay (line 586) | private static NewDisplay parseNewDisplay(String newDisplay) {
    method parseCaptureOrientation (line 618) | private static Pair<Orientation.Lock, Orientation> parseCaptureOrienta...
    method parseDisplayImePolicy (line 639) | private static int parseDisplayImePolicy(String value) {

FILE: server/src/main/java/com/genymobile/scrcpy/Server.java
  class Server (line 37) | public final class Server {
    class Completion (line 47) | private static class Completion {
      method Completion (line 51) | Completion(int running) {
      method addCompleted (line 55) | synchronized void addCompleted(boolean fatalError) {
    method Server (line 66) | private Server() {
    method scrcpy (line 70) | private static void scrcpy(Options options) throws IOException, Config...
    method prepareMainLooper (line 197) | private static void prepareMainLooper() {
    method main (line 212) | public static void main(String... args) {
    method internalMain (line 227) | private static void internalMain(String... args) throws Exception {

FILE: server/src/main/java/com/genymobile/scrcpy/Workarounds.java
  class Workarounds (line 25) | @SuppressLint("PrivateApi,BlockedPrivateApi,SoonBlockedPrivateApi,Discou...
    method Workarounds (line 53) | private Workarounds() {
    method apply (line 57) | public static void apply() {
    method fillAppInfo (line 78) | private static void fillAppInfo() {
    method fillAppContext (line 104) | private static void fillAppContext() {
    method fillConfigurationController (line 118) | private static void fillConfigurationController() {
    method getSystemContext (line 137) | static Context getSystemContext() {
    method createAudioRecord (line 148) | @TargetApi(AndroidVersions.API_30_ANDROID_11)

FILE: server/src/main/java/com/genymobile/scrcpy/audio/AudioCapture.java
  type AudioCapture (line 7) | public interface AudioCapture {
    method checkCompatibility (line 8) | void checkCompatibility() throws AudioCaptureException;
    method start (line 9) | void start() throws AudioCaptureException;
    method stop (line 10) | void stop();
    method read (line 19) | int read(ByteBuffer outDirectBuffer, MediaCodec.BufferInfo outBufferIn...

FILE: server/src/main/java/com/genymobile/scrcpy/audio/AudioCaptureException.java
  class AudioCaptureException (line 11) | public class AudioCaptureException extends Exception {

FILE: server/src/main/java/com/genymobile/scrcpy/audio/AudioCodec.java
  type AudioCodec (line 7) | public enum AudioCodec implements Codec {
    method AudioCodec (line 17) | AudioCodec(int id, String name, String mimeType) {
    method getType (line 23) | @Override
    method getId (line 28) | @Override
    method getName (line 33) | @Override
    method getMimeType (line 38) | @Override
    method findByName (line 43) | public static AudioCodec findByName(String name) {

FILE: server/src/main/java/com/genymobile/scrcpy/audio/AudioConfig.java
  class AudioConfig (line 5) | public final class AudioConfig {
    method AudioConfig (line 18) | private AudioConfig() {
    method createAudioFormat (line 22) | public static AudioFormat createAudioFormat() {

FILE: server/src/main/java/com/genymobile/scrcpy/audio/AudioDirectCapture.java
  class AudioDirectCapture (line 20) | public class AudioDirectCapture implements AudioCapture {
    method AudioDirectCapture (line 33) | public AudioDirectCapture(AudioSource audioSource) {
    method createAudioRecord (line 37) | @TargetApi(AndroidVersions.API_23_ANDROID_6_0)
    method startWorkaroundAndroid11 (line 56) | private static void startWorkaroundAndroid11() {
    method stopWorkaroundAndroid11 (line 70) | private static void stopWorkaroundAndroid11() {
    method tryStartRecording (line 74) | private void tryStartRecording(int attempts, int delayMs) throws Audio...
    method startRecording (line 94) | private void startRecording() throws AudioCaptureException {
    method checkCompatibility (line 107) | @Override
    method start (line 115) | @Override
    method stop (line 129) | @Override
    method read (line 137) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/audio/AudioEncoder.java
  class AudioEncoder (line 29) | public final class AudioEncoder implements AsyncProcessor {
    class InputTask (line 31) | private static class InputTask {
      method InputTask (line 34) | InputTask(int index) {
    class OutputTask (line 39) | private static class OutputTask {
      method OutputTask (line 43) | OutputTask(int index, MediaCodec.BufferInfo bufferInfo) {
    method AudioEncoder (line 74) | public AudioEncoder(AudioCapture capture, Streamer streamer, Options o...
    method createFormat (line 82) | private static MediaFormat createFormat(String mimeType, int bitRate, ...
    method inputThread (line 101) | @TargetApi(AndroidVersions.API_24_ANDROID_7_0)
    method outputThread (line 117) | private void outputThread(MediaCodec mediaCodec) throws IOException, I...
    method fixTimestamp (line 134) | private void fixTimestamp(MediaCodec.BufferInfo bufferInfo) {
    method start (line 153) | @Override
    method stop (line 175) | @Override
    method join (line 183) | @Override
    method end (line 190) | private synchronized void end() {
    method waitEnded (line 195) | private synchronized void waitEnded() {
    method encode (line 205) | @TargetApi(AndroidVersions.API_23_ANDROID_6_0)
    method createMediaCodec (line 319) | private static MediaCodec createMediaCodec(Codec codec, String encoder...
    class EncoderCallback (line 349) | private final class EncoderCallback extends MediaCodec.Callback {
      method onInputBufferAvailable (line 350) | @TargetApi(AndroidVersions.API_24_ANDROID_7_0)
      method onOutputBufferAvailable (line 360) | @Override
      method onError (line 369) | @Override
      method onOutputFormatChanged (line 375) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/audio/AudioPlaybackCapture.java
  class AudioPlaybackCapture (line 20) | public final class AudioPlaybackCapture implements AudioCapture {
    method AudioPlaybackCapture (line 27) | public AudioPlaybackCapture(boolean keepPlayingOnDevice) {
    method createAudioRecord (line 31) | @SuppressLint("PrivateApi")
    method checkCompatibility (line 110) | @Override
    method start (line 118) | @Override
    method stop (line 125) | @Override
    method read (line 133) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/audio/AudioRawRecorder.java
  class AudioRawRecorder (line 15) | public final class AudioRawRecorder implements AsyncProcessor {
    method AudioRawRecorder (line 22) | public AudioRawRecorder(AudioCapture capture, Streamer streamer) {
    method record (line 27) | private void record() throws IOException, AudioCaptureException {
    method start (line 67) | @Override
    method stop (line 86) | @Override
    method join (line 93) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/audio/AudioRecordReader.java
  class AudioRecordReader (line 13) | public class AudioRecordReader {
    method AudioRecordReader (line 25) | public AudioRecordReader(AudioRecord recorder) {
    method read (line 29) | @TargetApi(AndroidVersions.API_24_ANDROID_7_0)

FILE: server/src/main/java/com/genymobile/scrcpy/audio/AudioSource.java
  type AudioSource (line 6) | @SuppressLint("InlinedApi")
    method AudioSource (line 23) | AudioSource(String name, int directAudioSource) {
    method isDirect (line 28) | public boolean isDirect() {
    method getDirectAudioSource (line 32) | public int getDirectAudioSource() {
    method findByName (line 36) | public static AudioSource findByName(String name) {

FILE: server/src/main/java/com/genymobile/scrcpy/control/ControlChannel.java
  class ControlChannel (line 7) | public final class ControlChannel {
    method ControlChannel (line 12) | public ControlChannel(LocalSocket controlSocket) throws IOException {
    method recv (line 17) | public ControlMessage recv() throws IOException {
    method send (line 21) | public void send(DeviceMessage msg) throws IOException {

FILE: server/src/main/java/com/genymobile/scrcpy/control/ControlMessage.java
  class ControlMessage (line 8) | public final class ControlMessage {
    method ControlMessage (line 57) | private ControlMessage() {
    method createInjectKeycode (line 60) | public static ControlMessage createInjectKeycode(int action, int keyco...
    method createInjectText (line 70) | public static ControlMessage createInjectText(String text) {
    method createInjectTouchEvent (line 77) | public static ControlMessage createInjectTouchEvent(int action, long p...
    method createInjectScrollEvent (line 90) | public static ControlMessage createInjectScrollEvent(Position position...
    method createBackOrScreenOn (line 100) | public static ControlMessage createBackOrScreenOn(int action) {
    method createGetClipboard (line 107) | public static ControlMessage createGetClipboard(int copyKey) {
    method createSetClipboard (line 114) | public static ControlMessage createSetClipboard(long sequence, String ...
    method createSetDisplayPower (line 123) | public static ControlMessage createSetDisplayPower(boolean on) {
    method createEmpty (line 130) | public static ControlMessage createEmpty(int type) {
    method createUhidCreate (line 136) | public static ControlMessage createUhidCreate(int id, int vendorId, in...
    method createUhidInput (line 147) | public static ControlMessage createUhidInput(int id, byte[] data) {
    method createUhidDestroy (line 155) | public static ControlMessage createUhidDestroy(int id) {
    method createStartApp (line 162) | public static ControlMessage createStartApp(String name) {
    method getType (line 169) | public int getType() {
    method getText (line 173) | public String getText() {
    method getMetaState (line 177) | public int getMetaState() {
    method getAction (line 181) | public int getAction() {
    method getKeycode (line 185) | public int getKeycode() {
    method getActionButton (line 189) | public int getActionButton() {
    method getButtons (line 193) | public int getButtons() {
    method getPointerId (line 197) | public long getPointerId() {
    method getPressure (line 201) | public float getPressure() {
    method getPosition (line 205) | public Position getPosition() {
    method getHScroll (line 209) | public float getHScroll() {
    method getVScroll (line 213) | public float getVScroll() {
    method getCopyKey (line 217) | public int getCopyKey() {
    method getPaste (line 221) | public boolean getPaste() {
    method getRepeat (line 225) | public int getRepeat() {
    method getSequence (line 229) | public long getSequence() {
    method getId (line 233) | public int getId() {
    method getData (line 237) | public byte[] getData() {
    method getOn (line 241) | public boolean getOn() {
    method getVendorId (line 245) | public int getVendorId() {
    method getProductId (line 249) | public int getProductId() {

FILE: server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java
  class ControlMessageReader (line 12) | public class ControlMessageReader {
    method ControlMessageReader (line 21) | public ControlMessageReader(InputStream rawInputStream) {
    method read (line 25) | public ControlMessage read() throws IOException {
    method parseInjectKeycode (line 64) | private ControlMessage parseInjectKeycode() throws IOException {
    method parseBufferLength (line 72) | private int parseBufferLength(int sizeBytes) throws IOException {
    method parseString (line 81) | private String parseString(int sizeBytes) throws IOException {
    method parseString (line 87) | private String parseString() throws IOException {
    method parseByteArray (line 91) | private byte[] parseByteArray(int sizeBytes) throws IOException {
    method parseInjectText (line 98) | private ControlMessage parseInjectText() throws IOException {
    method parseInjectTouchEvent (line 103) | private ControlMessage parseInjectTouchEvent() throws IOException {
    method parseInjectScrollEvent (line 113) | private ControlMessage parseInjectScrollEvent() throws IOException {
    method parseBackOrScreenOnEvent (line 122) | private ControlMessage parseBackOrScreenOnEvent() throws IOException {
    method parseGetClipboard (line 127) | private ControlMessage parseGetClipboard() throws IOException {
    method parseSetClipboard (line 132) | private ControlMessage parseSetClipboard() throws IOException {
    method parseSetDisplayPower (line 139) | private ControlMessage parseSetDisplayPower() throws IOException {
    method parseUhidCreate (line 144) | private ControlMessage parseUhidCreate() throws IOException {
    method parseUhidInput (line 153) | private ControlMessage parseUhidInput() throws IOException {
    method parseUhidDestroy (line 159) | private ControlMessage parseUhidDestroy() throws IOException {
    method parseStartApp (line 164) | private ControlMessage parseStartApp() throws IOException {
    method parsePosition (line 169) | private Position parsePosition() throws IOException {

FILE: server/src/main/java/com/genymobile/scrcpy/control/ControlProtocolException.java
  class ControlProtocolException (line 5) | public class ControlProtocolException extends IOException {
    method ControlProtocolException (line 6) | public ControlProtocolException(String message) {

FILE: server/src/main/java/com/genymobile/scrcpy/control/Controller.java
  class Controller (line 39) | public class Controller implements AsyncProcessor, VirtualDisplayListener {
    class DisplayData (line 56) | private static final class DisplayData {
      method DisplayData (line 60) | private DisplayData(int virtualDisplayId, PositionMapper positionMap...
    method Controller (line 103) | public Controller(ControlChannel controlChannel, CleanUp cleanUp, Opti...
    method onNewVirtualDisplay (line 139) | @Override
    method setSurfaceCapture (line 151) | public void setSurfaceCapture(SurfaceCapture surfaceCapture) {
    method getUhidManager (line 155) | private UhidManager getUhidManager() {
    method initPointers (line 188) | private void initPointers() {
    method control (line 202) | private void control() throws IOException {
    method start (line 223) | @Override
    method stop (line 242) | @Override
    method join (line 250) | @Override
    method handleEvent (line 258) | private boolean handleEvent() throws IOException {
    method injectKeycode (line 341) | private boolean injectKeycode(int action, int keycode, int repeat, int...
    method injectChar (line 349) | private boolean injectChar(char c) {
    method injectText (line 366) | private int injectText(String text) {
    method getEventPointAndDisplayId (line 378) | private Pair<Point, Integer> getEventPointAndDisplayId(Position positi...
    method injectTouch (line 408) | private boolean injectTouch(int action, long pointerId, Position posit...
    method injectScroll (line 519) | private boolean injectScroll(Position position, float hScroll, float v...
    method scheduleDisplayPowerOff (line 547) | private static void scheduleDisplayPowerOff(int displayId) {
    method pressBackOrTurnScreenOn (line 554) | private boolean pressBackOrTurnScreenOn(int action) {
    method getClipboard (line 573) | private void getClipboard(int copyKey) {
    method setClipboard (line 593) | private boolean setClipboard(String text, boolean paste, long sequence) {
    method openHardKeyboardSettings (line 615) | private void openHardKeyboardSettings() {
    method injectKeyEvent (line 620) | private boolean injectKeyEvent(int action, int keyCode, int repeat, in...
    method pressReleaseKeycode (line 624) | private boolean pressReleaseKeycode(int keyCode, int injectMode) {
    method getActionDisplayId (line 628) | private int getActionDisplayId() {
    method startAppAsync (line 644) | private void startAppAsync(String name) {
    method startApp (line 653) | private void startApp(String name) {
    method getStartAppDisplayId (line 696) | private int getStartAppDisplayId() {
    method waitDisplayData (line 716) | private DisplayData waitDisplayData(long timeoutMillis) throws Interru...
    method setDisplayPower (line 736) | private void setDisplayPower(boolean on) {
    method resetVideo (line 751) | private void resetVideo() {

FILE: server/src/main/java/com/genymobile/scrcpy/control/DeviceMessage.java
  class DeviceMessage (line 3) | public final class DeviceMessage {
    method DeviceMessage (line 15) | private DeviceMessage() {
    method createClipboard (line 18) | public static DeviceMessage createClipboard(String text) {
    method createAckClipboard (line 25) | public static DeviceMessage createAckClipboard(long sequence) {
    method createUhidOutput (line 32) | public static DeviceMessage createUhidOutput(int id, byte[] data) {
    method getType (line 40) | public int getType() {
    method getText (line 44) | public String getText() {
    method getSequence (line 48) | public long getSequence() {
    method getId (line 52) | public int getId() {
    method getData (line 56) | public byte[] getData() {

FILE: server/src/main/java/com/genymobile/scrcpy/control/DeviceMessageSender.java
  class DeviceMessageSender (line 9) | public final class DeviceMessageSender {
    method DeviceMessageSender (line 16) | public DeviceMessageSender(ControlChannel controlChannel) {
    method send (line 20) | public void send(DeviceMessage msg) {
    method loop (line 26) | private void loop() throws IOException, InterruptedException {
    method start (line 33) | public void start() {
    method stop (line 46) | public void stop() {
    method join (line 52) | public void join() throws InterruptedException {

FILE: server/src/main/java/com/genymobile/scrcpy/control/DeviceMessageWriter.java
  class DeviceMessageWriter (line 11) | public class DeviceMessageWriter {
    method DeviceMessageWriter (line 18) | public DeviceMessageWriter(OutputStream rawOutputStream) {
    method write (line 22) | public void write(DeviceMessage msg) throws IOException {

FILE: server/src/main/java/com/genymobile/scrcpy/control/KeyComposition.java
  class KeyComposition (line 16) | public final class KeyComposition {
    method KeyComposition (line 26) | private KeyComposition() {
    method decompose (line 30) | public static String decompose(char c) {
    method grave (line 34) | private static String grave(char c) {
    method acute (line 38) | private static String acute(char c) {
    method circumflex (line 42) | private static String circumflex(char c) {
    method tilde (line 46) | private static String tilde(char c) {
    method umlaut (line 50) | private static String umlaut(char c) {
    method createDecompositionMap (line 54) | private static Map<Character, String> createDecompositionMap() {

FILE: server/src/main/java/com/genymobile/scrcpy/control/Pointer.java
  class Pointer (line 5) | public class Pointer {
    method Pointer (line 21) | public Pointer(long id, int localId) {
    method getId (line 26) | public long getId() {
    method getLocalId (line 30) | public int getLocalId() {
    method getPoint (line 34) | public Point getPoint() {
    method setPoint (line 38) | public void setPoint(Point point) {
    method getPressure (line 42) | public float getPressure() {
    method setPressure (line 46) | public void setPressure(float pressure) {
    method isUp (line 50) | public boolean isUp() {
    method setUp (line 54) | public void setUp(boolean up) {

FILE: server/src/main/java/com/genymobile/scrcpy/control/PointersState.java
  class PointersState (line 10) | public class PointersState {
    method indexOf (line 16) | private int indexOf(long id) {
    method isLocalIdAvailable (line 26) | private boolean isLocalIdAvailable(int localId) {
    method nextUnusedLocalId (line 36) | private int nextUnusedLocalId() {
    method get (line 45) | public Pointer get(int index) {
    method getPointerIndex (line 49) | public int getPointerIndex(long id) {
    method update (line 77) | public int update(MotionEvent.PointerProperties[] props, MotionEvent.P...
    method cleanUp (line 97) | private void cleanUp() {

FILE: server/src/main/java/com/genymobile/scrcpy/control/PositionMapper.java
  class PositionMapper (line 8) | public final class PositionMapper {
    method PositionMapper (line 13) | public PositionMapper(Size videoSize, AffineMatrix videoToDeviceMatrix) {
    method create (line 18) | public static PositionMapper create(Size videoSize, AffineMatrix filte...
    method getVideoSize (line 30) | public Size getVideoSize() {
    method map (line 34) | public Point map(Position position) {

FILE: server/src/main/java/com/genymobile/scrcpy/control/UhidManager.java
  class UhidManager (line 23) | public final class UhidManager {
    method UhidManager (line 46) | public UhidManager(DeviceMessageSender sender, String displayUniqueId) {
    method open (line 58) | public void open(int id, int vendorId, int productId, String name, byt...
    method registerUhidListener (line 88) | private void registerUhidListener(int id, FileDescriptor fd) {
    method unregisterUhidListener (line 114) | private void unregisterUhidListener(FileDescriptor fd) {
    method extractHidOutputData (line 120) | private static byte[] extractHidOutputData(ByteBuffer buffer) {
    method writeInput (line 150) | public void writeInput(int id, byte[] data) throws IOException {
    method buildUhidCreate2Req (line 165) | private static byte[] buildUhidCreate2Req(int vendorId, int productId,...
    method buildUhidInput2Req (line 214) | private static byte[] buildUhidInput2Req(byte[] data) {
    method close (line 235) | public void close(int id) {
    method closeAll (line 252) | public void closeAll() {
    method close (line 264) | private static void close(FileDescriptor fd) {
    method mustUseInputPort (line 272) | private boolean mustUseInputPort() {
    method addUniqueIdAssociation (line 276) | private void addUniqueIdAssociation() {
    method removeUniqueIdAssociation (line 282) | private void removeUniqueIdAssociation() {

FILE: server/src/main/java/com/genymobile/scrcpy/device/ConfigurationException.java
  class ConfigurationException (line 3) | public class ConfigurationException extends Exception {
    method ConfigurationException (line 4) | public ConfigurationException(String message) {

FILE: server/src/main/java/com/genymobile/scrcpy/device/DesktopConnection.java
  class DesktopConnection (line 16) | public final class DesktopConnection implements Closeable {
    method DesktopConnection (line 31) | private DesktopConnection(LocalSocket videoSocket, LocalSocket audioSo...
    method connect (line 41) | private static LocalSocket connect(String abstractName) throws IOExcep...
    method getSocketName (line 47) | private static String getSocketName(int scid) {
    method open (line 56) | public static DesktopConnection open(int scid, boolean tunnelForward, ...
    method getFirstSocket (line 118) | private LocalSocket getFirstSocket() {
    method shutdown (line 128) | public void shutdown() throws IOException {
    method close (line 143) | public void close() throws IOException {
    method sendDeviceMeta (line 155) | public void sendDeviceMeta(String deviceName) throws IOException {
    method getVideoFd (line 167) | public FileDescriptor getVideoFd() {
    method getAudioFd (line 171) | public FileDescriptor getAudioFd() {
    method getControlChannel (line 175) | public ControlChannel getControlChannel() {

FILE: server/src/main/java/com/genymobile/scrcpy/device/Device.java
  class Device (line 32) | public final class Device {
    method Device (line 47) | private Device() {
    method getDeviceName (line 51) | public static String getDeviceName() {
    method supportsInputEvents (line 55) | public static boolean supportsInputEvents(int displayId) {
    method injectEvent (line 60) | public static boolean injectEvent(InputEvent inputEvent, int displayId...
    method injectKeyEvent (line 72) | public static boolean injectKeyEvent(int action, int keyCode, int repe...
    method pressReleaseKeycode (line 79) | public static boolean pressReleaseKeycode(int keyCode, int displayId, ...
    method isScreenOn (line 84) | public static boolean isScreenOn(int displayId) {
    method expandNotificationPanel (line 89) | public static void expandNotificationPanel() {
    method expandSettingsPanel (line 93) | public static void expandSettingsPanel() {
    method collapsePanels (line 97) | public static void collapsePanels() {
    method getClipboardText (line 101) | public static String getClipboardText() {
    method setClipboardText (line 113) | public static boolean setClipboardText(String text) {
    method setDisplayPower (line 131) | public static boolean setDisplayPower(int displayId, boolean on) {
    method powerOffScreen (line 181) | public static boolean powerOffScreen(int displayId) {
    method rotateDevice (line 193) | public static void rotateDevice(int displayId) {
    method getCurrentRotation (line 213) | private static int getCurrentRotation(int displayId) {
    method listApps (line 224) | public static List<DeviceApp> listApps() {
    method getLaunchableApps (line 234) | @SuppressLint("QueryPermissionsNeeded")
    method getLaunchIntent (line 246) | public static Intent getLaunchIntent(PackageManager pm, String package...
    method toApp (line 255) | private static DeviceApp toApp(PackageManager pm, ApplicationInfo appI...
    method findByPackageName (line 261) | @SuppressLint("QueryPermissionsNeeded")
    method findByName (line 274) | @SuppressLint("QueryPermissionsNeeded")
    method startApp (line 291) | public static void startApp(String packageName, int displayId, boolean...

FILE: server/src/main/java/com/genymobile/scrcpy/device/DeviceApp.java
  class DeviceApp (line 3) | public final class DeviceApp {
    method DeviceApp (line 9) | public DeviceApp(String packageName, String name, boolean system) {
    method getPackageName (line 15) | public String getPackageName() {
    method getName (line 19) | public String getName() {
    method isSystem (line 23) | public boolean isSystem() {

FILE: server/src/main/java/com/genymobile/scrcpy/device/DisplayInfo.java
  class DisplayInfo (line 3) | public final class DisplayInfo {
    method DisplayInfo (line 14) | public DisplayInfo(int displayId, Size size, int rotation, int layerSt...
    method getDisplayId (line 24) | public int getDisplayId() {
    method getSize (line 28) | public Size getSize() {
    method getRotation (line 32) | public int getRotation() {
    method getLayerStack (line 36) | public int getLayerStack() {
    method getFlags (line 40) | public int getFlags() {
    method getDpi (line 44) | public int getDpi() {
    method getUniqueId (line 48) | public String getUniqueId() {

FILE: server/src/main/java/com/genymobile/scrcpy/device/NewDisplay.java
  class NewDisplay (line 3) | public final class NewDisplay {
    method NewDisplay (line 7) | public NewDisplay() {
    method NewDisplay (line 11) | public NewDisplay(Size size, int dpi) {
    method getSize (line 16) | public Size getSize() {
    method getDpi (line 20) | public int getDpi() {
    method hasExplicitSize (line 24) | public boolean hasExplicitSize() {
    method hasExplicitDpi (line 28) | public boolean hasExplicitDpi() {

FILE: server/src/main/java/com/genymobile/scrcpy/device/Orientation.java
  type Orientation (line 3) | public enum Orientation {
    type Lock (line 15) | public enum Lock {
    method Orientation (line 21) | Orientation(String name) {
    method getByName (line 25) | public static Orientation getByName(String name) {
    method fromRotation (line 35) | public static Orientation fromRotation(int ccwRotation) {
    method isFlipped (line 42) | public boolean isFlipped() {
    method getRotation (line 46) | public int getRotation() {

FILE: server/src/main/java/com/genymobile/scrcpy/device/Point.java
  class Point (line 5) | public class Point {
    method Point (line 9) | public Point(int x, int y) {
    method getX (line 14) | public int getX() {
    method getY (line 18) | public int getY() {
    method equals (line 22) | @Override
    method hashCode (line 34) | @Override
    method toString (line 39) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/device/Position.java
  class Position (line 5) | public class Position {
    method Position (line 9) | public Position(Point point, Size screenSize) {
    method Position (line 14) | public Position(int x, int y, int screenWidth, int screenHeight) {
    method getPoint (line 18) | public Point getPoint() {
    method getScreenSize (line 22) | public Size getScreenSize() {
    method rotate (line 26) | public Position rotate(int rotation) {
    method equals (line 39) | @Override
    method hashCode (line 51) | @Override
    method toString (line 56) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/device/Size.java
  class Size (line 7) | public final class Size {
    method Size (line 11) | public Size(int width, int height) {
    method getWidth (line 16) | public int getWidth() {
    method getHeight (line 20) | public int getHeight() {
    method getMax (line 24) | public int getMax() {
    method rotate (line 28) | public Size rotate() {
    method limit (line 32) | public Size limit(int maxSize) {
    method round8 (line 62) | public Size round8() {
    method isMultipleOf8 (line 83) | public boolean isMultipleOf8() {
    method toRect (line 87) | public Rect toRect() {
    method equals (line 91) | @Override
    method hashCode (line 103) | @Override
    method toString (line 108) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/device/Streamer.java
  class Streamer (line 15) | public final class Streamer {
    method Streamer (line 27) | public Streamer(FileDescriptor fd, Codec codec, boolean sendCodecMeta,...
    method getCodec (line 34) | public Codec getCodec() {
    method writeAudioHeader (line 38) | public void writeAudioHeader() throws IOException {
    method writeVideoHeader (line 47) | public void writeVideoHeader(Size videoSize) throws IOException {
    method writeDisableStream (line 58) | public void writeDisableStream(boolean error) throws IOException {
    method writePacket (line 69) | public void writePacket(ByteBuffer buffer, long pts, boolean config, b...
    method writePacket (line 85) | public void writePacket(ByteBuffer codecBuffer, MediaCodec.BufferInfo ...
    method writeFrameMeta (line 92) | private void writeFrameMeta(FileDescriptor fd, int packetSize, long pt...
    method fixOpusConfigPacket (line 111) | private static void fixOpusConfigPacket(ByteBuffer buffer) throws IOEx...
    method fixFlacConfigPacket (line 154) | private static void fixFlacConfigPacket(ByteBuffer buffer) throws IOEx...

FILE: server/src/main/java/com/genymobile/scrcpy/opengl/AffineOpenGLFilter.java
  class AffineOpenGLFilter (line 10) | public class AffineOpenGLFilter implements OpenGLFilter {
    method AffineOpenGLFilter (line 24) | public AffineOpenGLFilter(AffineMatrix transform) {
    method init (line 28) | @Override
    method draw (line 96) | @Override
    method release (line 130) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/opengl/GLUtils.java
  class GLUtils (line 13) | public final class GLUtils {
    method GLUtils (line 17) | private GLUtils() {
    method createProgram (line 21) | public static int createProgram(String vertexSource, String fragmentSo...
    method createShader (line 60) | public static int createShader(int type, String source) {
    method getShaderTypeString (line 81) | private static String getShaderTypeString(int type) {
    method checkGlError (line 95) | public static void checkGlError() {
    method getGlErrorMessage (line 104) | public static String getGlErrorMessage(String userError) {
    method toErrorString (line 113) | private static String toErrorString(int glError) {
    method createFloatBuffer (line 118) | public static FloatBuffer createFloatBuffer(float[] values) {

FILE: server/src/main/java/com/genymobile/scrcpy/opengl/OpenGLException.java
  class OpenGLException (line 5) | public class OpenGLException extends IOException {
    method OpenGLException (line 6) | public OpenGLException(String message) {
    method OpenGLException (line 10) | public OpenGLException(String message, Throwable cause) {

FILE: server/src/main/java/com/genymobile/scrcpy/opengl/OpenGLFilter.java
  type OpenGLFilter (line 3) | public interface OpenGLFilter {
    method init (line 10) | void init() throws OpenGLException;
    method draw (line 15) | void draw(int textureId, float[] texMatrix);
    method release (line 20) | void release();

FILE: server/src/main/java/com/genymobile/scrcpy/opengl/OpenGLRunner.java
  class OpenGLRunner (line 22) | public final class OpenGLRunner {
    method OpenGLRunner (line 41) | public OpenGLRunner(OpenGLFilter filter, float[] overrideTransformMatr...
    method OpenGLRunner (line 46) | public OpenGLRunner(OpenGLFilter filter) {
    method initOnce (line 50) | public static synchronized void initOnce() {
    method quit (line 61) | public static void quit() {
    method join (line 72) | public static void join() throws InterruptedException {
    method start (line 82) | public Surface start(Size inputSize, Size outputSize, Surface outputSu...
    method run (line 106) | private void run(Size inputSize, Size outputSize, Surface outputSurfac...
    method render (line 194) | private void render(Size outputSize) {
    method stopAndRelease (line 214) | public void stopAndRelease() {

FILE: server/src/main/java/com/genymobile/scrcpy/util/AffineMatrix.java
  class AffineMatrix (line 24) | public class AffineMatrix {
    method AffineMatrix (line 42) | public AffineMatrix(double a, double b, double c, double d, double e, ...
    method toString (line 51) | @Override
    method ndcFromPixels (line 62) | public static AffineMatrix ndcFromPixels(Size size) {
    method ndcToPixels (line 74) | public static AffineMatrix ndcToPixels(Size size) {
    method apply (line 86) | public Point apply(Point point) {
    method multiply (line 100) | public AffineMatrix multiply(AffineMatrix rhs) {
    method multiplyAll (line 121) | public static AffineMatrix multiplyAll(AffineMatrix... matrices) {
    method invert (line 138) | public AffineMatrix invert() {
    method fromCenter (line 192) | public AffineMatrix fromCenter() {
    method withAspectRatio (line 202) | public AffineMatrix withAspectRatio(double ar) {
    method withAspectRatio (line 212) | public AffineMatrix withAspectRatio(Size size) {
    method translate (line 224) | public static AffineMatrix translate(double x, double y) {
    method scale (line 235) | public static AffineMatrix scale(double x, double y) {
    method scale (line 246) | public static AffineMatrix scale(Size from, Size to) {
    method reframe (line 263) | public static AffineMatrix reframe(double x, double y, double w, doubl...
    method rotateOrtho (line 276) | public static AffineMatrix rotateOrtho(int ccwRotation) {
    method hflip (line 299) | public static AffineMatrix hflip() {
    method vflip (line 308) | public static AffineMatrix vflip() {
    method rotate (line 318) | public static AffineMatrix rotate(double ccwDegrees) {
    method to4x4 (line 330) | public void to4x4(float[] matrix) {
    method to4x4 (line 363) | public float[] to4x4() {

FILE: server/src/main/java/com/genymobile/scrcpy/util/Binary.java
  class Binary (line 3) | public final class Binary {
    method Binary (line 4) | private Binary() {
    method toUnsigned (line 8) | public static int toUnsigned(short value) {
    method toUnsigned (line 12) | public static int toUnsigned(byte value) {
    method u16FixedPointToFloat (line 22) | public static float u16FixedPointToFloat(short value) {
    method i16FixedPointToFloat (line 34) | public static float i16FixedPointToFloat(short value) {

FILE: server/src/main/java/com/genymobile/scrcpy/util/Codec.java
  type Codec (line 5) | public interface Codec {
    type Type (line 7) | enum Type {
    method getType (line 12) | Type getType();
    method getId (line 14) | int getId();
    method getName (line 16) | String getName();
    method getMimeType (line 18) | String getMimeType();
    method getMimeType (line 20) | static String getMimeType(MediaCodec codec) {

FILE: server/src/main/java/com/genymobile/scrcpy/util/CodecOption.java
  class CodecOption (line 6) | public class CodecOption {
    method CodecOption (line 10) | public CodecOption(String key, Object value) {
    method getKey (line 15) | public String getKey() {
    method getValue (line 19) | public Object getValue() {
    method parse (line 23) | public static List<CodecOption> parse(String codecOptions) {
    method parseOption (line 69) | private static CodecOption parseOption(String option) {

FILE: server/src/main/java/com/genymobile/scrcpy/util/CodecUtils.java
  class CodecUtils (line 11) | public final class CodecUtils {
    method CodecUtils (line 13) | private CodecUtils() {
    method setCodecOption (line 17) | public static void setCodecOption(MediaFormat format, String key, Obje...
    method getEncoders (line 29) | public static MediaCodecInfo[] getEncoders(MediaCodecList codecs, Stri...

FILE: server/src/main/java/com/genymobile/scrcpy/util/Command.java
  class Command (line 7) | public final class Command {
    method Command (line 8) | private Command() {
    method exec (line 12) | public static void exec(String... cmd) throws IOException, Interrupted...
    method execReadLine (line 20) | public static String execReadLine(String... cmd) throws IOException, I...
    method execReadOutput (line 34) | public static String execReadOutput(String... cmd) throws IOException,...

FILE: server/src/main/java/com/genymobile/scrcpy/util/HandlerExecutor.java
  class HandlerExecutor (line 10) | public class HandlerExecutor implements Executor {
    method HandlerExecutor (line 13) | public HandlerExecutor(Handler handler) {
    method execute (line 17) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/util/IO.java
  class IO (line 17) | public final class IO {
    method IO (line 18) | private IO() {
    method write (line 22) | private static int write(FileDescriptor fd, ByteBuffer from) throws IO...
    method writeFully (line 34) | public static void writeFully(FileDescriptor fd, ByteBuffer from) thro...
    method writeFully (line 58) | public static void writeFully(FileDescriptor fd, byte[] buffer, int of...
    method toString (line 62) | public static String toString(InputStream inputStream) {
    method isBrokenPipe (line 71) | public static boolean isBrokenPipe(IOException e) {
    method isBrokenPipe (line 76) | public static boolean isBrokenPipe(Exception e) {

FILE: server/src/main/java/com/genymobile/scrcpy/util/Ln.java
  class Ln (line 14) | public final class Ln {
    type Level (line 22) | public enum Level {
    method Ln (line 28) | private Ln() {
    method disableSystemStreams (line 32) | public static void disableSystemStreams() {
    method initLogLevel (line 45) | public static void initLogLevel(Level level) {
    method isEnabled (line 49) | public static boolean isEnabled(Level level) {
    method v (line 53) | public static void v(String message) {
    method d (line 60) | public static void d(String message) {
    method i (line 67) | public static void i(String message) {
    method w (line 74) | public static void w(String message, Throwable throwable) {
    method w (line 86) | public static void w(String message) {
    method e (line 90) | public static void e(String message, Throwable throwable) {
    method e (line 102) | public static void e(String message) {
    class NullOutputStream (line 106) | static class NullOutputStream extends OutputStream {
      method write (line 107) | @Override
      method write (line 112) | @Override
      method write (line 117) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/util/LogUtils.java
  class LogUtils (line 32) | public final class LogUtils {
    method LogUtils (line 34) | private LogUtils() {
    method buildEncoderListMessage (line 38) | private static String buildEncoderListMessage(String type, Codec[] cod...
    method buildVideoEncoderListMessage (line 69) | public static String buildVideoEncoderListMessage() {
    method buildAudioEncoderListMessage (line 73) | public static String buildAudioEncoderListMessage() {
    method getHwCodecType (line 77) | @TargetApi(AndroidVersions.API_29_ANDROID_10)
    method buildDisplayListMessage (line 88) | public static String buildDisplayListMessage() {
    method getCameraFacingName (line 110) | private static String getCameraFacingName(int facing) {
    method isCameraBackwardCompatible (line 123) | private static boolean isCameraBackwardCompatible(CameraCharacteristic...
    method buildCameraListMessage (line 138) | public static String buildCameraListMessage(boolean includeSizes) {
    method getUniqueSet (line 208) | private static SortedSet<Integer> getUniqueSet(Range<Integer>[] ranges) {
    method buildAppListMessage (line 217) | public static String buildAppListMessage() {
    method buildAppListMessage (line 222) | @SuppressLint("QueryPermissionsNeeded")

FILE: server/src/main/java/com/genymobile/scrcpy/util/Settings.java
  class Settings (line 6) | public final class Settings {
    method Settings (line 12) | private Settings() {
    method getValue (line 16) | public static String getValue(String table, String key) throws Setting...
    method putValue (line 22) | public static void putValue(String table, String key, String value) th...
    method getAndPutValue (line 29) | public static String getAndPutValue(String table, String key, String v...

FILE: server/src/main/java/com/genymobile/scrcpy/util/SettingsException.java
  class SettingsException (line 3) | public class SettingsException extends Exception {
    method createMessage (line 4) | private static String createMessage(String method, String table, Strin...
    method SettingsException (line 8) | public SettingsException(String method, String table, String key, Stri...

FILE: server/src/main/java/com/genymobile/scrcpy/util/StringUtils.java
  class StringUtils (line 3) | public final class StringUtils {
    method StringUtils (line 4) | private StringUtils() {
    method getUtf8TruncationIndex (line 8) | public static int getUtf8TruncationIndex(byte[] utf8, int maxLength) {

FILE: server/src/main/java/com/genymobile/scrcpy/util/Threads.java
  class Threads (line 8) | public final class Threads {
    method Threads (line 9) | private Threads() {
    method executeSynchronouslyOn (line 13) | public static <T> T executeSynchronouslyOn(Handler handler, Callable<T...

FILE: server/src/main/java/com/genymobile/scrcpy/video/CameraAspectRatio.java
  class CameraAspectRatio (line 3) | public final class CameraAspectRatio {
    method CameraAspectRatio (line 8) | private CameraAspectRatio(float ar) {
    method fromFloat (line 12) | public static CameraAspectRatio fromFloat(float ar) {
    method fromFraction (line 19) | public static CameraAspectRatio fromFraction(int w, int h) {
    method sensorAspectRatio (line 26) | public static CameraAspectRatio sensorAspectRatio() {
    method isSensor (line 30) | public boolean isSensor() {
    method getAspectRatio (line 34) | public float getAspectRatio() {

FILE: server/src/main/java/com/genymobile/scrcpy/video/CameraCapture.java
  class CameraCapture (line 47) | public class CameraCapture extends SurfaceCapture {
    method CameraCapture (line 81) | public CameraCapture(Options options) {
    method init (line 95) | @Override
    method prepare (line 115) | @Override
    method selectCamera (line 142) | private static String selectCamera(String explicitCameraId, CameraFaci...
    method selectSize (line 172) | @TargetApi(AndroidVersions.API_24_ANDROID_7_0)
    method resolveAspectRatio (line 240) | private static Float resolveAspectRatio(CameraAspectRatio ratio, Camer...
    method start (line 253) | @Override
    method stop (line 274) | @Override
    method release (line 282) | @Override
    method getSize (line 292) | @Override
    method setMaxSize (line 297) | @Override
    method openCamera (line 307) | @SuppressLint("MissingPermission")
    method createCaptureSession (line 355) | @TargetApi(AndroidVersions.API_31_ANDROID_12)
    method createCaptureRequest (line 383) | private CaptureRequest createCaptureRequest(Surface surface) throws Ca...
    method setRepeatingRequest (line 394) | @TargetApi(AndroidVersions.API_31_ANDROID_12)
    method isClosed (line 417) | @Override
    method requestInvalidate (line 422) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/video/CameraFacing.java
  type CameraFacing (line 6) | public enum CameraFacing {
    method CameraFacing (line 15) | CameraFacing(String name, int value) {
    method value (line 20) | int value() {
    method findByName (line 24) | public static CameraFacing findByName(String name) {

FILE: server/src/main/java/com/genymobile/scrcpy/video/CaptureReset.java
  class CaptureReset (line 7) | public class CaptureReset implements SurfaceCapture.CaptureListener {
    method consumeReset (line 14) | public boolean consumeReset() {
    method reset (line 18) | public synchronized void reset() {
    method setRunningMediaCodec (line 29) | public synchronized void setRunningMediaCodec(MediaCodec runningMediaC...
    method onInvalidated (line 33) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/video/DisplaySizeMonitor.java
  class DisplaySizeMonitor (line 18) | public class DisplaySizeMonitor {
    type Listener (line 20) | public interface Listener {
      method onDisplaySizeChanged (line 21) | void onDisplaySizeChanged();
    method start (line 41) | public void start(int displayId, Listener listener) {
    method stopAndRelease (line 85) | public void stopAndRelease() {
    method getSessionDisplaySize (line 101) | private synchronized Size getSessionDisplaySize() {
    method setSessionDisplaySize (line 105) | public synchronized void setSessionDisplaySize(Size sessionDisplaySize) {
    method checkDisplaySizeChanged (line 109) | private void checkDisplaySizeChanged() {

FILE: server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java
  class NewDisplayCapture (line 24) | public class NewDisplayCapture extends SurfaceCapture {
    method NewDisplayCapture (line 68) | public NewDisplayCapture(VirtualDisplayListener vdListener, Options op...
    method init (line 84) | @Override
    method prepare (line 104) | @Override
    method startNew (line 169) | public void startNew(Surface surface) {
    method start (line 209) | @Override
    method stop (line 230) | @Override
    method release (line 238) | @Override
    method getSize (line 248) | @Override
    method setMaxSize (line 253) | @Override
    method scaleDpi (line 259) | private static int scaleDpi(Size initialSize, int initialDpi, Size siz...
    method requestInvalidate (line 265) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java
  class ScreenCapture (line 28) | public class ScreenCapture extends SurfaceCapture {
    method ScreenCapture (line 49) | public ScreenCapture(VirtualDisplayListener vdListener, Options option...
    method init (line 62) | @Override
    method prepare (line 67) | @Override
    method start (line 103) | @Override
    method stop (line 163) | @Override
    method release (line 171) | @Override
    method getSize (line 185) | @Override
    method setMaxSize (line 190) | @Override
    method createDisplay (line 196) | private static IBinder createDisplay() throws Exception {
    method setDisplaySurface (line 204) | private static void setDisplaySurface(IBinder display, Surface surface...
    method requestInvalidate (line 215) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/video/SurfaceCapture.java
  class SurfaceCapture (line 13) | public abstract class SurfaceCapture {
    type CaptureListener (line 15) | public interface CaptureListener {
      method onInvalidated (line 16) | void onInvalidated();
    method invalidate (line 24) | protected void invalidate() {
    method init (line 31) | public final void init(CaptureListener listener) throws ConfigurationE...
    method init (line 39) | protected abstract void init() throws ConfigurationException, IOExcept...
    method release (line 44) | public abstract void release();
    method prepare (line 49) | public void prepare() throws ConfigurationException, IOException {
    method start (line 58) | public abstract void start(Surface surface) throws IOException;
    method stop (line 63) | public void stop() {
    method getSize (line 72) | public abstract Size getSize();
    method setMaxSize (line 79) | public abstract boolean setMaxSize(int maxSize);
    method isClosed (line 86) | public boolean isClosed() {
    method requestInvalidate (line 95) | public abstract void requestInvalidate();

FILE: server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java
  class SurfaceEncoder (line 29) | public class SurfaceEncoder implements AsyncProcessor {
    method SurfaceEncoder (line 55) | public SurfaceEncoder(SurfaceCapture capture, Streamer streamer, Optio...
    method streamCapture (line 65) | private void streamCapture() throws IOException, ConfigurationException {
    method prepareRetry (line 149) | private boolean prepareRetry(Size currentSize) {
    method chooseMaxSizeFallback (line 185) | private static int chooseMaxSizeFallback(Size failedSize) {
    method encode (line 197) | private void encode(MediaCodec codec, Streamer streamer) throws IOExce...
    method createMediaCodec (line 226) | private static MediaCodec createMediaCodec(Codec codec, String encoder...
    method createFormat (line 256) | private static MediaFormat createFormat(String videoMimeType, int bitR...
    method start (line 288) | @Override
    method stop (line 312) | @Override
    method join (line 320) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/video/VideoCodec.java
  type VideoCodec (line 8) | public enum VideoCodec implements Codec {
    method VideoCodec (line 18) | VideoCodec(int id, String name, String mimeType) {
    method getType (line 24) | @Override
    method getId (line 29) | @Override
    method getName (line 34) | @Override
    method getMimeType (line 39) | @Override
    method findByName (line 44) | public static VideoCodec findByName(String name) {

FILE: server/src/main/java/com/genymobile/scrcpy/video/VideoFilter.java
  class VideoFilter (line 9) | public class VideoFilter {
    method VideoFilter (line 14) | public VideoFilter(Size inputSize) {
    method getOutputSize (line 18) | public Size getOutputSize() {
    method getTransform (line 22) | public AffineMatrix getTransform() {
    method getInverseTransform (line 39) | public AffineMatrix getInverseTransform() {
    method transposeRect (line 46) | private static Rect transposeRect(Rect rect) {
    method addCrop (line 50) | public void addCrop(Rect crop, boolean transposed) {
    method addRotation (line 71) | public void addRotation(int ccwRotation) {
    method addOrientation (line 82) | public void addOrientation(Orientation captureOrientation) {
    method addOrientation (line 90) | public void addOrientation(int displayRotation, boolean locked, Orient...
    method addAngle (line 99) | public void addAngle(double cwAngle) {
    method addResize (line 107) | public void addResize(Size targetSize) {

FILE: server/src/main/java/com/genymobile/scrcpy/video/VideoSource.java
  type VideoSource (line 3) | public enum VideoSource {
    method VideoSource (line 9) | VideoSource(String name) {
    method findByName (line 13) | public static VideoSource findByName(String name) {

FILE: server/src/main/java/com/genymobile/scrcpy/video/VirtualDisplayListener.java
  type VirtualDisplayListener (line 5) | public interface VirtualDisplayListener {
    method onNewVirtualDisplay (line 6) | void onNewVirtualDisplay(int displayId, PositionMapper positionMapper);

FILE: server/src/main/java/com/genymobile/scrcpy/wrappers/ActivityManager.java
  class ActivityManager (line 19) | @SuppressLint("PrivateApi,DiscouragedPrivateApi")
    method create (line 29) | static ActivityManager create() {
    method ActivityManager (line 42) | private ActivityManager(IInterface manager) {
    method getGetContentProviderExternalMethod (line 46) | private Method getGetContentProviderExternalMethod() throws NoSuchMeth...
    method getRemoveContentProviderExternalMethod (line 60) | private Method getRemoveContentProviderExternalMethod() throws NoSuchM...
    method getContentProviderExternal (line 67) | @TargetApi(AndroidVersions.API_29_ANDROID_10)
    method removeContentProviderExternal (line 94) | void removeContentProviderExternal(String name, IBinder token) {
    method createSettingsProvider (line 103) | public ContentProvider createSettingsProvider() {
    method getStartActivityAsUserMethod (line 112) | private Method getStartActivityAsUserMethod() throws NoSuchMethodExcep...
    method startActivity (line 123) | public int startActivity(Intent intent) {
    method startActivity (line 127) | @SuppressWarnings("ConstantConditions")
    method getForceStopPackageMethod (line 150) | private Method getForceStopPackageMethod() throws NoSuchMethodException {
    method forceStopPackage (line 157) | public void forceStopPackage(String packageName) {

FILE: server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java
  class ClipboardManager (line 8) | public final class ClipboardManager {
    method create (line 11) | static ClipboardManager create() {
    method ClipboardManager (line 22) | private ClipboardManager(android.content.ClipboardManager manager) {
    method getText (line 26) | public CharSequence getText() {
    method setText (line 34) | public boolean setText(CharSequence text) {
    method addPrimaryClipChangedListener (line 40) | public void addPrimaryClipChangedListener(android.content.ClipboardMan...

FILE: server/src/main/java/com/genymobile/scrcpy/wrappers/ContentProvider.java
  class ContentProvider (line 17) | public final class ContentProvider implements Closeable {
    method ContentProvider (line 45) | ContentProvider(ActivityManager manager, Object provider, String name,...
    method getCallMethod (line 52) | @SuppressLint("PrivateApi")
    method call (line 78) | private Bundle call(String callMethod, String arg, Bundle extras) thro...
    method close (line 105) | public void close() {
    method getGetMethod (line 109) | private static String getGetMethod(String table) {
    method getPutMethod (line 122) | private static String getPutMethod(String table) {
    method getValue (line 135) | public String getValue(String table, String key) throws SettingsExcept...
    method putValue (line 151) | public void putValue(String table, String key, String value) throws Se...

FILE: server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayControl.java
  class DisplayControl (line 13) | @SuppressLint({"PrivateApi", "SoonBlockedPrivateApi", "BlockedPrivateApi"})
    method DisplayControl (line 45) | private DisplayControl() {
    method getGetPhysicalDisplayTokenMethod (line 49) | private static Method getGetPhysicalDisplayTokenMethod() throws NoSuch...
    method getPhysicalDisplayToken (line 56) | public static IBinder getPhysicalDisplayToken(long physicalDisplayId) {
    method getGetPhysicalDisplayIdsMethod (line 66) | private static Method getGetPhysicalDisplayIdsMethod() throws NoSuchMe...
    method getPhysicalDisplayIds (line 73) | public static long[] getPhysicalDisplayIds() {

FILE: server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayManager.java
  class DisplayManager (line 25) | @SuppressLint("PrivateApi,DiscouragedPrivateApi")
    type DisplayListener (line 31) | public interface DisplayListener {
      method onDisplayChanged (line 38) | void onDisplayChanged(int displayId);
    class DisplayListenerHandle (line 41) | public static final class DisplayListenerHandle {
      method DisplayListenerHandle (line 43) | private DisplayListenerHandle(Object displayListenerProxy) {
    method create (line 53) | static DisplayManager create() {
    method DisplayManager (line 64) | private DisplayManager(Object manager) {
    method parseDisplayInfo (line 69) | public static DisplayInfo parseDisplayInfo(String dumpsysDisplayOutput...
    method getDisplayInfoFromDumpsysDisplay (line 88) | private static DisplayInfo getDisplayInfoFromDumpsysDisplay(int displa...
    method parseDisplayFlags (line 98) | private static int parseDisplayFlags(String text) {
    method getGetDisplayInfoMethod (line 119) | private synchronized Method getGetDisplayInfoMethod() throws NoSuchMet...
    method getDisplayInfo (line 126) | public DisplayInfo getDisplayInfo(int displayId) {
    method getDisplayIds (line 155) | public int[] getDisplayIds() {
    method getCreateVirtualDisplayMethod (line 163) | private Method getCreateVirtualDisplayMethod() throws NoSuchMethodExce...
    method createVirtualDisplay (line 171) | public VirtualDisplay createVirtualDisplay(String name, int width, int...
    method createNewVirtualDisplay (line 176) | public VirtualDisplay createNewVirtualDisplay(String name, int width, ...
    method getRequestDisplayPowerMethod (line 184) | private Method getRequestDisplayPowerMethod() throws NoSuchMethodExcep...
    method requestDisplayPower (line 191) | @TargetApi(AndroidVersions.API_35_ANDROID_15)
    method registerDisplayListener (line 202) | public DisplayListenerHandle registerDisplayListener(DisplayListener l...
    method unregisterDisplayListener (line 242) | public void unregisterDisplayListener(DisplayListenerHandle listener) {

FILE: server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayWindowListener.java
  class DisplayWindowListener (line 10) | public class DisplayWindowListener extends IDisplayWindowListener.Stub {
    method onDisplayAdded (line 11) | @Override
    method onDisplayConfigurationChanged (line 16) | @Override
    method onDisplayRemoved (line 21) | @Override
    method onTransact (line 26) | @Override

FILE: server/src/main/java/com/genymobile/scrcpy/wrappers/InputManager.java
  class InputManager (line 15) | @SuppressLint("PrivateApi,DiscouragedPrivateApi")
    method create (line 31) | static InputManager create() {
    method InputManager (line 37) | private InputManager(android.hardware.input.InputManager manager) {
    method getInjectInputEventMethod (line 41) | private static Method getInjectInputEventMethod() throws NoSuchMethodE...
    method injectInputEvent (line 48) | public boolean injectInputEvent(InputEvent inputEvent, int mode) {
    method getSetDisplayIdMethod (line 75) | private static Method getSetDisplayIdMethod() throws NoSuchMethodExcep...
    method setDisplayId (line 82) | public static boolean setDisplayId(InputEvent inputEvent, int displayI...
    method getSetActionButtonMethod (line 93) | private static Method getSetActionButtonMethod() throws NoSuchMethodEx...
    method setActionButton (line 100) | public static boolean setActionButton(MotionEvent motionEvent, int act...
    method getAddUniqueIdAssociationByPortMethod (line 111) | private static Method getAddUniqueIdAssociationByPortMethod() throws N...
    method addUniqueIdAssociationByPort (line 119) | @TargetApi(AndroidVersions.API_35_ANDROID_15)
    method getRemoveUniqueIdAssociationByPortMethod (line 129) | private static Method getRemoveUniqueIdAssociationByPortMethod() throw...
    method removeUniqueIdAssociationByPort (line 137) | @TargetApi(AndroidVersions.API_35_ANDROID_15)

FILE: server/src/main/java/com/genymobile/scrcpy/wrappers/PowerManager.java
  class PowerManager (line 11) | public final class PowerManager {
    method create (line 15) | static PowerManager create() {
    method PowerManager (line 20) | private PowerManager(IInterface manager) {
    method getIsScreenOnMethod (line 24) | private Method getIsScreenOnMethod() throws NoSuchMethodException {
    method isScreenOn (line 35) | public boolean isScreenOn(int displayId) {

FILE: server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java
  class ServiceManager (line 14) | @SuppressLint("PrivateApi,DiscouragedPrivateApi")
    method ServiceManager (line 36) | private ServiceManager() {
    method getService (line 40) | static IInterface getService(String service, String type) {
    method getWindowManager (line 50) | public static WindowManager getWindowManager() {
    method getDisplayManager (line 58) | public static synchronized DisplayManager getDisplayManager() {
    method getInputManager (line 65) | public static InputManager getInputManager() {
    method getPowerManager (line 72) | public static PowerManager getPowerManager() {
    method getStatusBarManager (line 79) | public static StatusBarManager getStatusBarManager() {
    method getClipboardManager (line 86) | public static ClipboardManager getClipboardManager() {
    method getActivityManager (line 94) | public static ActivityManager getActivityManager() {
    method getCameraManager (line 101) | public static CameraManager getCameraManager() {

FILE: server/src/main/java/com/genymobile/scrcpy/wrappers/StatusBarManager.java
  class StatusBarManager (line 9) | public final class StatusBarManager {
    method create (line 18) | static StatusBarManager create() {
    method StatusBarManager (line 23) | private StatusBarManager(IInterface manager) {
    method getExpandNotificationsPanelMethod (line 27) | private Method getExpandNotificationsPanelMethod() throws NoSuchMethod...
    method getExpandSettingsPanel (line 40) | private Method getExpandSettingsPanel() throws NoSuchMethodException {
    method getCollapsePanelsMethod (line 54) | private Method getCollapsePanelsMethod() throws NoSuchMethodException {
    method expandNotificationsPanel (line 61) | public void expandNotificationsPanel() {
    method expandSettingsPanel (line 74) | public void expandSettingsPanel() {
    method collapsePanels (line 89) | public void collapsePanels() {

FILE: server/src/main/java/com/genymobile/scrcpy/wrappers/SurfaceControl.java
  class SurfaceControl (line 14) | @SuppressLint("PrivateApi")
    method SurfaceControl (line 36) | private SurfaceControl() {
    method openTransaction (line 40) | public static void openTransaction() {
    method closeTransaction (line 48) | public static void closeTransaction() {
    method setDisplayProjection (line 56) | public static void setDisplayProjection(IBinder displayToken, int orie...
    method setDisplayLayerStack (line 65) | public static void setDisplayLayerStack(IBinder displayToken, int laye...
    method setDisplaySurface (line 73) | public static void setDisplaySurface(IBinder displayToken, Surface sur...
    method createDisplay (line 81) | public static IBinder createDisplay(String name, boolean secure) throw...
    method getGetBuiltInDisplayMethod (line 85) | private static Method getGetBuiltInDisplayMethod() throws NoSuchMethod...
    method hasGetBuildInDisplayMethod (line 98) | public static boolean hasGetBuildInDisplayMethod() {
    method getBuiltInDisplay (line 107) | public static IBinder getBuiltInDisplay() {
    method getGetPhysicalDisplayTokenMethod (line 123) | private static Method getGetPhysicalDisplayTokenMethod() throws NoSuch...
    method getPhysicalDisplayToken (line 130) | public static IBinder getPhysicalDisplayToken(long physicalDisplayId) {
    method getGetPhysicalDisplayIdsMethod (line 140) | private static Method getGetPhysicalDisplayIdsMethod() throws NoSuchMe...
    method hasGetPhysicalDisplayIdsMethod (line 147) | public static boolean hasGetPhysicalDisplayIdsMethod() {
    method getPhysicalDisplayIds (line 156) | public static long[] getPhysicalDisplayIds() {
    method getSetDisplayPowerModeMethod (line 166) | private static Method getSetDisplayPowerModeMethod() throws NoSuchMeth...
    method setDisplayPowerMode (line 173) | public static boolean setDisplayPowerMode(IBinder displayToken, int mo...
    method destroyDisplay (line 184) | public static void destroyDisplay(IBinder displayToken) {

FILE: server/src/main/java/com/genymobile/scrcpy/wrappers/WindowManager.java
  class WindowManager (line 13) | public final class WindowManager {
    method create (line 36) | static WindowManager create() {
    method WindowManager (line 41) | private WindowManager(IInterface manager) {
    method getGetRotationMethod (line 45) | private Method getGetRotationMethod() throws NoSuchMethodException {
    method getFreezeDisplayRotationMethod (line 60) | private Method getFreezeDisplayRotationMethod() throws NoSuchMethodExc...
    method getIsDisplayRotationFrozenMethod (line 82) | private Method getIsDisplayRotationFrozenMethod() throws NoSuchMethodE...
    method getThawDisplayRotationMethod (line 97) | private Method getThawDisplayRotationMethod() throws NoSuchMethodExcep...
    method getRotation (line 119) | public int getRotation() {
    method freezeRotation (line 129) | public void freezeRotation(int displayId, int rotation) {
    method isRotationFrozen (line 152) | public boolean isRotationFrozen(int displayId) {
    method thawRotation (line 171) | public void thawRotation(int displayId) {
    method registerDisplayWindowListener (line 194) | @TargetApi(AndroidVersions.API_30_ANDROID_11)
    method unregisterDisplayWindowListener (line 204) | @TargetApi(AndroidVersions.API_30_ANDROID_11)
    method getGetDisplayImePolicyMethod (line 213) | @TargetApi(AndroidVersions.API_29_ANDROID_10)
    method getDisplayImePolicy (line 225) | @TargetApi(AndroidVersions.API_29_ANDROID_10)
    method getSetDisplayImePolicyMethod (line 240) | @TargetApi(AndroidVersions.API_29_ANDROID_10)
    method setDisplayImePolicy (line 252) | @TargetApi(AndroidVersions.API_29_ANDROID_10)

FILE: server/src/test/java/com/genymobile/scrcpy/control/ControlMessageReaderTest.java
  class ControlMessageReaderTest (line 16) | public class ControlMessageReaderTest {
    method testParseKeycodeEvent (line 18) | @Test
    method testParseTextEvent (line 42) | @Test
    method testParseLongTextEvent (line 62) | @Test
    method testParseTouchEvent (line 83) | @Test
    method testParseScrollEvent (line 118) | @Test
    method testParseBackOrScreenOnEvent (line 148) | @Test
    method testParseExpandNotificationPanelEvent (line 166) | @Test
    method testParseExpandSettingsPanelEvent (line 182) | @Test
    method testParseCollapsePanelsEvent (line 198) | @Test
    method testParseGetClipboardEvent (line 214) | @Test
    method testParseSetClipboardEvent (line 232) | @Test
    method testParseBigSetClipboardEvent (line 256) | @Test
    method testParseSetDisplayPower (line 285) | @Test
    method testParseRotateDevice (line 303) | @Test
    method testParseUhidCreate (line 319) | @Test
    method testParseUhidInput (line 348) | @Test
    method testParseUhidDestroy (line 370) | @Test
    method testParseOpenHardKeyboardSettings (line 388) | @Test
    method testParseStartApp (line 404) | @Test
    method testMultiEvents (line 425) | @Test
    method testPartialEvents (line 464) | @Test

FILE: server/src/test/java/com/genymobile/scrcpy/control/DeviceMessageWriterTest.java
  class DeviceMessageWriterTest (line 11) | public class DeviceMessageWriterTest {
    method testSerializeClipboard (line 13) | @Test
    method testSerializeAckSetClipboard (line 35) | @Test
    method testSerializeUhidOutput (line 54) | @Test

FILE: server/src/test/java/com/genymobile/scrcpy/util/BinaryTest.java
  class BinaryTest (line 6) | public class BinaryTest {
    method testU16FixedPointToFloat (line 8) | @Test
    method testI16FixedPointToFloat (line 21) | @Test

FILE: server/src/test/java/com/genymobile/scrcpy/util/CodecOptionsTest.java
  class CodecOptionsTest (line 8) | public class CodecOptionsTest {
    method testIntegerImplicit (line 10) | @Test
    method testInteger (line 21) | @Test
    method testLong (line 33) | @Test
    method testFloat (line 45) | @Test
    method testString (line 57) | @Test
    method testStringEscaped (line 69) | @Test
    method testList (line 81) | @Test

FILE: server/src/test/java/com/genymobile/scrcpy/util/CommandParserTest.java
  class CommandParserTest (line 10) | public class CommandParserTest {
    method testParseDisplayInfoFromDumpsysDisplay (line 11) | @Test
    method testParseDisplayInfoFromDumpsysDisplayWithRotation (line 53) | @Test
    method testParseDisplayInfoFromDumpsysDisplayAPI31 (line 95) | @Test
    method testParseDisplayInfoFromDumpsysDisplayAPI31NoFlags (line 142) | @Test
    method testParseDisplayInfoFromDumpsysDisplayAPI29WithNoFlags (line 188) | @Test

FILE: server/src/test/java/com/genymobile/scrcpy/util/StringUtilsTest.java
  class StringUtilsTest (line 8) | public class StringUtilsTest {
    method testUtf8Truncate (line 10) | @Test
Condensed preview — 353 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,660K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 69,
    "preview": "github: [rom1v]\nliberapay: rom1v\ncustom: [\"https://paypal.me/rom2v\"]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 951,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n_Please read the"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 773,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n - [ ] I have"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.md",
    "chars": 94,
    "preview": "---\nname: Question\nabout: Ask a question about scrcpy\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 14344,
    "preview": "name: Build\n\non:\n  workflow_dispatch:\n    inputs:\n      name:\n        description: 'Version name (default is ref name)'\n"
  },
  {
    "path": ".gitignore",
    "chars": 98,
    "preview": "build/\n/dist/\n/build-*/\n/build_*/\n/release-*/\n.idea/\n.gradle/\n/x/\nlocal.properties\n/scrcpy-server\n"
  },
  {
    "path": "FAQ.md",
    "chars": 6464,
    "preview": "# Frequently Asked Questions\n\n[Read in another language](#translations)\n\nHere are the common reported problems and their"
  },
  {
    "path": "LICENSE",
    "chars": 11387,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 7469,
    "preview": "**This GitHub repo (<https://github.com/Genymobile/scrcpy>) is the only official\nsource for the project. Do not download"
  },
  {
    "path": "app/data/bash-completion/scrcpy",
    "chars": 6378,
    "preview": "_scrcpy() {\n    local cur prev words cword\n    local opts=\"\n        --always-on-top\n        --angle\n        --audio-bit-"
  },
  {
    "path": "app/data/open_a_terminal_here.bat",
    "chars": 5,
    "preview": "@cmd\n"
  },
  {
    "path": "app/data/scrcpy-console.bat",
    "chars": 51,
    "preview": "@echo off\r\nscrcpy.exe --pause-on-exit=if-error %*\r\n"
  },
  {
    "path": "app/data/scrcpy-console.desktop",
    "chars": 472,
    "preview": "[Desktop Entry]\nName=scrcpy (console)\nGenericName=Android Remote Control\nComment=Display and control your Android device"
  },
  {
    "path": "app/data/scrcpy-noconsole.vbs",
    "chars": 212,
    "preview": "strCommand = \"cmd /c scrcpy.exe\"\r\n\r\nFor Each Arg In WScript.Arguments\r\n    strCommand = strCommand & \" \"\"\" & replace(Arg"
  },
  {
    "path": "app/data/scrcpy.desktop",
    "chars": 436,
    "preview": "[Desktop Entry]\nName=scrcpy\nGenericName=Android Remote Control\nComment=Display and control your Android device\n# For som"
  },
  {
    "path": "app/data/zsh-completion/_scrcpy",
    "chars": 7830,
    "preview": "#compdef scrcpy scrcpy.exe\n#\n# name: scrcpy\n# auth: hltdev [hltdev8642@gmail.com]\n# desc: completion file for scrcpy (al"
  },
  {
    "path": "app/deps/.gitignore",
    "chars": 6,
    "preview": "/work\n"
  },
  {
    "path": "app/deps/README",
    "chars": 964,
    "preview": "This directory (app/deps/) contains:\n\n*.sh          : shell scripts to download and build dependencies\n\npatches/      : "
  },
  {
    "path": "app/deps/_init",
    "chars": 1759,
    "preview": "# This file is intended to be sourced by other scripts, not executed\n\nprocess_args() {\n    if [[ $# != 3 ]]\n    then\n   "
  },
  {
    "path": "app/deps/adb_linux.sh",
    "chars": 753,
    "preview": "#!/usr/bin/env bash\nset -ex\n. $(dirname ${BASH_SOURCE[0]})/_init \"$@\"\n\nVERSION=36.0.0\nURL=\"https://dl.google.com/android"
  },
  {
    "path": "app/deps/adb_macos.sh",
    "chars": 755,
    "preview": "#!/usr/bin/env bash\nset -ex\n. $(dirname ${BASH_SOURCE[0]})/_init \"$@\"\n\nVERSION=36.0.0\nURL=\"https://dl.google.com/android"
  },
  {
    "path": "app/deps/adb_windows.sh",
    "chars": 852,
    "preview": "#!/usr/bin/env bash\nset -ex\n. $(dirname ${BASH_SOURCE[0]})/_init \"$@\"\n\nVERSION=36.0.0\nURL=\"https://dl.google.com/android"
  },
  {
    "path": "app/deps/dav1d.sh",
    "chars": 1588,
    "preview": "#!/usr/bin/env bash\nset -ex\n. $(dirname ${BASH_SOURCE[0]})/_init\nprocess_args \"$@\"\n\nVERSION=1.5.0\nURL=\"https://code.vide"
  },
  {
    "path": "app/deps/ffmpeg.sh",
    "chars": 3408,
    "preview": "#!/usr/bin/env bash\nset -ex\n. $(dirname ${BASH_SOURCE[0]})/_init\nprocess_args \"$@\"\n\nVERSION=7.1.1\nURL=\"https://ffmpeg.or"
  },
  {
    "path": "app/deps/libusb.sh",
    "chars": 1312,
    "preview": "#!/usr/bin/env bash\nset -ex\n. $(dirname ${BASH_SOURCE[0]})/_init\nprocess_args \"$@\"\n\nVERSION=1.0.29\nURL=\"https://github.c"
  },
  {
    "path": "app/deps/sdl.sh",
    "chars": 1632,
    "preview": "#!/usr/bin/env bash\nset -ex\n. $(dirname ${BASH_SOURCE[0]})/_init\nprocess_args \"$@\"\n\nVERSION=2.32.8\nURL=\"https://github.c"
  },
  {
    "path": "app/meson.build",
    "chars": 7877,
    "preview": "src = [\n    'src/main.c',\n    'src/adb/adb.c',\n    'src/adb/adb_device.c',\n    'src/adb/adb_parser.c',\n    'src/adb/adb_"
  },
  {
    "path": "app/scrcpy-windows.manifest",
    "chars": 495,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersi"
  },
  {
    "path": "app/scrcpy-windows.rc",
    "chars": 547,
    "preview": "#include <winuser.h>\n\n0 ICON \"data/icon.ico\"\n1 RT_MANIFEST \"scrcpy-windows.manifest\"\n2 VERSIONINFO\nBEGIN\n  BLOCK \"String"
  },
  {
    "path": "app/scrcpy.1",
    "chars": 23392,
    "preview": ".TH \"scrcpy\" \"1\"\n.SH NAME\nscrcpy \\- Display and control your Android device\n\n\n.SH SYNOPSIS\n.B scrcpy\n.RI [ options ]\n\n\n."
  },
  {
    "path": "app/src/adb/adb.c",
    "chars": 23657,
    "preview": "#include \"adb.h\"\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/types.h>\n"
  },
  {
    "path": "app/src/adb/adb.h",
    "chars": 3131,
    "preview": "#ifndef SC_ADB_H\n#define SC_ADB_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <inttypes.h>\n\n#include \"adb/adb_de"
  },
  {
    "path": "app/src/adb/adb_device.c",
    "chars": 1052,
    "preview": "#include \"adb_device.h\"\n\n#include <stdlib.h>\n#include <string.h>\n\nvoid\nsc_adb_device_destroy(struct sc_adb_device *devic"
  },
  {
    "path": "app/src/adb/adb_device.h",
    "chars": 977,
    "preview": "#ifndef SC_ADB_DEVICE_H\n#define SC_ADB_DEVICE_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"util/vector.h\"\n\nst"
  },
  {
    "path": "app/src/adb/adb_parser.c",
    "chars": 6087,
    "preview": "#include \"adb_parser.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/types.h>\n\n#include \"u"
  },
  {
    "path": "app/src/adb/adb_parser.h",
    "chars": 640,
    "preview": "#ifndef SC_ADB_PARSER_H\n#define SC_ADB_PARSER_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"adb/adb_device.h\"\n"
  },
  {
    "path": "app/src/adb/adb_tunnel.c",
    "chars": 5780,
    "preview": "#include \"adb_tunnel.h\"\n\n#include <assert.h>\n#include <inttypes.h>\n\n#include \"adb/adb.h\"\n#include \"util/log.h\"\n#include "
  },
  {
    "path": "app/src/adb/adb_tunnel.h",
    "chars": 1181,
    "preview": "#ifndef SC_ADB_TUNNEL_H\n#define SC_ADB_TUNNEL_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#include"
  },
  {
    "path": "app/src/android/input.h",
    "chars": 32121,
    "preview": "// copied from <https://android.googlesource.com/platform/frameworks/native/+/master/include/android/input.h>\n// blob 08"
  },
  {
    "path": "app/src/android/keycodes.h",
    "chars": 28337,
    "preview": "// copied from <https://android.googlesource.com/platform/frameworks/native/+/master/include/android/keycodes.h>\n// blob"
  },
  {
    "path": "app/src/audio_player.c",
    "chars": 3749,
    "preview": "#include \"audio_player.h\"\n\n#include \"util/log.h\"\n\n/** Downcast frame_sink to sc_audio_player */\n#define DOWNCAST(SINK) c"
  },
  {
    "path": "app/src/audio_player.h",
    "chars": 872,
    "preview": "#ifndef SC_AUDIO_PLAYER_H\n#define SC_AUDIO_PLAYER_H\n\n#include \"common.h\"\n\n#include <SDL2/SDL_audio.h>\n\n#include \"audio_r"
  },
  {
    "path": "app/src/audio_regulator.c",
    "chars": 17297,
    "preview": "#include \"audio_regulator.h\"\n\n#include <assert.h>\n#include <inttypes.h>\n#include <stdlib.h>\n#include <string.h>\n#include"
  },
  {
    "path": "app/src/audio_regulator.h",
    "chars": 2313,
    "preview": "#ifndef SC_AUDIO_REGULATOR_H\n#define SC_AUDIO_REGULATOR_H\n\n#include \"common.h\"\n\n#include <stdatomic.h>\n#include <stdbool"
  },
  {
    "path": "app/src/cli.c",
    "chars": 107936,
    "preview": "#include \"cli.h\"\n\n#include <assert.h>\n#include <getopt.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#in"
  },
  {
    "path": "app/src/cli.h",
    "chars": 578,
    "preview": "#ifndef SCRCPY_CLI_H\n#define SCRCPY_CLI_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"options.h\"\n\nenum sc_paus"
  },
  {
    "path": "app/src/clock.c",
    "chars": 916,
    "preview": "#include \"clock.h\"\n\n#include <assert.h>\n\n#include \"util/log.h\"\n\n//#define SC_CLOCK_DEBUG // uncomment to debug\n\n#define "
  },
  {
    "path": "app/src/clock.h",
    "chars": 1075,
    "preview": "#ifndef SC_CLOCK_H\n#define SC_CLOCK_H\n\n#include \"common.h\"\n\n#include \"util/tick.h\"\n\nstruct sc_clock_point {\n    sc_tick "
  },
  {
    "path": "app/src/common.h",
    "chars": 368,
    "preview": "#ifndef SC_COMMON_H\n#define SC_COMMON_H\n\n#include \"config.h\"\n#include \"compat.h\"\n\n#define ARRAY_LEN(a) (sizeof(a) / size"
  },
  {
    "path": "app/src/compat.c",
    "chars": 2259,
    "preview": "#include \"compat.h\"\n\n#include \"config.h\"\n\n#include <assert.h>\n#ifndef HAVE_REALLOCARRAY\n# include <errno.h>\n#endif\n#incl"
  },
  {
    "path": "app/src/compat.h",
    "chars": 3248,
    "preview": "#ifndef SC_COMPAT_H\n#define SC_COMPAT_H\n\n#include \"config.h\"\n\n#include <libavcodec/version.h>\n#include <libavformat/vers"
  },
  {
    "path": "app/src/control_msg.c",
    "chars": 13804,
    "preview": "#include \"control_msg.h\"\n\n#include <assert.h>\n#include <inttypes.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"u"
  },
  {
    "path": "app/src/control_msg.h",
    "chars": 3974,
    "preview": "#ifndef SC_CONTROLMSG_H\n#define SC_CONTROLMSG_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include "
  },
  {
    "path": "app/src/controller.c",
    "chars": 6191,
    "preview": "#include \"controller.h\"\n\n#include <assert.h>\n\n#include \"util/log.h\"\n\n// Drop droppable events above this limit\n#define S"
  },
  {
    "path": "app/src/controller.h",
    "chars": 1468,
    "preview": "#ifndef SC_CONTROLLER_H\n#define SC_CONTROLLER_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"control_msg.h\"\n#in"
  },
  {
    "path": "app/src/coords.h",
    "chars": 434,
    "preview": "#ifndef SC_COORDS\n#define SC_COORDS\n\n#include <stdint.h>\n\nstruct sc_size {\n    uint16_t width;\n    uint16_t height;\n};\n\n"
  },
  {
    "path": "app/src/decoder.c",
    "chars": 2826,
    "preview": "#include \"decoder.h\"\n\n#include <errno.h>\n#include <libavcodec/packet.h>\n#include <libavutil/avutil.h>\n\n#include \"util/lo"
  },
  {
    "path": "app/src/decoder.h",
    "chars": 574,
    "preview": "#ifndef SC_DECODER_H\n#define SC_DECODER_H\n\n#include \"common.h\"\n\n#include <libavcodec/avcodec.h>\n\n#include \"trait/frame_s"
  },
  {
    "path": "app/src/delay_buffer.c",
    "chars": 6037,
    "preview": "#include \"delay_buffer.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <libavcodec/avcodec.h>\n\n#include \"util/log.h"
  },
  {
    "path": "app/src/delay_buffer.h",
    "chars": 1423,
    "preview": "#ifndef SC_DELAY_BUFFER_H\n#define SC_DELAY_BUFFER_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <libavutil/frame"
  },
  {
    "path": "app/src/demuxer.c",
    "chars": 9304,
    "preview": "#include \"demuxer.h\"\n\n#include <assert.h>\n#include <inttypes.h>\n#include <libavcodec/avcodec.h>\n#include <libavutil/chan"
  },
  {
    "path": "app/src/demuxer.h",
    "chars": 1050,
    "preview": "#ifndef SC_DEMUXER_H\n#define SC_DEMUXER_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"trait/packet_source.h\"\n#"
  },
  {
    "path": "app/src/device_msg.c",
    "chars": 2593,
    "preview": "#include \"device_msg.h\"\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"util/binary.h\"\n#include "
  },
  {
    "path": "app/src/device_msg.h",
    "chars": 1061,
    "preview": "#ifndef SC_DEVICEMSG_H\n#define SC_DEVICEMSG_H\n\n#include \"common.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n#include <sy"
  },
  {
    "path": "app/src/display.c",
    "chars": 10885,
    "preview": "#include \"display.h\"\n\n#include <assert.h>\n#include <inttypes.h>\n#include <string.h>\n#include <libavutil/pixfmt.h>\n\n#incl"
  },
  {
    "path": "app/src/display.h",
    "chars": 1353,
    "preview": "#ifndef SC_DISPLAY_H\n#define SC_DISPLAY_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <libav"
  },
  {
    "path": "app/src/events.c",
    "chars": 1578,
    "preview": "#include \"events.h\"\n\n#include <assert.h>\n\n#include \"util/log.h\"\n#include \"util/thread.h\"\n\nbool\nsc_push_event_impl(uint32"
  },
  {
    "path": "app/src/events.h",
    "chars": 820,
    "preview": "#ifndef SC_EVENTS_H\n#define SC_EVENTS_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <SDL2/SD"
  },
  {
    "path": "app/src/file_pusher.c",
    "chars": 4775,
    "preview": "#include \"file_pusher.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"adb/adb.h\"\n#include \"ut"
  },
  {
    "path": "app/src/file_pusher.h",
    "chars": 1224,
    "preview": "#ifndef SC_FILE_PUSHER_H\n#define SC_FILE_PUSHER_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"util/intr.h\"\n#in"
  },
  {
    "path": "app/src/fps_counter.c",
    "chars": 5036,
    "preview": "#include \"fps_counter.h\"\n\n#include <assert.h>\n#include <stdint.h>\n\n#include \"util/log.h\"\n\n#define SC_FPS_COUNTER_INTERVA"
  },
  {
    "path": "app/src/fps_counter.h",
    "chars": 1270,
    "preview": "#ifndef SC_FPSCOUNTER_H\n#define SC_FPSCOUNTER_H\n\n#include \"common.h\"\n\n#include <stdatomic.h>\n#include <stdbool.h>\n\n#incl"
  },
  {
    "path": "app/src/frame_buffer.c",
    "chars": 2190,
    "preview": "#include \"frame_buffer.h\"\n\n#include <assert.h>\n\n#include \"util/log.h\"\n\nbool\nsc_frame_buffer_init(struct sc_frame_buffer "
  },
  {
    "path": "app/src/frame_buffer.h",
    "chars": 1016,
    "preview": "#ifndef SC_FRAME_BUFFER_H\n#define SC_FRAME_BUFFER_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <libavutil/frame"
  },
  {
    "path": "app/src/hid/hid_event.h",
    "chars": 426,
    "preview": "#ifndef SC_HID_EVENT_H\n#define SC_HID_EVENT_H\n\n#include \"common.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n\n#define SC_"
  },
  {
    "path": "app/src/hid/hid_gamepad.c",
    "chars": 14368,
    "preview": "#include \"hid_gamepad.h\"\n\n#include <assert.h>\n#include <inttypes.h>\n#include <stddef.h>\n#include <sys/types.h>\n\n#include"
  },
  {
    "path": "app/src/hid/hid_gamepad.h",
    "chars": 1505,
    "preview": "#ifndef SC_HID_GAMEPAD_H\n#define SC_HID_GAMEPAD_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#inclu"
  },
  {
    "path": "app/src/hid/hid_keyboard.c",
    "chars": 10640,
    "preview": "#include \"hid_keyboard.h\"\n\n#include <assert.h>\n#include <string.h>\n\n#include \"util/log.h\"\n\n#define SC_HID_MOD_NONE 0x00\n"
  },
  {
    "path": "app/src/hid/hid_keyboard.h",
    "chars": 1775,
    "preview": "#ifndef SC_HID_KEYBOARD_H\n#define SC_HID_KEYBOARD_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#inc"
  },
  {
    "path": "app/src/hid/hid_mouse.c",
    "chars": 6333,
    "preview": "#include \"hid_mouse.h\"\n\n#include <stdint.h>\n\n// 1 byte for buttons + padding, 1 byte for X position, 1 byte for Y positi"
  },
  {
    "path": "app/src/hid/hid_mouse.h",
    "chars": 759,
    "preview": "#ifndef SC_HID_MOUSE_H\n#define SC_HID_MOUSE_H\n\n#include \"common.h\"\n\n#include \"hid/hid_event.h\"\n#include \"input_events.h\""
  },
  {
    "path": "app/src/icon.c",
    "chars": 7945,
    "preview": "#include \"icon.h\"\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n"
  },
  {
    "path": "app/src/icon.h",
    "chars": 181,
    "preview": "#ifndef SC_ICON_H\n#define SC_ICON_H\n\n#include \"common.h\"\n\n#include <SDL2/SDL_surface.h>\n\nSDL_Surface *\nscrcpy_icon_load("
  },
  {
    "path": "app/src/input_events.h",
    "chars": 17452,
    "preview": "#ifndef SC_INPUT_EVENTS_H\n#define SC_INPUT_EVENTS_H\n\n#include \"common.h\"\n\n#include <assert.h>\n#include <stdbool.h>\n#incl"
  },
  {
    "path": "app/src/input_manager.c",
    "chars": 35917,
    "preview": "#include \"input_manager.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n#include <SDL2/SDL.h>\n\n#include "
  },
  {
    "path": "app/src/input_manager.h",
    "chars": 1862,
    "preview": "#ifndef SC_INPUTMANAGER_H\n#define SC_INPUTMANAGER_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n#incl"
  },
  {
    "path": "app/src/keyboard_sdk.c",
    "chars": 12383,
    "preview": "#include \"keyboard_sdk.h\"\n\n#include <assert.h>\n#include <ctype.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <stri"
  },
  {
    "path": "app/src/keyboard_sdk.h",
    "chars": 782,
    "preview": "#ifndef SC_KEYBOARD_SDK_H\n#define SC_KEYBOARD_SDK_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"controller.h\"\n"
  },
  {
    "path": "app/src/main.c",
    "chars": 3265,
    "preview": "#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdio.h>\n#ifdef HAVE_V4L2\n# include <libavdevice/avdevice.h>\n#endif\n"
  },
  {
    "path": "app/src/mouse_capture.c",
    "chars": 4044,
    "preview": "#include \"mouse_capture.h\"\n\n#include \"shortcut_mod.h\"\n#include \"util/log.h\"\n\nvoid\nsc_mouse_capture_init(struct sc_mouse_"
  },
  {
    "path": "app/src/mouse_capture.h",
    "chars": 899,
    "preview": "#ifndef SC_MOUSE_CAPTURE_H\n#define SC_MOUSE_CAPTURE_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include <SDL2/SDL.h>\n"
  },
  {
    "path": "app/src/mouse_sdk.c",
    "chars": 5289,
    "preview": "#include \"mouse_sdk.h\"\n\n#include <assert.h>\n#include <stdint.h>\n\n#include \"android/input.h\"\n#include \"control_msg.h\"\n#in"
  },
  {
    "path": "app/src/mouse_sdk.h",
    "chars": 435,
    "preview": "#ifndef SC_MOUSE_SDK_H\n#define SC_MOUSE_SDK_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"controller.h\"\n#inclu"
  },
  {
    "path": "app/src/opengl.c",
    "chars": 1668,
    "preview": "#include \"opengl.h\"\n\n#include <assert.h>\n#include <stdio.h>\n#include <string.h>\n#include <SDL2/SDL.h>\n\nvoid\nsc_opengl_in"
  },
  {
    "path": "app/src/opengl.h",
    "chars": 718,
    "preview": "#ifndef SC_OPENGL_H\n#define SC_OPENGL_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <SDL2/SDL_opengl.h>\n\nstruct "
  },
  {
    "path": "app/src/options.c",
    "chars": 4818,
    "preview": "#include \"options.h\"\n\n#include <stddef.h>\n\nconst struct scrcpy_options scrcpy_options_default = {\n    .serial = NULL,\n  "
  },
  {
    "path": "app/src/options.h",
    "chars": 9171,
    "preview": "#ifndef SCRCPY_OPTIONS_H\n#define SCRCPY_OPTIONS_H\n\n#include \"common.h\"\n\n#include <assert.h>\n#include <stdbool.h>\n#includ"
  },
  {
    "path": "app/src/packet_merger.c",
    "chars": 1258,
    "preview": "#include \"packet_merger.h\"\n\n#include <stdlib.h>\n#include <string.h>\n#include <libavutil/avutil.h>\n\n#include \"util/log.h\""
  },
  {
    "path": "app/src/packet_merger.h",
    "chars": 1205,
    "preview": "#ifndef SC_PACKET_MERGER_H\n#define SC_PACKET_MERGER_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n#in"
  },
  {
    "path": "app/src/receiver.c",
    "chars": 6565,
    "preview": "#include \"receiver.h\"\n\n#include <assert.h>\n#include <inttypes.h>\n#include <SDL2/SDL_clipboard.h>\n\n#include \"device_msg.h"
  },
  {
    "path": "app/src/receiver.h",
    "chars": 1024,
    "preview": "#ifndef SC_RECEIVER_H\n#define SC_RECEIVER_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"uhid/uhid_output.h\"\n#i"
  },
  {
    "path": "app/src/recorder.c",
    "chars": 24921,
    "preview": "#include \"recorder.h\"\n\n#include <assert.h>\n#include <inttypes.h>\n#include <stdlib.h>\n#include <string.h>\n#include <libav"
  },
  {
    "path": "app/src/recorder.h",
    "chars": 2208,
    "preview": "#ifndef SC_RECORDER_H\n#define SC_RECORDER_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <lib"
  },
  {
    "path": "app/src/scrcpy.c",
    "chars": 33220,
    "preview": "#include \"scrcpy.h\"\n\n#include <assert.h>\n#include <inttypes.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib."
  },
  {
    "path": "app/src/scrcpy.h",
    "chars": 379,
    "preview": "#ifndef SCRCPY_H\n#define SCRCPY_H\n\n#include \"common.h\"\n\n#include \"options.h\"\n\nenum scrcpy_exit_code {\n    // Normal prog"
  },
  {
    "path": "app/src/screen.c",
    "chars": 29268,
    "preview": "#include \"screen.h\"\n\n#include <assert.h>\n#include <string.h>\n#include <SDL2/SDL.h>\n\n#include \"events.h\"\n#include \"icon.h"
  },
  {
    "path": "app/src/screen.h",
    "chars": 4700,
    "preview": "#ifndef SC_SCREEN_H\n#define SC_SCREEN_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <SDL2/SD"
  },
  {
    "path": "app/src/server.c",
    "chars": 36927,
    "preview": "#include \"server.h\"\n\n#include <assert.h>\n#include <inttypes.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h"
  },
  {
    "path": "app/src/server.h",
    "chars": 3564,
    "preview": "#ifndef SC_SERVER_H\n#define SC_SERVER_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"adb/ad"
  },
  {
    "path": "app/src/shortcut_mod.h",
    "chars": 1810,
    "preview": "#ifndef SC_SHORTCUT_MOD_H\n#define SC_SHORTCUT_MOD_H\n\n#include \"common.h\"\n\n#include <assert.h>\n#include <stdbool.h>\n#incl"
  },
  {
    "path": "app/src/sys/unix/file.c",
    "chars": 2289,
    "preview": "#include \"util/file.h\"\n\n#include <limits.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/sta"
  },
  {
    "path": "app/src/sys/unix/process.c",
    "chars": 5912,
    "preview": "#include \"util/process.h\"\n\n#include <assert.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <signal.h>\n#include <stdio"
  },
  {
    "path": "app/src/sys/win/file.c",
    "chars": 827,
    "preview": "#include \"util/file.h\"\n\n#include <windows.h>\n\n#include <sys/stat.h>\n\n#include \"util/log.h\"\n#include \"util/str.h\"\n\nchar *"
  },
  {
    "path": "app/src/sys/win/process.c",
    "chars": 7208,
    "preview": "#include \"util/process.h\"\n\n#include <processthreadsapi.h>\n\n#include <assert.h>\n\n#include \"util/log.h\"\n#include \"util/str"
  },
  {
    "path": "app/src/trait/frame_sink.h",
    "chars": 579,
    "preview": "#ifndef SC_FRAME_SINK_H\n#define SC_FRAME_SINK_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <libavcodec/avcodec."
  },
  {
    "path": "app/src/trait/frame_source.c",
    "chars": 1627,
    "preview": "#include \"frame_source.h\"\n\n#include <assert.h>\n\nvoid\nsc_frame_source_init(struct sc_frame_source *source) {\n    source->"
  },
  {
    "path": "app/src/trait/frame_source.h",
    "chars": 861,
    "preview": "#ifndef SC_FRAME_SOURCE_H\n#define SC_FRAME_SOURCE_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"trait/frame_si"
  },
  {
    "path": "app/src/trait/gamepad_processor.h",
    "chars": 1344,
    "preview": "#ifndef SC_GAMEPAD_PROCESSOR_H\n#define SC_GAMEPAD_PROCESSOR_H\n\n#include \"common.h\"\n\n#include \"input_events.h\"\n\n/**\n * Ga"
  },
  {
    "path": "app/src/trait/key_processor.h",
    "chars": 1649,
    "preview": "#ifndef SC_KEY_PROCESSOR_H\n#define SC_KEY_PROCESSOR_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"input_events"
  },
  {
    "path": "app/src/trait/mouse_processor.h",
    "chars": 1510,
    "preview": "#ifndef SC_MOUSE_PROCESSOR_H\n#define SC_MOUSE_PROCESSOR_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"input_ev"
  },
  {
    "path": "app/src/trait/packet_sink.h",
    "chars": 959,
    "preview": "#ifndef SC_PACKET_SINK_H\n#define SC_PACKET_SINK_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <libavcodec/avcode"
  },
  {
    "path": "app/src/trait/packet_source.c",
    "chars": 1952,
    "preview": "#include \"packet_source.h\"\n\n#include <assert.h>\n\nvoid\nsc_packet_source_init(struct sc_packet_source *source) {\n    sourc"
  },
  {
    "path": "app/src/trait/packet_source.h",
    "chars": 951,
    "preview": "#ifndef SC_PACKET_SOURCE_H\n#define SC_PACKET_SOURCE_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"trait/packet"
  },
  {
    "path": "app/src/uhid/gamepad_uhid.c",
    "chars": 5032,
    "preview": "#include \"gamepad_uhid.h\"\n\n#include <assert.h>\n#include <inttypes.h>\n#include <string.h>\n#include <SDL2/SDL_gamecontroll"
  },
  {
    "path": "app/src/uhid/gamepad_uhid.h",
    "chars": 463,
    "preview": "#ifndef SC_GAMEPAD_UHID_H\n#define SC_GAMEPAD_UHID_H\n\n#include \"common.h\"\n\n#include \"controller.h\"\n#include \"hid/hid_game"
  },
  {
    "path": "app/src/uhid/keyboard_uhid.c",
    "chars": 5001,
    "preview": "#include \"keyboard_uhid.h\"\n\n#include <assert.h>\n#include <string.h>\n#include <SDL2/SDL_keyboard.h>\n#include <SDL2/SDL_ke"
  },
  {
    "path": "app/src/uhid/keyboard_uhid.h",
    "chars": 641,
    "preview": "#ifndef SC_KEYBOARD_UHID_H\n#define SC_KEYBOARD_UHID_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"controller.h"
  },
  {
    "path": "app/src/uhid/mouse_uhid.c",
    "chars": 3267,
    "preview": "#include \"mouse_uhid.h\"\n\n#include <assert.h>\n#include <string.h>\n\n#include \"hid/hid_mouse.h\"\n#include \"input_events.h\"\n#"
  },
  {
    "path": "app/src/uhid/mouse_uhid.h",
    "chars": 384,
    "preview": "#ifndef SC_MOUSE_UHID_H\n#define SC_MOUSE_UHID_H\n\n#include <stdbool.h>\n\n#include \"controller.h\"\n#include \"trait/mouse_pro"
  },
  {
    "path": "app/src/uhid/uhid_output.c",
    "chars": 742,
    "preview": "#include \"uhid_output.h\"\n\n#include <inttypes.h>\n\n#include \"uhid/keyboard_uhid.h\"\n#include \"util/log.h\"\n\nvoid\nsc_uhid_dev"
  },
  {
    "path": "app/src/uhid/uhid_output.h",
    "chars": 599,
    "preview": "#ifndef SC_UHID_OUTPUT_H\n#define SC_UHID_OUTPUT_H\n\n#include \"common.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n\n/**\n * "
  },
  {
    "path": "app/src/usb/aoa_hid.c",
    "chars": 15255,
    "preview": "#include \"aoa_hid.h\"\n\n#include <assert.h>\n#include <inttypes.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <sys/typ"
  },
  {
    "path": "app/src/usb/aoa_hid.h",
    "chars": 2158,
    "preview": "#ifndef SC_AOA_HID_H\n#define SC_AOA_HID_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"hid/"
  },
  {
    "path": "app/src/usb/gamepad_aoa.c",
    "chars": 3160,
    "preview": "#include \"gamepad_aoa.h\"\n\n#include <stdbool.h>\n\n#include \"input_events.h\"\n#include \"util/log.h\"\n\n/** Downcast gamepad pr"
  },
  {
    "path": "app/src/usb/gamepad_aoa.h",
    "chars": 474,
    "preview": "#ifndef SC_GAMEPAD_AOA_H\n#define SC_GAMEPAD_AOA_H\n\n#include \"common.h\"\n\n#include \"hid/hid_gamepad.h\"\n#include \"usb/aoa_h"
  },
  {
    "path": "app/src/usb/keyboard_aoa.c",
    "chars": 3177,
    "preview": "#include \"keyboard_aoa.h\"\n\n#include <assert.h>\n\n#include \"input_events.h\"\n#include \"util/log.h\"\n\n/** Downcast key proces"
  },
  {
    "path": "app/src/usb/keyboard_aoa.h",
    "chars": 512,
    "preview": "#ifndef SC_KEYBOARD_AOA_H\n#define SC_KEYBOARD_AOA_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"hid/hid_keyboa"
  },
  {
    "path": "app/src/usb/mouse_aoa.c",
    "chars": 2557,
    "preview": "#include \"mouse_aoa.h\"\n\n#include <assert.h>\n#include <stddef.h>\n\n#include \"hid/hid_mouse.h\"\n#include \"input_events.h\"\n#i"
  },
  {
    "path": "app/src/usb/mouse_aoa.h",
    "chars": 410,
    "preview": "#ifndef SC_MOUSE_AOA_H\n#define SC_MOUSE_AOA_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"usb/aoa_hid.h\"\n#incl"
  },
  {
    "path": "app/src/usb/scrcpy_otg.c",
    "chars": 6717,
    "preview": "#include \"scrcpy_otg.h\"\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include <SDL2/SDL.h>\n\n#ifdef _WIN"
  },
  {
    "path": "app/src/usb/scrcpy_otg.h",
    "chars": 180,
    "preview": "#ifndef SCRCPY_OTG_H\n#define SCRCPY_OTG_H\n\n#include \"common.h\"\n\n#include \"options.h\"\n#include \"scrcpy.h\"\n\nenum scrcpy_ex"
  },
  {
    "path": "app/src/usb/screen_otg.c",
    "chars": 10379,
    "preview": "#include \"screen_otg.h\"\n\n#include <assert.h>\n#include <stddef.h>\n\n#include \"icon.h\"\n#include \"options.h\"\n#include \"util/"
  },
  {
    "path": "app/src/usb/screen_otg.h",
    "chars": 1225,
    "preview": "#ifndef SC_SCREEN_OTG_H\n#define SC_SCREEN_OTG_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n#include "
  },
  {
    "path": "app/src/usb/usb.c",
    "chars": 11362,
    "preview": "#include \"usb.h\"\n\n#include <assert.h>\n\n#include \"util/log.h\"\n#include \"util/vector.h\"\n\nstruct sc_vec_usb_devices SC_VECT"
  },
  {
    "path": "app/src/usb/usb.h",
    "chars": 1921,
    "preview": "#ifndef SC_USB_H\n#define SC_USB_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <libusb-1.0/libusb.h>\n\n#include \"u"
  },
  {
    "path": "app/src/util/acksync.c",
    "chars": 1570,
    "preview": "#include \"acksync.h\"\n\n#include <assert.h>\n\nbool\nsc_acksync_init(struct sc_acksync *as) {\n    bool ok = sc_mutex_init(&as"
  },
  {
    "path": "app/src/util/acksync.h",
    "chars": 1454,
    "preview": "#ifndef SC_ACK_SYNC_H\n#define SC_ACK_SYNC_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n#include \"uti"
  },
  {
    "path": "app/src/util/audiobuf.c",
    "chars": 4607,
    "preview": "#include \"audiobuf.h\"\n\n#include <stdlib.h>\n#include <string.h>\n#include <util/log.h>\n#include <util/memory.h>\n\nbool\nsc_a"
  },
  {
    "path": "app/src/util/audiobuf.h",
    "chars": 1745,
    "preview": "#ifndef SC_AUDIOBUF_H\n#define SC_AUDIOBUF_H\n\n#include \"common.h\"\n\n#include <assert.h>\n#include <stdatomic.h>\n#include <s"
  },
  {
    "path": "app/src/util/average.c",
    "chars": 483,
    "preview": "#include \"average.h\"\n\n#include <assert.h>\n\nvoid\nsc_average_init(struct sc_average *avg, unsigned range) {\n    avg->range"
  },
  {
    "path": "app/src/util/average.h",
    "chars": 802,
    "preview": "#ifndef SC_AVERAGE\n#define SC_AVERAGE\n\n#include \"common.h\"\n\nstruct sc_average {\n    // Current average value\n    float a"
  },
  {
    "path": "app/src/util/binary.h",
    "chars": 2059,
    "preview": "#ifndef SC_BINARY_H\n#define SC_BINARY_H\n\n#include \"common.h\"\n\n#include <assert.h>\n#include <stdint.h>\n\nstatic inline voi"
  },
  {
    "path": "app/src/util/env.c",
    "chars": 541,
    "preview": "#include \"env.h\"\n\n#include <stdlib.h>\n#include <string.h>\n#ifdef _WIN32\n# include \"util/str.h\"\n#endif\n\nchar *\nsc_get_env"
  },
  {
    "path": "app/src/util/env.h",
    "chars": 221,
    "preview": "#ifndef SC_ENV_H\n#define SC_ENV_H\n\n#include \"common.h\"\n\n// Return the value of the environment variable (may be NULL).\n/"
  },
  {
    "path": "app/src/util/file.c",
    "chars": 1244,
    "preview": "#include \"file.h\"\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"util/log.h\"\n\nchar *\nsc_file_get_local_path(const c"
  },
  {
    "path": "app/src/util/file.h",
    "chars": 976,
    "preview": "#ifndef SC_FILE_H\n#define SC_FILE_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#ifdef _WIN32\n# define SC_PATH_SEPARATOR"
  },
  {
    "path": "app/src/util/intmap.c",
    "chars": 353,
    "preview": "#include \"intmap.h\"\n\nconst struct sc_intmap_entry *\nsc_intmap_find_entry(const struct sc_intmap_entry entries[], size_t "
  },
  {
    "path": "app/src/util/intmap.h",
    "chars": 534,
    "preview": "#ifndef SC_ARRAYMAP_H\n#define SC_ARRAYMAP_H\n\n#include \"common.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n\nstruct sc_int"
  },
  {
    "path": "app/src/util/intr.c",
    "chars": 1948,
    "preview": "#include \"intr.h\"\n\n#include <assert.h>\n\n#include \"util/log.h\"\n\nbool\nsc_intr_init(struct sc_intr *intr) {\n    bool ok = s"
  },
  {
    "path": "app/src/util/intr.h",
    "chars": 1595,
    "preview": "#ifndef SC_INTR_H\n#define SC_INTR_H\n\n#include \"common.h\"\n\n#include <stdatomic.h>\n#include <stdbool.h>\n\n#include \"util/ne"
  },
  {
    "path": "app/src/util/log.c",
    "chars": 4499,
    "preview": "#include \"log.h\"\n\n#if _WIN32\n# include <windows.h>\n#endif\n#include <assert.h>\n#include <stdarg.h>\n#include <stdio.h>\n#in"
  },
  {
    "path": "app/src/util/log.h",
    "chars": 1014,
    "preview": "#ifndef SC_LOG_H\n#define SC_LOG_H\n\n#include \"common.h\"\n\n#include <SDL2/SDL_log.h>\n\n#include \"options.h\"\n\n#define LOG_STR"
  },
  {
    "path": "app/src/util/memory.c",
    "chars": 259,
    "preview": "#include \"memory.h\"\n\n#include <stdlib.h>\n#include <errno.h>\n\nvoid *\nsc_allocarray(size_t nmemb, size_t size) {\n    size_"
  },
  {
    "path": "app/src/util/memory.h",
    "chars": 285,
    "preview": "#ifndef SC_MEMORY_H\n#define SC_MEMORY_H\n\n#include <stddef.h>\n\n/**\n * Allocate an array of `nmemb` items of `size` bytes "
  },
  {
    "path": "app/src/util/net.c",
    "chars": 6631,
    "preview": "#include \"net.h\"\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifdef _WIN32\n# include <ws2tcpip.h>\n  typ"
  },
  {
    "path": "app/src/util/net.h",
    "chars": 2269,
    "preview": "#ifndef SC_NET_H\n#define SC_NET_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#in"
  },
  {
    "path": "app/src/util/net_intr.c",
    "chars": 2303,
    "preview": "#include \"net_intr.h\"\n\nbool\nnet_connect_intr(struct sc_intr *intr, sc_socket socket, uint32_t addr,\n                 uin"
  },
  {
    "path": "app/src/util/net_intr.h",
    "chars": 937,
    "preview": "#ifndef SC_NET_INTR_H\n#define SC_NET_INTR_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <std"
  },
  {
    "path": "app/src/util/process.c",
    "chars": 2708,
    "preview": "#include \"process.h\"\n\n#include <assert.h>\n\nenum sc_process_result\nsc_process_execute(const char *const argv[], sc_pid *p"
  },
  {
    "path": "app/src/util/process.h",
    "chars": 4331,
    "preview": "#ifndef SC_PROCESS_H\n#define SC_PROCESS_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include \"util/"
  },
  {
    "path": "app/src/util/process_intr.c",
    "chars": 778,
    "preview": "#include \"process_intr.h\"\n\nssize_t\nsc_pipe_read_intr(struct sc_intr *intr, sc_pid pid, sc_pipe pipe, char *data,\n       "
  },
  {
    "path": "app/src/util/process_intr.h",
    "chars": 375,
    "preview": "#ifndef SC_PROCESS_INTR_H\n#define SC_PROCESS_INTR_H\n\n#include \"common.h\"\n\n#include \"util/intr.h\"\n#include \"util/process."
  },
  {
    "path": "app/src/util/rand.c",
    "chars": 657,
    "preview": "#include \"rand.h\"\n\n#include <stdlib.h>\n\n#include \"tick.h\"\n\nvoid sc_rand_init(struct sc_rand *rand) {\n    sc_tick seed = "
  },
  {
    "path": "app/src/util/rand.h",
    "chars": 268,
    "preview": "#ifndef SC_RAND_H\n#define SC_RAND_H\n\n#include \"common.h\"\n\n#include <inttypes.h>\n\nstruct sc_rand {\n    unsigned short xsu"
  },
  {
    "path": "app/src/util/str.c",
    "chars": 8290,
    "preview": "#include \"str.h\"\n\n#include <assert.h>\n#include <errno.h>\n#include <limits.h>\n#include <stdio.h>\n#include <stdlib.h>\n#inc"
  },
  {
    "path": "app/src/util/str.h",
    "chars": 3832,
    "preview": "#ifndef SC_STR_H\n#define SC_STR_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#in"
  },
  {
    "path": "app/src/util/strbuf.c",
    "chars": 1825,
    "preview": "#include \"strbuf.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"util/log.h\"\n\nbool\nsc_strbuf_"
  },
  {
    "path": "app/src/util/strbuf.h",
    "chars": 1358,
    "preview": "#ifndef SC_STRBUF_H\n#define SC_STRBUF_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <string."
  },
  {
    "path": "app/src/util/term.c",
    "chars": 936,
    "preview": "#include \"term.h\"\n\n#include <assert.h>\n\n#ifdef _WIN32\n# include <windows.h>\n#else\n# include <unistd.h>\n# include <sys/io"
  },
  {
    "path": "app/src/util/term.h",
    "chars": 448,
    "preview": "#ifndef SC_TERM_H\n#define SC_TERM_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n/**\n * Return the terminal dimensions\n *"
  },
  {
    "path": "app/src/util/thread.c",
    "chars": 5072,
    "preview": "#include \"thread.h\"\n\n#include <assert.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <SDL2/SDL_"
  },
  {
    "path": "app/src/util/thread.h",
    "chars": 1721,
    "preview": "#ifndef SC_THREAD_H\n#define SC_THREAD_H\n\n#include \"common.h\"\n\n#include <stdatomic.h>\n#include <stdbool.h>\n\n#include \"tic"
  },
  {
    "path": "app/src/util/tick.c",
    "chars": 1551,
    "preview": "#include \"tick.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <time.h>\n#ifdef _WIN32\n# include <windows.h>\n#endif\n"
  },
  {
    "path": "app/src/util/tick.h",
    "chars": 665,
    "preview": "#ifndef SC_TICK_H\n#define SC_TICK_H\n\n#include \"common.h\"\n\n#include <stdint.h>\n\ntypedef int64_t sc_tick;\n#define PRItick "
  },
  {
    "path": "app/src/util/timeout.c",
    "chars": 1760,
    "preview": "#include \"timeout.h\"\n\n#include <assert.h>\n#include <stddef.h>\n\n#include \"util/log.h\"\n\nbool\nsc_timeout_init(struct sc_tim"
  },
  {
    "path": "app/src/util/timeout.h",
    "chars": 792,
    "preview": "#ifndef SC_TIMEOUT_H\n#define SC_TIMEOUT_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n\n#include \"util/thread.h\"\n#include "
  },
  {
    "path": "app/src/util/vecdeque.h",
    "chars": 9527,
    "preview": "#ifndef SC_VECDEQUE_H\n#define SC_VECDEQUE_H\n\n#include \"common.h\"\n\n#include <assert.h>\n#include <stdbool.h>\n#include <std"
  },
  {
    "path": "app/src/util/vector.h",
    "chars": 14325,
    "preview": "#ifndef SC_VECTOR_H\n#define SC_VECTOR_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint."
  },
  {
    "path": "app/src/v4l2_sink.c",
    "chars": 9662,
    "preview": "#include \"v4l2_sink.h\"\n\n#include <assert.h>\n#include <errno.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string."
  },
  {
    "path": "app/src/v4l2_sink.h",
    "chars": 745,
    "preview": "#ifndef SC_V4L2_SINK_H\n#define SC_V4L2_SINK_H\n\n#include \"common.h\"\n\n#include <stdbool.h>\n#include <libavcodec/avcodec.h>"
  },
  {
    "path": "app/src/version.c",
    "chars": 2170,
    "preview": "#include \"version.h\"\n\n#include <stdio.h>\n#include <libavcodec/avcodec.h>\n#include <libavformat/avformat.h>\n#include <lib"
  },
  {
    "path": "app/src/version.h",
    "chars": 105,
    "preview": "#ifndef SC_VERSION_H\n#define SC_VERSION_H\n\n#include \"common.h\"\n\nvoid\nscrcpy_print_version(void);\n\n#endif\n"
  },
  {
    "path": "app/tests/test_adb_parser.c",
    "chars": 8936,
    "preview": "#include \"common.h\"\n\n#include <assert.h>\n\n#include \"adb/adb_device.h\"\n#include \"adb/adb_parser.h\"\n\nstatic void test_adb_"
  },
  {
    "path": "app/tests/test_audiobuf.c",
    "chars": 3196,
    "preview": "#include \"common.h\"\n\n#include <assert.h>\n#include <string.h>\n\n#include \"util/audiobuf.h\"\n\nstatic void test_audiobuf_simp"
  },
  {
    "path": "app/tests/test_binary.c",
    "chars": 3611,
    "preview": "#include \"common.h\"\n\n#include <assert.h>\n\n#include \"util/binary.h\"\n\nstatic void test_write16be(void) {\n    uint16_t val "
  },
  {
    "path": "app/tests/test_cli.c",
    "chars": 4405,
    "preview": "#include \"common.h\"\n\n#include <assert.h>\n#include <string.h>\n\n#include \"cli.h\"\n#include \"options.h\"\n\nstatic void test_fl"
  },
  {
    "path": "app/tests/test_control_msg_serialize.c",
    "chars": 14342,
    "preview": "#include \"common.h\"\n\n#include <assert.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"control_msg.h\"\n\nstatic void "
  },
  {
    "path": "app/tests/test_device_msg_deserialize.c",
    "chars": 2738,
    "preview": "#include \"common.h\"\n\n#include <assert.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"device_ms"
  },
  {
    "path": "app/tests/test_orientation.c",
    "chars": 3070,
    "preview": "#include \"common.h\"\n\n#include <assert.h>\n\n#include \"options.h\"\n\nstatic void test_transforms(void) {\n    #define O(X) SC_"
  },
  {
    "path": "app/tests/test_str.c",
    "chars": 11822,
    "preview": "#include \"common.h\"\n\n#include <assert.h>\n#include <limits.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n"
  }
]

// ... and 153 more files (download for full content)

About this extraction

This page contains the full source code of the Genymobile/scrcpy GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 353 files (1.5 MB), approximately 393.9k tokens, and a symbol index with 2212 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!