Monday, 12 November 2012

Python 3 Clipboard and File Manipulation in Windows


This script reads the contents of the clipboard and renames the most recently downloaded file accordingly (if it's a particular type). It also moves the file to a new directory and opens it.

Programmers are funny sometimes. We'd rather spend 2x longer developing a program/script to do our repetitive tasks for us than to just do them! That's exactly what this is. I used this while marking assignments because I found I wasted a lot of time on this. I know there are other ways (like downloading assignments in bulk) but it wasn't even a question in my mind, I had to do it this way :)

import os
import sys
from time import sleep
import clipboard_code as win_clipboard # should be in same DIR

##########################
########## Main ##########
##########################

modified = ""
append_string = " - Assignment 2 MARKED"
source_dir = "C:\\Users\\me\\Downloads"
old_listdir = os.listdir(source_dir)
destination_dir = "C:\\Users\\me\\Dropbox\\ADS\\Assignment 2\\marked"

while True:
    ##### Clipboard Phase #####
    s = ""
    try:
        s = win_clipboard.Get()
    except (TypeError):
        # the contents of the clipboard isn't text
        s = ""
        modified = ""
    
    # print(s)
    if (s + append_string) != modified and s != "":
        modified = s + append_string
        print(s, " -> ", modified)
        s = modified
    
    ##### File Moving & Renaming Phase #####
    listdir = os.listdir(source_dir)
    if old_listdir != listdir:
        if not modified:
            print("ERROR: found a new file but no text from the clipboard")
            # print("resetting old_listdir")
            old_listdir = listdir
        else:
            newfileslist = [file for file in listdir if file not in old_listdir]
            newfile = ""
            if newfileslist == []:
                print("Error figuring out which file was new")
            else:
                newfile = os.path.join(source_dir, newfileslist[0])
                print("\tNEWFILE:", newfile)
            
            
            if newfile and newfile.count(".docx") >= 1:
                newfilename = modified + ".docx"
                newpath = os.path.join(destination_dir, newfilename)
                print("Moving\n", newfile, "\nto\n", newpath)
                os.rename(newfile, newpath)
                sleep(0.2)
                os.system("call \"" + newpath + "\"")
            else:
                print("File is not a docx. User must handle it manually")
                
    sleep(0.75)

So what's in clipboard_code.py? It's code taken from a gentleman named kapace that I found somewhere off Google. It's not the neatest code but it works well.

import ctypes

#Get required functions, strcpy..
strcpy = ctypes.cdll.msvcrt.strcpy
ocb = ctypes.windll.user32.OpenClipboard        #Basic Clipboard functions
ecb = ctypes.windll.user32.EmptyClipboard
gcd = ctypes.windll.user32.GetClipboardData
scd = ctypes.windll.user32.SetClipboardData
ccb = ctypes.windll.user32.CloseClipboard
ga = ctypes.windll.kernel32.GlobalAlloc     # Global Memory allocation
gl = ctypes.windll.kernel32.GlobalLock       # Global Memory Locking
gul = ctypes.windll.kernel32.GlobalUnlock
GMEM_DDESHARE = 0x2000 

def Get( ):
    ocb(None) # Open Clip, Default task
    pcontents = gcd(1) # 1 means CF_TEXT.. too lazy to get the token thingy ... 
    data = ctypes.c_char_p(pcontents).value
    #gul(pcontents) ?
    ccb()
    return bytes.decode(data)

def Paste( data ):
    ocb(None) # Open Clip, Default task
    ecb()
    hCd = ga( GMEM_DDESHARE, len( str.encode(data) )+1 )
    pchData = gl(hCd)
    strcpy(ctypes.c_char_p(pchData),str.encode(data))
    gul(hCd)
    scd(1,hCd)
    ccb()

I've gone with the Windows-only version of messing with the clipboard because I couldn't get it to work through Tkinter. I got Tkinter to open and read the clipboard but pasting or reading a second time didn't work. Also if I put text into the clipboard with Tkinter then any program I pasted it into would freeze until the python script closed. Weird! I don't recommend using Tkinter for clipboard stuff.

No comments:

Post a Comment