132 lines
3.7 KiB
JavaScript
132 lines
3.7 KiB
JavaScript
const { spawn } = require('child_process');
|
|
const logger = require('../../utils/logger');
|
|
|
|
const CLIPBOARD_THRESHOLD = 500 * 1024;
|
|
|
|
class ClipboardService {
|
|
constructor() {
|
|
this.threshold = CLIPBOARD_THRESHOLD;
|
|
}
|
|
|
|
async read() {
|
|
return new Promise((resolve, reject) => {
|
|
const psCode = `
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
Add-Type -AssemblyName System.Drawing
|
|
|
|
if ([Windows.Forms.Clipboard]::ContainsText()) {
|
|
$text = [Windows.Forms.Clipboard]::GetText()
|
|
Write-Output "TYPE:TEXT"
|
|
Write-Output $text
|
|
} elseif ([Windows.Forms.Clipboard]::ContainsImage()) {
|
|
$image = [Windows.Forms.Clipboard]::GetImage()
|
|
if ($image -ne $null) {
|
|
$ms = New-Object System.IO.MemoryStream
|
|
$image.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)
|
|
$bytes = $ms.ToArray()
|
|
$base64 = [Convert]::ToBase64String($bytes)
|
|
Write-Output "TYPE:IMAGE"
|
|
Write-Output $base64
|
|
}
|
|
} else {
|
|
Write-Output "TYPE:EMPTY"
|
|
}
|
|
`;
|
|
|
|
const ps = spawn('powershell', ['-NoProfile', '-Command',
|
|
'[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; ' + psCode
|
|
], { encoding: 'utf8' });
|
|
let output = '';
|
|
|
|
ps.stdout.on('data', (data) => {
|
|
output += data.toString();
|
|
});
|
|
|
|
ps.stderr.on('data', (data) => {
|
|
logger.error('Clipboard read error', { error: data.toString() });
|
|
});
|
|
|
|
ps.on('close', () => {
|
|
const lines = output.trim().split('\n');
|
|
const typeLine = lines[0];
|
|
|
|
if (typeLine && typeLine.includes('TYPE:TEXT')) {
|
|
const text = lines.slice(1).join('\n');
|
|
resolve({
|
|
type: 'text',
|
|
data: text,
|
|
size: Buffer.byteLength(text, 'utf8')
|
|
});
|
|
} else if (typeLine && typeLine.includes('TYPE:IMAGE')) {
|
|
const base64 = lines.slice(1).join('');
|
|
const size = Math.ceil(base64.length * 0.75);
|
|
resolve({
|
|
type: 'image',
|
|
data: base64,
|
|
size: size
|
|
});
|
|
} else {
|
|
resolve({ type: 'empty', data: null, size: 0 });
|
|
}
|
|
});
|
|
|
|
ps.on('error', (err) => {
|
|
logger.error('Clipboard read failed', { error: err.message });
|
|
resolve({ type: 'empty', data: null, size: 0 });
|
|
});
|
|
});
|
|
}
|
|
|
|
async set(content) {
|
|
return new Promise((resolve, reject) => {
|
|
let psCode;
|
|
|
|
if (content.type === 'text') {
|
|
const escapedText = content.data
|
|
.replace(/'/g, "''")
|
|
.replace(/\r\n/g, '`r`n')
|
|
.replace(/\n/g, '`n');
|
|
psCode = `
|
|
$OutputEncoding = [Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
[Windows.Forms.Clipboard]::SetText('${escapedText}')
|
|
Write-Output "SUCCESS"
|
|
`;
|
|
} else if (content.type === 'image') {
|
|
psCode = `
|
|
$OutputEncoding = [Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
Add-Type -AssemblyName System.Drawing
|
|
$bytes = [Convert]::FromBase64String('${content.data}')
|
|
$ms = New-Object System.IO.MemoryStream(,$bytes)
|
|
$image = [System.Drawing.Image]::FromStream($ms)
|
|
[Windows.Forms.Clipboard]::SetImage($image)
|
|
Write-Output "SUCCESS"
|
|
`;
|
|
} else {
|
|
resolve(false);
|
|
return;
|
|
}
|
|
|
|
const ps = spawn('powershell', ['-NoProfile', '-Command', psCode]);
|
|
let output = '';
|
|
|
|
ps.stdout.on('data', (data) => {
|
|
output += data.toString();
|
|
});
|
|
|
|
ps.on('close', () => {
|
|
resolve(output.includes('SUCCESS'));
|
|
});
|
|
|
|
ps.on('error', () => resolve(false));
|
|
});
|
|
}
|
|
|
|
isSmallContent(size) {
|
|
return size <= this.threshold;
|
|
}
|
|
}
|
|
|
|
module.exports = ClipboardService;
|