- C++ 97.3%
- Makefile 2.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .github/workflows | ||
| examples | ||
| include | ||
| tests | ||
| .gitignore | ||
| CONTROLLER-DATA.md | ||
| FEATURES.md | ||
| FOLLOW-UP.md | ||
| HANDOFF.md | ||
| INVESTIGATION.md | ||
| KEYBOARD-MOUSE.md | ||
| LIBRARIES.md | ||
| LICENSE | ||
| Makefile | ||
| NOTICE.md | ||
| PLAN.md | ||
| PRODUCTION-INTEGRATION.md | ||
| README.md | ||
| STATIC-EVIDENCE.md | ||
| USAGE.md | ||
| VALIDATION.md | ||
PS5 Native Gamepad, Keyboard and Mouse Input Research
Independently documented guidance for native, low-latency PlayStation 5 input. The repository covers gamepad, USB keyboard, and USB mouse lifecycle and batching; every verified DualSense field; motion, touch, feedback, and adaptive triggers; and the responsibilities of the underlying PS5 libraries.
The normal application path is deliberately small: use libSceUserService to
resolve the signed-in player, then libScePad, libSceKeyboard, or
libSceMouse for the selected device. No SDL input subsystem, raw HID report
parser, controller pairing code, or privileged device-control interface is
required.
Project status
| Area | Status |
|---|---|
| Signed-in user and pad lifecycle | Device-tested |
| Digital buttons | Device-tested in working applications |
| Left and right sticks | Device-tested in working applications |
| Analog L2 and R2 | Device-tested in working applications |
| Batched low-latency reads | Device-tested in UI and streaming applications |
| Current-state polling | Device-tested at approximately 243–250 Hz |
| Sample timestamp and connection generation | Contract-tested and behavior corroborated |
| Two-contact touch data | Contract-tested; dedicated physical test pending |
| Orientation, acceleration, and angular velocity | Contract-tested; dedicated physical test pending |
| Controller information and reported dead zones | Contract-tested and behavior corroborated |
| Vibration and light bar | Contract-tested; repository device test pending |
| Adaptive trigger effects and state | Contract-tested; repository device test pending |
| Specialized device classes | Partial compatibility evidence only |
| Native keyboard queue and 96-byte record | Device-tested with timestamped HID key transitions |
| Native mouse queue and 40-byte record | Device-tested with motion, clicks, wheel, and tilt |
| Keyboard/mouse hot-plug | Device-tested with retained handles across receiver removal and reconnection |
| CI | Builds strict C++20 examples and runs host-side contract checks |
Platform interfaces can change. Re-run the layout checks and device tests before assuming compatibility with another system-software version.
Main findings
| Finding | Result |
|---|---|
| Recommended libraries | libSceUserService plus libScePad, libSceKeyboard, or libSceMouse |
| Lowest-risk low-latency API | scePadRead(handle, samples, 64) |
| Driver interaction | One platform-driver request per batch read |
| Returned order | Oldest retained sample first; newest sample last |
| Maximum normal batch | 64 records, 7,680 bytes total |
| Normal record size | 120 bytes |
| Current-state API | scePadReadState, with cached-state fallback |
| Short button transitions | Preserved by processing every batched record |
| Observed production batch | Up to 7 records despite a 4 ms application poll |
| USB versus Bluetooth | Hidden behind the same Pad API |
libSceHidControl |
Specialized Jedi/Spark service controls, not the normal gamepad queue |
libSceBluetoothHid |
Raw Bluetooth transport, not a faster application input path |
| Keyboard path | sceKeyboardRead(handle, samples, 16) with USB HID usages |
| Mouse path | sceMouseRead(handle, samples, 64) with relative axes and wheels |
| Keyboard/mouse loading | Load native sysmodule IDs 0x0106 and 0x00a9 before initialization |
| Physical index discovery | Open every accepted index and retain successful handles for hot-plug and multiple devices |
| Empty/inactive reads | Process exactly the returned count; a neutral record may be returned for an inactive index |
| Hot-plug behavior | Existing handles reported removal and resumed input after reconnection; no reopen was needed |
Recommended input path
Signed-in application user
-> scePadInit
-> scePadOpen(user, standard port, index 0)
-> scePadRead(handle, records, 64)
-> neutralize disconnected or system-intercepted records
-> process every button and touch transition oldest-first
-> publish the final record as current analog and motion state
-> simulation or UI update
-> render
Call the read immediately before the application consumes input. Reading after
simulation adds an avoidable application frame of latency. Do not surround the
batch read with scePadReadState calls on the same handle; both enter the same
globally locked read core.
Capability matrix
| Capability | Native representation | Notes |
|---|---|---|
| Create, Options, D-pad, face buttons | ScePadData.buttons |
Verified button mask |
| L1/R1, L2/R2, L3/R3 | Digital mask | L2/R2 also provide analog travel |
| Touch-pad click | Digital mask bit 0x00100000 |
Separate from touch contacts |
| System interception | Mask bit 0x80000000 |
Discard the sample and publish neutral state |
| Left/right sticks | Four unsigned bytes | Range 0–255, center 128 |
| Analog triggers | Two unsigned bytes | Range 0–255 |
| Touch pad | Up to two contacts | X/Y, stable contact ID, controller-specific resolution |
| Motion | Quaternion + acceleration + angular velocity | Timestamp every sample |
| Connection | 32-bit state + generation byte | Clear cached edges/calibration when generation changes |
| Vibration | Two unsigned levels | Low- and high-frequency components |
| Light bar | RGB parameter | Reset restores platform behavior |
| Adaptive triggers | Off, feedback, weapon, vibration | Separate L2/R2 commands and state values |
| PS button | System-owned | Not exposed as a normal application button |
| Mute button and controller audio | Separate services | Not verified in the normal 120-byte Pad record |
See Controller data format for the exact offsets, button values, coordinate handling, timestamps, and connection rules.
Physical keyboards and mice use separate native queues. See Native keyboard and mouse input for their exact layouts, batch limits, lifecycle, idle semantics, and C++20 examples.
Quick start
The examples are portable C++20 contract snippets. Host checks require no vendor SDK, firmware files, proprietary headers, or console toolchain.
git clone git@github.com:blackbearreloaded/ps5-native-gamepad-input-research.git
cd ps5-native-gamepad-input-research
make check
make check verifies all documented gamepad, keyboard, and mouse structure
sizes and offsets; exercises edge and neutral-state behavior; checks axis
conversion and mouse no-record semantics; and compiles every portable example
with strict C++20 warnings.
For a native PS5 application, import libSceUserService and libScePad, then
use the declarations in include/ps5_pad.hpp:
#include "ps5_pad.hpp"
#include <array>
#include <cstddef>
#include <cstdint>
#include <span>
std::int32_t user_id{};
sceUserServiceInitialize(nullptr);
sceUserServiceGetInitialUser(&user_id);
scePadInit();
const auto handle =
scePadOpen(user_id, ps5::pad::kPortTypeStandard, 0, nullptr);
std::array<ps5::pad::Data, ps5::pad::kMaxSamples> samples{};
const auto count = scePadRead(
handle, samples.data(), static_cast<std::int32_t>(samples.size()));
if (count < 0)
handle_error(count);
for (const auto& sample :
std::span{samples}.first(static_cast<std::size_t>(count)))
process_sample(sample);
Production code must check every return value, neutralize disconnected or intercepted records, stop active output effects, and close the handle during shutdown. Usage and lifecycle provides the complete sequence.
Implementation guidance
- Open a standard pad for the real signed-in user, not the system user.
- Use
scePadRead(..., 64)when press/release fidelity matters. - Process every returned record in order and retain the final record as the current analog, touch, and motion state.
- Treat disconnection and system interception as a neutral controller; raw zero-filled stick fields are not neutral because their center is 128.
- Use sample timestamps for ordering and motion integration, not render time.
- Read once near input consumption and keep one owner per pad handle.
- Use
libScePadfeedback calls instead of constructing raw Bluetooth output reports. - Validate touch, motion, vibration, lighting, and trigger effects on the target controller and firmware before advertising those features.
Documentation
| Document | Purpose |
|---|---|
| Usage and lifecycle | Imports, signed-in user, open/read/close, polling models, multi-user handling, and errors |
| Controller data format | Exact 120-byte layout, buttons, axes, touch, motion, timing, and connection state |
| Controller features | Information, dead zones, motion configuration, vibration, light bar, and adaptive triggers |
| Native keyboard and mouse input | Keyboard/mouse lifecycle, exact records, batching, HID usages, relative axes, and idle rules |
| Library responsibilities | UserService, Pad, Keyboard, and Mouse versus lower-level HID services |
| Low-latency investigation | Queue behavior, driver path, API comparison, and recommended architecture |
| Static compatibility evidence | Functional read behavior, independently documented layouts, and library conclusions |
| Validation | Working applications, aggregate device evidence, publication boundary, and acceptance matrix |
| Production integration | Batched streaming telemetry, protocol lifecycle, local chords, mouse mode, and latency diagnosis |
| Follow-up experiments | Remaining latency measurements and optional ABI investigations |
| Examples | Feature-focused native C++20 examples |
Examples
| Example | Demonstrates |
|---|---|
01-lifecycle.cpp |
Signed-in user, ownership-aware initialization, RAII open, and shutdown |
02-current-state.cpp |
Cached latest-state polling and correct neutral synthesis |
03-low-latency-batch.cpp |
64-record drain with chronological press/release edges |
04-full-joystick.cpp |
Both sticks, analog triggers, complete button mask, and signed axes |
05-motion-touch.cpp |
Motion configuration and two-contact extraction |
06-feedback.cpp |
Vibration, light bar, adaptive-trigger feedback, and safe reset |
07-controller-info.cpp |
Connection, device class, dead zones, and touch resolution |
08-keyboard-batch.cpp |
Sixteen-record keyboard drain and chronological HID-usage edges |
09-mouse-batch.cpp |
Sixty-four-record relative mouse drain and correct no-record/neutral handling |
native-keyboard-mouse-poc |
Deployable source overlay for attached-device capture evidence |
The validation guide also summarizes two complete integrations: a native controller-forwarding path and an SDL-free UI adapter. Both were physically exercised with a DualSense; private application paths and logs are intentionally not part of this repository.
Repository layout
README.md Research overview and application guidance
USAGE.md Initialization, polling, shutdown, and errors
CONTROLLER-DATA.md Exact input-record contract
KEYBOARD-MOUSE.md Native keyboard and mouse contracts
FEATURES.md Motion, touch, feedback, and controller information
LIBRARIES.md Native library selection and scope
INVESTIGATION.md Low-latency read-path analysis
STATIC-EVIDENCE.md Functional compatibility evidence
VALIDATION.md Device evidence and publication boundary
PRODUCTION-INTEGRATION.md Production batching, multiplexing, and telemetry lessons
FOLLOW-UP.md Remaining optional experiments
include/ps5_*.hpp Independently authored C++20 compatibility declarations
examples/ Small feature-focused C++20 examples
tests/layout_check.cpp ABI size and offset regression
tests/logic_check.cpp Edge, neutral-state, and axis regression
tests/keyboard_mouse_check.cpp Keyboard/mouse queue behavior regression
.github/workflows/examples.yml Host-side CI validation
Methodology
The investigation combined independently authored compatibility declarations, host-side contract tests, functional analysis of the application-facing interfaces, and runtime behavior from working applications using physical devices. Proprietary files, private task data, binary fingerprints, analysis databases, and internal addresses are not published.
Evidence labels are intentionally narrow:
- Device-tested: the path executed successfully on a PS5 or was physically confirmed with a controller.
- Contract-tested: independently authored sizes, offsets, values, or prototypes passed layout and host-side checks.
- Behavior corroborated: functional conclusions agree with application telemetry and compatibility analysis.
- Experimental: a plausible interface exists, but physical behavior, privileges, or some structure fields remain incomplete.
External projects and acknowledgements
| Project | Relevance |
|---|---|
| Ghostcontrol — PS5 USB Controller Patcher | Inspiration and related investigation into third-party USB controller support and virtual DualSense input by StonedModder |
Scope
This repository publishes independently authored documentation and small examples. It does not contain vendor SDK files, firmware or system modules, retail binaries, decrypted content, signing material, credentials, cryptographic keys, analysis databases, controller firmware, copied vendor source, or proprietary headers. It does not provide an exploit or access-control bypass, pair devices, update device firmware, or replace platform device policy.
The PS button, microphone mute control, speaker/microphone audio, headset routing, raw Bluetooth registration, and privileged system interception are outside the verified normal application-input contract.
See NOTICE.md for the legal-use boundary, third-party rights, and trademark attribution.
License and attribution
Repository-authored documentation and examples are licensed under GPL-3.0. See LICENSE and NOTICE.md.
PlayStation, PS5, and DualSense are trademarks of Sony Interactive Entertainment. This independent project is not affiliated with or endorsed by Sony Interactive Entertainment.
This project was developed with assistance from OpenAI Codex, including some original interface artwork. Project maintainers reviewed and validated the resulting code, tests, documentation, dependencies, and generated assets.