Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

The window, status bar, and menus

Copperline opens a single window: the emulated display presented at a TV-like 4:3 aspect ratio, above a status bar with the machine’s controls. The window scales continuously when resized.

Keyboard shortcuts

The app shortcut modifier is Cmd on macOS and Alt on Linux/Windows.

macOSLinux/WindowsAction
Cmd+QAlt+QQuit
Cmd+EAlt+EOpen / close the menu (also the status bar’s hamburger button); releases a captured mouse
Cmd+SAlt+SSave a screenshot (copperline-screenshot-<YYYYMMDDHHmmSS>.png in the screenshots folder; the on-screen confirmation overlay is not part of the saved image)
Cmd+RAlt+RStart / stop a video-with-audio recording (below)
Cmd+Shift+RAlt+Shift+RStart / stop an input recording (below)
Cmd+Shift+SAlt+Shift+SSave a state (copperline-state-<YYYYMMDDHHmmSS>.clstate in the states folder)
Cmd+Shift+LAlt+Shift+LLoad a save state from a file dialog
Cmd+1..Cmd+9, Cmd+0Alt+1..Alt+9, Alt+0Quick-save to numbered slot 1-10
Cmd+Shift+1..Cmd+Shift+0Alt+Shift+1..Alt+Shift+0Quick-load from that slot
Cmd+DAlt+DSwap to the next disk in a drive’s configured playlist
Cmd+GAlt+GCapture / release the host mouse (clicking the display also captures)
Cmd+BAlt+BOpen the debugger window
Cmd+KAlt+KOpen the debugger console
Cmd+JAlt+JToggle joystick input mode: gamepad / keyboard (also the status-bar icon)
Cmd+MAlt+MTurn the monitor bezel off, or back on to the chosen front (Video Settings > Monitor Bezel picks it; [display] bezel sets the start-up value)
Cmd+Shift+AAlt+Shift+ACycle the audio output: Default, each host device, then Disabled (also Audio Settings > Audio Output)
Cmd+AAlt+ACycle Paula’s audio filter: auto, on, off (also Audio Settings > Audio Filter)
Cmd+Shift++ / Cmd+Shift+-Alt+Shift++ / Alt+Shift+-Raise / lower the parallel-port sampler input gain (only when a sampler is attached; also Parallel Port > Sampler Gain)
Cmd+Shift+> / Cmd+Shift+<Alt+Shift+> / Alt+Shift+<Raise / lower the host mouse sensitivity (also the launcher’s Input tab)
Cmd+FAlt+FToggle fullscreen on / off
Cmd+Shift+FAlt+Shift+FShow / hide the status bar
Cmd+PAlt+PToggle the performance overlay ([display] perf_overlay sets the start-up value)
Cmd+WAlt+WToggle Warp Speed (turbo) on / off
Cmd+Shift+WAlt+Shift+WCycle the Warp Speed limit: 2x, 4x, 8x, 16x, Max
Cmd+ZAlt+ZRewind the machine one step (needs [emulation] rewind or Emulation Settings > Rewind)
EscEscClose an open menu or overlay panel (in a tool window, that window); otherwise passed through to the Amiga
Ctrl+Amiga+AmigaCtrl+Amiga+AmigaKeyboard reset (warm reboot)

Host modifiers that are passed through to the emulated keyboard map onto the Amiga keyboard: Alt becomes Amiga Alt, Cmd/Super becomes the left/right Amiga keys, and left Ctrl becomes Amiga Ctrl, so Ctrl+Amiga+Amiga is typed naturally. The Amiga keyboard has no right Ctrl, so host right Ctrl also acts as the right Amiga key -- handy on PC/laptop keyboards that lack a right Super/Win key.

All other keys are sent to the emulated machine through the real path: a bit-timed keyboard-MCU model clocks each transition into CIA-A’s serial register over the emulated KCLK/KDAT lines, with the real handshake, power-up stream, and recovery protocol -- so even software that talks to the keyboard hardware directly behaves. Ctrl+Amiga+Amiga runs the authentic reset protocol (reset warning, then KCLK held low), so the reboot lands a fraction of a second after the chord, as on real hardware.

Status bar

The status bar (44 pixels below the display) holds, left to right (it can be hidden entirely with Cmd+Shift+F / Alt+Shift+F or Video Settings > Status Bar):

On-screen keyboard

