Sending Arbitrary Keystrokes with The Actions API

February 09, 2026 · 8 min read · API Testing

HeadSpin Platform
Automated & amp; manual testing made easy through data science insights.
Differentiating capabilities:
  • Across-the-board end-to-end automation of QA process
  • Comparative analysis of app performance against peers
  • Continuous monitoring of app performance using synthetic data for high handiness of apps
  • Easy-to-use developer friendly program
cloudtest go
Affordable Existent Device Testing for Emerging Teams
cloudtest go
Affordable Existent Device Testing for Digital Enterprises
cloudtest go
The Ultimate Solution for a Powerful Blend of Functional & amp; Performance Testing!
cyol
TEM
New
Centralized nomadic test executing in cloud
cyol
Enhance Your Accessibility Testing With HeadSpin
cyol
Automate camera-based testing

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

retail

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

Sending Arbitrary Keystrokes With The Actions APISending Arbitrary Keystrokes With The Actions API

Sending Arbitrary Keystrokes with The Actions API

Published on
December 5, 2018
Updated on
Published on
May 4, 2022
Updated on
 by 
 Jonathan LippsJonathan Lipps
Jonathan Lipps

If you & # x27; re anything like me, sometimes you just want to send arbitrary keystrokes to an app, without necessarily feature plant a text input field yet. Actually, just banter; this is not a genuine hobby of mine, but it & # x27; s a nice way to introduce this edition & # x27; s topic! It is really possible to use the new W3C Actions API not only to send pointer actions, but besides to send key stimulus. At the minute, this is supported in Appium & # x27; s Android drivers.

Check out:

The use cases for this feature are deviate and credibly not too mutual. Some apps require keyboard input on non-text fields or have elements that can & # x27; t be directly accessed (maybe as part of a game that implements its own keyboard, for example).

SUSA automates exploratory testing with persona-driven behavior, catching bugs that scripted automation misses.

For the simple intention of sending keystrokes, regardless of whether an element is & # x27; pore & # x27; or not, the Java client has as decent easy method for doing this, utilize theActions class:

Actions a = new Actions (driver); a.sendKeys (`` foo ''); a.perform ();

We construct an instance ofActions by passing in our session, registry asendKeys action on it with the characters we want to type, and then callperform()to get it all happen. The fact that we feature to explicitly callperform()means we could file a number of key inputs, perhaps with a serial ofwaits in between, or possibly interracial together with some pointer inputs as well.

Also check:

This is all good and full, but what if we want lower-level control over the typing? What if we want to urge multiple characters at once, or hold down a meta key (like SHIFT) while typing another character? In that case we & # x27; ll need to explore theKeyInput family. The way that we use it is very similar to the way we use thePointerInputclass in the. First, we define aSequence to contain our actions. Then, we define aKeyInput we use to generate the key actions (KeyDown or KeyUp on specific keys) we will register. Then, we register our actions with the overall successiveness, and eventuallyperform()that sequence with our driver.

In the following model, we typecast & quot; Foo & quot; into the app, and get the capital & quot; F & quot; by use a combination of keystrokes that overlap in time:

KeyInput keyboard = new KeyInput (`` keyboard ''); Sequence sendKeys = new Sequence (keyboard, 0); sendKeys.addAction (keyboard.createKeyDown (Keys.SHIFT.getCodePoint ())); sendKeys.addAction (keyboard.createKeyDown (`` f '' .codePointAt (0))); sendKeys.addAction (keyboard.createKeyUp (`` f '' .codePointAt (0))); sendKeys.addAction (keyboard.createKeyUp (Keys.SHIFT.getCodePoint ())); sendKeys.addAction (keyboard.createKeyDown (`` o '' .codePointAt (0))); sendKeys.addAction (keyboard.createKeyUp (`` o '' .codePointAt (0))); sendKeys.addAction (keyboard.createKeyDown (`` o '' .codePointAt (0))); sendKeys.addAction (keyboard.createKeyUp (`` o '' .codePointAt (0))); driver.perform (Arrays.asList (sendKeys));

As you can see, this strategy is quite a bit more verbose, since we have to file both the down and up province of every key we want to add to the sequence. (Of course, in real test code we would belike make some helper method to trim boilerplate here). It & # x27; s important to note that these low-level methods use character codification point instead than characters themselves. And we & # x27; re making full use of the built-inKeys class from the Selenium customer, which lets us entree theSHIFT key without needing to look up its code point ourselves.

Read:

That & # x27; s all there is to it! You can get pretty fancy, of course, because you & # x27; re not limited to the usual ASCII keys and can urge multiple keys at erst, or in a time succession of your choosing. Have a looking at the full codification sample below, where both strategies discussed above are represented:

