493 lines
9.9 KiB
Text
493 lines
9.9 KiB
Text
---
|
|
title: Clipboard Operations
|
|
description: Copy and paste text with the system clipboard
|
|
sidebar:
|
|
order: 1
|
|
---
|
|
|
|
import { Card, CardGrid } from "@astrojs/starlight/components";
|
|
|
|
## Clipboard Operations
|
|
|
|
Wails provides a **unified clipboard API** that works across all platforms. Copy and paste text with simple, consistent methods on Windows, macOS, and Linux.
|
|
|
|
## Quick Start
|
|
|
|
```go
|
|
// Copy text to clipboard
|
|
app.Clipboard.SetText("Hello, World!")
|
|
|
|
// Get text from clipboard
|
|
text, ok := app.Clipboard.Text()
|
|
if ok {
|
|
fmt.Println("Clipboard:", text)
|
|
}
|
|
```
|
|
|
|
**That's it!** Cross-platform clipboard access.
|
|
|
|
## Copying Text
|
|
|
|
### Basic Copy
|
|
|
|
```go
|
|
success := app.Clipboard.SetText("Text to copy")
|
|
if !success {
|
|
app.Logger.Error("Failed to copy to clipboard")
|
|
}
|
|
```
|
|
|
|
**Returns:** `bool` - `true` if successful, `false` otherwise
|
|
|
|
### Copy from Service
|
|
|
|
```go
|
|
type ClipboardService struct {
|
|
app *application.Application
|
|
}
|
|
|
|
func (c *ClipboardService) CopyToClipboard(text string) bool {
|
|
return c.app.Clipboard.SetText(text)
|
|
}
|
|
```
|
|
|
|
**Call from JavaScript:**
|
|
|
|
```javascript
|
|
import { CopyToClipboard } from './bindings/myapp/clipboardservice'
|
|
|
|
await CopyToClipboard("Text to copy")
|
|
```
|
|
|
|
### Copy with Feedback
|
|
|
|
```go
|
|
func copyWithFeedback(text string) {
|
|
if app.Clipboard.SetText(text) {
|
|
app.Dialog.Info().
|
|
SetTitle("Copied").
|
|
SetMessage("Text copied to clipboard!").
|
|
Show()
|
|
} else {
|
|
app.Dialog.Error().
|
|
SetTitle("Copy Failed").
|
|
SetMessage("Failed to copy to clipboard.").
|
|
Show()
|
|
}
|
|
}
|
|
```
|
|
|
|
## Pasting Text
|
|
|
|
### Basic Paste
|
|
|
|
```go
|
|
text, ok := app.Clipboard.Text()
|
|
if !ok {
|
|
app.Logger.Error("Failed to read clipboard")
|
|
return
|
|
}
|
|
|
|
fmt.Println("Clipboard text:", text)
|
|
```
|
|
|
|
**Returns:** `(string, bool)` - Text and success flag
|
|
|
|
### Paste from Service
|
|
|
|
```go
|
|
func (c *ClipboardService) PasteFromClipboard() string {
|
|
text, ok := c.app.Clipboard.Text()
|
|
if !ok {
|
|
return ""
|
|
}
|
|
return text
|
|
}
|
|
```
|
|
|
|
**Call from JavaScript:**
|
|
|
|
```javascript
|
|
import { PasteFromClipboard } from './bindings/myapp/clipboardservice'
|
|
|
|
const text = await PasteFromClipboard()
|
|
console.log("Pasted:", text)
|
|
```
|
|
|
|
### Paste with Validation
|
|
|
|
```go
|
|
func pasteText() (string, error) {
|
|
text, ok := app.Clipboard.Text()
|
|
if !ok {
|
|
return "", errors.New("clipboard empty or unavailable")
|
|
}
|
|
|
|
// Validate
|
|
if len(text) == 0 {
|
|
return "", errors.New("clipboard is empty")
|
|
}
|
|
|
|
if len(text) > 10000 {
|
|
return "", errors.New("clipboard text too large")
|
|
}
|
|
|
|
return text, nil
|
|
}
|
|
```
|
|
|
|
## Complete Examples
|
|
|
|
### Copy Button
|
|
|
|
**Go:**
|
|
|
|
```go
|
|
type TextService struct {
|
|
app *application.Application
|
|
}
|
|
|
|
func (t *TextService) CopyText(text string) error {
|
|
if !t.app.Clipboard.SetText(text) {
|
|
return errors.New("failed to copy")
|
|
}
|
|
return nil
|
|
}
|
|
```
|
|
|
|
**JavaScript:**
|
|
|
|
```javascript
|
|
import { CopyText } from './bindings/myapp/textservice'
|
|
|
|
async function copyToClipboard(text) {
|
|
try {
|
|
await CopyText(text)
|
|
showNotification("Copied to clipboard!")
|
|
} catch (error) {
|
|
showError("Failed to copy: " + error)
|
|
}
|
|
}
|
|
|
|
// Usage
|
|
document.getElementById('copy-btn').addEventListener('click', () => {
|
|
const text = document.getElementById('text').value
|
|
copyToClipboard(text)
|
|
})
|
|
```
|
|
|
|
### Paste and Process
|
|
|
|
**Go:**
|
|
|
|
```go
|
|
type DataService struct {
|
|
app *application.Application
|
|
}
|
|
|
|
func (d *DataService) PasteAndProcess() (string, error) {
|
|
// Get clipboard text
|
|
text, ok := d.app.Clipboard.Text()
|
|
if !ok {
|
|
return "", errors.New("clipboard unavailable")
|
|
}
|
|
|
|
// Process text
|
|
processed := strings.TrimSpace(text)
|
|
processed = strings.ToUpper(processed)
|
|
|
|
return processed, nil
|
|
}
|
|
```
|
|
|
|
**JavaScript:**
|
|
|
|
```javascript
|
|
import { PasteAndProcess } from './bindings/myapp/dataservice'
|
|
|
|
async function pasteAndProcess() {
|
|
try {
|
|
const result = await PasteAndProcess()
|
|
document.getElementById('output').value = result
|
|
} catch (error) {
|
|
showError("Failed to paste: " + error)
|
|
}
|
|
}
|
|
```
|
|
|
|
### Copy Multiple Formats
|
|
|
|
```go
|
|
type CopyService struct {
|
|
app *application.Application
|
|
}
|
|
|
|
func (c *CopyService) CopyAsPlainText(text string) bool {
|
|
return c.app.Clipboard.SetText(text)
|
|
}
|
|
|
|
func (c *CopyService) CopyAsJSON(data interface{}) bool {
|
|
jsonBytes, err := json.MarshalIndent(data, "", " ")
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return c.app.Clipboard.SetText(string(jsonBytes))
|
|
}
|
|
|
|
func (c *CopyService) CopyAsCSV(rows [][]string) bool {
|
|
var buf bytes.Buffer
|
|
writer := csv.NewWriter(&buf)
|
|
|
|
for _, row := range rows {
|
|
if err := writer.Write(row); err != nil {
|
|
return false
|
|
}
|
|
}
|
|
|
|
writer.Flush()
|
|
return c.app.Clipboard.SetText(buf.String())
|
|
}
|
|
```
|
|
|
|
### Clipboard Monitor
|
|
|
|
```go
|
|
type ClipboardMonitor struct {
|
|
app *application.Application
|
|
lastText string
|
|
ticker *time.Ticker
|
|
stopChan chan bool
|
|
}
|
|
|
|
func NewClipboardMonitor(app *application.Application) *ClipboardMonitor {
|
|
return &ClipboardMonitor{
|
|
app: app,
|
|
stopChan: make(chan bool),
|
|
}
|
|
}
|
|
|
|
func (cm *ClipboardMonitor) Start() {
|
|
cm.ticker = time.NewTicker(1 * time.Second)
|
|
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-cm.ticker.C:
|
|
cm.checkClipboard()
|
|
case <-cm.stopChan:
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (cm *ClipboardMonitor) Stop() {
|
|
if cm.ticker != nil {
|
|
cm.ticker.Stop()
|
|
}
|
|
cm.stopChan <- true
|
|
}
|
|
|
|
func (cm *ClipboardMonitor) checkClipboard() {
|
|
text, ok := cm.app.Clipboard.Text()
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
if text != cm.lastText {
|
|
cm.lastText = text
|
|
cm.app.Event.Emit("clipboard-changed", text)
|
|
}
|
|
}
|
|
```
|
|
|
|
### Copy with History
|
|
|
|
```go
|
|
type ClipboardHistory struct {
|
|
app *application.Application
|
|
history []string
|
|
maxSize int
|
|
}
|
|
|
|
func NewClipboardHistory(app *application.Application) *ClipboardHistory {
|
|
return &ClipboardHistory{
|
|
app: app,
|
|
history: make([]string, 0),
|
|
maxSize: 10,
|
|
}
|
|
}
|
|
|
|
func (ch *ClipboardHistory) Copy(text string) bool {
|
|
if !ch.app.Clipboard.SetText(text) {
|
|
return false
|
|
}
|
|
|
|
// Add to history
|
|
ch.history = append([]string{text}, ch.history...)
|
|
|
|
// Limit size
|
|
if len(ch.history) > ch.maxSize {
|
|
ch.history = ch.history[:ch.maxSize]
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (ch *ClipboardHistory) GetHistory() []string {
|
|
return ch.history
|
|
}
|
|
|
|
func (ch *ClipboardHistory) RestoreFromHistory(index int) bool {
|
|
if index < 0 || index >= len(ch.history) {
|
|
return false
|
|
}
|
|
|
|
return ch.app.Clipboard.SetText(ch.history[index])
|
|
}
|
|
```
|
|
|
|
## Frontend Integration
|
|
|
|
### Using Browser Clipboard API
|
|
|
|
For simple text, you can use the browser's clipboard API:
|
|
|
|
```javascript
|
|
// Copy
|
|
async function copyText(text) {
|
|
try {
|
|
await navigator.clipboard.writeText(text)
|
|
console.log("Copied!")
|
|
} catch (error) {
|
|
console.error("Copy failed:", error)
|
|
}
|
|
}
|
|
|
|
// Paste
|
|
async function pasteText() {
|
|
try {
|
|
const text = await navigator.clipboard.readText()
|
|
return text
|
|
} catch (error) {
|
|
console.error("Paste failed:", error)
|
|
return ""
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note:** Browser clipboard API requires HTTPS or localhost, and user permission.
|
|
|
|
### Using Wails Clipboard
|
|
|
|
For system-wide clipboard access:
|
|
|
|
```javascript
|
|
import { CopyToClipboard, PasteFromClipboard } from './bindings/myapp/clipboardservice'
|
|
|
|
// Copy
|
|
async function copy(text) {
|
|
const success = await CopyToClipboard(text)
|
|
if (success) {
|
|
console.log("Copied!")
|
|
}
|
|
}
|
|
|
|
// Paste
|
|
async function paste() {
|
|
const text = await PasteFromClipboard()
|
|
return text
|
|
}
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### ✅ Do
|
|
|
|
- **Check return values** - Handle failures gracefully
|
|
- **Provide feedback** - Let users know copy succeeded
|
|
- **Validate pasted text** - Check format and size
|
|
- **Use appropriate method** - Browser API vs Wails API
|
|
- **Handle empty clipboard** - Check before using
|
|
- **Trim whitespace** - Clean pasted text
|
|
|
|
### ❌ Don't
|
|
|
|
- **Don't ignore failures** - Always check success
|
|
- **Don't copy sensitive data** - Clipboard is shared
|
|
- **Don't assume format** - Validate pasted data
|
|
- **Don't poll too frequently** - If monitoring clipboard
|
|
- **Don't copy large data** - Use files instead
|
|
- **Don't forget security** - Sanitise pasted content
|
|
|
|
## Platform Differences
|
|
|
|
### macOS
|
|
|
|
- Uses NSPasteboard
|
|
- Supports rich text (future)
|
|
- System-wide clipboard
|
|
- Clipboard history (system feature)
|
|
|
|
### Windows
|
|
|
|
- Uses Windows Clipboard API
|
|
- Supports multiple formats (future)
|
|
- System-wide clipboard
|
|
- Clipboard history (Windows 10+)
|
|
|
|
### Linux
|
|
|
|
- Uses X11/Wayland clipboard
|
|
- Primary and clipboard selections
|
|
- Varies by desktop environment
|
|
- May require clipboard manager
|
|
|
|
## Limitations
|
|
|
|
### Current Version
|
|
|
|
- **Text only** - Images not yet supported
|
|
- **No format detection** - Plain text only
|
|
- **No clipboard events** - Must poll for changes
|
|
- **No clipboard history** - Implement yourself
|
|
|
|
### Future Features
|
|
|
|
- Image support
|
|
- Rich text support
|
|
- Multiple formats
|
|
- Clipboard change events
|
|
- Clipboard history API
|
|
|
|
## Next Steps
|
|
|
|
<CardGrid>
|
|
<Card title="Bindings" icon="rocket">
|
|
Call Go functions from JavaScript.
|
|
|
|
[Learn More →](/features/bindings/methods)
|
|
</Card>
|
|
|
|
<Card title="Events" icon="star">
|
|
Use events for clipboard notifications.
|
|
|
|
[Learn More →](/features/events/system)
|
|
</Card>
|
|
|
|
<Card title="dialogs" icon="information">
|
|
Show copy/paste feedback.
|
|
|
|
[Learn More →](/features/dialogs/message)
|
|
</Card>
|
|
|
|
<Card title="Services" icon="puzzle">
|
|
Organise clipboard code.
|
|
|
|
[Learn More →](/features/bindings/services)
|
|
</Card>
|
|
</CardGrid>
|
|
|
|
---
|
|
|
|
**Questions?** Ask in [Discord](https://discord.gg/JDdSxwjhGf) or check the [clipboard examples](https://github.com/wailsapp/wails/tree/v3-alpha/v3/examples).
|