The keyboard button in the status bar, or Input Settings > On-Screen Keyboard, draws an Amiga keyboard in a strip between the display and the status bar. The window grows to make room for it: the picture keeps its size, the canvas gets taller, and hiding the keyboard gives the height back. A window you have resized yourself keeps its size, and the display reflows into it as usual.

It is an A600 -- the one Amiga keyboard with no numeric keypad, so the whole machine fits the window’s width at a usable cap size. Clicking a cap sends that key’s rawkey to the emulated keyboard MCU over the same authentic serial protocol a host keystroke uses, and is recorded the same way, so on-screen keys are captured by --record-input and replay from the resulting --script file. The two keyboards are independent holders of the same key: pressing a cap the host keyboard is already holding down changes nothing for the machine, and the key comes up only when the last of the two lets go.

The keyboard is the way to reach the keys a host keyboard has no equivalent of -- Help, both Amiga keys, and the #/~ key beside Return -- and the way to drive a session entirely with the mouse.

Performance overlay

Cmd+P (macOS) / Alt+P, Video Settings > Performance, or [display] perf_overlay = true shows a live emulation-performance readout in the top-right corner of the display, one line per data point at the menu’s font size (it follows Menu Size), refreshed twice a second:

LineMeaning
50.0 fpsEmulated video frames retired per host second: 50 (PAL) or 60 (NTSC) when the machine holds real time, lower when the host cannot keep up, far higher under Warp Speed
x1.00Speed factor: emulated seconds advanced per host second (the effective multiplier under Warp Speed)
emu 3.2 msHost milliseconds of emulation work per emulated frame, pacing sleeps excluded
host 16%Share of host wall time spent emulating. In real-time mode this is the share of the frame budget (20.0 ms PAL, 16.7 ms NTSC) used per frame
audio 148 msLive audio output lead -- the cushion that absorbs host scheduling hiccups (steady state is about 150 ms)
xrun 0Audio underrun frames per second: the audible symptom of the host falling behind
slip 0Times the pacer fell hopelessly behind real time (over ~100 ms, e.g. a host stall) and dropped emulated time instead of chasing it, since the last guest reset

Copperline never skips frames to keep pace: when the host cannot sustain real time the machine slows down (fps and the speed factor fall below nominal while host sits near 100%), and only a stall beyond the pacer’s catch-up limit drops emulated time, counted by slip. Under Warp Speed the presentation shows one frame per burst, but every emulated frame is still computed.

Like the transient message overlay, the readout is painted into the presentation only: screenshots, frame dumps, and recordings never include it. While a video recording is running the block steps below the REC badge. COPPERLINE_PERF_OVERLAY=1|0 overrides the config for a single run, and --perf-overlay shows it from the command line; the launcher’s Perf overlay row (A/V & Emu, Video) makes it stick. The same counters are exported through the control protocol’s status reply for headless runs (see Control protocol).

Drag and drop

Disk images can be dropped anywhere on the emulator window:

The chooser opens after the drop rather than offering per-drive drop targets because the windowing layer reports file drops without a cursor position. For the same reason drops are unavailable under native Wayland (X11/XWayland works).

The pop-up menu with a category open

The menu, with a category open beside it.

The hamburger button at the right of the status bar opens the menu, as does Cmd+E / Alt+E. It grows upward from the status bar and dims the picture behind it, so what it covers stays readable without competing for attention. The dimming is a window effect: it never appears in a screenshot, a frame dump, or a recording.

The top level holds the tools, then a category per area of the machine, then the ROM, the shortcut reference and About... last. A category is marked > and opens a list of its own beside it; a setting with more than two values opens a further list of those values with the one in force ticked, and a setting that is simply on or off is ticked in place. Categories with nothing to offer -- the serial and parallel ports on a machine with nothing on them -- are not shown at all.

Point at a category and it opens; point at one of its rows and that row is where the keyboard is. The cursor keys walk the same path -- up and down within a list, right into a category, left back out -- and Return picks the row under the cursor. Esc steps back one level, and closes the menu from the top.

Picking a row that opens something else -- a window, a panel, a file dialog -- closes the menu behind it. Changing a setting leaves the menu up with the new value marked, so a run of changes costs one open rather than one each. Opening the menu also releases a captured mouse.

Menu Size under Video Settings draws the whole menu at 1x or 2x. The start-up size is [display] menu_scale, --menu-scale, or Menu size on the launcher’s A/V & Emu page (Video category).

Tool windows are separate native windows so the emulated display remains visible; the debugger and frame analyzer can be open at the same time. They take their keys and clicks through their own windows, and the main window keeps driving the Amiga while they are open -- resume the machine from the debugger and you can play on while watching it. Overlay panels are drawn over the display and are modal: while one is open, key presses and display clicks stay in the UI instead of reaching the Amiga. Esc in a tool window closes that window; Esc in the main window closes the menu or overlay panel, and otherwise belongs to the Amiga.

Tools

Audio Settings

Video Settings

Input Settings

Serial Port and Parallel Port

Shown only when something is on the port.

Emulation Settings

Warp Settings

Recording

Save State

And last

The keyboard shortcuts window

The Keyboard Shortcuts window.

Machine configuration screen

Starting Copperline with no machine specified -- no ./copperline.toml, no --config, no ROM or override, and not a headless run -- opens the configuration screen instead of booting. It is also available any time from the menu’s Machine Configuration... item, seeded with the running machine’s settings.

The machine configuration screen

The configuration screen: the machine selector across the top, category tabs down the left, settings on the right, and the action bar along the bottom. Here an A1200 is selected on the Memory tab; Zorro III RAM is greyed with the reason “needs 32-bit CPU” (the A1200’s 68EC020 has a 24-bit bus).

The layout is:

The Boot Priority sub-page of the Storage tab

The Boot Priority sub-page: an A1200 whose IDE master boots at priority 0, its slave with the Bootable box cleared (showing the -128 that stores), and one SCSI unit of a fitted A2091 carrying a disk of its own. A greyed Info: label heads a note on the valid priority range.

Saved files use the same schema as a hand-written copperline.toml (see Configuration reference), so the screen and the config file are interchangeable: configure a machine and save it, or load an existing config to tweak it. Run builds the machine in place, so the configuration screen and a direct --config launch produce an identical machine.

Create Image

Storage -> Create Image... makes new, empty disk images: Floppy Disk writes an ADF, Hard Disk writes an HDF. These pages write a file and nothing else; none of their settings belongs to the machine, so none of it is saved to a configuration file.

Save... opens a file dialog, then writes the image. The status line reports progress and the finished size; the write runs in the background, so the window stays responsive while a large image is written.

Floppy Disk

OptionEffect
DensityDD (880K) or HD (1.76M). Sets the image size: 901,120 or 1,802,240 bytes.
ContainerStandard ADF writes the sectors in order. Extended ADF wraps them in the UAE-1ADF container, which stores one record per track.
FilesystemUnformatted leaves the image blank for the Amiga to format. OFS and FFS write a boot block, root block and bitmap.
DOSTypeThe DOS type’s options: International case folding, Dir cache, Long names. See DOSType below.
Volume nameThe name the volume mounts under.
BootableWrites the boot code that loads dos.library, so the disk boots rather than only mounting.

Hard Disk

OptionEffect
SizeA whole number up to 9999, in the unit beside it. Click MB/GB to change the unit. The image is rounded up to the next whole cylinder.
GeometryAuto derives cylinders/surfaces/sectors from the size. Custom sets them by hand, and adds a Configure button that opens the geometry editor.
PartitioningRDB writes a Rigid Disk Block and one partition filling the drive. None writes no partition table.
FilesystemAs for a floppy. With RDB the type is recorded in the partition entry; with None the volume starts at block 0.
DOSTypeAs for a floppy.
Device nameThe device the partition mounts as, e.g. DH0. RDB only.
Volume nameThe name the volume mounts under.
BootableSets the partition’s bootable flag. RDB only.
Boot priorityThe partition’s de_BootPri, -128 to 127. Kickstart enters DF0: at 5, so 6 boots the hard disk ahead of a floppy. Applies while Bootable is ticked.
Read onlyMarks the finished file read-only on this computer.
Sparse imageOn by default: the file is created at full length with only its structure written, and the host fills the rest in as it is used. Clear it to write the whole file now, which takes as long as writing that many bytes takes.

An image larger than 2048 GB can be made only with Partitioning: None and Filesystem: Unformatted: every block number an RDB or an AmigaDOS volume uses is a 32-bit field.

With Sparse image cleared, the volume the file is being written to is checked for room first, and the write is refused if there is not enough.

Geometry editor

Reached from Configure on the Hard Disk page once Geometry is set to Custom. The geometry set here decides the image’s size; the Size box seeds it.

