Copyright Matthew Armstrong. Source-available under the
PolyForm Noncommercial License 1.0.0: free to use and change for
non-commercial purposes. Provided as is, with no warranty and no liability.
Not affiliated with Activision, Infinity Ward, Treyarch, Valve, ASUS, the
Bazzite project or any of the mod teams below.

One tap-friendly app that gets three classic shooters ready for handheld PCs
(ROG Ally, Steam Deck, Legion Go) on Bazzite or SteamOS (and Windows):

Game Campaign Multiplayer
Call of Duty: Black Ops (2010) Hidden gamepad mode switched on Same, plus Plutonium's configs
Call of Duty 4: Modern Warfare (2007) IW3SP-MOD installed: gamepad + aim assist CoD4x: steps and official page (assisted)
Call of Duty: Modern Warfare 2 (2009) IW-Pad installed: full controller support IW4x installed: native controller + aim assist

Plus, for all three:

  • Steam launch options written for you (with Steam closed), so the normal Steam Play button starts the modded game under Proton. Your own launch options are never overwritten without asking.
  • Full HD locked at every start (or 1440p / 4K): set in the game's config files and again on the command line, so a game that falls back to "safe" or "recommended" settings (MW2's 640-pixel habit) comes straight back.
  • Five one-tap graphics tiers per game (Off, Battery saver, Balanced, Quality, Ultra): the game's own settings plus a matching SweetFX preset, so you never have to dig through the effects overlay.
  • Look: ReShade/SweetFX-style sharpening and colour through vkBasalt on Linux, switched on per game.
  • Touchscreen help for the menus.

Every replaced game file is backed up and Remove puts it back.

MW2 page

Step by step

  1. Install the games in Steam and start each once (Black Ops needs that to write its config files).
  2. Open Handheld Ops and pick a game tab.
  3. Press Install (or Controller ON for Black Ops). Downloads come straight from each mod's official release page; the log shows every step.
  4. Quit Steam (Steam menu > Exit), then press Write to Steam. Or press Copy and paste each line into Steam > game > Properties > General > Launch Options yourself.
  5. Start Steam again and play from your library as usual. In Steam Input, use a Gamepad layout for these games.

CoD4 page

What the launch options look like

bash -c 'exec "${@/iw4mp.exe/iw4x.exe}"' -- %command% 

Steam fills in %command% with its own Proton command; bash swaps the stock
.exe for the mod's. The same form is documented by IW-Pad. With the look on,
ENABLE_VKBASALT=1 VKBASALT_CONFIG_FILE="..." goes in front.

Graphics tiers

Graphics tiers

Tap a tier on the game's page. It is applied straight away (quit the game
first) and again whenever you press Write to Steam.

Tier Game settings (only those the game already has) Effects
Off left as they are none
Battery saver 60 fps cap, vsync off, AA off, shadows off, 4x texture filtering, depth of field off, textures one step lower light CAS sharpening
Balanced (default) 60 fps cap, vsync off, 2x AA, shadows on, 8x filtering, best textures SMAA + CAS sharpening
Quality 90 fps cap, vsync off, 4x AA, shadows on, 16x filtering, best textures SMAA + vibrance + luma sharpen
Ultra (SweetFX) 120 fps cap, vsync off, 4x AA, shadows on, 16x filtering, best textures SMAA + vibrance + contrast curve + luma sharpen
  • Bazzite / Linux: each game gets its own vkBasalt file; the Steam launch option points at it. Quality and Ultra download the SweetFX shaders the first time (automatically).
  • Windows: press Install ReShade essentials for the game on the Look tab. That installs ReShade without its long effect-package list, adds only the 5 effects the tiers use (10 small files) and applies the tier. ReShade's own list then shows just those 5, the start-up tutorial is off, and Home still opens it. Effects you installed before stay on disk, hidden; Show my other effects brings them back.
  • Already have ReShade? It is never reinstalled or overwritten: the button keeps your d3d9.dll, your own presets and effect packages, and only changes five lines of ReShade.ini (which preset, the two shader folders, skip unused effects, tutorial done). The original ReShade.ini is saved the first time; Restore my ReShade puts it back exactly. A d3d9.dll that is not ReShade (another mod) is left alone and reported.
  • The fps caps suit a 120 Hz handheld screen; in Steam Gaming Mode you can also cap frames in the Quick Access menu. Leave the Steam scaling filter (FSR) alone: with the Full HD lock the game already runs at the screen's resolution, and FSR only helps when a game renders below it.

Conflicting settings are removed

Conflict warning, then Put back

