Controller and keyboard¶
Autopilot
The VPK (v5+) embeds an autopilot (menus → game) that automatically switches off on the player's first physical action: touch nothing and it drives all the way into play; touch anything and control is handed back immediately. It stays continuously active for headless testing.
Default controls¶
The mapping below is what controls.txt remaps, and the R + … / L + …
layers and the item assist further down apply to it. Since 0.1.18-beta the
built-in default binds the aim action to L, so the
sticks run in aim mode. This default is a beta, shipped to gather community
feedback. To get the previous scheme back, put l=lclick in controls.txt
(with no other aim binding): see Aim assist.
| Vita input | Diablo II action |
|---|---|
| Left stick | Walk only in game (never attacks or picks anything up); out of a game, the plain stick behaviour |
| Right stick | Free cursor (aiming, menus, panels, HUD), no click by itself |
| Touch screen | Absolute cursor; short tap = left click |
| L (held) | Aim assist in game (acts on the best target); a plain left click in menus, open panels and out of game — remappable, see below (also a combo layer, see below) |
| R (held) | Right click — remappable, see below (also a combo layer, see below) |
| Cross | R — toggle walk/run |
| Circle | Shift (held) — attack in place / forced cast |
| Square (held) | Item assist — show ground items, browse, pick up (square=alt gives plain Alt back) |
| Triangle | W — weapon swap |
| D-pad ↑ / ← / ↓ / → | Belt potions 1 / 2 / 3 / 4 |
| Start | Esc (menu / close) |
| Select | Radial menu — remappable, see below |
Cross alone no longer clicks in menus: L does.
L and R being remappable never changes their second role: R still arms
every R + … combo below, and L its own L + … combo layer, regardless
of what pressing either one alone currently does.
R layer (R held + …) and L layer (L held + …)¶
| Combo | Action |
|---|---|
| R + Triangle | Virtual keyboard (open; close with Select — it also opens by itself on text fields, see below) |
| R + D-pad | F1 / F2 / F3 / F4 — quick skills |
| L + Cross | I — inventory |
| L + Circle | Tab — automap |
| L + Square | O — mercenary inventory |
| R + Select | Space — close all panels (fixed, not remappable) |
| L + Start | Screenshot (fixed, not remappable) |
R + Triangle, R + Select and L + Start always win: they're checked before
any controls.txt remap, so binding those same combos to something else
has no effect (the title-screen controls panel, see below, and
controls.reference.txt both call this out). Every other R + … slot
above starts bound; the mirror L + … layer starts with three bindings
(inventory, automap, mercenary inventory) and every other L + … slot is
free for controls.txt to fill in. Note that L is also the aim button: the
L + … combos fire the aim action too while L is down (as l=lclick clicked
during L combos before).
Item assist¶
On Square by default (square=items; square=alt restores plain Alt).
Bind the items action to any other button if you prefer, and hold it:
- the game shows the ground-item name labels, exactly as with Alt;
- the D-pad jumps the cursor from label to label (the nearest one in the direction pressed), so the highlighted item is the one the game itself reports as hovered;
- L (the aim button) or Cross picks the highlighted item up — with
aimon L, hold Square and press L, no need to reach for Cross. The cursor goes onto the label, and the click is only sent once the game has reported the item as hovered: clicking earlier is read by the game as "walk there"; - with nothing on the ground, the D-pad, Cross and L keep their normal bindings (potions, walk/run, aim), so holding the button never eats a potion;
- the right stick still moves the cursor by hand — landing on a label focuses it; the left stick (direct movement) cancels any pick-up.
alt stays available as a plain Alt for anyone who prefers it. The
buttons items can be bound to are the same as for any action: face
buttons, D-pad, r+/l+ layers, l=, r=, select= (avoid binding it
to Cross or the D-pad themselves, since it takes those over while held).
Validated on the host (logic tests); on a console only through the maintainer's own play so far.
Aim assist¶
On by default, bound to L (l=aim). It costs frame time: the camera and
unit hooks that feed it are installed whenever the bindings carry aim, and
their cost is not benchmarked yet. Bind aim to another button — for example
cross=aim — and hold it. To opt out, put l=lclick in controls.txt
(with no other aim binding): the hooks are then not installed and the
sticks go back to the plain scheme below.
While aim is bound (the default), the sticks run in aim mode, in game:
| Vita input | With aim bound |
|---|---|
| Left stick | Move only: the character walks in the stick's direction (radius follows tilt), never attacking, talking or picking anything up by accident; release = hard stop |
| Right stick | Free cursor, as on PC: it clicks nothing by itself, and it reaches the HUD (belt, skill buttons) |
aim button (held) |
Acts on the best target: your own corpse within reach, else whatever the cursor sits on, else the enemy closest to the axis inside a ±35° cone around the cursor (never one outside it), else the nearest chest / door / portal / NPC (or, outside a town, the nearest enemy), else a level exit, else your own corpse anywhere on screen, else a plain left click at the cursor (held with the button; the right stick keeps aiming) |
Without aim bound (opt-out), the sticks keep the earlier plain behaviour
(left stick = direct movement: the cursor orbits the character with a held
left click; right stick = free mouse, no click) and L is a plain left click.
Out of a game (menus, character select) the plain stick behaviour always
applies, and the aim button is a plain left click there — which is why
L now clicks in the menus.
A diamond marks the current hostile target (gold once the game confirms the
hover). It can be hidden: diamond=off in controls.txt (the aim itself is
unchanged; diamond=on is the default). Assisted aiming only ever borrows the cursor: it moves onto the
target, holds the click once the game reports the hover, and puts the cursor
back where you left it on release — as does the stop click that ends a walk.
The cursor beats everything: whatever it sits on is what aim acts on,
ahead of any cone. Distances are measured in the world, not in screen pixels,
and a unit the game refuses to hover — a critter, a vulture still in the air —
is dropped after a moment instead of capturing every press (up to 32 such
units are remembered, so a pack of critters no longer hides the monster
behind it).
A tap is enough, even at low frame rates. The click waits for the game
to report the hover, which takes about two rendered frames (≈80 ms at 25 fps,
≈400 ms at 5 fps). A tap released before that used to do nothing; it now
keeps waiting for up to 4 frames and clicks once. Holding the button behaves
as before. Separately, every button and the touch screen are read from the
console's whole sample history (60 Hz) rather than once per input tick, so a
short press between two slow frames is no longer lost (see
src/platform/pad_sampler.h).
Open panels (inventory, chest, vendor, NPC menus, Larzuk's add-socket
window…): both sticks move the cursor and aim is a left click. The list of
panels is read from the game's UI flags; the add-socket window (index 0x0E)
was added in 0.1.18-beta and has only had a first console test.
Everything else — potions, skills, Alt, item assist, the radial menu — stays
with the ordinary controls.txt mapping, and the two combine: the item
assist's cyan marker shows the focused ground item whether or not aim is
bound.
Tuning keys (all optional, controls.txt):
orbit_min=40 # px (at 600 lines), walk-ring radius at a light stick push
orbit_max=110 # px, full stick
cone=35 # aim cone half-angle around the cursor, degrees
hover_h=28 # default hover height above a unit's feet, px
diamond=on # off = hide the aim marker (the aim still works)
hud_h=60 # bottom band ASSISTED clicks never enter, px (the cursor
# you drive does go there, or the belt would be unreachable)
reach=300 # how far `aim` reaches for a chest/door/NPC, world units
hostile_reach=800 # how far `aim` reaches for a monster (in or out of the cone), world units
Not carried over from the earlier scheme=aim experiment: skill slots that
snap their cast onto a target (and the slot1..7 = hostile/ground/corpse
choice), dedicated panel-mode face buttons, L held = stand still, and the
D-pad loot browse with native labels (the item assist replaces it). Those live
on in the git history and the manette/pad-core-port branch. scheme= and
D2_PAD no longer exist.
Validation: host logic tests (pad_core), plus the maintainer's hands-on checks on a console (NPC menus, touch, title-screen menus). The frame-time cost of the hooks is not measured, and the default change is not yet tested by the community.
Radial menu (Select)¶
Pressing Select immediately opens a 7-sector menu centered on screen. The left stick points at a sector (it lights up gold); releasing Select confirms whichever sector is pointed at that exact instant. Bringing the stick back to center before releasing Select cancels (no sector is then selected, even if one had been hovered just before).
| Sector | D2 action |
|---|---|
| Skills (top) | T — skill tree |
| Quests | Q — quest log |
| Map | Tab — automap |
| Inventory | I — inventory |
| Chat | Enter — chat line |
| Party | P — party screen |
| Character | C — character sheet |
This menu replaces the old dedicated shortcuts for each of these actions (character, skills, quests, automap, inventory): one gesture for all seven, instead of seven combinations to remember. The virtual keyboard is deliberately not included: it opens by itself whenever a text field takes focus, and otherwise keeps its own dedicated gesture — R + Triangle.
Virtual keyboard (R + Triangle)¶
The keyboard opens by itself when a text field takes focus — character
name, Battle.net account and password, game name and password. Closing stays
manual (Select or the FERMER key — Start/Enter validates the field but
leaves the keyboard open), and a closed keyboard does not reopen until
another field takes focus (or the same one loses and regains it). R + Triangle
still opens it at any time. D2_KBAUTO=0 in ux0:data/d2vita/env.txt turns
the automatic opening off. The keyboard draws at 80% opacity by default — the
character/menu stays faintly visible behind it — adjustable with
D2_KBALPHA=0-100 (100 = the old fully opaque look). Below 100, blending is
done on the GPU (a separate textured layer, composed alongside the radial
menu) whenever that path is armed; if it isn't, the keyboard falls back to
drawing translucency on the CPU, which reads the screen to blend and costs
noticeably more per frame — opaque (100) is always the fast path either way.
The runtime reads the game's own "focused control"
state to know this (read-only, the control's header only — never the text).
Each transition is logged in boot_progress.txt as clavier: focus champ ON
or clavier: focus champ OFF (capped at 64 lines per session). In-game chat
is not covered yet (phase 2).
| Input | Action |
|---|---|
| D-pad | Navigate keys |
| Cross | Type the selected key |
| Circle | Backspace |
| Start | Enter |
| Select (or the FERMER key) | Close the keyboard |
| Touch tap on a key | Type it directly |
The virtual keyboard's own rendering (font, layout) comes from the generic
winx86 engine (src/platform/vita_kb.h/vita_kb_font.h). The trigger is
d2vita-specific: R + Triangle.
Settings panel (title screen)¶
A small "Settings" tab (called "Controls" up to 0.2.0) sits in the left letterbox band of the title screen. Tap it to open a full-screen editor with three tabs:
- Buttons — a grid of every button (L, R, Select, face buttons, D-pad, Start) by layer: plain, with R held, with L held. Each cell is the action that combination fires. The three fixed ones (R+Select = Space, R+Triangle = keyboard, L+Start = screenshot) are shown greyed out.
- Tuning — the aim cone, monster and object reach, hover height, HUD band, aim marker, cursor speed, deadzone and walk-ring sizes, each with its default and range.
- Game — the functional switches that live in
ux0:data/d2vita/env.txt: native 960×544 drawing, 640×480 zoom, menu shape (4:3 or stretched), HUD gap filling, the two single-player options (ladder runewords, unlimited Akara reset — both off, they differ from the original game), sound, automatic keyboard and its opacity, and private-servers-only. Performance and debug variables are deliberately not offered.env.txtis only read when the game starts, so these changes apply at the next launch (the panel says so); an option set back to its default simply loses its line, and the rest of the file (includingD2SCHED=,D2WRITE=and any line you added) is left alone.
Colours: white = default, gold = customised, green = changed and not saved
yet. Buttons and Tuning changes apply at once; closing the panel writes
only what you changed into ux0:data/d2vita/controls.txt (your
comments and other lines are kept; an old alias such as croix= is
replaced, not duplicated) and the Game tab's changes into env.txt.
| Input | Effect |
|---|---|
| D-pad | Buttons: move in the grid. Tuning and Game: Up/Down pick, Left/Right change (hold to repeat) |
| Cross / Square | Next / previous action (or value +/−), hold to repeat |
| Triangle | Put the focused item back to its default |
| L / R | Switch tab |
| Circle / Start | Save and close |
| Touch | Tap a cell to focus it, tap again to cycle; the < > ends of a cell step it (hold to repeat); tap a tab or the footer buttons |
Binding aim to a button when none was bound at launch needs a restart of
the game (the aim hooks are armed at boot); the panel says so.
Remapping without a rebuild¶
File ux0:data/d2vita/controls.txt. A fully-commented reference copy is
seeded there automatically the very first time the game boots (never
overwrites a file you already have — delete yours and it comes back next
boot); the walkthrough below covers the same ground.
cross=rclick
r+triangle=f5
l+circle=perso # L layer (defaults: l+cross=inv, l+circle=automap, l+square=vk:0x4F)
l=lclick # L's OWN action, held alone (default: aim; lclick = opt out of aim assist)
r=none # R's OWN action, held alone (default: rclick) — "none" disables it
select=inv # Select's OWN action, pressed alone (default: opens the radial menu)
cross=aim # any button, layer or l=/r=/select= can carry `aim` (see Aim assist)
orbit=70 # direct-movement radius (px), plain mode
sens=18 # right stick speed (default 18)
deadzone=0.15 # default 0.15
anchor_y=470 # character's vertical anchor (for a 1000-tall resolution)
diamond=off # hide the aim assist's diamond (default on)
Accepted ranges for the numeric keys — a value outside it is refused (the
default stays) and reported in boot_progress.txt: orbit 10–400, sens
1–100, deadzone 0–0.9 (a fraction: 0.15, not 15), anchor_y 100–900,
orbit_min/orbit_max 5–400, cone 5–90, hover_h 0–150, hud_h 0–300,
reach 50–2000, hostile_reach 100–2000. In particular orbit=1000, which some older builds used,
is refused: it would push the walk point off the screen and nothing could be
controlled any more. A UTF-8 byte-order mark at the start of the file (added
by some Windows editors) is ignored.
Buttons: cross/croix, circle/rond, square/carre,
triangle, up, down, left, right, start (prefix with r+ for
the R layer, l+ for the L layer — never both on the same line). l=,
r= and select= are separate top-level keys (no button prefix): they
set what L, R and Select do by themselves, not a combo.
Actions: lclick, rclick, alt, items, aim, shift, tab/automap,
esc/echap, inv, perso, skills, quests, swap, space, run,
enter, pot1-pot4, f1-f8, vk:0xNN (raw key code), none.
A line the game doesn't recognise — an unknown key or button, an unknown
action, a number outside its range, or (r+select=/l+select=) a combo Select doesn't have — is
never applied, and now says so: check boot_progress.txt for
controls.txt ignore "..." lines, one per rejected line (capped at 8).
Before this, a bad line simply did nothing with no indication why —
the most common case being a controls.txt copied from a build with a
different set of keys than the one actually running.
Not yet possible: a single button driving more than one action in sequence (e.g. "open the map and start running").
Diagnostics¶
D2_INPUTLOG=1 in env.txt logs the raw button words received — useful
for debugging a remap that doesn't behave as expected. Only enable it for
diagnostics, not for normal play (logging has a cost).
Known gotcha
If the chat box is open, Esc closes it first (a second press is needed to open the menu).