OptionEffect
Cylinders, Surfaces, Sectors per trackThe drive’s stated geometry. Surfaces x sectors is one cylinder; the RDB states the partition in cylinders, so these set the granularity a partition can start and end on.
Reserved blocksBlocks at the front of the partition the filesystem never allocates. Two -- the length of the boot block -- unless there is a reason to say otherwise.
Drive, Type, RevisionWhat the drive answers when asked what it is. HDToolBox shows the first two as its Drive and Type columns. Each box holds as many characters as its RDB field: 8, 16 and 4.

Apply returns to the Hard Disk page. Auto puts every figure back to what the size implies, and the identity back to Amiga / the size / Copperline’s version.

The geometry editor of the Create Image sub-page

The geometry editor, with the drive identity below the figures and a note of the size they come to.

DOSType

The Filesystem row picks OFS or FFS; the DOSType row picks the options that filesystem carries. Between them they name one of the eight AmigaDOS types:

TickedType
--DOS0 (OFS), DOS1 (FFS)
InternationalDOS2, DOS3
International + Dir cacheDOS4, DOS5
International + Long namesDOS6, DOS7

Dir cache and Long names are two values of one field, so ticking one greys the other. Both are international, so International shows ticked and greyed alongside either.

Dir cache needs Kickstart 3.0, International needs 2.0, and Long names needs a filesystem no Kickstart provides.

Recording video

Cmd+R on macOS or Alt+R on Linux/Windows (or the menu’s “Record Video”) starts capturing the emulated display and sound to copperline-video-<YYYYMMDDHHmmSS>.avi in the recordings folder; pressing it again stops and finalizes the file. A red REC badge sits in the display’s top-right corner while a recording runs -- like the screenshot overlay, the badge, status bar, and menus are never part of the captured video.

The file is an AVI with lossless ZMBV video (the DOSBox capture codec: zlib-compressed keyframes plus frame deltas, which keeps typical Amiga output to a few MB per minute) and uncompressed 16-bit stereo PCM audio at 44.1 kHz. It plays directly in VLC, mpv, and anything else built on ffmpeg; for other players, transcode with ffmpeg -i copperline-video-<ts>.avi out.mp4.

Frames and audio are captured on the emulated timeline, not the host clock: the recording stays in sync even when the host stutters, and a capture made under Warp Speed plays back at normal speed. The audio track is tapped before the status bar’s volume slider, so recordings keep full level regardless of the live output volume. Pausing (or powering off) suspends the capture; recording resumes when emulation continues.

Recording input

Cmd+Shift+R on macOS or Alt+Shift+R on Linux/Windows (or the menu’s “Record Input”) starts logging every input event that reaches the emulated machine -- key presses with their hold times (typed on the host keyboard or clicked on the on-screen one, which reaches the machine by the same path), mouse buttons and motion, joystick / CD32-pad controls, analogue pot positions, and floppy inserts, on whichever port carries each device -- each stamped with its emulated time. Pressing it again stops the recording and writes copperline-input-<YYYYMMDDHHmmSS>.clscript in the recordings folder: a plain text file of scripted-input directives that copperline --script FILE replays exactly, because the core is deterministic and the events re-fire at the same emulated timestamps.

This is the direct way to turn “I can reproduce it by hand” into a regression: play the sequence once while recording, then keep the script (optionally together with a save state to skip the lead-in) as a deterministic, shareable reproduction. The format and the headless --record-input variant are described in Input recording and script files.

Save states

Cmd+Shift+S on macOS or Alt+Shift+S on Linux/Windows (or the menu’s “Save State”) writes a snapshot of the whole emulated machine to copperline-state-<YYYYMMDDHHmmSS>.clstate in the states folder: CPU, chip/slow/fast RAM, ROM, the full chipset and CIA state, floppy images (including unsaved in-memory changes), expansion boards, and CD/NVRAM state. Cmd+Shift+L / Alt+Shift+L (or “Load State...”) restores one; the machine continues from exactly the saved point, byte-for-byte -- the core is deterministic, so a resumed run is indistinguishable from one that was never interrupted.

States are taken at emulated-frame boundaries and are versioned: a file from an older, incompatible build is refused with a clear message rather than producing a corrupt machine.

A state is self-contained: it carries its own RAM, ROM, and chipset, so loading one always restores the machine it was taken on -- even if you launched Copperline with a different config. When the loaded machine differs from the running one -- a different model, chipset, video standard, RAM size, or even a different Kickstart of the same machine (the ROM is fingerprinted) -- the load reconfigures to match the state and tells you so (the load message names the restored machine, e.g. “reconfigured to A1200 / 68EC020 / AGA / PAL”); your current config is not silently mixed in. Two caveats:

