Skip to content

Instantly share code, notes, and snippets.

@CTimmerman
Last active July 5, 2023 15:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CTimmerman/370271d0519f3c8db749 to your computer and use it in GitHub Desktop.
Save CTimmerman/370271d0519f3c8db749 to your computer and use it in GitHub Desktop.
Share clipboard
# -*- coding: utf-8 -*-
"""
Share clipboard
by Cees Timmerman
01-12-2014 v0.1 Works fine except Tk.clipboard_append()
02-12-2014 v0.9 Nonblocking sockets (didn't help Tk) and clipboard module instead of tkinter.
02-12-2014 v0.99 Bidirectional clipboard sharing. clipboard/pyperclip fails on Unicode like “, though.
08-12-2014 v1.0 pyperclip 1.5.7 supports Unicode (with emoji: 📋) on Windows.
"""
import socket, struct, sys, threading
import pyperclip as clp # C:\Python34\Scripts\pip install pyperclip
#import win32clipboard as clp
# TODO: support more than CF_UNICODE.
#formats = {val: name for name, val in vars(clp).items() if name.startswith('CF_')}
#print(formats)
CF_UNICODETEXT = 13
def format_name(fmt):
if fmt in formats:
return formats[fmt]
try:
return clp.GetClipboardFormatName(fmt)
except:
return "unknown"
def copy(data, fmt=CF_UNICODETEXT):
return fmt, clp.copy(data)
def paste(fmt=CF_UNICODETEXT):
return fmt, clp.paste()
'''
pasted = None
def copy(data, fmt=CF_UNICODETEXT):
printu("Copy %r" % data)
printu("Copy %r" % type(data))
if fmt == CF_UNICODETEXT:
if type(data) == bytes:
data = data.decode('utf-16-le')
data = data.encode('utf-16-le')
printu("Copy %r" % data)
clp.OpenClipboard()
clp.EmptyClipboard()
clp.SetClipboardData(fmt, data)
clp.CloseClipboard()
def paste(fmt=CF_UNICODETEXT):
global pasted
clp.OpenClipboard()
if clp.IsClipboardFormatAvailable(CF_UNICODETEXT):
data = clp.GetClipboardData(CF_UNICODETEXT)
else:
f = 0
while 1:
f = clp.EnumClipboardFormats(f)
if f == 0: break
formats = []
try:
formats.append("format: %s, %s" % (f, format_name(f)))
data = clp.GetClipboardData(f) #CF_UNICODETEXT)
except: data= ""
if data != pasted:
print(data)
print(pasted)
#print('\n'.join(formats))
clp.CloseClipboard()
pasted = data
printu("Paste %r" % data)
return fmt, data
'''
def ascii(s):
return s.encode('ascii', errors='replace').decode()
def printu(s):
print(ascii(s))
def dec(s):
if not s: return ''
return s.decode('utf-8')
def enc(s):
return s.encode('utf-8')
# http://stackoverflow.com/a/17668009/819417
def send_msg(sock, msg, fmt=CF_UNICODETEXT):
if type(msg) != bytes:
msg = bytes(msg, 'utf8')
msglen = len(msg)
# Prefix each message with a 4-byte length (network byte order).
msg = struct.pack('>I', msglen) + msg
msg = struct.pack('>I', fmt) + msg
sock.sendall(msg)
def recv_msg(sock):
raw_msgfmt = recvall(sock, 4)
if not raw_msgfmt: return None
fmt = struct.unpack('>I', raw_msgfmt)[0]
raw_msglen = recvall(sock, 4)
if not raw_msglen: return None
msglen = struct.unpack('>I', raw_msglen)[0]
data = recvall(sock, msglen)
return fmt, data
def recvall(sock, n):
# Helper function to recv n bytes or return None if EOF is hit.
data = bytes()
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet: return None
data += packet
return data
# http://stackoverflow.com/questions/17453212/multi-threaded-tcp-server-in-python
class ClientThread(threading.Thread):
def __init__(my, ip, port, sock):
threading.Thread.__init__(my)
my.ip = ip
my.port = port
my.sock = sock
def run(my):
global new_clip
printu("%s connected to %s" % (my.ip, str(my.port)))
old_clip = None
while 1:
if new_clip and (new_clip != old_clip):
printu("To %s: %r" % (ip, new_clip))
old_clip = new_clip
send_msg(my.sock, new_clip)
try:
fmt, data = recv_msg(my.sock)
if fmt == CF_UNICODETEXT: data = dec(data)
if data != old_clip:
printu("From %s: %r" % (my.ip, data))
old_clip = data
new_clip = data
copy(data, fmt)
except socket.timeout: pass
printu("%s:%s disconnected." % (my.ip, my.port))
if 1 < len(sys.argv) < 4:
cs = sys.argv[1]
ip = sys.argv[2] if len(sys.argv) == 3 else "0.0.0.0"
else:
printu("Usage: %s <C|S> [IP]")
sys.exit()
port = 9999
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(2)
if cs == "S":
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((ip, port))
sock.listen(4)
threads = []
# Listen for connections.
while 1:
fmt, new_clip = paste()
try:
(new_sock, (ip, port)) = sock.accept()
new_sock.settimeout(4)
new_thread = ClientThread(ip, port, new_sock)
new_thread.start()
threads.append(new_thread)
except socket.timeout: pass
# Wait for threads to finish.
for t in threads:
t.join()
else:
old_clip = None
sock.connect((ip, port))
while 1:
try:
fmt, data = recv_msg(sock)
printu("From: %r %r" % (fmt, data))
if fmt == CF_UNICODETEXT: data = dec(data)
printu("From: %r %r" % (fmt, data))
old_clip = data
copy(data, fmt)
except socket.timeout: pass
fmt, new_clip = paste()
if new_clip != old_clip:
printu("To: %s %r" % (fmt, new_clip))
old_clip = new_clip
printu("Sending %s" % type(new_clip))
#if type(new_clip) != bytes: new_clip = enc(new_clip)
send_msg(sock, new_clip)
"""
Share clipboard
by Cees Timmerman
02-12-2014 v0.1b Sometimes works, sometimes doesn't.
"""
import socket, sys, threading
from time import sleep, time
try: from tkinter import Tk # Python 3
except: from Tkinter import Tk
def dec(s):
return s.decode('utf-8')
def enc(s):
return s.encode('utf-8')
# http://stackoverflow.com/questions/17453212/multi-threaded-tcp-server-in-python
class ClientThread(threading.Thread):
def __init__(my, sock):
threading.Thread.__init__(my)
my.sock = sock
def run(my):
print("Connection from : %s:%s" % (ip, str(port)))
#my.sock.send(enc("\nWelcome to the server\n\n"))
'''
data = "dummydata"
while len(data):
data = dec(clientsock.recv(2048))
print("Client sent : "+data)
my.sock.send(enc("You sent me : "+data))
'''
old_clip = None
while True:
if new_clip != old_clip:
print("New clip: %r" % new_clip)
old_clip = new_clip
my.sock.sendall(enc(new_clip))
print("Sent: %r" % new_clip)
sleep(1)
print("Client disconnected.")
if 1 < len(sys.argv) < 4:
cs = sys.argv[1]
ip = sys.argv[2] if len(sys.argv) == 3 else "0.0.0.0"
else:
print("Usage: %s <C|S> [IP]")
sys.exit()
new_clip = ""
tk = Tk()
tk.withdraw() # hide window
port = 9999
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
if cs == "S":
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((ip, port))
threads = []
# Listen for connections.
while True:
tk.update()
try:
new_clip = tk.clipboard_get()
except Exception as err:
print(err)
sock.listen(4)
print("%s" % time())
try:
(clientsock, (ip, port)) = sock.accept()
newthread = ClientThread(clientsock)
newthread.start()
threads.append(newthread)
except socket.timeout: pass
# Wait for threads to finish.
for t in threads:
t.join()
else:
sock.connect((ip, port))
while True:
try:
data = dec(sock.recv(1024))
print(data)
#tk.withdraw()
#tk.update()
try:
tk.clipboard_clear()
tk.clipboard_append(data) # Causes error on server: _tkinter.TclError: CLIPBOARD selection doesn't exist or form "STRING" not defined
tk.update()
except Exception as err:
print(err)
#tk.destroy()
except socket.timeout: pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment