Files
decky-vaultwarden/clipboard.py
T

124 lines
3.7 KiB
Python

"""
Clipboard management with 60-second auto-clear.
Uses xclip/xdotool for SteamOS (KDE Plasma).
"""
import asyncio
import subprocess
import time
from typing import Optional
# Clipboard state
_clipboard_timers: dict = {}
_clipboard_contents: dict = {}
async def copy_to_clipboard(text: str, clear_after: int = 60, label: str = "default") -> dict:
"""Copy text to clipboard with auto-clear after specified seconds."""
global _clipboard_timers, _clipboard_contents
try:
# Cancel any existing timer for this label
if label in _clipboard_timers:
_clipboard_timers[label].cancel()
# Store the text
_clipboard_contents[label] = text
# Copy to clipboard using xclip
process = await asyncio.create_subprocess_exec(
"xclip", "-selection", "clipboard",
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
await process.communicate(input=text.encode("utf-8"))
if process.returncode != 0:
# Fallback to xsel if xclip not available
process = await asyncio.create_subprocess_exec(
"xsel", "--clipboard", "--input",
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
await process.communicate(input=text.encode("utf-8"))
if process.returncode != 0:
return {"success": False, "error": "No clipboard tool available (xclip or xsel)"}
# Set up auto-clear timer
async def clear_clipboard():
await asyncio.sleep(clear_after)
await clear_clipboard_label(label)
timer = asyncio.create_task(clear_clipboard())
_clipboard_timers[label] = timer
return {
"success": True,
"clear_after": clear_after,
"expires_at": int(time.time()) + clear_after,
}
except FileNotFoundError:
return {"success": False, "error": "xclip/xsel not found. Install with: pacman -S xclip"}
except Exception as e:
return {"success": False, "error": str(e)}
async def clear_clipboard_label(label: str = "default") -> dict:
"""Clear the clipboard for a specific label."""
global _clipboard_timers, _clipboard_contents
# Cancel timer if exists
if label in _clipboard_timers:
_clipboard_timers[label].cancel()
del _clipboard_timers[label]
# Clear clipboard content
if label in _clipboard_contents:
del _clipboard_contents[label]
# Clear the actual clipboard
try:
process = await asyncio.create_subprocess_exec(
"xclip", "-selection", "clipboard",
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
await process.communicate(input=b"")
except FileNotFoundError:
pass
return {"success": True}
async def clear_all_clipboards() -> dict:
"""Clear all clipboard contents and cancel all timers."""
global _clipboard_timers, _clipboard_contents
for label in list(_clipboard_timers.keys()):
_clipboard_timers[label].cancel()
_clipboard_timers.clear()
_clipboard_contents.clear()
await clear_clipboard_label("default")
return {"success": True}
def get_clipboard_status(label: str = "default") -> dict:
"""Get the status of clipboard content for a label."""
global _clipboard_contents, _clipboard_timers
if label not in _clipboard_contents:
return {"has_content": False}
return {
"has_content": True,
"label": label,
"has_timer": label in _clipboard_timers,
}