Quick-save slots

Naming a file is the wrong interaction for the “before this jump” save you take twenty times an hour, so there are ten numbered slots as well. Cmd/Alt+<digit> saves to that slot and Cmd/Alt+Shift+<digit> loads it, with 0 as the tenth. The menu’s Quick Save and Quick Load lists reach the same ten, each row naming when that slot was written or showing it as empty.

A quick save overwrites its slot without asking -- that is the point of it -- and loading a slot that has never been written reports “Slot N is empty” rather than failing. Slots are ordinary .clstate files, identical in format to a named save, kept in the states folder below. And because they are per user and not per machine, a slot may hold a state from a different Amiga than the one running. That is safe: as above, the state carries its own machine and the load reconfigures to match it and says so.

The headless flags --save-state-after SECS PATH and --load-state PATH script the same feature for debugging workflows: snapshot a long-running program just before the scene under investigation once, then iterate from the state in seconds instead of re-emulating minutes. The file format and what exactly is (and is not) captured are specified in the internals chapter.

Where files go

Everything Copperline produces is kept per user rather than per working directory, so it is reachable however Copperline was launched. The host-data directory is:

HostLocation
Linux/BSD$XDG_CONFIG_HOME/copperline/, else ~/.config/copperline/
macOS~/.config/copperline/
Windows%APPDATA%\copperline\

with a folder inside it for each kind of file: screenshots/, states/ (named saves and the quick-save slots), recordings/ (video captures and recorded input scripts), nvram/ (battery-backed clock RAM and CD32 game saves), traces/ (debugger traces and waveform captures), and configs/ (configurations saved from the configuration screen). Each folder is created on first use, and each can be moved with the [paths] section of the configuration or the configuration screen’s A/V & Emu -> Paths page -- see Configuration reference. Headless flags that take an explicit path (--screenshot-after and friends) write exactly where they are told and ignore all of this.

A battmem.nvram or cd32-nvram.bin left in the working directory by an earlier Copperline keeps being used from there -- they hold real game saves, so nothing is moved or abandoned behind your back.

For a self-contained installation, create an empty file named portable.txt beside the Copperline executable (or beside the downloaded .AppImage) and restart Copperline. That folder then becomes the host-data directory, and all of the folders above -- plus gamepad calibration, keyboard mappings, the default WHDLoad library and other per-user host data -- live inside it, so the whole installation moves as one folder. Delete portable.txt to return to the platform location above; Copperline does not move existing files in either direction.

Controller ports

An Amiga has two game ports, and either accepts any controller. Copperline models that: each port carries a device -- mouse, joystick, cd32 pad, analogue paddles, or none -- set with [input] port1/port2 in the config (or --port1/--port2, or the launcher’s Input tab). The default is the stock wiring, a mouse in port 1 and a joystick in port 2 (a CD32 pad on the CD32 profile). The runtime menu’s Port 1 Device / Port 2 Device items hot-plug a different device live, exactly like swapping the physical plug: the old device’s lines release, and the port’s quadrature counters hold.

The host mouse drives the (lowest-numbered) port with a mouse plugged in and feeds its JOYxDAT counters. Click the display (or press Cmd+G on macOS or Alt+G on Linux/Windows) to capture the host mouse; the same shortcut releases it. The click that takes the capture is a window action and is not passed to the Amiga, so the first click that reaches the guest is the first one aimed at it -- otherwise a single click on a gadget arrives as two, close enough together to read as a double click.

While an overlay panel is open, host cursor motion is not fed to the emulated mouse. Tool windows are not modal that way: with the debugger or analyzer open, motion and clicks over the main window’s display still drive the Amiga, and the capture click and shortcut work as usual. A panel or tool window opened while the mouse was captured borrows the cursor and hands the capture back when the last of them closes, so a visit to the debugger does not leave the machine uncaptured -- which matters most in fullscreen, where there is no desktop to reach for. An explicit Cmd/Alt+G release settles it the other way: the capture stays off.

Uncaptured, host cursor motion over the display still drives the emulated mouse, and [input] mouse_sensitivity scales it the same way it scales captured motion. At the default setting the factor is 1.0 and the pointer tracks the host cursor one-for-one.

[input] mouse_capture (--mouse-capture, the launcher’s Input tab) changes when the grab is taken: auto grabs whenever the window has the focus and on entering fullscreen, so no host cursor is ever loose over the display, and manual grabs only on the shortcut, leaving display clicks to go straight to the Amiga. See Mouse capture.

