//go:build darwin package input /* #cgo CFLAGS: -x objective-c #cgo LDFLAGS: -framework AppKit -framework CoreGraphics -framework Carbon -framework ApplicationServices #include #include #include #include #include #include static int ensureInputPermission(void) { NSDictionary* opts = @{(__bridge NSString*)kAXTrustedCheckOptionPrompt: @YES}; return AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)opts) ? 1 : 0; } static void setClipboardText(const char* text) { NSPasteboard* pb = [NSPasteboard generalPasteboard]; [pb clearContents]; NSString* str = [NSString stringWithUTF8String:text]; [pb setString:str forType:NSPasteboardTypeString]; } static char* getClipboardText(void) { NSPasteboard* pb = [NSPasteboard generalPasteboard]; NSString* str = [pb stringForType:NSPasteboardTypeString]; if (!str) return NULL; const char* utf8 = [str UTF8String]; if (!utf8) return NULL; return strdup(utf8); } static void simulateCmdV() { CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState); CGEventRef cmdDown = CGEventCreateKeyboardEvent(source, (CGKeyCode)kVK_Command, true); CGEventSetFlags(cmdDown, kCGEventFlagMaskCommand); CGEventPost(kCGHIDEventTap, cmdDown); CGEventRef vDown = CGEventCreateKeyboardEvent(source, (CGKeyCode)kVK_ANSI_V, true); CGEventSetFlags(vDown, kCGEventFlagMaskCommand); CGEventPost(kCGHIDEventTap, vDown); CGEventRef vUp = CGEventCreateKeyboardEvent(source, (CGKeyCode)kVK_ANSI_V, false); CGEventSetFlags(vUp, kCGEventFlagMaskCommand); CGEventPost(kCGHIDEventTap, vUp); CGEventRef cmdUp = CGEventCreateKeyboardEvent(source, (CGKeyCode)kVK_Command, false); CGEventSetFlags(cmdUp, 0); CGEventPost(kCGHIDEventTap, cmdUp); CFRelease(cmdDown); CFRelease(vDown); CFRelease(vUp); CFRelease(cmdUp); CFRelease(source); } static void typeUnicodeChar(unsigned int codepoint) { CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState); UniChar chars[2]; int len = 0; if (codepoint <= 0xFFFF) { chars[0] = (UniChar)codepoint; len = 1; } else { codepoint -= 0x10000; chars[0] = (UniChar)(0xD800 + (codepoint >> 10)); chars[1] = (UniChar)(0xDC00 + (codepoint & 0x3FF)); len = 2; } CGEventRef keyDown = CGEventCreateKeyboardEvent(source, 0, true); CGEventKeyboardSetUnicodeString(keyDown, len, chars); CGEventPost(kCGHIDEventTap, keyDown); CGEventRef keyUp = CGEventCreateKeyboardEvent(source, 0, false); CGEventKeyboardSetUnicodeString(keyUp, len, chars); CGEventPost(kCGHIDEventTap, keyUp); CFRelease(keyDown); CFRelease(keyUp); CFRelease(source); } */ import "C" import ( "fmt" "time" "unsafe" ) type darwinPaster struct{} func newPlatformPaster() Paster { return &darwinPaster{} } func (p *darwinPaster) Paste(text string, keepClipboard bool) error { if C.ensureInputPermission() == 0 { return fmt.Errorf("accessibility permission is required to paste") } var oldClip *string if !keepClipboard { cOld := C.getClipboardText() if cOld != nil { old := C.GoString(cOld) oldClip = &old C.free(unsafe.Pointer(cOld)) } } cstr := C.CString(text) defer C.free(unsafe.Pointer(cstr)) C.setClipboardText(cstr) time.Sleep(60 * time.Millisecond) C.simulateCmdV() if !keepClipboard && oldClip != nil { go func(old string) { time.Sleep(600 * time.Millisecond) cOld := C.CString(old) defer C.free(unsafe.Pointer(cOld)) C.setClipboardText(cOld) }(*oldClip) } return nil } func (p *darwinPaster) TypeText(text string) error { if C.ensureInputPermission() == 0 { return fmt.Errorf("accessibility permission is required to type") } for _, r := range text { C.typeUnicodeChar(C.uint(r)) } return nil }