-
-
Save NaviVani-dev/9a8a704a31313fd5ed5fa68babf7bc3a to your computer and use it in GitHub Desktop.
| #!/bin/bash | |
| # a little script i made to open two gamescope sessions of steam | |
| # i SUCK at making bash script, so expect a lot of bugs or issues :< | |
| # made for arch linux in mind | |
| # you need another account on your device to use this | |
| # if u use pipewire and your audio is not working, take a look at this: | |
| # https://wiki.archlinux.org/title/PipeWire#Multi-user_audio_sharing | |
| # The gamescope params for both of the processes | |
| GAMESCOPE_PARAMS="-e -b -w 960 -h 360 -W 1440 -H 540" | |
| # Params for both steams | |
| STEAM_PARAMS="-gamepadui" | |
| # The secondary account you will use | |
| RUNAS_ACC="YOUR SECONDARY ACCOUNT" | |
| GAMESCOPE_BIN="/usr/bin/gamescope" | |
| RUNAS_BIN="/usr/bin/run-as" | |
| STEAM_BIN="/usr/bin/steam" | |
| CHANGED_DEVICES=() | |
| GAMESCOPE_PRIMARY_PID="" | |
| GAMESCOPE_SECONDARYPID="" | |
| # hiding kde panels using this: | |
| # https://github.com/luisbocanegra/plasma-panel-colorizer | |
| toggle_panels() { | |
| local state="$1" | |
| local value="false" | |
| if [ "$state" = "true" ]; then | |
| value="true" | |
| fi | |
| local status="string:stockPanelSettings.visible {\"enabled\": true, \"value\": $value}" | |
| dbus-send --session --type=signal /preset "luisbocanegra.panel.colorizer.all.property" "$status" | |
| } | |
| startup() { | |
| echo "Hiding the KDE panels!" | |
| toggle_panels "false" | |
| } | |
| cleanup() { | |
| echo "Showing the KDE panels again" | |
| toggle_panels "true" | |
| echo "Returning ownership to every device" | |
| return_devices_ownership | |
| if [[ -n "$GAMESCOPE_PRIMARY_PID" ]]; then | |
| echo "Killing primary gamescope..." | |
| kill -TERM "$GAMESCOPE_PRIMARY_PID" 2>/dev/null || true | |
| fi | |
| if [[ -n "$GAMESCOPE_SECONDARY_PID" ]]; then | |
| echo "Killing secondary gamescope..." | |
| kill -TERM "$GAMESCOPE_SECONDARY_PID" 2>/dev/null || true | |
| fi | |
| } | |
| show_devices_list() { | |
| local devices="" | |
| local name="" | |
| while IFS= read -r line; do | |
| if [[ $line == N:\ Name=* ]]; then | |
| name=$(echo "$line" | sed 's/N: Name=//' | tr -d '"') | |
| fi | |
| if [[ $line == *Handlers=* ]]; then | |
| local event_dev=$(echo "$line" | grep -o 'event[0-9]*' | sed 's/event//') | |
| if [[ -n $name && -n $event_dev ]]; then | |
| # aditional info 4 controllers | |
| local device_info="" | |
| if [[ $name == *"Xbox"* || $name == *"Controller"* || $name == *"Gamepad"* || $name == *"Joystick"* ]]; then | |
| device_info=" " | |
| elif [[ $name == *"Keyboard"* || $name == *"keyboard"* ]]; then | |
| device_info=" ⌨️" | |
| elif [[ $name == *"Mouse"* || $name == *"mouse"* ]]; then | |
| device_info=" " | |
| fi | |
| devices+="$event_dev - $name$device_info"$'\n' | |
| name="" | |
| fi | |
| fi | |
| done < /proc/bus/input/devices | |
| echo -e "$devices" | |
| } | |
| change_device_ownership() { | |
| local profile="$1" | |
| local device="$2" | |
| local device_path="/dev/input/event$device" | |
| sudo chown "$profile" "$device_path" | |
| sudo chmod 600 "$device_path" | |
| } | |
| get_devices_to_change() { | |
| local profile="$1" | |
| echo "Select the devices to transfer for the $profile profile:" | |
| show_devices_list | |
| echo "Please, input your device list divided by a comma (1,2,3,4,etc):" | |
| read input_string | |
| IFS=',' read -r -a NEW_DEVICES <<< "$input_string" | |
| CHANGED_DEVICES+=("${NEW_DEVICES[@]}") | |
| for device in "${NEW_DEVICES[@]}"; do | |
| change_device_ownership "$profile" "$device" | |
| done | |
| } | |
| return_devices_ownership() { | |
| for device in "${CHANGED_DEVICES[@]}"; do | |
| local device_path="/dev/input/event$device" | |
| sudo chown root:input "$device_path" "$device_path" | |
| sudo chmod 660 "$device_path" "$device_path" | |
| done | |
| } | |
| primary_gamescope() { | |
| eval "$GAMESCOPE_BIN $GAMESCOPE_PARAMS -- $STEAM_BIN $STEAM_PARAMS" | |
| GAMESCOPE_PRIMARY_PID=$! | |
| } | |
| secondary_gamescope() { | |
| eval "sudo $RUNAS_BIN -X $RUNAS_ACC -- env PULSE_SERVER=tcp:127.0.0.1:4713 $GAMESCOPE_BIN $GAMESCOPE_PARAMS -- $STEAM_BIN $STEAM_PARAMS" | |
| GAMESCOPE_SECONDARY_PID=$! | |
| } | |
| trap cleanup EXIT INT TERM | |
| main() { | |
| echo "DualScope by NaviVani " | |
| if [[ $EUID -eq 0 ]]; then | |
| echo "Running as sudo, exiting..." | |
| exit 1 | |
| fi | |
| for bin in "$GAMESCOPE_BIN" "$STEAM_BIN" "$RUNAS_BIN"; do | |
| if [[ ! -x "$bin" ]]; then | |
| echo "The $bin executable was not found, exiting..." | |
| exit 1 | |
| fi | |
| done | |
| get_devices_to_change "$(whoami)" | |
| get_devices_to_change "$RUNAS_ACC" | |
| echo "Killing steam before starting..." | |
| pkill steam | |
| while pgrep steam > /dev/null; do | |
| sleep 1 | |
| done | |
| startup | |
| echo "Opening gamescope sessions!" | |
| secondary_gamescope & | |
| primary_gamescope | |
| } | |
| main "$@" |
Hey! discovered your script and thought. Yes! that's an idea! so I took a few minutes and made it compatible with arch. I thought since it was your original idea ill give you my script based on yours. Free use for anyone. oh and fyi, managing input through system paths is stupid difficult with little pay off. It's easier to use steams controller isolation and simply disable input from that specific controller.
#!/usr/bin/env bash
DualScope (single-user, Garuda/Arch, two Steam instances)
Launch two Gamescope + Steam sessions with isolated runtimes.
set -euo pipefail
PRIMARY_W=1280
PRIMARY_H=720
SECONDARY_W=1280
SECONDARY_H=720
PRIMARY_RATE="60"
SECONDARY_RATE="60"
STEAM_PARAMS="-gamepadui"
GAMESCOPE_BIN="/usr/bin/gamescope"
STEAM_BIN="/usr/bin/steam"
COMMON_GAMESCOPE_FLAGS=(-e -b)
PRIMARY_PID=""
SECONDARY_PID=""
log() { printf "[DualScope] %s\n" "$*"; }
require_bin() {
local bin="$1"
if [[ ! -x "$bin" ]]; then
log "Missing binary: $bin"
exit 1
fi
}
cleanup() {
[[ -n "${PRIMARY_PID}" ]] && kill -TERM "${PRIMARY_PID}" 2>/dev/null || true
[[ -n "${SECONDARY_PID}" ]] && kill -TERM "${SECONDARY_PID}" 2>/dev/null || true
}
trap cleanup EXIT INT TERM
build_gs_args() {
local w="$1" h="$2" rate="${3:-}"
local args=("${COMMON_GAMESCOPE_FLAGS[@]}" -w "${w}" -h "${h}" -W "${w}" -H "${h}")
[[ -n "${rate}" ]] && args+=(-r "${rate}")
echo "${args[@]}"
}
launch_primary() {
local args
args=$(build_gs_args "${PRIMARY_W}" "${PRIMARY_H}" "${PRIMARY_RATE}")
log "Launching primary Steam..."
"${GAMESCOPE_BIN}" ${args} -- "${STEAM_BIN}" ${STEAM_PARAMS} &
PRIMARY_PID=$!
}
launch_secondary() {
local args
args=$(build_gs_args "${SECONDARY_W}" "${SECONDARY_H}" "${SECONDARY_RATE}")
log "Launching secondary Steam with isolated runtime..."
Create a separate runtime dir for the second instance
mkdir -p "$HOME/.steam-second"
HOME="$HOME/.steam-second" "${GAMESCOPE_BIN}" ${args} -- "${STEAM_BIN}" ${STEAM_PARAMS} &
SECONDARY_PID=$!
}
main() {
if [[ $EUID -eq 0 ]]; then
log "Do not run as root."
exit 1
fi
require_bin "${GAMESCOPE_BIN}"
require_bin "${STEAM_BIN}"
log "Launching two independent Steam+Gamescope sessions..."
launch_primary
sleep 1
launch_secondary
log "Primary PID: ${PRIMARY_PID}"
log "Secondary PID: ${SECONDARY_PID}"
wait "${PRIMARY_PID}" || true
wait "${SECONDARY_PID}" || true
}
main "$@"
Thanks for this script, I'm having one small issue though. I'm on Nobara Linux (copied over the run-as.py and enable_graphical_services.sh) and everything seems to work fine. But I can't lock input to specific users. As in, the controller controls both instances and the keyboard+Mouse control both instances as well. Any help would be appreciated.
I've been using AI to try to help me but it sends me down pointless rabbithole after pointless rabbithole, chasing my tail on things that didn't need fixing in the first place.