# What Is OTG Mode in scrcpy and How Does It Work Without USB Debugging?

> Discover OTG mode in scrcpy and control your Android device with keyboard and mouse using the Android Open Accessory protocol, bypassing USB debugging and ADB.

- Repository: [Genymobile/scrcpy](https://github.com/Genymobile/scrcpy)
- Tags: deep-dive
- Published: 2026-02-25

---

**OTG mode is a special scrcpy operation mode that controls an Android device using keyboard, mouse, and gamepad input without requiring ADB or enabled USB debugging, utilizing the Android Open Accessory (AOA) protocol instead.**

OTG mode in the Genymobile/scrcpy repository provides a "headless" control solution for scenarios where enabling USB debugging is impossible or undesirable. Unlike standard scrcpy operation that streams video and audio via ADB, OTG mode creates only a minimal SDL window to capture host input events and forwards them to the device as USB HID reports.

## How OTG Mode Works in scrcpy

The implementation relies on a direct USB accessory connection rather than the Android Debug Bridge. The workflow involves four distinct phases orchestrated through the USB stack in [`app/src/usb/scrcpy_otg.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/scrcpy_otg.c).

### USB Device Selection and AOA Handshake

First, scrcpy scans the USB bus to locate the target device. It opens the device using its own USB abstraction layer (`sc_usb_*` functions) rather than relying on ADB daemon availability.

```c
/* From app/src/usb/scrcpy_otg.c lines 24-33 */
// USB device selection and opening
ok = sc_usb_init(&s->usb);
if (!ok) goto end;

ok = sc_usb_select_device(&s->usb, serial);
if (!ok) goto end;

```

Once the USB device is open, scrcpy initiates the Android Open Accessory handshake. The `sc_aoa_init` function establishes the AOA connection, and `sc_aoa_start` opens the accessory interface:

```c
/* From app/src/usb/scrcpy_otg.c lines 39-44 & 80-84 */
ok = sc_aoa_init(&s->aoa, &s->usb, NULL);
if (!ok) goto end;

ok = sc_aoa_start(&s->aoa);
if (!ok) goto end;

```

### HID Device Registration

After establishing the AOA connection, scrcpy registers Human Interface Device (HID) interfaces for each requested input type. This registration occurs in [`app/src/usb/keyboard_aoa.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/keyboard_aoa.c), [`app/src/usb/mouse_aoa.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/mouse_aoa.c), and [`app/src/usb/gamepad_aoa.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/gamepad_aoa.c).

For keyboard input, `sc_keyboard_aoa_init` sends an HID "open" descriptor via `sc_aoa_push_open` and initializes the HID state structure:

```c
/* From app/src/usb/keyboard_aoa.c lines 65-77 */
bool sc_keyboard_aoa_init(struct sc_keyboard_aoa *kb, struct sc_aoa *aoa) {
    // Send HID open descriptor to register keyboard interface
    if (!sc_aoa_push_open(aoa, SC_HID_KEYBOARD, SC_HID_ID_KEYBOARD)) {
        return false;
    }
    // Initialize HID keyboard state
    sc_hid_keyboard_init(&kb->hid);
    kb->aoa = aoa;
    return true;
}

```

Similar initialization occurs for mouse and gamepad devices through `sc_mouse_aoa_init` and `sc_gamepad_aoa_init`.

### SDL Event Loop and Input Forwarding

The final component is the minimal SDL environment created in [`app/src/usb/screen_otg.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/screen_otg.c). Unlike standard scrcpy which creates a video display window, OTG mode initializes only `SDL_INIT_EVENTS` and creates a small control window without video rendering.

The `sc_screen_otg_handle_event` function captures all SDL input events and dispatches them to the appropriate AOA processor:

```c
/* From app/src/usb/screen_otg.c lines 62-84 */
static void sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event) {
    switch (event->type) {
        case SDL_KEYDOWN:
        case SDL_KEYUP:
            if (screen->keyboard) {
                sc_keyboard_aoa_process_key(screen->keyboard, &event->key);
            }
            break;
        case SDL_MOUSEMOTION:
        case SDL_MOUSEBUTTONDOWN:
        case SDL_MOUSEBUTTONUP:
            if (screen->mouse) {
                sc_mouse_aoa_process_mouse(screen->mouse, &event);
            }
            break;
        // ... gamepad handling
    }
}

```

When keyboard events occur, `sc_keyboard_aoa_process_key` (defined in [`app/src/usb/keyboard_aoa.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/keyboard_aoa.c)) translates SDL keycodes into HID reports and sends them via `sc_aoa_push_input_with_ack_to_wait`:

```c
/* From app/src/usb/keyboard_aoa.c */
static void sc_key_processor_process_key(struct sc_key_processor *kp,
                                          const struct sc_key_event *event,
                                          uint64_t ack_to_wait) {
    if (event->repeat) return;  // HID repeats handled by Android

    struct sc_keyboard_aoa *kb = container_of(kp, struct sc_keyboard_aoa, key_processor);
    struct sc_hid_input hid_input;

    if (sc_hid_keyboard_generate_input_from_key(&kb->hid, &hid_input, event)) {
        sc_aoa_push_input_with_ack_to_wait(kb->aoa, &hid_input, ack_to_wait);
    }
}

```

