mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-19 09:41:17 -07:00
feat(ui): add Windows clipboard image support and Alt+V paste workaround (#15218)
Co-authored-by: sgeraldes <sgeraldes@users.noreply.github.com>
This commit is contained in:
@@ -30,10 +30,24 @@ export const IMAGE_EXTENSIONS = [
|
||||
const PATH_PREFIX_PATTERN = /^([/~.]|[a-zA-Z]:|\\\\)/;
|
||||
|
||||
/**
|
||||
* Checks if the system clipboard contains an image (macOS only for now)
|
||||
* Checks if the system clipboard contains an image (macOS and Windows)
|
||||
* @returns true if clipboard contains an image
|
||||
*/
|
||||
export async function clipboardHasImage(): Promise<boolean> {
|
||||
if (process.platform === 'win32') {
|
||||
try {
|
||||
const { stdout } = await spawnAsync('powershell', [
|
||||
'-NoProfile',
|
||||
'-Command',
|
||||
'Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Clipboard]::ContainsImage()',
|
||||
]);
|
||||
return stdout.trim() === 'True';
|
||||
} catch (error) {
|
||||
debugLogger.warn('Error checking clipboard for image:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform !== 'darwin') {
|
||||
return false;
|
||||
}
|
||||
@@ -44,20 +58,21 @@ export async function clipboardHasImage(): Promise<boolean> {
|
||||
const imageRegex =
|
||||
/«class PNGf»|TIFF picture|JPEG picture|GIF picture|«class JPEG»|«class TIFF»/;
|
||||
return imageRegex.test(stdout);
|
||||
} catch {
|
||||
} catch (error) {
|
||||
debugLogger.warn('Error checking clipboard for image:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the image from clipboard to a temporary file (macOS only for now)
|
||||
* Saves the image from clipboard to a temporary file (macOS and Windows)
|
||||
* @param targetDir The target directory to create temp files within
|
||||
* @returns The path to the saved image file, or null if no image or error
|
||||
*/
|
||||
export async function saveClipboardImage(
|
||||
targetDir?: string,
|
||||
): Promise<string | null> {
|
||||
if (process.platform !== 'darwin') {
|
||||
if (process.platform !== 'darwin' && process.platform !== 'win32') {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -71,6 +86,40 @@ export async function saveClipboardImage(
|
||||
// Generate a unique filename with timestamp
|
||||
const timestamp = new Date().getTime();
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
const tempFilePath = path.join(tempDir, `clipboard-${timestamp}.png`);
|
||||
// The path is used directly in the PowerShell script.
|
||||
const psPath = tempFilePath.replace(/'/g, "''");
|
||||
|
||||
const script = `
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
if ([System.Windows.Forms.Clipboard]::ContainsImage()) {
|
||||
$image = [System.Windows.Forms.Clipboard]::GetImage()
|
||||
$image.Save('${psPath}', [System.Drawing.Imaging.ImageFormat]::Png)
|
||||
Write-Output "success"
|
||||
}
|
||||
`;
|
||||
|
||||
const { stdout } = await spawnAsync('powershell', [
|
||||
'-NoProfile',
|
||||
'-Command',
|
||||
script,
|
||||
]);
|
||||
|
||||
if (stdout.trim() === 'success') {
|
||||
try {
|
||||
const stats = await fs.stat(tempFilePath);
|
||||
if (stats.size > 0) {
|
||||
return tempFilePath;
|
||||
}
|
||||
} catch {
|
||||
// File doesn't exist
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// AppleScript clipboard classes to try, in order of preference.
|
||||
// macOS converts clipboard images to these formats (WEBP/HEIC/HEIF not supported by osascript).
|
||||
const formats = [
|
||||
|
||||
Reference in New Issue
Block a user