Free tools Windows power users keep installed
One-click scans. No signup required.
Most Firefox failures with browser.keys() are caused by sending the right key to the wrong target. First use WebdriverIO’s current Key constants, then verify that the intended element is focused and keyboard-interactable. Only after those checks should you investigate Firefox, geckodriver, and WebdriverIO versions.
This sequence covers special keys, modifier combinations, text entry, focus and frame problems, overlays, driver configuration, and the legacy moz:webdriverClick capability.
| # | Preview | Product | Price | |
|---|---|---|---|---|
| 1 |
|
Keyboard Shortcuts Guide Firefox for Windows | $0.99 | Buy on Amazon |
| 2 |
|
Hotkeys Practical Guide for PC Users: from keyboard shortcuts for Windows and programs: Microsoft... | $4.99 | Buy on Amazon |
1. Use the current WebdriverIO key API
Import Key from webdriverio instead of relying on hand-written Unicode escape sequences or browser-specific mappings. The WebdriverIO API reference documents browser-level key input such as Enter, Control combinations, and arrow navigation. See the current Key and browser.keys documentation.
import { Key } from 'webdriverio'
await browser.keys(Key.Enter)
await browser.keys([Key.Ctrl, 'a'])
await browser.keys([Key.ArrowDown, Key.Enter])
Key.Ctrl is cross-platform: WebdriverIO maps it to Command on macOS and Control on Windows and Linux. The browser-level command sends input to whichever element currently has focus. If focus is on the document body, a hidden control, or a different window, the call can appear to do nothing even though the command was delivered.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minute#1 Best Overall
Choose the right input form
| Need | Use | Reason |
|---|---|---|
| Press Enter, Escape, Tab, an arrow, or another special key | browser.keys(Key.Enter) |
Acts on the currently focused element. |
| Send a modifier chord | browser.keys([Key.Ctrl, 'a']) |
Sends the modifier and printable key as one sequence. |
| Replace a known input’s contents | await input.setValue('text') |
Targets that element and replaces its value. |
| Append text to a known input | await input.addValue('text') |
Targets that element and appends to its existing value. |
WebdriverIO documents setValue() and addValue() as higher-level element methods. They are usually more reliable than trying to focus an input indirectly with a browser-wide key command.
2. Send text to a specific element
If the problem is text entry rather than keyboard navigation, locate the control and use an element method. This avoids ambiguity about focus.
const search = await $('#search')
await search.waitForDisplayed()
await search.click()
await search.setValue('Firefox WebDriver')
await browser.keys(Key.Enter)
Use setValue() when existing content must be replaced. Use addValue() when the existing value should remain. Use browser.keys() for actions that intentionally belong to the focused control, such as submitting with Enter or moving through a menu with arrow keys. The related WebDriver commands are described in WebdriverIO’s elementSendKeys documentation.
3. Check Firefox focus and interactability
Firefox’s geckodriver checks whether an element is focusable when it receives keys. A failure can therefore reflect page state, not a broken key mapping. Before changing capabilities, check each item below.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
- Correct window: switch to the window or tab that contains the control.
- Correct frame: switch into the iframe before locating or typing into an element inside it.
- Visible: the element is displayed and not positioned off-screen.
- Enabled: the control is not disabled or read-only when the operation requires editing.
- Focused: click the intended element, or explicitly focus it with a script when appropriate.
- Uncovered: a modal, cookie banner, loading layer, or other overlay is not intercepting input.
- Editable: the selector resolves to an input, textarea, contenteditable region, or another keyboard target rather than a wrapper element.
Make focus observable
const field = await $('input[name="email"]')
await field.waitForDisplayed()
await field.waitForEnabled()
await field.click()
const activeTag = await browser.execute(() => document.activeElement?.tagName)
console.log('active element:', activeTag)
await browser.keys('person@example.com')
If the logged active element is not the expected control, fix the selector, frame, window, or overlay before testing another key constant.
Handle iframes and windows
const frame = await $('iframe[data-testid="checkout"]')
await frame.waitForDisplayed()
await browser.switchToFrame(frame)
const card = await $('input[name="cardnumber"]')
await card.click()
await card.setValue('4242424242424242')
await browser.switchToParentFrame()
For a new tab or popup, obtain its window handle and switch to it before locating the target. A correct selector in the wrong browsing context is still the wrong target.
4. Diagnose the exact failure
Capture the complete exception, the command that failed, and the target state. “Keys do not work” can mean different problems.
| Symptom | Likely cause | Next action |
|---|---|---|
element not interactable |
The target cannot receive keyboard input. | Verify visibility, enabled state, focus, overlays, and element type. |
| No exception, no visible change | Focus is elsewhere or the key has no effect in the current state. | Click the control, inspect document.activeElement, and test a visible text field. |
| Only special keys fail | Incorrect constants or an invalid key sequence. | Use Key.Enter, Key.Ctrl, and other documented constants. |
| Text goes to the wrong field | Browser-level input is using stale or unexpected focus. | Use the element’s setValue() or addValue(). |
| Failure occurs only in one test page | Page JavaScript, an overlay, or a custom widget intercepts input. | Reproduce with a native input and inspect the page state. |
5. Verify Firefox, geckodriver, and WebdriverIO versions
Do not assume Firefox itself is defective until the target and focus checks pass. geckodriver is a separate WebDriver-facing proxy between WebdriverIO and Firefox, and Firefox and geckodriver use different version schemes. Record all three versions in the failing run:
Rank #2
npx wdio --version
firefox --version
geckodriver --version
WebdriverIO supports pinning the geckodriver binary separately with wdio:geckodriverOptions.geckoDriverVersion. Use a compatible browser/driver combination, rerun the smallest reproducible test, and keep the recorded versions with any bug report. The driver relationship and binary configuration are covered in Mozilla’s geckodriver overview and WebdriverIO’s driver-binaries guide.
Example capability configuration
export const config = {
capabilities: [{
browserName: 'firefox',
'wdio:geckodriverOptions': {
geckoDriverVersion: 'YOUR_COMPATIBLE_VERSION'
}
}]
}
Replace the version with one appropriate for your Firefox installation; the documentation does not establish one universal pairing for every environment.
6. Treat moz:webdriverClick as a diagnostic only
Mozilla documents moz:webdriverClick as changing interactability checks for clicks and sending keys. Setting it to false temporarily disables conformant checks, but Mozilla also describes the capability as temporary and subject to removal after stabilization. It is therefore legacy and version-sensitive guidance, not a routine fix.
capabilities: [{
browserName: 'firefox',
'moz:webdriverClick': false
}]
Use this only to determine whether strict interactability checking explains a reproducible case. Prefer fixing focusability, overlays, frames, and selectors. If a native, visible, enabled control still fails with a current compatible setup, reduce the test and report the exact error and versions rather than leaving this capability enabled permanently. See Mozilla’s Firefox capabilities reference.
Recommended Free Tools
7. A minimal Firefox regression test
This test separates key mapping from page-specific behavior by using a native input and an explicit focus step.
import { Key } from 'webdriverio'
describe('Firefox keyboard input', () => {
it('types, selects, and submits', async () => {
await browser.url('https://example.test/form')
const input = await $('#query')
await input.waitForDisplayed()
await input.waitForEnabled()
await input.click()
await input.setValue('first value')
await browser.keys([Key.Ctrl, 'a'])
await browser.keys('second value')
await browser.keys(Key.Enter)
await expect($('#results')).toBeDisplayed()
})
})
If this succeeds while the original test fails, compare the original page’s focus, iframe, overlay, custom widget, and event handlers. If it fails too, preserve the minimal test and version output for driver investigation.
8. Performance and reliability practices
- Wait for the specific control rather than adding arbitrary long sleeps.
- Use one explicit focus action before a browser-level key sequence.
- Prefer element methods for deterministic text replacement.
- Keep keyboard sequences short; split navigation and text entry when a page changes focus.
- After an action that opens a dialog or tab, wait for that context before sending keys.
- Log the selector, window/frame state, active element, and software versions when a failure occurs.
- Run a small Firefox-only reproduction before changing global capabilities.
Or skip the browser setup
If your goal is to obtain a clean screenshot rather than drive interactive keyboard behavior, ScreenshotNeo makes one HTTP request and returns PNG, JPEG, WebP, or PDF. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
See the ScreenshotNeo documentation for authentication and options.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Every plan includes the full feature set, including full-page and lazy-image capture, CSS-selector element shots, dark mode, device presets, retina scale, PDF controls, custom CSS and JavaScript, click and wait actions, request blocking, headers, cookies, user-agent, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed links, async webhooks, bulk capture for up to 100 URLs per call, usage data, and an OpenAPI specification. The Free plan includes 1,000 shots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Quick Recap
9. Final diagnostic order
- Use documented
Keyconstants. - Decide whether the action belongs to the focused element or a specific input.
- Verify window, frame, visibility, enabled state, focus, and overlays.
- Capture the exact exception and active-element information.
- Record WebdriverIO, Firefox, and geckodriver versions.
- Pin a compatible geckodriver and retest a minimal case.
- Use
moz:webdriverClick: falseonly as a temporary diagnostic. - Report a reproducible driver issue if a valid, focusable target still fails.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

