Input

Every device is read once per tick into one input record; the game reads only that record (as of 2026-11-10).

This page is for developers. For the keys, buttons and gestures a player uses, see Controls; for typed cheat words, Cheats & Diagnostics.

One input record per tick

At the start of each tick GalaxyEggbertGame::CaptureInput() (src/GalaxyEggbertCNA/GalaxyEggbertGame.cpp) fills tickInput_, a ResumeInput (src/GalaxyEggbert/Game/ResumeLog.hpp):

FieldContents
keysThe XNA Keys values held, sorted: the keyboard with the gamepad merged in as keys (below).
mouseX, mouseY, wheel, buttonsThe mouse; buttons is a bit set of left, middle, right, X1, X2.
viewportWidth, viewportHeightThe viewport the positions refer to.
touchesEvery finger: id, x, y and state (pressed, moved, released).
touchControlsEnabledWhether CNA reports a touch screen (TouchPanel::GetCapabilities()).
cheatLetterOne typed letter a-z in press order, 0 for none, -1 when typed letters are not captured.
accelValid, accelReset, accelYThe accelerometer reading, when it is on.

After that, nothing in the tick asks a device. CurrentKeyboardState() and CurrentMouseState() rebuild XNA states from the record, and the phase handlers, InputPad and the editor work on those. This is what lets a recorded list of these records replay a game exactly (Game Loop).

Keyboard

The held keys come from CNA's Keyboard::GetState(). Play turns them into movement in src/GalaxyEggbert/Game/ControlInput.hpp, where aliases are combined per direction:

// src/GalaxyEggbert/Game/ControlInput.hpp
return {
    float(keys.IsKeyDown(Keys::Right) || keys.IsKeyDown(Keys::D)) -
        float(keys.IsKeyDown(Keys::Left) || keys.IsKeyDown(Keys::A)),
    float(keys.IsKeyDown(Keys::Up) || keys.IsKeyDown(Keys::W)) -
        float(keys.IsKeyDown(Keys::Down) || keys.IsKeyDown(Keys::S)),
    keys.IsKeyDown(Keys::X) || keys.IsKeyDown(Keys::RightControl)};

In the tank, VehicleFireKeyboard() turns Left Ctrl into F (fire) before anything else reads it. The remaining play keys (Left Ctrl jump, Space action, Left Shift crouch, Right Shift look up, Esc, F-keys, Tab) are read by name where they are used.

Typed letters through KeyDownEXT

Held-key snapshots miss a key pressed and released between two updates, and they lose the order of letters. The game therefore subscribes to CNA's Keyboard::KeyDownEXT event, which delivers each physical press in order. In Play, letters go into a queue and CaptureInput() puts one of them per tick into cheatLetter; InputPad matches the typed cheat words from that stream. A recognised word's prefix keeps its letters from also steering Blupi until they are released (InputPad::FilterGameplayKeyboard()). This needs no text-input mode or on-screen keyboard, so it works with a keyboard attached to a touch device.

The same event feeds the editor's command keys, the typed names of galaxies and demos, and the demo idle timer. Building with -DGALAXY_EGGBERT_ENABLE_CHEATS=OFF removes typed cheats and the hidden cheat menu.

Gamepad

src/GalaxyEggbert/Game/GamepadInput.hpp is engine-independent. The host fills a GamepadFrame from the first connected pad among XNA's PlayerIndex One to Four (ReadGamepadFrame()), and GamepadKeys() names the keyboard keys it stands for. ReadKeyboardState() (src/GalaxyEggbertCNA/GameHelpers.hpp) adds those keys to the keyboard's, so the pad drives every phase the keyboard drives.

PadBecomesMeaning in play
Left stick (past 0.5) or D-padArrow keyswalk, turn, turn around
ALeft Ctrl and Enterjump (climb in the helicopter); confirm in menus
B or XSpaceaction
Right triggerFfire in the tank or helicopter
RBRight Ctrlback up
LBLeft Shiftcrouch
YRight Shiftlook up
Start or BackEscapepause

In the main menu and the editor the pad is not turned into keys: there it drives an on-screen cursor. EditorDeviceControls (src/GalaxyEggbert/Editor/) reads the pad and touch directly and produces the keyboard, mouse and camera movement the editor understands (sticks fly and look, A places, X removes). Since 2026-11-10 the demo positions, the galaxy screen and the world screen can be driven with the arrows or the D-pad: FocusNavigator.hpp keeps one button chosen (drawn lit) and hands the screen a mouse pressed at that button's centre when A or Enter is pressed; moving the mouse or touching ends the choice.

Mouse

Touch

Each finger from TouchPanel::GetState() is stored in the record. The on-screen pad of the original (stick, Jump, Action, Pause, a crouch button now shown always, plus Galaxy's back-up button and, in the tank or helicopter, Fire) is drawn, and its mouse hit areas are active, only when CNA reports a touch screen (since 2026-11-08); on a desktop without one the mouse stays free for the camera.

Where there is no keyboard, a name (a galaxy, a demo) is typed on an on-screen keyboard (ScreenKeyboard.hpp, 2026-11-10).

Accelerometer

The Setup's Accelerometer switch (off by default, accelActive=) and sensitivity slider (accelSensitivity=, 0-100, 50 by default) come from the original. When it is on and CNA reports a sensor (Microsoft::Devices::Sensors::Accelerometer), AccelTurnInput() turns the device's tilt (its Y component) into steering with the original's dead zone, and only after the device has once been held level. While readings arrive, the on-screen stick gives way to Forward and Back buttons (GALAXY_ACCEL_PAD=1 shows them without a sensor). Replays read the recorded value, never the device.

Menus: the 640×480 layout

The original's screens are 640×480 images. InputPad and Hud keep the original's layout and scale it with the window's height (scale = height / 480): the 640-wide image is centred and the bars beside it are filled with the menu's own images. Buttons use the original's rectangles, scaled the same way, and are hit-tested against the mouse or touch position (QuadBatch::InRect()). As in the original, buttons fire on release, except Jump on the pad, which acts while held. The F1 help panel's close box shows the mapping:

// src/GalaxyEggbert/Game/ControlInput.hpp, ControlsHelp::OverClose()
const float scale=std::min(width/640.f,height/480.f);
const float ox=(width-640*scale)*.5f,oy=(height-480*scale)*.5f;
return scale>0 && x>=ox+550*scale && x<=ox+620*scale &&
       y>=oy+18*scale && y<=oy+54*scale;

Enter (or the pad's A) confirms the Resume question, Pause and the Win/Lost screens; Escape goes back. The help panel freezes the screen and swallows its closing key, so closing it cannot also pause or leave a menu.

Recording input for resume and demos

File formats and where the files go: Save Data & Resume and Demos & Recordings.

What has been tested. Keyboard and mouse live on Linux; the gamepad with an SDL virtual gamepad under Xvfb; touch through the touch code paths and captures. No physical gamepad or touch screen has been tried, and the accelerometer has not run on a real device.

Tests

Related: InputPad, ResumeLog, DemoReplay, GalaxyEggbertGame.