Picking a tier (or Write to Steam) first clears anything that would undo it:

  • Extra game config files such as an autoexec.cfg in the game's players or main folder: lines that set vsync, the fps cap, anti-aliasing, shadows, texture settings or the resolution are turned off (commented out with a // handheld-ops off: marker, backup first). Other lines, key binds, the game's own config.cfg and files a mod installed are left alone. The Graphics card warns before and shows Put back after.
  • ReShade settings that override a tier (Windows): a start-up preset, NoReloadOnInit, preset-switch hotkeys and preset shortcut keys are set to off; Handheld Ops' own presets for other tiers are removed. Your own preset files are kept. Restore my ReShade undoes everything in ReShade.ini.
  • Old launch options that contain only vkBasalt, an exe swap or the resolution are replaced (and remembered for Put back). Launch options with anything else of yours still ask first.

Aim feel (Black Ops)

If aim feels floaty: every graphics tier turns vsync off, the usual cause
of input lag. Then check Steam Input for the game (Controller settings > right
stick: smaller deadzone, Linear or Aggressive response curve). The Black Ops
page also has an experimental Look speed button that changes the game's
input_viewSensitivity (1, 1.25, 1.5, 2); it is not confirmed that the PC
game uses that setting for the gamepad.

Screen resolution (Full HD as the minimum)

Screen resolution card

On by default for all three games at 1920x1080; tap to choose 2560x1440 or
3840x2160, or switch it off. It is set in two places:

  1. The config files: r_mode in every engine config under the game's players folder (CoD4 keeps them in players/profiles/<name>/), plus r_fullscreen 1, r_aspectRatio "wide 16:9" and com_recommendedSet 1 where the game already has those lines. com_recommendedSet 1 tells the game its recommended settings were already applied, so it stops replacing yours with auto-detected ones.
  2. The launch option: +set r_mode 1920x1080 +set r_fullscreen 1 after %command%. These engines apply command-line settings after reading the config, so the resolution comes back even if the config was reset.

If a game asks "Run in safe mode?" after a crash, answer No. In Gaming
Mode, also check the game's Steam properties for a Game Resolution option and
choose Native.

Black Ops

Black Ops page

