I've released libaoahid, a library that lets a PC send keyboard, mouse, gamepad, and multi-touch input to an Android device over a USB cable. It's implemented in C++20 but exposes a stable C ABI, so it can be used from C, C++, or any language that can call C. It's MIT-licensed.
It started when I wanted to build something to automate Android. While looking for a way to do it I came across AOA's HID feature, but implementing it ran into bug after bug. So I set out to build a library that takes care of the complicated parts while keeping full flexibility and as little latency as possible.
The device needs no root and no app. To Android it looks like a USB keyboard or touchscreen has been plugged in, so the input is handled like any ordinary device's. It runs on Windows and Linux, and can also be used from Python, C#, and Rust.
Demo
This is aoahid_player, an app built with the library. It plays back a CSV script, then changes the volume and the track from the PC.
Compared with other approaches
The usual ways to drive Android from a PC are adb shell input and accessibility services. The first needs USB debugging and injects input in software; the second needs an app installed on the device and granted permissions.
With the HID feature of AOA 2.0, which libaoahid uses, you just plug the device in. No settings, no app.
How it works
Since Android 4.1, Android has had Android Open Accessory (AOA) 2.0. Its HID feature lets a USB-connected PC register a virtual input device on the phone and send input through it.
Building something practical on raw AOA is harder than it looks. The HID descriptor has to be in a shape Android accepts, and multi-touch only works if each finger's state is tracked properly. libaoahid takes care of that.
At the same time, the library never picks values such as resolution or bit width for you; the caller specifies all of them, so you always know exactly what is being sent.
Supported input
| Kind | Covers | Tested on hardware |
|---|---|---|
| Touch | Multi-touch | Yes |
| Keyboard | Every key at once | Yes |
| Mouse | Motion, buttons, wheel | Yes |
| Gamepad | Sticks, buttons, D-pad | Yes |
| Media keys | Volume, play/pause, next track | Yes |
| Pen and others | Pressure, hover, etc. | Not yet |
Tested on a Samsung Galaxy Tab S11 and a POCO F6 Pro, from both Windows 10 and Arch Linux.
Usage
Prebuilt archives are on Releases. To build from source you need CMake 3.20+, a C++20 compiler, and libusb 1.0.30 or later:
git clone https://github.com/nemarpuc/libaoahid
cd libaoahid
cmake -S . -B build -DAOAHID_BUILD_SHARED=ON
cmake --build build --config Release
Moving a mouse looks like this (error handling left out):
/* Find and open the device */
aoahid_discover(ctx, 500, &found);
aoahid_device_open(ctx, aoahid_discovery_get(found, 0), &device_options, &dev);
/* Define a mouse and register it on the device */
mopt.button_count = 3;
mopt.x = (aoahid_integer_field){-127, 127, 8};
mopt.y = (aoahid_integer_field){-127, 127, 8};
aoahid_spec_create_mouse(&mopt, &spec);
aoahid_node_open(dev, spec, &node_options, &mouse);
/* Send input */
aoahid_mouse_move(mouse, 10, -5);
aoahid_node_submit_blocking(mouse, 500);
Complete, runnable code and small programs for checking behavior on a real device are in examples. Setup steps are in the QUICKSTART.
A bridge for using adb at the same time
On Windows, only one process can open a USB device. So even with the driver on WinUSB or libusbK, AOA input and adb normally couldn't be used together.
That's why I made aoahid_adb_proxy. It relays adb traffic over the app's own USB connection to a local port, so while input is being sent you can still use adb and scrcpy with adb connect 127.0.0.1:6555.
Samsung on Windows
When a Samsung device is connected to Windows, Samsung's own USB driver gets installed. With it, input works but the adb bridge doesn't.
Replacing the driver for the whole device with WinUSB using Zadig fixes it. Regular adb keeps working on WinUSB, but tools that need the manufacturer's driver, such as Samsung Smart Switch, may stop working. The detailed steps are in aoahid_player's README.
aoahid_player
The app in the demo. It plays back actions written in CSV and can record real actions into CSV. It also supports looping, speed changes, live control with the PC's mouse and keyboard, and playback to several devices at once.
@screen 1080x2400
t,0,1,500,500,16
t,0,0,500,500,16
This script taps the screen at (500, 500). Prebuilt downloads for Windows and Linux are on Releases.
What's next
Some input types, such as pen, haven't been tested on hardware yet. AOA is an Android feature, so iOS isn't supported.
I'd like to hear what you would use it for, and whether you've hit similar driver problems with other manufacturers on Windows. Let me know in the comments. Bug reports and feature requests are welcome as GitHub issues.
- libaoahid: https://github.com/nemarpuc/libaoahid
- aoahid_adb_proxy: https://github.com/nemarpuc/aoahid_adb_proxy
- aoahid_player: https://github.com/nemarpuc/aoahid_player
This article was written with the help of AI. Much of the code in these projects was also written with an AI coding assistant; the design, hardware testing, and review were done by me.
Top comments (0)