fix: Cyrillic window titles garbled in device list
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 <noreply@anthropic.com>
This commit is contained in:
+28
-10
@@ -22,21 +22,31 @@ function getFfmpegPath() {
|
|||||||
function runCommand(cmd, args, timeoutMs = 10000) {
|
function runCommand(cmd, args, timeoutMs = 10000) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const proc = spawn(cmd, args, { stdio: ['pipe', 'pipe', 'pipe'] })
|
const proc = spawn(cmd, args, { stdio: ['pipe', 'pipe', 'pipe'] })
|
||||||
let stdout = '', stderr = ''
|
const outBufs = [], errBufs = []
|
||||||
proc.stdout.on('data', d => stdout += d)
|
proc.stdout.on('data', d => outBufs.push(d))
|
||||||
proc.stderr.on('data', d => stderr += d)
|
proc.stderr.on('data', d => errBufs.push(d))
|
||||||
proc.on('close', () => resolve({ stdout, stderr }))
|
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: '' }))
|
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 ───────────────────
|
// ─── 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() {
|
function getWindowsWindowsList() {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
// Each line: "WindowTitle|||ProcessName"
|
// Force UTF-8 console output so Node receives proper Unicode
|
||||||
const ps1 = [
|
const ps1 = [
|
||||||
|
'[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;',
|
||||||
|
'$OutputEncoding = [System.Text.Encoding]::UTF8;',
|
||||||
'Get-Process',
|
'Get-Process',
|
||||||
'| Where-Object { $_.MainWindowTitle -ne "" }',
|
'| Where-Object { $_.MainWindowTitle -ne "" }',
|
||||||
'| Sort-Object MainWindowTitle',
|
'| Sort-Object MainWindowTitle',
|
||||||
@@ -46,9 +56,17 @@ function getWindowsWindowsList() {
|
|||||||
execFile(
|
execFile(
|
||||||
'powershell.exe',
|
'powershell.exe',
|
||||||
['-NonInteractive', '-NoProfile', '-WindowStyle', 'Hidden', '-Command', ps1],
|
['-NonInteractive', '-NoProfile', '-WindowStyle', 'Hidden', '-Command', ps1],
|
||||||
{ timeout: 8000, windowsHide: true },
|
// encoding: 'buffer' — receive raw bytes, we decode manually as UTF-8
|
||||||
(err, stdout) => {
|
{ timeout: 8000, windowsHide: true, encoding: 'buffer' },
|
||||||
if (err || !stdout) { resolve([]); return }
|
(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')
|
const wins = stdout.trim().split('\n')
|
||||||
.map(l => l.trim().replace(/\r$/, ''))
|
.map(l => l.trim().replace(/\r$/, ''))
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
|
|||||||
Reference in New Issue
Block a user