For education purposes only · no game files included · bring your own THUG2
Guide 05

Controls

How keyboard input reaches a game that only understands a PS2 pad: Enter in menus, keys whose meaning depends on the screen, the Numpad 1 caveman fix, and a main menu that THUG2 doesn't think is a main menu.

GoalThe classic Tony Hawk PC keyboard layout (THUG1's, which THUG2 PC players know by heart), working in menus, while skating and in Create-A-Park.

1Everything becomes a PS2 pad

The engine reads DUALSHOCK 2 style raw data: two bytes of active-low buttons, four stick bytes, twelve pressure bytes. Keyboard and controller both fill one sPadState, which is packed into that format.

excerptWn32/Code/Plat/Sys/SIO/p_siodev.cpp
Training, keyboard only: W to push.
Training, keyboard only: W to push, Num 2 to crouch and ollie.

2Enter, Space, Escape: the other path

Menus also read a typed-character buffer (SIO::KeyboardRead), which is how Enter/Space choose and Escape backs out or pauses. SDL events feed it; mapping those keys to pad buttons as well would fire twice.

excerptWn32/Code/Plat/Sys/SIO/p_keyboard.cpp

3Sample the context when a key goes down

Numpad 2 is ollie while skating, accept in a menu and "place" in the park editor; Numpad 7 is nollie when skating and "lower" in the editor. The context is captured on key-down and kept until release, so a key held across a menu opening doesn't change meaning halfway.

excerptWn32/Code/Plat/Sys/SIO/p_siodev.cpp

4Fix the caveman

Numpad 1/3 pressed L2/R2, which is not how you get off the board on an Xbox build. They're the Xbox Black/White buttons, which live in a byte the PS2 format doesn't have, and only reach the game when the device is in digital mode.

diffWn32/Code/Plat/Sys/SIO/p_siodev.cpp ยท THUG1 port

switch_control.q: Xbox_Trigger = {{ Press , Black , 10 }}. Four words of script, one afternoon of reading pad bytes.

5Know where you are (THUG2 edition)

Deciding "menu or skating" leans on a few checks: is a menu focused, is the game paused, is the game mode the front end. THUG1's front end is a game mode with is_frontend = 1. THUG2's main menu is a level (load_mainmenu) in an ordinary game mode, and its modes don't have is_frontend at all. The engine read the missing value into an uninitialised int, the stack said "yes", and every level counted as a menu: the grind key grabbed and the grab key ground. Now a missing value is "no", and the main menu level counts as a menu by name.

diffWn32/Code/Plat/Sys/SIO/p_siodev.cpp · 0694250

The whole hunt is in chapter 5.

6The default layout

KeySkatingMenusCreate-A-Park
W A S Dmovemovemove selection
Numpad 2 / 4 / 6 / 8ollie / flip / grab, talk / grindaccept / – / – / backplace / rotate / rotate / delete
Numpad 7 / 9nollie, spin left / switch, spin right–lower / raise
Numpad 1 / 3get off / back on board–zoom in / out
Z X C Vcamera–camera
Pchange view––
Enter / Escapechat (online) / pauseaccept / backplace / pause

All of these can be changed now: Keyboard settings.