Instantly share code, notes, and snippets.
Last active
July 5, 2023 15:15
-
Save CTimmerman/370271d0519f3c8db749 to your computer and use it in GitHub Desktop.
Share clipboard
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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