adb shell input: tap, swipe, type text and send keyevents
Most people reach for adb shell input the first time they need to poke an Android app from a script instead of a finger. Maybe you’re smoke-testing a build after every CI run, maybe you’re driving a kiosk device that has no keyboard attached, or maybe you just want to automate a repetitive tap sequence you’re tired of doing by hand. Whatever the reason, input is the fastest way in, because it’s already sitting on every Android device as part of the platform, no extra app or server required.
This is for developers and QA people who are comfortable with a terminal and already have adb talking to a device. I’m not going to cover installing Android Studio or setting up an emulator from scratch, just what happens after you’ve got a shell open. If you haven’t paired your machine with the device yet, sort that out first with adb authorization and RSA keys explained, since none of the commands below work until the device trusts your computer.
By the end you’ll be able to tap coordinates, swipe between two points, type text into a focused field (including the space-escaping gotcha that trips up almost everyone the first time), and send keyevents like back, home, and enter. I’ll also be straight about where this approach falls apart, because it does, well before you’re running hundreds of devices.
what you need
- a computer with the Android SDK platform-tools installed, so you have the
adbbinary on your PATH - an Android device or emulator with USB debugging enabled, already authorized against your machine
- a USB cable, or a working adb over Wi-Fi connection if you’d rather skip the cable
- the app you want to drive already installed and, ideally, already open in the foreground
- no paid tooling required for anything in this article; platform-tools is free and comes straight from Google
step by step
1. confirm adb sees the device
adb devices
Expected output looks like this, one line per attached device:
List of devices attached
R58N8038ABC device
If it breaks: unauthorized means the RSA prompt on the device wasn’t accepted, go back to the authorization article above. offline usually clears with adb kill-server followed by adb start-server. If nothing shows up at all, check the cable (some USB-C cables are charge-only) or that USB debugging is actually toggled on in developer options.
2. get the screen resolution and density
adb shell wm size
adb shell wm density
Typical output:
Physical size: 1080x2340
Physical density: 420
Every coordinate you send in the next steps is in raw physical pixels, matching the numbers from wm size, not dp. That distinction matters the moment you reuse a script on a different phone. Google’s own screen density documentation explains why the same UI element sits at wildly different pixel coordinates across devices with different densities, and it’s the reason hardcoded taps are the single biggest source of flaky scripts.
If it breaks: on a locked-down OEM skin, wm size occasionally returns nothing useful. Fall back to adb shell screencap /sdcard/screen.png and eyeball the resolution from the file.
3. tap a coordinate
adb shell input tap 540 1600
This injects a single tap at x=540, y=1600 in physical pixels on the current display. If the app is in the foreground and there’s a tappable element under that point, it reacts exactly like a finger would.
If it breaks: nothing happens because the screen is asleep, so wake it first with adb shell input keyevent 224 (KEYCODE_WAKEUP), then unlock if needed. Or nothing happens because the target app isn’t actually in front, in which case launch it explicitly first with the commands covered in adb pm and am commands to manage apps.
4. swipe between two points
adb shell input swipe 540 2000 540 800 300
The five arguments are x1, y1, x2, y2, and an optional duration in milliseconds. Leave the duration off and the AOSP input tool defaults to a fast flick; the actual source for this behavior lives in the Input.java command source if you want to see exactly how it interpolates the motion between the two points.
If it breaks: too short a duration reads as a fling and overshoots your intended scroll distance. Too long a duration crosses the long-press threshold and the OS treats it as a drag instead of a swipe. 250 to 400ms is a reasonable starting range for a normal scroll gesture; tune from there.
5. type text into a focused field
adb shell input text hello%sworld
input text sends characters through whatever input method is currently active, so it only works if a text field already has focus, tap it first if it doesn’t. The awkward part is spaces: the shell you’re typing in, plus the shell adb spawns on the device, both try to interpret a literal space as an argument separator. Wrapping the string in quotes on your local machine sometimes survives the trip and sometimes doesn’t, depending on your OS and adb version, so the reliable fix is to replace every space with %s, which the input tool decodes back into a space on the device side. Avoid &, |, <, >, and unescaped quotes in the text you’re sending, they can get interpreted by the intermediate shell rather than typed literally. Don’t expect emoji or most non-ASCII characters to come through cleanly either, this path goes through the same synthetic input pipeline as a hardware keyboard, not a full IME.
If it breaks: characters silently vanish because the field never actually got focus, verify with a screenshot before assuming the command failed. If special characters mangle the string, quote more aggressively or switch to %s for every space rather than mixing quoting styles.
6. send a keyevent
adb shell input keyevent KEYCODE_BACK
adb shell input keyevent 4
Both lines above do the same thing, since keycodes can be sent by name or by their integer value. Some that come up constantly: KEYCODE_HOME (3), KEYCODE_BACK (4), KEYCODE_ENTER (66), KEYCODE_DEL (67, backspace), KEYCODE_APP_SWITCH (187), KEYCODE_VOLUME_UP (24), KEYCODE_VOLUME_DOWN (25). The full, canonical list lives in the KeyEvent reference on developer.android.com. Newer platform-tools builds also accept a --longpress flag before the keycode to simulate a held key rather than a tap, useful for things like a long-press-to-select gesture.
If it breaks: a misspelled keycode name returns Error: Invalid keycode, switch to the numeric form if you’re not sure of the exact string. If the event fires but the app doesn’t react, check whether a system dialog or the soft keyboard currently has focus instead of your target app.
7. chain it into a script
Once each piece works on its own, a short shell script strings them together. This example opens Settings, waits for it to load, then backs out:
adb shell am start -a android.settings.SETTINGS
sleep 1
adb shell input tap 540 400
sleep 1
adb shell input keyevent KEYCODE_BACK
If it breaks: the most common failure is timing, the script fires the next command before the UI has finished rendering the previous screen. sleep between steps is crude but works; if you need something sturdier than fixed delays, that’s usually the sign you’ve outgrown blind coordinate scripting (more on that below).
8. verify visually before trusting the script
adb exec-out screencap -p > check.png
Use exec-out rather than piping adb shell screencap through a plain redirect, the latter mangles binary PNG data on some shells by translating line endings. If you’d rather watch it happen live instead of grabbing static screenshots, scrcpy mirrors the device screen to your desktop in real time, which is the fastest way to confirm your taps are landing where you think they are.
If it breaks: a corrupted or zero-byte PNG almost always means the redirect method above, not exec-out, was used. Re-run with exec-out.
common pitfalls
- hardcoding coordinates copied from one device and running the same script against a different phone or a rotated screen, where the resolution and density don’t match
- sending taps to a screen that’s asleep or locked, since the OS just swallows the input with no error printed
- assuming
input texthandles emoji, accented characters, or complex punctuation the same way a real keyboard would, it doesn’t - treating
inputas if it has built-in waits or element detection, it has neither, so a script with nosleepcalls races the UI and fails intermittently - running commands against multiple attached devices without the
-s <serial>flag, soadb shell input taplands on whichever device adb happens to pick
scaling this
At around 10 devices, -s <serial> in a loop and a USB hub gets you through most testing. Coordinates still need adjusting per device model, but that’s manageable by hand.
At 100 devices, cabling and hub power become the actual bottleneck before your scripts do, and a single adb server process starts to feel the strain of many simultaneous adb shell input calls. This is usually the point where teams move to adb over Wi-Fi to cut the physical tether, and where the tradeoffs between emulators and real hardware, covered in emulator vs real device testing, start to actually matter for your budget and your bug reports.
At 1000 devices, blind coordinate scripting stops being viable on its own. There’s no retry logic, no “wait until this element exists,” and no way to assert on view state, so a fleet this size needs a framework that reads the actual view hierarchy instead of guessing pixels. That’s the comparison covered in UiAutomator2 vs Appium for Android automation. It’s also the scale where physically racking and cabling your own hardware stops making sense, and renting already-set-up devices does. Worth being precise about what that gets you: cloudf.one rents real Android phones on dedicated hardware in Singapore, each with its own persistent Singapore mobile IP, controlled from the browser, Singapore-only. There’s no self-service adb on it. adb and Appium reach a rented phone only through a WireGuard tunnel that cloudf.one sets up on request by emailing [email protected], so plan for that step before assuming any of the commands in this article will reach a rented phone directly.
where to go next
If you’re still driving one or a handful of devices by hand, the natural next steps are launching and managing the apps you’re tapping through in adb pm and am commands to manage apps, and cutting the USB cable with adb over Wi-Fi wireless debugging. Once coordinate scripts start feeling brittle, read UiAutomator2 vs Appium for Android automation before you invest more time patching around input’s limits. For everything else on the site, the article index is the place to browse.
Written by Xavier Fok
disclosure: this article may contain affiliate links. if you buy through them we may earn a commission at no extra cost to you. verdicts are independent of payouts. last reviewed by Xavier Fok on 2026-09-14.