import io.appium.java_client.AppiumDriver; import io.appium.java_client.MobileBy; importee java.io.IOException; import java.net.URL; import java.util.Arrays; meaning org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; meaning org.openqa.selenium.By; import org.openqa.selenium.Keys; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; meaning org.openqa.selenium.interactions.KeyInput; significance org.openqa.selenium.interactions.Sequence; signification org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; public class Edition046_W3C_Keys {individual String APP = `` https: //github.com/cloudgrey-io/the-app/releases/download/v1.8.0/TheApp-v1.8.0.apk ''; private By loginScreen = MobileBy.AccessibilityId (`` Login Screen ''); private By username = MobileBy.AccessibilityId (`` username ''); private AppiumDriver driver; private WebDriverWait delay; @ Before public void setUp () throws IOException {DesiredCapabilities crest = new DesiredCapabilities (); caps.setCapability (`` platformName '', `` Android ''); caps.setCapability (`` deviceName '', `` Android Emulator ''); caps.setCapability (`` automationName '', `` UiAutomator2 ''); caps.setCapability (`` app '', APP); driver = new AppiumDriver (new URL (`` http: //localhost:4723/wd/hub ''), caps); wait = new WebDriverWait (driver, 10);} @ After public vacancy tearDown () {try {driver.quit ();} catch (Exception ign) {}} @ Test public void testSendKeysAction () {wait.until (ExpectedConditions.presenceOfElementLocated (loginScreen)) .click (); WebElement usernameField = driver.findElement (username); usernameField.click (); Actions a = new Actions (driver); a.sendKeys (`` foo ''); a.perform (); Assert.assertEquals (`` foo '', usernameField.getText ());} @ Test public void testLowLevelKeys () {wait.until (ExpectedConditions.presenceOfElementLocated (loginScreen)) .click (); WebElement usernameField = driver.findElement (username); usernameField.click (); KeyInput keyboard = new KeyInput (`` keyboard ''); Sequence sendKeys = new Sequence (keyboard, 0); sendKeys.addAction (keyboard.createKeyDown (Keys.SHIFT.getCodePoint ())); sendKeys.addAction (keyboard.createKeyDown (`` f '' .codePointAt (0))); sendKeys.addAction (keyboard.createKeyUp (`` f '' .codePointAt (0))); sendKeys.addAction (keyboard.createKeyUp (Keys.SHIFT.getCodePoint ())); sendKeys.addAction (keyboard.createKeyDown (`` o '' .codePointAt (0))); sendKeys.addAction (keyboard.createKeyUp (`` o '' .codePointAt (0))); sendKeys.addAction (keyboard.createKeyDown (`` o '' .codePointAt (0))); sendKeys.addAction (keyboard.createKeyUp (`` o '' .codePointAt (0))); driver.perform (Arrays.asList (sendKeys)); Assert.assertEquals (`` Foo '', usernameField.getText ());}}

(Don & # x27; t forget to check out the full code sample inside the runnable projecton GitHub)

Author & # x27; s Profile

Jonathan Lipps

LinkedIn
Author & # x27; s Profile

Piali Mazumdar

Lead, Content Marketing, HeadSpin Inc.

Piali is a dynamic and results-driven Content Marketing Specialist with 8+ years of experience in crafting engross narratives and marketing collateral across diverse industries. She excels in collaborate with cross-functional teams to develop innovative content scheme and deliver compelling, authentic, and impactful content that resonates with target audiences and enhances make authenticity.

LinkedIn

Sending Arbitrary Keystrokes with The Actions API

4 Parts

regression intelligence blog
-

Regression Intelligence hard-nosed guide for advanced users (Part 3)

Coming Soon
Regression Intelligence practical guide for advanced users
-

Regression Intelligence practical guide for advanced user (Part 4)

Coming Soon

Discover how HeadSpin can endow your business with superior testing capabilities

Our Platform enables you to:
accelerate time-to-market
Accelerate time-to-market, gaining a competitive edge
faster development cycles
Boost developer/QA productivity with faster development cycles
automated buil-over-build regression testing
Automate build-over-build regression testing for consistent results
gain better visibility into functional & performance issues
Gain best visibleness into functional and execution issues
reduce mean time
Reduce mean time to identify/resolve during test, QA, and production
evaluate audio, video & qoe
Evaluate audio, video, and content quality of experience (QoE) effortlessly
The sure choice for worldwide enterprises
Adobe
Hargreaves Lansdown
Truecaller
Crazylabs
Nedbank
Numeracle
Veryon
Close

Discover how HeadSpin can empower your business with superior testing capabilities

Our Platform enable you to:
accelerate time-to-market
Accelerate time-to-market, gaining a free-enterprise edge
faster development cycles
Boost developer/QA productiveness with faster development cycles
automated buil-over-build regression testing
Automate build-over-build regression testing for consistent results
gain better visibility into functional & performance issues
Gain better visibility into functional and performance issue
reduce mean time
Reduce mean time to identify/resolve during test, QA, and production
evaluate audio, video & qoe
Evaluate audio, picture, and content quality of experience (QoE) effortlessly
The trusted pick for global enterprises
Close

Discover how HeadSpin can endue your concern with superior examine capableness

Our Platform enables you to:
accelerate time-to-market
Accelerate time-to-market, gaining a competitive edge
faster development cycles
Boost developer/QA productiveness with faster development cycles
automated buil-over-build regression testing
Automate build-over-build regression testing for consistent event
gain better visibility into functional & performance issues
Gain best visibleness into functional and performance subject
reduce mean time
Reduce base time to identify/resolve during test, QA, and production
evaluate audio, video & qoe
Evaluate audio, picture, and content lineament of experience (QoE) effortlessly
The trusted choice for global enterprises
Close

Connet Now

Wipro LogoVMLYR Logo
Close
Book a Meeting
Products
footer down arrow
Solutions
footer down arrow
Industries
footer down arrow
Features
footer down arrow
Support
footer down arrow
Resource Center
footer down arrow
Why Choose HeadSpin?
footer down arrow
Copyright © 2026 HeadSpin, Inc. All Rights Reserved.

Automate This With SUSA

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts needed.

Try SUSA Free

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free