Skip to content

Instantly share code, notes, and snippets.

@peteristhegreat
Last active April 3, 2024 01:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peteristhegreat/888d34a0f4f5b710d9331023f5fbfb88 to your computer and use it in GitHub Desktop.
Save peteristhegreat/888d34a0f4f5b710d9331023f5fbfb88 to your computer and use it in GitHub Desktop.
Couch Play, Split Screen for Emulated Games, Retroarch + Nucleus Co-Op + AHK, Setup

Introduction

Running roms in an emulator can be a very nostalgic experience and something you want to share with the next generation or with friends.

Many of the better emulated games for older systems are single player.

Running multiple copies of an old single player game can make for a very enjoyable experience.

The Nucleus Co-Op project is fantastic at making games allow for couch-play, splitscreen, etc, for games that didn't design that into the PC versions of the game.

Maybe there will be a game guide + plugin for Nucleus Co-op at some point made specifically for retroarch. For now I am using some of the debugging tools it comes with to get retroarch to allow multiple instances all with focus and a separate controller for each.

Retroarch

https://www.retroarch.com/?page=platforms

Download and install for Windows.

Or use chocolatey to install choco install retroarch

For this tutorial we are installing to

C:/tools/RetroArch-Win64

Install a Core

Install a core such as for n64 or for gba.

  • Nintendo - Nintendo 64 (Mupen64Plus-Next)
  • Nintendo - Game Boy Advance (mGBA)

Install a rom

Get a rom from the internet for a game you or your family owns.

Put it in a predictable folder on your computer.

Create duplicates of the rom for each person that will be playing the single player game simultaneously.

Such as:

SinglePlayerGame.n64 (downloaded into your C:/roms/n64 folder)
cp SinglePlayerGame.n64 Alice-controller1-spg.n64
cp SinglePlayerGame.n64 Bob-controller2-spg.n64
cp SinglePlayerGame.n64 Charlie-controller3-spg.n64

Setup AutoSaving/AutoLoading

At some point this can probably be done directly by loading an additional config file... for now I change it thru the UI.

Context: Retroarch > Settings > Saving

  Increment Save State Index Automatically
    ON
  Auto Save State
    ON
  Load Save State Automatically
    ON
  Save State Thumbnails
    ON

AutoHotKey - AHK

https://www.autohotkey.com/download/

Download and install for Windows.

Or use chocolatey to install choco install autohotkey.install

AHK in this case is going to be used to toggle the WindowStyle to show the WindowTitle + Border or not.

Here is the script to do it when <Win> + W is pressed on the keyboard.

; FWT - Fullscreen window toggle
; https://autohotkey.com/boards/viewtopic.php?p=123166#p123166
FWT(hwnd:="") {
    static MONITOR_DEFAULTTONEAREST := 0x00000002
    static WS_CAPTION               := 0x00C00000
    static WS_SIZEBOX               := 0x00040000
    static WindowStyle              := WS_CAPTION|WS_SIZEBOX
    static A                        := []
    if (!hwnd)                    ; If no window handle is supplied, use the window under the mouse
        MouseGetPos,,, hwnd
    Win := "ahk_id " hwnd                                                          ; Store WinTitle
    WinGet, S, Style, % Win                                                      ; Get window style
    if (S & WindowStyle) {                                                      ; If not borderless
        A[Win, "Style"] := S & WindowStyle                                   ; Store existing style
        ; WinGet, IsMaxed, MinMax, % Win                  ; Get/store whether the window is maximized
        ; if (A[Win, "Maxed"] := IsMaxed = 1 ? true : false)
            ; WinRestore, % Win
        ; WinGetPos, X, Y, W, H, % Win                                   ; Store window size/location
        ; A[Win, "X"] := X, A[Win, "Y"] := Y, A[Win, "W"] := W, A[Win, "H"] := H
        WinSet, Style, % -WindowStyle, % Win                                       ; Remove borders
        ; hMon := DllCall("User32\MonitorFromWindow", "Ptr", hwnd, "UInt", MONITOR_DEFAULTTONEAREST)
        ; VarSetCapacity(monInfo, 40), NumPut(40, monInfo, 0, "UInt")
        ; DllCall("User32\GetMonitorInfo", "Ptr", hMon, "Ptr", &monInfo)
        ; WinMove, % Win,,  monLeft   := NumGet(monInfo,  4, "Int")          ; Move and resize window
                       ; ,  monTop    := NumGet(monInfo,  8, "Int")
                       ; , (monRight  := NumGet(monInfo, 12, "Int")) - monLeft
                       ; , (monBottom := NumGet(monInfo, 16, "Int")) - monTop
    }
    else if A[Win] {                                                                ; If borderless
        WinSet, Style, % "+" A[Win].Style, % Win                                  ; Reapply borders
        ; WinMove, % Win,, A[Win].X, A[Win].Y, A[Win].W, A[Win].H       ; Return to original position
        ; if (A[Win].Maxed)                                                    ; Maximize if required
            ; WinMaximize, % Win
        A.Delete(Win)
    }
}