## Why OTG Mode Does Not Require USB Debugging

Standard scrcpy operation relies on the Android Debug Bridge (ADB) protocol, which requires the "USB debugging" developer option to be enabled on the target device. ADB runs as a daemon on the device and communicates over a specific USB interface.

OTG mode bypasses ADB entirely by utilizing the **Android Open Accessory (AOA) protocol**. When a device supports AOA (Android 4.1+), it can recognize connected USB hosts as accessories and communicate with them through standard USB endpoints. Since AOA operates at the USB accessory level rather than the Android debug level, it does not require the USB debugging option to be enabled.

The input injection occurs at the system level through HID reports, which Android processes exactly as it would physical keyboard or mouse events from a real USB peripheral.

## Running scrcpy in OTG Mode

To activate OTG mode, use the `--otg` flag. This creates a minimal control window without video or audio streaming.

```bash

# Basic OTG mode (keyboard + mouse)

scrcpy --otg

# Specify device by serial when multiple devices are connected

scrcpy --otg -s 0123456789abcdef

# Disable keyboard input (mouse only)

scrcpy --otg --keyboard=disabled

# Disable mouse input (keyboard only)

scrcpy --otg --mouse=disabled

# Enable gamepad support via AOA

scrcpy --otg --gamepad=aoa

# Or use the short form:

scrcpy -G --otg

```

The OTG window remains small and minimal since it only serves to capture host input events. All processing occurs through the AOA HID interfaces registered during initialization.

## Key Source Files and Implementation Details

The OTG functionality is implemented across several specialized files in the `app/src/usb/` directory:

- **[`app/src/usb/scrcpy_otg.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/scrcpy_otg.c)** – Orchestrates the entire OTG workflow, including USB device selection (`sc_usb_select_device`), AOA initialization (`sc_aoa_init`), and HID device setup.

- **[`app/src/usb/screen_otg.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/screen_otg.c)** – Creates the minimal SDL window and handles the event loop (`sc_screen_otg_handle_event`) that captures keyboard, mouse, and gamepad events.

- **[`app/src/usb/keyboard_aoa.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/keyboard_aoa.c)** – Implements the HID keyboard interface over AOA, including initialization (`sc_keyboard_aoa_init`) and key event processing (`sc_key_processor_process_key`).

- **[`app/src/usb/mouse_aoa.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/mouse_aoa.c)** – Provides the HID mouse interface through AOA protocol functions.

- **[`app/src/usb/gamepad_aoa.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/gamepad_aoa.c)** – Handles optional gamepad support via AOA HID reports.

- **[`doc/otg.md`](https://github.com/Genymobile/scrcpy/blob/main/doc/otg.md)** – Official documentation covering user-facing OTG mode options and usage examples.

These components collectively enable scrcpy to function as a USB HID accessory controller, completely bypassing the ADB infrastructure required for standard screen mirroring.

## Summary

- **OTG mode** allows scrcpy to control Android devices via keyboard, mouse, and gamepad without enabling USB debugging or using ADB.
- The implementation uses the **Android Open Accessory (AOA) protocol** to register HID devices directly over USB.
- Input events are captured through a minimal SDL window and translated into **HID reports** that Android processes as physical peripheral input.
- Key source files include [`app/src/usb/scrcpy_otg.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/scrcpy_otg.c) for orchestration and [`app/src/usb/keyboard_aoa.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/usb/keyboard_aoa.c) for HID input processing.
- Activate OTG mode with the `--otg` flag, optionally combining with `--keyboard`, `--mouse`, or `--gamepad=aoa` flags.

## Frequently Asked Questions

### Does OTG mode work on all Android devices?

OTG mode requires Android 4.1 (API level 16) or higher with support for the Android Open Accessory (AOA) protocol. Most modern devices support AOA, but some manufacturers may disable or limit accessory mode in their USB stack. If the device does not enter accessory mode when connected, scrcpy will fail to initialize the AOA connection.

### Can I see the device screen while using OTG mode?

No. OTG mode intentionally does not stream video or audio. It creates only a minimal SDL window to capture input events from your host machine. To view the device screen simultaneously, you would need to use standard scrcpy with USB debugging enabled, or use a separate physical display for the Android device.

### What input devices are supported in OTG mode?

OTG mode supports **keyboard**, **mouse**, and **gamepad** input. Keyboard and mouse are enabled by default when using `--otg`. Gamepad support must be explicitly enabled with `--gamepad=aoa` or `-G`. Each input type registers as a separate HID interface over the AOA protocol, allowing Android to treat them as standard USB peripherals.

### Is OTG mode secure for locked-down or production devices?

Yes. Because OTG mode uses the AOA protocol rather than ADB, it does not require the "USB debugging" developer option to be enabled. This makes it suitable for controlling production devices, kiosks, or enterprise hardware where enabling developer options violates security policies. However, physical USB access to the device is still required, and the device must support AOA protocol connections.