A USB gamepad drives the emulated digital joystick on whichever port one is plugged into: directions through JOYxDAT, fire through /FIRx, and a second button through POTxY/POTGOR. A cd32 device speaks the CD32 serial button protocol instead, including the red/blue/green/yellow and transport buttons, on either port. An analogue device presents pot resistances on the POTxX/POTxY pins; no live host device maps to it yet -- drive it with --pot-after scripting or the control protocol’s input.analogue.

Copperline can also emulate the joystick from the host keyboard. There are two explicit input modes, and the active one is always shown by the gamepad / keyboard icon in the status bar (next to the volume control), so a “my keys aren’t working” surprise can be spotted and fixed at a glance:

With joysticks (or pads) in both ports -- a two-player setup -- the gamepad and the cursor-key mapping drive one port each, and the mode picks which source gets the lower-numbered port. Whenever no physical pad is present, a second keyboard mapping on the numeric keypad stands in for it, so two players can share one keyboard.

With mice in both ports, the host mouse drives the lower-numbered one and the cursor-key mapping drives the second as an emulated mouse (in keyboard mode; in gamepad mode the second mouse is undriven and the keyboard passes through). The same applies whenever the keyboard-routed port carries a mouse: the mapping’s keys become the pointer.

Click the status-bar icon to flip between them; the menu’s Joystick Input item and Cmd+J on macOS / Alt+J on Linux and Windows do the same. Set the starting mode with [input] joystick in the config (or --joystick MODE, or the launcher’s Input tab).

The primary keyboard mapping is FS-UAE-compatible: cursor keys for directions, and Right Ctrl, Right Alt or Left Ctrl for fire, with Left Alt as the second button (the left-hand fire keys pair naturally with the right-hand arrows, and compact keyboards often lack the right-side modifiers). For CD32 pad buttons, C is red/fire, X is blue, D is green, S is yellow, Return is play/pause, Z is rewind, and A is forward. On a mouse port the same keys drive the pointer: cursor keys move it, the fire keys are the left button, X or Left Alt the right, and D the middle. The second (numpad) mapping is 8/2/4/6 for directions, 0 for fire, . for the second button, and numpad Enter for play. While a mapping owns its keys, they are not sent to the Amiga keyboard.

Those are the defaults; every binding is editable from the menu’s Input Mapping... item (see Input mapping). A held fire button can also be turned into a pulse train with the Autofire item or [input] autofire_hz.

Gamepad calibration

Pads are read through raw gilrs events with no controller database, so each controller is calibrated once: push each control when prompted. This records raw axis/button codes and directions, which makes any pad work regardless of database coverage and handles inverted or odd axis layouts automatically.

The gamepad calibration window

The calibration window mid-flow. Skip covers pads without the CD32 extras.

Run it either from the menu (“Calibrate Gamepad...”) -- which ends with a live test of the finished bindings and a Save button that makes them live immediately -- or from the terminal with copperline --calibrate-gamepad. The steps are the four directions, fire (CD32 red), button 2 (CD32 blue), and the optional CD32 green/yellow/play/rewind/forward buttons; every step waits for the pad to return to neutral before sampling, so a held control cannot bleed into the next binding.

Calibrations are saved per controller UUID in ~/.config/copperline/gamepads.toml ($XDG_CONFIG_HOME respected; %APPDATA%\copperline\ on Windows, or beside the executable in portable mode).

Input mapping

The keyboard also stands in for a controller, on two independent mappings so one keyboard can drive a two-player setup (see Controller ports). The menu’s Input Mapping... item edits both.

The input mapping window

Editing the first keyboard mapping, with the Fire row armed for capture.

Pick the mapping with the Controller 1 / Controller 2 tabs, then Set on a row and press the key to bind (Escape cancels that row without closing the panel). Clear unbinds a control entirely, Defaults restores the built-in layouts, and Save writes the map and applies it to the running machine. Closing the window discards the edits.

A control may hold several keys, and they OR together: fire ships bound to Right Ctrl, Right Alt, Left Ctrl and C, so compact keyboards without the right-hand modifiers still work, and releasing one alias while another is held keeps the button down. Binding a key removes it from wherever it was before -- including from the other mapping -- so the two controllers can never end up fighting over one key.

Saved maps live next to the gamepad calibrations, in ~/.config/copperline/keymap.toml (same per-platform locations as above). Deleting the file restores the defaults.