#w::FWT(WinExist("A"))    ; Win+W to fullscreen the active window
!^w::FWT()                ; Ctrl+Alt+W to fullscreen the window under the mouse

Save the above script into borderless.ahk and double click on it. It now shows up in the system tray.

Proto Input

https://nucleus-coop.github.io/docs/protoinput/

Download and install Nucleus Coop and you should find a copy of ProtoInputHost.exe on your machine.

For this tutorial it is installed into

C:\nucleus\NucleusCo-op\ProtoInputHost.exe

Duplicate the RetroArch folder

While retroarch is closed, let's turn off the menu bar in the retroarch windowed mode in the retoarch.cfg file:

ui_menubar_enable = "false"

This can probably be done with a custom config getting loaded at runtime instead of putting some many copies of the entire folder... But I didn't know what things would have issues when running multiple copies... if there were any shared resources, etc or if it would stomp on some setting if I exited the programs out in a different order... So here goes.

cp C:/tools/RetroArch-Win64 C:/tools/RetroArch-Win64-1
cp C:/tools/RetroArch-Win64 C:/tools/RetroArch-Win64-2
cp C:/tools/RetroArch-Win64 C:/tools/RetroArch-Win64-3

Create some additional shortcuts for the retroarch.exe's in each of the new folders you made.

e.g.

C:/tools/"retroarch.exe - alice-controller1".lnk   # references RetroArch-Win64-1
C:/tools/"retroarch.exe - bob-controller2".lnk     # references RetroArch-Win64-2
C:/tools/"retroarch.exe - charlie-controller3".lnk # references RetroArch-Win64-3

Now modify 2 more settings in each of the retroarch.cfg files in each of the program folders.

# In RetroArch-Win64-1 aka alice-controller1 folder
input_player1_joypad_index = "1"
input_player2_joypad_index = "2"
input_player3_joypad_index = "3"


# In RetroArch-Win64-2 aka alice-controller2 folder
input_player1_joypad_index = "2"  # Note, swapped with player2
input_player2_joypad_index = "1"
input_player3_joypad_index = "3"


# In RetroArch-Win64-2 aka alice-controller3 folder
input_player1_joypad_index = "3"  # Note, swapped with player3
input_player2_joypad_index = "2"
input_player3_joypad_index = "1"

Now open 1 copy of each retroarch and turn on 3 controllers.

Open the rom named c:/roms/n64/Alice-controller1-spg.n64 in the first instance of retroarch.

Open the rom named c:/roms/n64/Bob-controller2-spg.n64 in the second instance of retroarch.

Open the rom named c:/roms/n64/Charlie-controller1-spg.n64 in the third instance of retoarch.

As each game loads, it freezes when the program loses focus. Also each windowed game has a title bar (but no menu bar).

Now open C:\nucleus\NucleusCo-op\ProtoInputHost.exe (or whereever you installed Nucleus Co-op.

Search for programs named retro. Select the three instances and click add.

You can leave the settings on default, but I like to see the cursor, so I change:

Context: Proto Input

    Launch
      Lock input with the End key
        (unchecked)
    Hooks
      Cursor Visibility
        (unchecked)
      Clip Cursor
        (unchecked)

Finally, click: Proto Input > Launch > Inject Instances (button)

Now each window can be repositioned manually and resized. After each window is in the right place, click one then press <Win> + W.

Now you have an awesome way to each kid in the room to play on the TV without needing N computers turned on and setup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment