From 6b0c2ca0ae7a704bbf48094c6d6441905192a8e3 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 16 Apr 2026 01:27:22 +0300 Subject: [PATCH] fix: Cyrillic window titles garbled in device list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PowerShell on Russian Windows outputs text in CP1251/CP866 by default. Node.js reads stdout as UTF-8 → Cyrillic becomes mojibake. Fix: force UTF-8 output at the start of every PowerShell command: [Console]::OutputEncoding = [System.Text.Encoding]::UTF8; $OutputEncoding = [System.Text.Encoding]::UTF8; Receive stdout as raw Buffer (encoding:'buffer'), strip UTF-8 BOM if present, then decode explicitly with .toString('utf8'). Also fixed runCommand() to collect chunks into Buffer arrays and decode as UTF-8 (FFmpeg always outputs UTF-8 regardless of locale). Co-Authored-By: Claude Sonnet 4.6 --- electron/devices.js | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/electron/devices.js b/electron/devices.js index cc6ff3a..8f52005 100644 --- a/electron/devices.js +++ b/electron/devices.js @@ -22,21 +22,31 @@ function getFfmpegPath() { function runCommand(cmd, args, timeoutMs = 10000) { return new Promise((resolve) => { const proc = spawn(cmd, args, { stdio: ['pipe', 'pipe', 'pipe'] }) - let stdout = '', stderr = '' - proc.stdout.on('data', d => stdout += d) - proc.stderr.on('data', d => stderr += d) - proc.on('close', () => resolve({ stdout, stderr })) + const outBufs = [], errBufs = [] + proc.stdout.on('data', d => outBufs.push(d)) + proc.stderr.on('data', d => errBufs.push(d)) + const finish = () => { + // FFmpeg outputs UTF-8; on Russian Windows system tools may use CP1251, + // but FFmpeg is always UTF-8 — safe to decode as utf8 here. + const stdout = Buffer.concat(outBufs).toString('utf8') + const stderr = Buffer.concat(errBufs).toString('utf8') + resolve({ stdout, stderr }) + } + proc.on('close', finish) proc.on('error', () => resolve({ stdout: '', stderr: '' })) - setTimeout(() => { try { proc.kill() } catch {} ; resolve({ stdout, stderr }) }, timeoutMs) + setTimeout(() => { try { proc.kill() } catch {} }, timeoutMs) }) } // ─── Windows — enumerate application windows via PowerShell ─────────────────── -// Uses execFile to pass arguments as array → no quoting/escaping issues +// KEY: force UTF-8 output BEFORE any text is written, receive as Buffer, +// then decode as UTF-8 — this fixes Cyrillic/Unicode window titles on Russian Windows. function getWindowsWindowsList() { return new Promise((resolve) => { - // Each line: "WindowTitle|||ProcessName" + // Force UTF-8 console output so Node receives proper Unicode const ps1 = [ + '[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;', + '$OutputEncoding = [System.Text.Encoding]::UTF8;', 'Get-Process', '| Where-Object { $_.MainWindowTitle -ne "" }', '| Sort-Object MainWindowTitle', @@ -46,9 +56,17 @@ function getWindowsWindowsList() { execFile( 'powershell.exe', ['-NonInteractive', '-NoProfile', '-WindowStyle', 'Hidden', '-Command', ps1], - { timeout: 8000, windowsHide: true }, - (err, stdout) => { - if (err || !stdout) { resolve([]); return } + // encoding: 'buffer' — receive raw bytes, we decode manually as UTF-8 + { timeout: 8000, windowsHide: true, encoding: 'buffer' }, + (err, stdoutBuf) => { + if (err || !stdoutBuf || !stdoutBuf.length) { resolve([]); return } + + // Decode the buffer as UTF-8 (PowerShell wrote UTF-8 BOM-less) + // Strip UTF-8 BOM if present (EF BB BF) + let buf = stdoutBuf + if (buf[0] === 0xEF && buf[1] === 0xBB && buf[2] === 0xBF) buf = buf.slice(3) + const stdout = buf.toString('utf8') + const wins = stdout.trim().split('\n') .map(l => l.trim().replace(/\r$/, '')) .filter(Boolean)