Fix monitor resolution issue with correct monitor detection
Build check / build (push) Has been cancelled
Build check / build (push) Has been cancelled
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "octo-launcher",
|
"name": "octo-launcher",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "An Electron application for launching and updating the OctoWoW client",
|
"description": "An Electron application for launching and updating the OctoWoW client",
|
||||||
"author": "OctoWoW",
|
"author": "OctoWoW",
|
||||||
"copyright": "Copyright © 2026 OctoWoW",
|
"copyright": "Copyright © 2026 OctoWoW",
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import os from 'node:os';
|
||||||
|
import { spawn } from 'node:child_process';
|
||||||
|
|
||||||
|
import Logger from 'electron-log/main';
|
||||||
|
|
||||||
|
const SCRIPT = [
|
||||||
|
'$ErrorActionPreference = "Stop"',
|
||||||
|
"Add-Type -TypeDefinition @'",
|
||||||
|
'using System;',
|
||||||
|
'using System.Runtime.InteropServices;',
|
||||||
|
'public static class VmmfDisplays {',
|
||||||
|
' [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]',
|
||||||
|
' public struct DISPLAY_DEVICE {',
|
||||||
|
' public int cb;',
|
||||||
|
' [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)] public string DeviceName;',
|
||||||
|
' [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] public string DeviceString;',
|
||||||
|
' public int StateFlags;',
|
||||||
|
' [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] public string DeviceID;',
|
||||||
|
' [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] public string DeviceKey;',
|
||||||
|
' }',
|
||||||
|
' [DllImport("user32.dll", EntryPoint="EnumDisplayDevicesA", CharSet=CharSet.Ansi)]',
|
||||||
|
' public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);',
|
||||||
|
'}',
|
||||||
|
"'@",
|
||||||
|
'$dd = New-Object VmmfDisplays+DISPLAY_DEVICE',
|
||||||
|
'$dd.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($dd)',
|
||||||
|
'for ($i = 0; [VmmfDisplays]::EnumDisplayDevices([NullString]::Value, $i, [ref]$dd, 0); $i++) {',
|
||||||
|
' if ($dd.StateFlags -band 4) { Write-Output $i; exit 0 }',
|
||||||
|
'}',
|
||||||
|
'exit 1'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
export const detectPrimaryDisplayIndex = (): Promise<number> => {
|
||||||
|
if (os.platform() !== 'win32') return Promise.resolve(0);
|
||||||
|
|
||||||
|
const encoded = Buffer.from(SCRIPT, 'utf16le').toString('base64');
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
let settled = false;
|
||||||
|
const finish = (index: number) => {
|
||||||
|
if (settled) return;
|
||||||
|
settled = true;
|
||||||
|
clearTimeout(timer);
|
||||||
|
resolve(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
const child = spawn(
|
||||||
|
'powershell.exe',
|
||||||
|
['-NoProfile', '-NonInteractive', '-EncodedCommand', encoded],
|
||||||
|
{ windowsHide: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
child.kill();
|
||||||
|
Logger.warn('Primary display detection timed out');
|
||||||
|
finish(0);
|
||||||
|
}, 8000);
|
||||||
|
|
||||||
|
let stdout = '';
|
||||||
|
child.stdout.on('data', d => (stdout += String(d)));
|
||||||
|
child.on('error', e => {
|
||||||
|
Logger.warn('Primary display detection failed to launch PowerShell', e);
|
||||||
|
finish(0);
|
||||||
|
});
|
||||||
|
child.on('exit', code => {
|
||||||
|
const index = Number(stdout.trim());
|
||||||
|
if (code === 0 && Number.isInteger(index) && index >= 0) {
|
||||||
|
Logger.info(`Detected primary display at device index ${index}`);
|
||||||
|
finish(index);
|
||||||
|
} else {
|
||||||
|
Logger.warn('Primary display detection failed, defaulting to 0');
|
||||||
|
finish(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -13,6 +13,7 @@ import Preferences from './preferences';
|
|||||||
import Observable from './observable';
|
import Observable from './observable';
|
||||||
import Updater from './updater';
|
import Updater from './updater';
|
||||||
import { addDll, removeDll } from './dllsTxt';
|
import { addDll, removeDll } from './dllsTxt';
|
||||||
|
import { detectPrimaryDisplayIndex } from './displays';
|
||||||
|
|
||||||
const MOD_DOWNLOAD_TIMEOUT_MS = 60_000;
|
const MOD_DOWNLOAD_TIMEOUT_MS = 60_000;
|
||||||
|
|
||||||
@@ -113,8 +114,10 @@ class ModsClass extends Observable<ModsStatus> {
|
|||||||
if (clientDir) {
|
if (clientDir) {
|
||||||
const vmmfDll = path.join(clientDir, 'VanillaMultiMonitorFix.dll');
|
const vmmfDll = path.join(clientDir, 'VanillaMultiMonitorFix.dll');
|
||||||
const vmmfCfg = path.join(clientDir, 'VMMFix_preferred_monitor.txt');
|
const vmmfCfg = path.join(clientDir, 'VMMFix_preferred_monitor.txt');
|
||||||
if ((await fs.pathExists(vmmfDll)) && !(await fs.pathExists(vmmfCfg)))
|
if ((await fs.pathExists(vmmfDll)) && !(await fs.pathExists(vmmfCfg))) {
|
||||||
await fs.writeFile(vmmfCfg, '0\n', 'utf8').catch(() => {});
|
const index = await detectPrimaryDisplayIndex();
|
||||||
|
await fs.writeFile(vmmfCfg, `${index}\n`, 'utf8').catch(() => {});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const m of MODS) {
|
for (const m of MODS) {
|
||||||
|
|||||||
Reference in New Issue
Block a user