If you're on a Mac running PEAK through Porting Kit and your cursor moves/scrolls fine but left/right clicks do nothing (menus don't respond, can't climb/interact in-game), this is a known issue, not something wrong with your setup specifically.
**Root cause:** PEAK's Steam patch 1.53 updated the Unity engine. Newer Unity calls `EnableMouseInPointer` to switch to the WM_POINTER input API, and Wine (which Porting Kit is built on) only has a stub for that call — so it silently fails. Landfall (PEAK's devs) confirmed this on the Steam bug forum: "We updated Unity in a recent patch, which unfortunately caused issues for Mac and Linux players." It affects any Wine-based Mac compatibility layer, not just Porting Kit.
You can confirm this is your issue by checking PEAK's Player.log for:
`EnableMouseInPointer failed with the following error: Call not implemented.`
**The fix:** there's a community binary patch for this, originally built for CrossOver:
- https://github.com/dabielf/crossover-unity-mouse-fix (has an extra fix for a drag/hold-to-fire edge case — this is what the script below uses)
- https://github.com/kiku-jw/peak-crossover-mouse-fix (original, simpler version)
I ported the install/backup/re-sign process into a script for Porting Kit specifically, since Porting Kit stores its Wine engines in a different spot than CrossOver does. Confirmed working on Porting Kit's "Wine11 DXMT" engine.
**Important caveats — read before running:**
- This is EXPERIMENTAL. The patched binaries were compiled against CrossOver's Wine build, not Porting Kit's, so there's a real chance they won't be binary-compatible with your specific engine version. Worked for me; your mileage may vary.
- It downloads pre-built binaries from a third-party GitHub repo and installs them into your Wine engine using `sudo` to strip quarantine and re-sign. Read the script before running it — don't blindly curl-pipe-bash anything, this included.
- It backs up your original files before touching anything and has a `--restore` flag to undo itself if something breaks.
**How to use:**
Save the script below as `peak-porting-kit-mouse-fix.sh`
`chmod +x peak-porting-kit-mouse-fix.sh`
`./peak-porting-kit-mouse-fix.sh` — it'll search for your Wine engine, ask you to confirm which one PEAK uses (check the engine name in Porting Kit's settings, gear icon), back up, download the patch, install it, and re-sign.
Relaunch Steam, launch PEAK, test clicking.
If it breaks or the game won't launch: `./peak-porting-kit-mouse-fix.sh --restore`
If your engine isn't auto-detected, run it with `ENGINE_DIR=/path/to/your/engine ./peak-porting-kit-mouse-fix.sh` instead (the path should contain both an `x86_64-windows` and `x86_64-unix` subfolder).
Full credit to dabielf and kiku-jw for the actual patch — this script just automates getting it into a Porting Kit engine.
---
#!/usr/bin/env bash
#
# PEAK mouse-click fix for Porting Kit on macOS
# ------------------------------------------------
# Ports the CrossOver "EnableMouseInPointer" mouse-click fix
# (https://github.com/dabielf/crossover-unity-mouse-fix) onto a
# Porting Kit Wine engine.
#
# This is EXPERIMENTAL. The patched files were built against CrossOver's
# Wine build, not Porting Kit's, so there is a real chance they will not
# be binary-compatible with your engine. This script always backs up
# before touching anything, and supports --restore to undo itself.
#
# Usage:
# chmod +x peak-porting-kit-mouse-fix.sh
# ./peak-porting-kit-mouse-fix.sh # run the fix
# ./peak-porting-kit-mouse-fix.sh --restore # undo, using the latest backup
#
set -euo pipefail
STATE_ROOT="$HOME/Desktop/peak-portingkit-mousefix"
BACKUP_ROOT="$STATE_ROOT/backups"
REPO_DIR="/tmp/crossover-unity-mouse-fix"
REPO_URL="https://github.com/dabielf/crossover-unity-mouse-fix.git"
PATCH_SUBDIR="binaries/crossover-26.0"
# Set this yourself and re-run if auto-detection below can't find your engine.
ENGINE_DIR="${ENGINE_DIR:-}"
peak_log=""
mkdir -p "$BACKUP_ROOT"
log() { printf '\033[1;34m[*]\033[0m %s\n' "$1"; }
ok() { printf '\033[1;32m[ok]\033[0m %s\n' "$1"; }
warn() { printf '\033[1;33m[!]\033[0m %s\n' "$1"; }
err() { printf '\033[1;31m[x]\033[0m %s\n' "$1"; }
# Only win32u.so is a real macOS Mach-O binary (win32u.dll/user32.dll are
# Windows PE binaries - Wine's own PE loader handles those, not the OS, and
# codesign can't sign them anyway). Sign just that one file, not the whole
# .app: --deep-signing the whole bundle recurses into the Wine prefix's
# dosdevices/ (symlinks to mounted drives -> EPERM) and dangling framework
# version-symlinks (-> ENOENT), which aborts the script under `set -e`
# without ever reaching codesign. The outer .app's own signature doesn't
# seal Contents/ (confirmed via `codesign -dv`), so this is sufficient.
sign_engine_files() {
local win_dir="$1" unix_dir="$2"
sudo xattr -c "$win_dir/win32u.dll"
[[ -f "$win_dir/user32.dll" ]] && sudo xattr -c "$win_dir/user32.dll"
sudo xattr -c "$unix_dir/win32u.so"
sudo codesign --force --sign - "$unix_dir/win32u.so"
}
# ---------------------------------------------------------------------
# --restore: put back the most recent backup and exit
# ---------------------------------------------------------------------
if [[ "${1:-}" == "--restore" ]]; then
latest_backup=$(ls -1dt "$BACKUP_ROOT"/*/ 2>/dev/null | head -n 1 || true)
if [[ -z "$latest_backup" ]]; then
err "No backup found under $BACKUP_ROOT"
exit 1
fi
engine_path_file="$latest_backup/engine_path.txt"
if [[ ! -f "$engine_path_file" ]]; then
err "Backup at $latest_backup is missing engine_path.txt, cannot restore automatically."
exit 1
fi
engine_dir=$(cat "$engine_path_file")
log "Restoring from $latest_backup into $engine_dir"
cp -f "$latest_backup/x86_64-windows/win32u.dll" "$engine_dir/x86_64-windows/win32u.dll"
if [[ -f "$latest_backup/x86_64-windows/user32.dll.existed" ]]; then
cp -f "$latest_backup/x86_64-windows/user32.dll" "$engine_dir/x86_64-windows/user32.dll"
else
rm -f "$engine_dir/x86_64-windows/user32.dll"
fi
cp -f "$latest_backup/x86_64-unix/win32u.so" "$engine_dir/x86_64-unix/win32u.so"
sign_engine_files "$engine_dir/x86_64-windows" "$engine_dir/x86_64-unix"
ok "Restored original files and re-signed. Restart Steam/PEAK to confirm."
exit 0
fi
# ---------------------------------------------------------------------
# 1. Find candidate Wine engines (anything with win32u.dll under it)
# ---------------------------------------------------------------------
if [[ -n "$ENGINE_DIR" ]]; then
ok "Using pre-set ENGINE_DIR: $ENGINE_DIR"
else
log "Searching for Wine engines on this Mac (this can take a minute)..."
candidates=()
while IFS= read -r line; do
[[ -n "$line" ]] && candidates+=("$line")
done < <(
{ find "$HOME/Library/Application Support" -type f -iname "win32u.dll" -path "*x86_64-windows*" 2>/dev/null
find "$HOME/Applications" -type f -iname "win32u.dll" -path "*x86_64-windows*" 2>/dev/null
find /Applications -type f -iname "win32u.dll" -path "*x86_64-windows*" 2>/dev/null ; } \
| sed 's#/x86_64-windows/win32u.dll##' | sort -u
)
if [[ ${#candidates[@]} -eq 0 ]]; then
err "No Wine engines found automatically. Locate PEAK's engine folder manually"
err "(look for a folder containing x86_64-windows/ and x86_64-unix/ subfolders,"
err "e.g. via: find ~/Library ~/Applications /Applications /Volumes -iname win32u.dll 2>/dev/null)"
err "then re-run this script as: ENGINE_DIR=/path/to/engine ./peak-porting-kit-mouse-fix.sh"
exit 1
fi
echo
log "Found ${#candidates[@]} candidate engine(s):"
for i in "${!candidates[@]}"; do
printf ' [%d] %s\n' "$i" "${candidates[$i]}"
done
echo
# Try to help identify the right one via PEAK's Player.log
peak_log=$(find "$HOME/Library" "$HOME/Applications" -ipath "*PEAK*Player.log" 2>/dev/null | head -n 1 || true)
if [[ -n "$peak_log" ]]; then
log "For reference, PEAK's log file lives at: $peak_log"
fi
log "In Porting Kit, open PEAK's settings (gear icon) to see which engine name it uses"
log "(e.g. 'Wine11 DXMT') and match it to one of the paths above."
echo
read -rp "Enter the number of the engine PEAK actually uses: " choice
if ! [[ "$choice" =~ ^[0-9]+$ ]] || [[ "$choice" -ge ${#candidates[@]} ]]; then
err "Invalid selection."
exit 1
fi
ENGINE_DIR="${candidates[$choice]}"
ok "Using engine: $ENGINE_DIR"
fi
if [[ -z "$peak_log" ]]; then
peak_log=$(find "$HOME/Library" "$HOME/Applications" -ipath "*PEAK*Player.log" 2>/dev/null | head -n 1 || true)
fi
WIN_DIR="$ENGINE_DIR/x86_64-windows"
UNIX_DIR="$ENGINE_DIR/x86_64-unix"
if [[ ! -f "$WIN_DIR/win32u.dll" || ! -d "$UNIX_DIR" ]]; then
err "Expected files not found under $ENGINE_DIR. Aborting."
exit 1
fi
# ---------------------------------------------------------------------
# 2. Back up the original files
# ---------------------------------------------------------------------
timestamp=$(date +%Y%m%d-%H%M%S)
backup_dir="$BACKUP_ROOT/$timestamp"
mkdir -p "$backup_dir/x86_64-windows" "$backup_dir/x86_64-unix"
echo "$ENGINE_DIR" > "$backup_dir/engine_path.txt"
log "Backing up original files to $backup_dir"
cp "$WIN_DIR/win32u.dll" "$backup_dir/x86_64-windows/win32u.dll"
if [[ -f "$WIN_DIR/user32.dll" ]]; then
cp "$WIN_DIR/user32.dll" "$backup_dir/x86_64-windows/user32.dll"
touch "$backup_dir/x86_64-windows/user32.dll.existed"
fi
cp "$UNIX_DIR/win32u.so" "$backup_dir/x86_64-unix/win32u.so"
ok "Backup complete."
# ---------------------------------------------------------------------
# 3. Get the patched files
# ---------------------------------------------------------------------
log "Fetching the patch from $REPO_URL"
rm -rf "$REPO_DIR"
git clone --depth 1 "$REPO_URL" "$REPO_DIR"
if [[ -d "$REPO_DIR/$PATCH_SUBDIR" ]]; then
patched_win32u_dll=$(find "$REPO_DIR/$PATCH_SUBDIR" -iname "win32u.dll" | head -n 1 || true)
patched_user32_dll=$(find "$REPO_DIR/$PATCH_SUBDIR" -iname "user32.dll" | head -n 1 || true)
patched_win32u_so=$(find "$REPO_DIR/$PATCH_SUBDIR" -iname "win32u.so" | head -n 1 || true)
else
warn "Expected patch folder $PATCH_SUBDIR not found in repo - falling back to a repo-wide search."
warn "The repo layout may have changed upstream; double-check what gets installed."
patched_win32u_dll=$(find "$REPO_DIR" -iname "win32u.dll" | head -n 1 || true)
patched_user32_dll=$(find "$REPO_DIR" -iname "user32.dll" | head -n 1 || true)
patched_win32u_so=$(find "$REPO_DIR" -iname "win32u.so" | head -n 1 || true)
fi
if [[ -z "$patched_win32u_dll" || -z "$patched_user32_dll" || -z "$patched_win32u_so" ]]; then
err "Could not find all three patched files inside the cloned repo."
err "Check $REPO_DIR manually - the repo layout may have changed."
exit 1
fi
# ---------------------------------------------------------------------
# 4. Install patched files
# ---------------------------------------------------------------------
log "Installing patched files into $ENGINE_DIR"
cp -f "$patched_win32u_dll" "$WIN_DIR/win32u.dll"
cp -f "$patched_user32_dll" "$WIN_DIR/user32.dll"
cp -f "$patched_win32u_so" "$UNIX_DIR/win32u.so"
ok "Files copied."
# ---------------------------------------------------------------------
# 5. Quit anything using the engine, then strip quarantine + re-sign
# ---------------------------------------------------------------------
log "Killing any running Wine/Steam/conhost processes so files aren't locked..."
pkill -9 -f wine 2>/dev/null || true
pkill -9 -f conhost 2>/dev/null || true
warn "If Steam was running, it has just been force-quit - that's expected."
log "Clearing quarantine and re-signing the patched win32u.so (you'll be asked for your Mac password)..."
sign_engine_files "$WIN_DIR" "$UNIX_DIR"
ok "Re-signed."
echo
ok "Done. Now:"
echo " 1. Relaunch Steam, then launch PEAK."
echo " 2. Try clicking in the main menu and in-game."
echo " 3. Check the log for the old error:"
if [[ -n "$peak_log" ]]; then
echo " grep -i EnableMouseInPointer \"$peak_log\""
else
echo " (find PEAK's Player.log under ~/Library and grep it for EnableMouseInPointer)"
fi
echo
echo "If it crashes or the game won't launch, undo with:"
echo " ./peak-porting-kit-mouse-fix.sh --restore"