Files
totk-pc-recomp/docs/controls.md
T
Valiantsin DzerakhandClaude Opus 5.5 e3e72dfb44 Keep the repository to what players and contributors use; move the agent setup and working notes out of git
docs/building.md merges the two toolchain docs and the README build steps, and lists the developer checks. The
Maxwell reference moves to docs/maxwell.md. architecture.md loses the milestone table, controls.md describes timed
script lines and input recording, and the tester guide includes shader preparation.

The agent skills, hooks, playbook, backlog and the study notes on upstream projects are the maintainer's local setup:
.claude/, notes/ and CLAUDE.local.md are ignored now, and tools/worktree.py links them into task worktrees. AGENTS.md
keeps the project rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 13:12:50 +03:00

6.4 KiB

Controls

Input comes from the first SDL3 gamepad, the keyboard and the mouse, merged into one Switch controller (runtime/input_win.c). Buttons are ORed; each stick takes the source with the larger deflection. Keys and mouse buttons count only while the game window is in the foreground. TOTK_INPUT=none disables both (automated runs). TOTK_* settings can also be set in totk.ini next to totk.exe (input = none, motion = 0, rumble = 0); the environment overrides the file. TOTK_RUMBLE_STRENGTH is the rumble strength in percent (0 to 300, default 130; 0 is the same as rumble = 0). TOTK_RUMBLE_CURVE is the exponent applied to the amplitude before the strength (0.2 to 1.5, default 0.6; lower makes weak pulses stronger, 1 is linear). TOTK_RUMBLE_TRIGGERS=1 also drives the impulse triggers of an Xbox pad.

Switch Gamepad (by position) Keyboard and mouse Action in the world
Left stick left stick W A S D move
Right stick right stick mouse; arrow keys as a second source camera
Y west left mouse button attack
ZL left trigger (over 50%) right mouse button, Z shield, lock on
ZR right trigger (over 50%) F, X bow
X north Space jump
B south Left Shift run, cancel
A east E interact, pick up
L left shoulder Q abilities
R right shoulder R throw weapon
Left stick click left stick click Left Ctrl crouch
Right stick click right stick click C first-person view
D-pad left, up, right, down D-pad 1 2 3 4 quick-select
Plus Start Tab menu, inventory
Minus Back M map

Esc is unbound in the game; it releases the mouse cursor (see Mouse camera). Z and X duplicate ZL and ZR so menu pages turn with two neighbouring keys; the menu tabs (L, R) are Q and R. The mouse wheel is unbound. The bindings are two tables in runtime/input_map.c, input_bindings (platform-neutral key ids) and input_pad_bindings (gamepad inputs by position); runtime/input_win.c translates Win32 virtual keys and SDL buttons, so a remapping page can edit both later.

Remapping

totk.ini rebinds the buttons, one line per Switch button: bind_<button> = <entry>, <entry>, .... The button is A B X Y L R ZL ZR PLUS MINUS LEFT UP RIGHT DOWN LCLICK RCLICK. An entry is pad:<name> or key:<name>:

  • pad names: south east west north l r zl zr start back lstick rstick dpad_left dpad_up dpad_right dpad_down (zl, zr are the triggers)
  • key names: a to z, 0 to 9, space tab lshift lctrl up down left right mouse_l mouse_r mouse_m
  • none leaves the button unbound.

A line replaces every default of that button, pad and keyboard, so list the keys you still want. Buttons without a line keep the table above. Names are case-insensitive. An invalid entry logs one input: bind ... line and is skipped; a line without a valid entry changes nothing. The sticks and the mouse camera are not remappable. The TOTK_BIND_<button> environment variables work like any other setting. Bindings are read once at start.

A pad that reports its face buttons swapped (A/B and X/Y, as some GuliKit models do) is fixed with:

bind_A = pad:south, key:E
bind_B = pad:east, key:lshift
bind_X = pad:west, key:space
bind_Y = pad:north, key:mouse_l

Mouse camera

Mouse motion (raw input) becomes right-stick deflection. Each presented frame takes the counts moved since the last frame, divides by the frame time and sets the deflection to counts per second * TOTK_MOUSE_SENS / 3000 of full, held for that frame, so the turn rate does not depend on the frame rate. This is not mouselook: the game's stick curve and dead zone still apply, so very slow movements do nothing and a fast flick saturates. The mouse deflection competes with the gamepad and arrow keys by the larger-deflection rule.

TOTK_MOUSE_SENS (0 to 10, default 1; higher turns faster, 0 turns the mouse camera and the cursor capture off). While the window is the foreground window the cursor is hidden and confined to the client area. It is released on focus loss, minimise, while F11 changes the window, during a size or move loop and while a text entry is open. Esc releases it by hand: the cursor shows, the mouse camera and mouse buttons stop, and the window can be moved, minimised or closed. A mouse click inside the client area captures it again; that click does not reach the game. Activating the window by a click on its title bar or border does not capture, so it can be dragged or closed right away; Alt+Tab or a click in the client area captures as before. TOTK_INPUT=none disables the capture too.

The stick direction bits (StickLLeft to StickRDown) are derived from the sticks at 50% deflection. A gamepad plugged in later is picked up within one second; with none connected the log says input: no gamepad.

Scripted input

TOTK_INPUT_SCRIPT=<file> replays presses. It is ORed with real input and still applies under TOTK_INPUT=none. One event per line, # starts a comment:

<frame> <button> [hold_frames]            # A B X Y L R ZL ZR PLUS MINUS LEFT UP RIGHT DOWN LCLICK RCLICK; hold defaults to 4
<frame> LSTICK|RSTICK <x> <y> [hold_frames]   # -32767..32767, up is +y
@<ms> <button> [hold_ms]                  # timed on the world clock
@<ms> LSTICK|RSTICK <x> <y> [hold_ms]

<frame> counts presented frames. @<ms> counts milliseconds of the world clock: game time stepped since the end of the first save load (the player leaves the title screen's origin), so a timed event lands at the same game time at any frame rate and load length. A later load, such as fast travel, still shifts what follows. Each event logs once (input: script frame N: A). tools/input/load_save.txt loads the first save from the title screen.

TOTK_INPUT_RECORD=<file> (input_record in totk.ini, or Input recording in the menu) writes the merged input in the same format, one line per button press and per stick segment: events before the world clock starts by frame, the rest timed. The file replays as a script, which makes it the repro to attach to a bug report.

RenderDoc capture (blocked)

TOTK_RDOC=<frame>[,...] (runtime/rdoc_win.c; TOTK_RDOC_DIR, TOTK_RDOC_DLL) loads RenderDoc before vkCreateInstance. RenderDoc hides VK_EXT_external_memory_host, which the back end requires for guest pool imports (runtime/vk_memory.c), so device creation fails under it. A capture needs a copy-based pool fallback first.