Welcome, guest | Sign In | My Account | Store | Cart
#!/usr/bin/python2.5
# -*- coding: utf-8 -*-
""" A shared clipboard using a network accessible file. Inspired by [1] but
supports Linux, unicode, and interrupting (if paused virtual machine).

[1]:http://www.devx.com/opensource/Article/37233/1954
"""


import codecs
import os
try: # use killable process because xsel/xclip sometimes stalls
   
from killableprocess import Popen # http://svn.smedbergs.us/python-processes/trunk/
except ImportError:
   
from subprocess import Popen
from subprocess import PIPE

import signal
import sys
import time

#### Clipboard files and functions per system ####
# Mac stuff removed since I can't test, see [1] above.

if sys.platform == 'win32':
    clipboard_fn
= r'w:\apps\clipboard\clipboard.txt'
    log_fn
= r'w:\apps\clipboard\log_clipboard.txt'
   
import win32clipboard

   
def openClipboard():
        win32clipboard
.OpenClipboard()
   
def closeClipboard():
       
try:
            win32clipboard
.CloseClipboard()
       
except Exception, e:
           
print e
           
pass
   
def getClipboardData():
       
from win32clipboard import CF_UNICODETEXT
       
if win32clipboard.IsClipboardFormatAvailable(CF_UNICODETEXT):
           
return win32clipboard.GetClipboardData().decode('cp1252')
       
else:
           
return None
   
def setClipboardData(data): # “ Václav
        win32clipboard
.EmptyClipboard()
        win32clipboard
.SetClipboardData(win32clipboard.CF_UNICODETEXT,
            data
)
           
elif sys.platform == 'linux2':
    clipboard_fn
= r'/home/reagle/e/win/apps/clipboard/clipboard.txt'
    log_fn
= r'/home/reagle/e/win/apps/clipboard/log_clipboard.txt'
   
def openClipboard():
       
pass
   
def closeClipboard():
       
pass
   
def getClipboardData(): # xclip needs iso-8859-1 for ver < 0.11 #failed
        my_logger
.debug('  %s: getClipboardData' % sys.platform)
        p
= Popen(['/usr/bin/xsel', '-t', '200', '-o'], stdout=PIPE)
        p
.wait(2)
        result
= p.communicate()[0].decode('utf-8')
        my_logger
.debug('  %s: gotClipboardData "%s"' % (sys.platform, result))
       
return result
   
def setClipboardData(data):
        my_logger
.debug('  %s: setClipboardData data = "%s"' % (sys.platform, data))
        p
= Popen(['/usr/bin/xsel', '-t', '200', '-i'], stdin=PIPE)
        result
= p.communicate(input=data.encode('utf-8'))
        p
.wait(2)
        my_logger
.debug('  %s: setClipboardData done' % sys.platform)
       
return result
else:
   
print "Unknown system"
    sys
.exit()


#### Logging ####
#import logging
#import logging.handlers
#my_logger = logging.getLogger('MyLogger')
#my_logger.setLevel(logging.DEBUG) # CRITICAL
#handler = logging.StreamHandler(sys.stderr)
##handler = logging.handlers.RotatingFileHandler(
           
##log_fn, maxBytes=2000, backupCount=0) # log_fn
#my_logger.addHandler(handler)

class Logger:
   
def debug(self, msg):
       
pass
       
#now = time.localtime(time.time())
       
#print time.strftime("%H%M%S", now) + msg.encode('utf-8')
my_logger
= Logger()


#### File Object ####

class File:
   
def __init__(self, clipboard_fn):
       
self.prev_mtime = self.mtime = None
       
self.clipboard_fn = clipboard_fn
   
   
def hasUpdated(self):
       
'''Checking file attribute lessens file blocking of read'''
       
self.prev_mtime = self.mtime
       
self.mtime = os.stat(self.clipboard_fn).st_mtime # last time clipboard_fn modified
       
return self.mtime != self.prev_mtime

   
def update(self):
       
self.mtime = os.stat(self.clipboard_fn).st_mtime
        my_logger
.debug('  %s: updated mtime "%s"' % (sys.platform, self.mtime))

   
def write(self, data):
        my_logger
.debug('  %s: opening clipboard_fn for write' % sys.platform)
        fd
= codecs.open(self.clipboard_fn, 'w', 'utf-8')
        fd
.write(data)
        fd
.close()
        my_logger
.debug('  %s: closed clipboard_fn for write' % sys.platform)
        my_logger
.debug('  %s: wrote "%s"' % (sys.platform, data))

   
def read(self):
        my_logger
.debug('%s:  clipboard_fn updated, opening for read'  % sys.platform)
        fd
= codecs.open(self.clipboard_fn, 'r', 'utf-8')
        data
= fd.read()
        my_logger
.debug("  %s: getting data = '%s'"  % (sys.platform, data))
        fd
.close()
        my_logger
.debug('  %s: closed clipboard_fn for read'  % sys.platform)
       
return data

clipboard_file
= File(clipboard_fn)


#### Poll clipboard loop #####

wait_no
= 0

def monitorClipboard(clipboard_fn):
    prev_data
= u''
   
while (True):
        time
.sleep(1)
       
try:
            openClipboard
()
       
except:
            my_logger
.debug('OpenClipboard() failed')
           
continue
       
       
try:
            data
= getClipboardData()
           
if data and data != prev_data:  # write to clipboard_fn
                my_logger
.debug('\n\n%s:  update clipboard update: "%s" != "%s"'
                   
% (sys.platform, data[0:10], prev_data[0:10]))
                clipboard_file
.write(data)
                prev_data
= data
                clipboard_file
.update()
           
else:   # local clipboard hasn't changed, did remote clipboard change?
               
if clipboard_file.hasUpdated():
                    data
= clipboard_file.read()
                   
if data != prev_data:
                        setClipboardData
(data)
                        prev_data
= data
            sys
.stdout.flush()
       
except Exception, e:
            my_logger
.debug(str(e))
            time
.sleep(5)   # for network upon resume: wait 5 seconds, 3 times
            wait_no
+= 1
           
if wait_no == 3:
                sys
.exit()
       
else:
            wait_no
= 0     # if suceeded, reset wait
        closeClipboard
()

def main():
    monitorClipboard
(clipboard_fn)

if __name__=='__main__':
    main
()

History