Controller Test Guide
A reference for the DeskTest.net Controller Test. Covers how it reads buttons, triggers, D-pad, and analog sticks through the browser Gamepad API, how to read the verdict, and what to do about stick drift, stuck buttons, missing rumble, and a controller the browser will not detect.
What does the Controller Test check?
The tool drives the browser's Gamepad API. It listens for the gamepadconnected event and polls navigator.getGamepads() in a requestAnimationFrame loop, reading each button's pressed state and analog value and each axis's position live. No plugin, no extension, no upload. It works best in Chromium browsers (Chrome, Edge) and also runs in Firefox and Safari. The test runs in two steps:
- Controller is detected. Feature-detects the Gamepad API, then waits for your controller. A browser keeps a gamepad hidden until it delivers its first input, so you press a button to wake it. Once seen, the tool reports the controller
idstring, whether the browser recognized a standard mapping, and the button and axis counts. - Every control registers and no stick drifts. A live view lists every button with a fill bar (analog triggers show their 0.00-1.00 value), draws each analog stick as a 2D pad with a moving dot, and lists every raw axis. Press each control and watch it light green. Then release the sticks: any axis still past the dead zone turns red, which is drift. An optional rumble test fires the controller's vibration motors.
A summary verdict at the top names the most likely cause and a recommended next step.
When should I run this?
- Suspected stick drift. The character walks or the camera pans on its own. Release the sticks and watch the pads: a dot that will not return to center is drift.
- A dead or mushy button or trigger. Confirm every face button, bumper, trigger, and D-pad direction still registers, and see the analog trigger travel as a number.
- A new or secondhand controller. Verify all controls and rumble before you rely on it or before a return window closes.
- Is it the controller or the game? If a control works here but not in one game, the game's bindings or an in-app remapper is the culprit, not the hardware.
- After pairing over Bluetooth. Confirm the pad actually reaches the browser and that rumble and both sticks come through in that connection mode.
- Cloud gaming or browser games. Check the controller is visible to the browser at all before blaming a web game for ignoring it.
Reading the results
In the input step each button lights green while held; the fill bar tracks its value so analog triggers show partial travel. Each stick is a square pad with a crosshair, a dashed dead-zone ring, and a dot that follows the stick. Push a stick fully and the dot reaches the edge, confirming full range. The raw axes list shows every axis value between -1.00 and 1.00 with a center-anchored bar.
Each step row carries a status badge: Pending (gray), Running (yellow), Pass (green), Partial (yellow), or Fail (red). A partial means what you tested worked but coverage was incomplete - for example you did not press many buttons, or never swept a stick to its edge. That is not a fault, just an incomplete run. On fail or partial the row expands with the diagnosis and a numbered checklist.
The verdict is a pass only when the controller was detected, you exercised a healthy share of the controls, both sticks moved, and no stick drifts and no button is held at the finish. It is a fail for stick drift or a stuck button. If you reported that rumble did not buzz, a pass notes that so it is not lost.
Copy Diagnostic Report copies a plain-text report: controller id, mapping, button and axis counts, which buttons were exercised, each stick's maximum excursion, any drifting axes with their resting value, any button held at the finish, the rumble result, and the diagnosis from each step. Paste it into a ticket or a return request.
Understanding stick drift
An analog stick reports its position as two axes, each from -1.00 to 1.00, with 0.00 meaning centered. In practice a healthy stick rests at a tiny non-zero value - a few hundredths - which is why controllers and games apply a dead zone: readings inside a small radius around center are treated as zero. Drift is when the resting value grows past that dead zone, so the system reads constant motion even though you are not touching the stick.
This tool uses a dead zone of 0.12 for the live display and flags an axis as drift when it rests past 0.15. That is why the instruction says to let go of both sticks before you click Done: the tool samples the axis values at that moment, and if you are still nudging a stick it will look like drift. Release everything, wait a beat, then finish.
Common failures and fixes
The tool produces a named diagnosis for every failure path. Each maps to a fix. In step order:
gamepad-api-unsupported: the Gamepad API is missing
The browser does not expose navigator.getGamepads. Every current desktop browser supports it, so this means a very old browser or a restricted context.
- Update the browser. The Gamepad API shipped in Chrome 21, Edge, Firefox 29, and Safari 10.1.
- If you opened the test inside another app's in-page browser, an Electron shell, or an iframe, open it as its own browser tab. A parent frame can switch off gamepad access with a Permissions-Policy header.
no-gamepad: no controller detected
The test was cancelled before any controller sent input. Usually a connection issue, not a broken pad.
- Power on the controller and pair it (Bluetooth) or plug it in (USB), then rerun and press a button to wake it. The browser cannot see a gamepad until it sends input.
- Bluetooth pads must be paired in the OS first (Windows Settings, macOS Bluetooth, or your Linux manager). Putting the pad in pairing mode alone is not enough.
- Try another USB cable and port. Many cables are charge-only and carry no data, which is a classic reason a wired pad seems dead.
- Confirm the OS sees the device: Windows
joy.cpl(Set up USB game controllers), or a system gamepad tester. If the OS does not see it either, the fault is the driver, the pairing, or the hardware - not the browser.
stick-drift: a stick reads off-center at rest
An axis stayed past the dead zone with the stick released. First rule out that you were touching it; then treat it as hardware.
- Rerun and make sure you fully release both sticks before clicking Done.
- Blow compressed air around the base of the drifting stick and work it through its full range several times. Dust and grit under the module are a common, sometimes fixable cause.
- As a stopgap, raise the dead zone in the game or the controller's companion app (Steam controller settings, Xbox Accessories, DualSense settings). This masks light drift without fixing it.
- Persistent drift means the potentiometer is worn. Replace the stick module (Hall-effect modules resist drift) or replace the controller.
stuck-button: a button read as held at the finish
A button or trigger was still asserted when the test ended.
- If you were holding a button when you clicked Done, rerun and release everything first.
- If nothing was held, the button is physically stuck. Work it a few times and blow out debris with compressed air.
- A trigger resting above zero can be a mis-calibrated analog trigger. Recalibrate in the OS (
joy.cplon Windows) or the vendor app. - If it stays stuck, the switch or sensor is failing. Swap controllers to confirm.
no-coverage: nothing registered (partial)
The controller was detected but no button or stick input arrived during the input step.
- Click the page once to focus it, then rerun and press every control. A page that does not have focus can still miss input in some browsers.
- Close any controller remapper or overlay - Steam Input, DS4Windows, or a vendor tool can capture the pad so the browser sees nothing.
- Confirm live input in the OS tester (
joy.cpl). If the OS sees nothing either, the problem is upstream of the browser.
incomplete: coverage incomplete (partial)
The controls you tested worked and no drift was found, but not every button was pressed or a stick was not swept to its edge.
- Rerun and hit every control: all buttons, both triggers, all four D-pad directions, and push each stick fully to its edges.
- If a specific button or direction never lights up no matter how hard you press, that control is dead. Isolate it against the OS tester to confirm it is the hardware.
Rumble did not buzz
Rumble is optional and never fails the test on its own. If the report shows vibration as not supported, the controller or browser does not expose a vibration actuator - common on older pads, in some Bluetooth modes, and in non-Chromium browsers. If you sent a pulse and felt nothing, the motors may be disconnected or the connection mode does not carry rumble; try a wired connection and a Chromium browser to confirm.
For IT and support
Controller behavior sits on three layers: hardware (the pad and its link), OS (driver, pairing, calibration), and per-app (the browser, a remapper, the game). This test sees the browser's view, but the failure pattern points at the layer to fix.
Standard vs. non-standard mapping. When the browser recognizes a controller it reports mapping: "standard" and button and axis indexes follow a fixed Xbox-style order. An unrecognized pad reports an empty mapping and a driver-specific order; it still works, but index 0 is no longer guaranteed to be the bottom face button. The tool labels controls generically in that case and never fails a control just for being in an unexpected slot.
Remappers capture the device. Steam Input, DS4Windows, and vendor software can grab a controller and re-present it, so the raw pad the browser sees may differ from what a game sees, or the browser may see nothing. When a user reports odd bindings or a missing controller, check for these tools first.
Charge-only cables and USB hubs. A cable with no data lines, or an unpowered hub that browns out on rumble, produces an intermittent or undetected controller. Test plugged directly into the machine with a known-good data cable.
Drift as an RMA signal. A resting axis value past the dead zone is objective evidence of stick wear. The copied report captures the axis and its value, which is useful in a warranty or return request.
Behind the scenes
The Gamepad API is deliberately minimal. A controller shows up as a Gamepad object with a buttons array (each with a boolean pressed and an analog value) and an axes array of floats from -1 to 1. navigator.getGamepads() returns fresh, immutable snapshots, so the tool re-reads it every animation frame rather than holding a stale reference.
A gamepad is hidden until it delivers input, both for privacy (it is a fingerprinting vector) and to avoid listing idle devices. That is why step 1 asks you to press a button: the gamepadconnected event and the first non-null getGamepads() entry both arrive only after that first input.
Standard mapping fixes button 0 to the bottom face button, 6 and 7 to the analog triggers, 12-15 to the D-pad, and axes 0-3 to the two sticks. Drift is judged by sampling the axis values at the moment you click Done and flagging any past 0.15; the live dead zone is 0.12.
Rumble uses gamepad.vibrationActuator.playEffect('dual-rumble', ...) where available (Chromium), falling back to the older hapticActuators[0].pulse(). Where neither exists the test reports rumble as unsupported rather than failing. Because the browser cannot know whether the motors actually moved, the tool asks you to confirm whether you felt it.
The polling loop, the connect and disconnect listeners, and any pending vibration are all torn down when the test finishes or is reset, so no animation-frame loop is left running in the background. Nothing leaves the browser tab: no controller id, no input trace, no telemetry. Open DevTools, Network tab, and confirm there are no outbound requests while the test runs.
Related
- Controller Test - the diagnostic itself
- Keyboard Test Guide - test a keyboard's keys and rollover
- Mouse Test Guide - buttons, scroll, and pointer movement
- USB Test Guide - inspect the port and cable feeding a wired controller or dongle
- DeskTest.net home
- About DeskTest.net