Skip to content

Clipboard & Shell

This content is not available in your language yet.

Electron clipboard.* / shell.* 호환 API. Frontend JS + Zig/Rust/Go/Node 백엔드 SDK 모두 노출된다.

APImacOSLinuxWindows
clipboard.readText/writeText/clear✅ NSPasteboard✅ GTK clipboard text✅ Win32 CF_UNICODETEXT
clipboard.readHTML/writeHTML✅ NSPasteboard public.html✅ GTK text/html target✅ Win32 CF_HTML (HTML Format)
shell.openExternal✅ NSWorkspace + URL scheme 검사✅ GIO default URI handler✅ ShellExecuteW + scheme 검사
shell.openPath✅ NSWorkspace file://✅ GIO file URI default handler✅ ShellExecuteW
shell.showItemInFolder✅ activateFileViewerSelectingURLs: + 사전 fileExistsAtPath:✅ FileManager1 D-Bus ShowItems✅ explorer.exe /select
shell.beep✅ NSBeep✅ GDK display beep✅ MessageBeep
shell.trashItem✅ NSFileManager Trash✅ GIO g_file_trash✅ SHFileOperationW

Linux는 GTK clipboard text/HTML target과 GIO default URI handler/file URI/Trash, FileManager1 D-Bus, GDK beep 경로를 사용한다. Windows는 plain text에는 CF_UNICODETEXT, HTML에는 Win32 HTML Format (CF_HTML) 오프셋 헤더를 사용하고, shell API는 ShellExecute/explorer/MessageBeep/SHFileOperation 계열을 사용한다. RTF/image/buffer 같은 clipboard 확장 format은 아직 macOS 중심이며, 미지원 format은 graceful 응답 (success: false / 빈 값)으로 떨어진다.

import { clipboard } from '@suji/api';
await clipboard.readText(); // → string (빈 문자열이면 클립보드 빔)
await clipboard.writeText(text); // → boolean (성공 여부)
await clipboard.clear(); // → boolean
const r = suji.clipboard.readText(); // ?[]const u8 — raw JSON
const r = suji.clipboard.writeText("hi");
const r = suji.clipboard.clear();
let r = suji::clipboard::read_text(); // Option<String>
let r = suji::clipboard::write_text("hi");
let r = suji::clipboard::clear();

Go 백엔드 (github.com/ohah/suji-go/clipboard)

섹션 제목: “Go 백엔드 (github.com/ohah/suji-go/clipboard)”
import "github.com/ohah/suji-go/clipboard"
text := clipboard.ReadText()
clipboard.WriteText("hi")
clipboard.Clear()
import { clipboard } from '@suji/node';
await clipboard.readText();
await clipboard.writeText("hi");
await clipboard.clear();
import { shell } from '@suji/api';
await shell.openExternal("https://example.com"); // → boolean
await shell.showItemInFolder("/tmp/file.txt"); // → boolean (경로 존재해야 true)
await shell.beep(); // → boolean
await shell.trashItem("/tmp/file.txt"); // → boolean
suji.shell.openExternal("https://...");
suji.shell.showItemInFolder("/path");
suji.shell.beep();
suji.shell.trashItem("/path");
suji::shell::open_external("https://...");
suji::shell::show_item_in_folder("/path");
suji::shell::beep();
suji::shell::trash_item("/path");
import "github.com/ohah/suji-go/shell"
shell.OpenExternal("https://...")
shell.ShowItemInFolder("/path")
shell.Beep()
shell.TrashItem("/path")
import { shell } from '@suji/node';
await shell.openExternal("https://...");
await shell.showItemInFolder("/path");
await shell.beep();
await shell.trashItem("/path");

URL 검증 단계:

  1. JSON unescape → text.len + 1 > 4096이면 false 즉시 (path 한도)
  2. scheme 존재/문법 검사 — 빈 scheme 또는 control char 포함이면 false
  3. macOS: NSURL.URLWithString + NSWorkspace.openURL
  4. Linux: GIO g_app_info_launch_default_for_uri
  5. Windows: ShellExecuteW("open", url); scheme 없는 상대 입력과 control char는 사전 차단

scheme 없는 input("noschemejustwords" 같은 relative URL)은 사전 차단 — URLWithString이 relative URL을 통과시켜 그대로 openURL/ShellExecuteW에 보내면 OS가 원치 않는 dialog나 path 추측을 할 수 있어 회피한다.

  1. 존재하지 않는 path는 false
  2. macOS/Windows: 시스템 기본 앱으로 path를 open
  3. Linux: GFile 존재 검증 → file:// URI 변환 → GIO default application launch

등록된 기본 앱이 없거나 desktop environment가 launch를 거부하면 false.

  1. 존재하지 않는 path는 false
  2. macOS: NSURL.fileURLWithPath: + NSArray.arrayWithObject:NSWorkspace.activateFileViewerSelectingURLs: (modern API. selectFile:inFileViewerRootedAtPath:은 deprecated)
  3. Linux: GFile 존재 검증 → file:// URI 변환 → session D-Bus org.freedesktop.FileManager1.ShowItems
  4. Windows: path 존재 검증 후 explorer.exe /select,"<path>"ShellExecuteW로 실행

Linux에서 FileManager1 서비스가 없거나 D-Bus 호출이 실패하면 false.

  • macOS: NSBeep() 직접 호출 — AppKit C symbol
  • Linux: gdk_display_beep(gdk_display_get_default())
  • Windows: MessageBeep(MB_OK)

동기 호출이며, Linux에서 display가 없으면 no-op로 반환한다.

  • macOS: NSFileManager.trashItemAtURL:resultingItemURL:error:
  • Linux: GIO g_file_trash (freedesktop Trash spec)
  • Windows: SHFileOperationW + FOF_ALLOWUNDO

존재하지 않는 path, path 한도 초과, 또는 filesystem이 Trash를 지원하지 않는 경우 false.

text/path/url 페이로드는 모두 escapeJsonStrFull로 인코딩 — \n/\t/\r 보존, control char \u00XX. 백슬래시/따옴표 round-trip 정확. UTF-8 멀티바이트(한글/이모지) 그대로 통과.

응답 디코딩(클립보드 read의 text 필드)도 동일 — 모든 control char 보존.

  • 텍스트/HTML 클립보드 플랫폼 — macOS(NSPasteboard), Linux(GTK clipboard text/html), Windows(CF_UNICODETEXT + CF_HTML)는 native 동작. RTF/image/buffer 확장은 아직 macOS 중심이며, 미지원 format은 false를 반환한다.
  • Clipboard 텍스트 16KB 한도 — 텍스트가 16KB를 초과하면 false를 반환한다.
  • URL/path 4KB 한도 — URL 및 path는 4KB를 초과할 수 없다.
  • Linux 확장 formatclipboard.readImage / writeBuffer 동등 기능은 향후 지원 예정이다.