Controller ON sets the game's hidden gpad_enabled in the Singleplayer/
Zombies and Multiplayer configs (and Plutonium's copies). Optional aim
slowdown (campaign/Zombies only, experimental, never Multiplayer).

CoD4x (CoD4 multiplayer)

CoD4x comes with its own installer, and how the Steam copy behaves with it is
unclear (see RESEARCH.md), so the app gives the steps and opens
the official release page instead of installing it.

Controller in IW3SP-MOD (CoD4 campaign)

IW3SP-MOD's gamepad code comes from IW4x: it is switched on by
gpad_enabled (Handheld Ops adds +set gpad_enabled 1 at every start) and
reads Xbox-style (XInput) pads. If yours is a PlayStation, Switch or other
pad, start the game from Steam with Steam Input on (after Write to Steam),
so Steam presents it as an Xbox pad. Starting iw3sp_mod.exe outside Steam
(an old shortcut, Explorer) gets no Steam Input. Fallback: in Steam, Games >
Add a Non-Steam Game > iw3sp_mod.exe, and play that entry.

CoD4: stick works in menus but not in the game: IW3SP-MOD stops reading
the sticks for moving and looking whenever the mouse moves even a little
(or a keyboard key is pressed). Mouse in the game on the Controller card
is set to Off for CoD4 by default (+set in_mouse 0), so the pad stays in
charge; the pad drives the menus. Tap Write to Steam once. Use Steam
Input's Xbox controller layout.

CoD4: left trigger latches aim on until pressed again: that is the
toggle-aim bind. Turn Controller override on (Controller card), keep
Aim: Hold to aim, tap Write to Steam. In the game console (~) look
for "Handheld Ops controller file loaded".

Close Steam: next to Write to Steam. Steam is asked to close cleanly and
ended after 30 seconds if needed. Use it in Desktop Mode (in Gaming Mode
Steam is the whole screen, so the app refuses).

Controller override (CoD4 IW3SP-MOD, MW2 IW4x): tick Controller
override
on the game's page and Handheld Ops writes its own controller file
(handheld_pad.cfg, in the game's main folder) and loads it at every start,
so you set the bindings here and never touch the mod. Defaults are IW4x's
own: hold to aim, normal sticks. Pick from the dropdowns: Button layout
(Default, Tactical, Lefty, Nomad, Default Alt), Aim (hold or toggle), Sticks
(Default = left moves, right looks; Southpaw swaps them), Look speed, and
any single button. Put the defaults back undoes it; I edit the
file myself
keeps your hand-edited file. After tapping, press Write to
Steam
once, then start from Steam. Proof it loaded: open the game console
with ~, it prints "Handheld Ops controller file loaded". Controller
report
lists what the game saved and what Handheld Ops will start with
(also saved as a text file to send).

Left trigger latches aim on until pressed again / look feels heavy: the
Controller sticks card shows what the left trigger is bound to. Hold to
aim fix
(on by default) changes a toggle bind to hold. Look speed steps
x1, x1.5, x2, x3. Tap Write to Steam, then start from Steam.

Right stick works in menus but not in the game: first set Steam Input to
Xbox controller (CoD4 > Controller settings > Browse configs / choose the
Xbox controller layout). That is what fixed it on the Ally; the default
"controller" layout did not. If it is still dead: the view turns by the
stick times the game's turn speed settings, and 0 means no turning. The
Controller sticks card shows the saved values and Turn speed fix (on by
default) sets standard ones at every start. Tap Write to Steam, then start
from Steam. Still nothing: tell me what the card shows.

Right stick does nothing (left stick and buttons work): the sticks are
tied to moving and looking by bindaxis lines the game keeps in its profile
config (players/profiles/<name>/config.cfg). A config without right-stick
lines leaves the right stick dead. The Controller sticks card on the CoD4
page shows whether the right stick is bound, and Right stick fix (on by
default) adds IW4x's default lines for a stick with no binding at all (a
custom layout such as southpaw is kept); switched off it takes out
exactly the lines it added. It runs on Write to Steam, Start, and the button
itself:

bindaxis A_LSTICK_X VA_SIDE MAP_SQUARED bindaxis A_LSTICK_Y VA_FORWARD MAP_SQUARED bindaxis A_RSTICK_X VA_YAW MAP_LINEAR bindaxis A_RSTICK_Y VA_PITCH MAP_LINEAR 

0.4.2 also put these four on the start command line (+bindaxis ...), and
with 0.4.2 the controller stopped working altogether in IW3SP-MOD. 0.4.3 takes
them off the command line. Show last start log (Windows) shows the exact
command the game was started with.

Display: borderless window (Windows)

Display mode

Switching away (Alt+Tab) from these DirectX 9 games in exclusive fullscreen
can end in "DirectX encountered an unrecoverable error". On Windows the
default for IW4x is a borderless window at the locked resolution
(+set r_fullscreen 0 +set r_noborder 1 +set vid_xpos 0 +set vid_ypos 0),
which switches away cleanly. Tap Display to go back to fullscreen.

IW3SP-MOD (CoD4 campaign) starts in fullscreen by default (0.4.2+).
Started borderless it opened as a 1280x720 window in the top-left corner
whatever the locked resolution was. Borderless can still be picked for it
(Display button) to test. If Alt+Tab crashes CoD4 in fullscreen, avoid
switching away in game for now. Stock games keep fullscreen (they have no
borderless mode).

Safety

  • MW2 campaign / Special Ops: play offline only. IW-Pad warns that the Steam build's singleplayer still has remote-code-execution holes. The app shows this before installing.
  • IW4x is about 800 MB; the app checks free space first.

The look (Linux)

Look tab

  1. Pick a graphics tier on each game's page (see Graphics tiers above).
  2. Press Write to Steam so the Play button uses that game's vkBasalt file.
  3. In game, Home switches the effects off and on.

On Windows, use the normal ReShade installer (all three
games are DirectX 9).

On Windows

Handheld Ops runs on Windows too (tested so far only by pretending, on Linux;
see Known limitations). The differences:

  • Steam's Play button starts the mod through a small Handheld Ops launcher ("pythonw.exe" "...\steam-launch.pyw" %command%, no console window). It starts the mod for the right mode (e.g. CoD4 Singleplayer -> IW3SP-MOD) and the stock game otherwise (CoD4 Multiplayer). Because Steam started it, Steam Input can turn any controller into an Xbox pad, which is what IW3SP-MOD and IW4x read. The desktop / Start menu shortcuts start the mod directly (fine for Xbox-style pads).
  • The resolution lock still works from Steam: "Write to Steam" (Steam closed) sets each game's launch option to +set r_mode 1920x1080 +set r_fullscreen 1, which Steam adds to the game's command line. The Start buttons and shortcuts pass the same, and the config files are set too.
  • Look: vkBasalt is Linux-only, so the Look tab installs ReShade from reshade.me with just the essentials (see Graphics tiers).

Look tab on Windows

Touchscreen

Help tab

  • Steam Gaming Mode: a tap is a left mouse click where you touched.
  • If taps do nothing: hold the Armoury Crate button for Mouse Mode.
  • Desktop Mode: the touchscreen is a normal mouse.

Command line

HandheldOps-Linux.sh --list HandheldOps-Linux.sh --install iw3sp # also: iwpad, iw4x, bo1-gamepad HandheldOps-Linux.sh --remove iw4x HandheldOps-Linux.sh --install bo1-gamepad --aim-slowdown HandheldOps-Linux.sh --get-shaders --look sweetfx --look-for mw2 HandheldOps-Linux.sh --screen mw2=1920x1080 # or 2560x1440, 3840x2160, off HandheldOps-Linux.sh --steam cod4 --steam mw2 # resolution + launch options (Steam closed) HandheldOps-Linux.sh --tier mw2=quality # off, battery, balanced, quality, ultra HandheldOps-Linux.sh --put-back bo1 # undo removed conflicts HandheldOps-Windows.bat --display mw2=borderless # or fullscreen HandheldOps-Linux.sh --stick-fix cod4=off # take the stick lines out (on = add) HandheldOps-Linux.sh --look-speed 1.25 # Black Ops gamepad look speed (experimental) HandheldOps-Linux.sh --show-options HandheldOps-Windows.bat --reshade mw2 # Windows: official ReShade setup on MW2 HandheldOps-Windows.bat --shortcuts cod4 # Windows: shortcuts for installed mods HandheldOps-Linux.sh --game-dir "/path/to/Call of Duty 4" --list HandheldOps-Linux.sh --ui web # the web page (also: gui, dialogs, text) HandheldOps-Linux.sh --version 

What exists and what doesn't

Part State
Finds the three games in every Steam library (SD card too) Works on test data
Black Ops controller ON/OFF, backups, undo Works on test data
IW-Pad install / update / remove Real download and install done (simulated MW2 folder)
IW4x install / update / remove from its update.json manifests Real 787 MB install, no-change update and full removal done (simulated MW2 folder)
IW3SP-MOD install / update / remove Works against a stand-in server; the real host (gitea.com) is blocked from the build machine
CoD4x Steps + official page only
Writing Steam launch options Works on a test copy of Steam's file; exe swap checked in bash
Resolution lock (configs + launch option) Works on test configs; arguments checked in bash to reach the game after the exe swap; not yet seen in the real games
Look (vkBasalt) presets Loaded by real vkBasalt on software Vulkan
Graphics tiers (Linux) All four vkBasalt files loaded by real vkBasalt with the real SweetFX shaders; values read in; game-setting changes tested on Black Ops-style configs
Graphics tiers (Windows ReShade preset) Preset and ReShade.ini format taken from ReShade's source; tested against sample files; not yet seen in ReShade itself
Windows Steam launcher (mod via Play, Steam Input) The launcher script run end to end with stand-in .exe files: SP starts the mod with its settings, MP stays stock; Steam Input through it not yet seen on Windows
Borderless window (IW4x / IW3SP-MOD) r_noborder confirmed in IW4x's source; not yet seen in IW4x. IW3SP-MOD: tried on Windows, opened at 1280x720 in a corner, so it defaults to fullscreen
Controller override file (handheld_pad.cfg + +exec) Written, rewritten and kept when hand-edited, and the launch option only when ticked, all tested; the file name and main folder are what CoD4 normally searches, not yet seen loading in the game
IW3SP-MOD turn speed (in-game look) Values are the usual console ones; added as +set, skipped when the config has a value above zero; not yet seen in the game
IW3SP-MOD stick bindings (right stick) Names taken from IW4x's source and its thumbstick_default.cfg; config add/take-out tested on sample files. 0.4.2 (lines in the config and on the command line) left the controller dead on Windows; 0.4.3 uses the config only, not yet seen in the game
Removing conflicts (autoexec-style files, ReShade overrides, old launch options) and Put back Tested on sample files; byte-for-byte put back
Existing ReShade kept, exact restore Tested with a full existing install (DLL, own preset, effect package): nothing overwritten, ReShade.ini restored byte for byte
ReShade essentials install (headless setup + 10 files) Headless behaviour read from ReShade's setup source; the 10 files downloaded for real; SweetFX SMAA compiled through vkBasalt; headless setup not yet run on Windows
Aim feel: vsync off / look speed Written; effect on the feel not yet tested
SweetFX shader download Real download with git done; the zip route (no git) works against a stand-in server
Windows: resolution launch option, Start buttons, shortcuts, ReShade setup Logic tested on Linux by pretending to be Windows; not yet run on Windows (reshade.me and GitHub zip links are blocked from the build machine)
Tested on a real ROG Ally / with the real games Not yet
HD textures, new lighting Back burner (see RESEARCH.md)

More

Source code: The-Dorkknight/handheld-ops on GitHub