**Summary** [HZe] 2009-10-17: If you use the clipboard to transfer some of information, sometimes it happens that you copy something and then in the process of coming to the program you want to paste it in, you copy something else and bumm, your first copy is lost. This tool tries to prevent this, by keeping a history of the clipboard selections. Additionally, it allows to execute a diff; this make sense if the last two entries of the history are file names. **Code** ---- ======tcl ###################################################### # ClipboardMonitor # by Holger Zeinert # # This small tool monitors the clipboard and adds every # new content to a list. From this list, automatically # the last two entries are selected. # # LIMITATION: # Currently, on UNIX the clipboard CLIPBOARD is # used, not PRIMARY. # Also, it's not tested very much on UNIX. # I use it mainly on Windows. # set progVersion "Clipboard Monitor v0.24" set usage " $progVersion" append usage { by Holger Zeinert This tool monitors the clipboard and keeps a list of snapshots from the content. This keeps track of things that were in the clipboard and items can be reused later. If you select one entry in the list, this entry can be exported to the clipboard by pressing the button "export" "Clear" resets the list. Please note that this will at least enter the current content of the clipboard again in the list. The content of the list is also stored in a private configuration file, so that the current content is preserved even if the tool is closed and opened again. Also be careful when copying passwords over the clipboard when this tool is running. Those will be visible in plain text! And they are saved uncrypted in the history file of the tool. If you want to do a diff, use the text editor of your choice and go to the first file, copy the file name to the clipboard, go to the second file, copy the file name to the clipboard. Then, in this tool the last two (selected) entries show the two filenames Press "diff" to invoke tkdiff. You also may select two files from the list to do the diff on. } ###################################################### # Utility procedures # proc scan_clp {{update_list 0}} { global CONFIG if {![catch {set content [clipboard get]}]} { if {$content != [lindex $CONFIG(clpList) end]} { lappend CONFIG(clpList) $content set update_list 1 } } if {$update_list} { update_listbox wm title . "scan_clp: new data" after 500 } after 500 scan_clp wm title . $::progVersion } proc exit_handler {} { # save current content to private configuration write_rc } proc getrcname {} { global env argv0 tcl_platform if {[string match "win*" $tcl_platform(platform)]} { set filename [file join $env(USERPROFILE) "[file rootname [file tail $argv0]].rc"] } else { set filename [file join ~ "[file rootname ".[file tail $argv0]"].rc"] } return $filename } proc read_rc {} { global CONFIG catch { set fp [open [getrcname] r] array set CONFIG [read $fp] close $fp } # set defaults / !! Todo: needs edit !! if {![info exists CONFIG(diff)]} { if {[file exists c:/zeinert/tools/tkdiff.bat]} { set CONFIG(diff) c:/zeinert/tools/tkdiff.bat } else { # set CONFIG(diff) tkdiff set CONFIG(diff) examdiff } } #set CONFIG(diff) examdiff set CONFIG(diff) C:/Programme/Util/ExamDiff/ExamDiff.exe } proc write_rc {} { global CONFIG set fp [open [getrcname] w] # try to write arrag get a little nicer, so that a human could edit it foreach {var value} [array get CONFIG] { puts $fp "[list $var]\n[list $value]\n" } close $fp } ##################################################### # GUI handlers # proc update_listbox {} { global lb global CONFIG set l [llength $CONFIG(clpList)] $lb selection clear 0 $l #$lb selection set [expr $l-2] end; # select last 2 entries $lb selection set end; # select only last entry $lb yview end return } proc export_clp {} { global lb global CONFIG set s [$lb curselection] if {[llength $s] != 1} { tk_messageBox -message "Please select exactly one entry" } else { clipboard clear clipboard append [lindex $CONFIG(clpList) [lindex $s 0]] } return } proc process_clp {} { global lb global CONFIG set s [$lb curselection] if {[llength $s] != 1} { tk_messageBox -message "Please select exactly one entry" } else { set txt1 [lindex $CONFIG(clpList) [lindex $s 0]] set txt2 [string tolower $txt1] clipboard clear clipboard append $txt2 } return } ### ### ### ### if 0 { # Patterns to look for: # Input1 - Forum Post subject: Re: Problem. New postPosted: 2016-01-13 14:15 Reply with quote ... # Input2 - IP/RIPE: RIPE NCC Network Coordination RIPE Database (Whois) Website Your IP address is: 89.246.201.51 ... # Input3 - CDex : CDex version :1.79 Disk ID :A90C9D0C Volume ID :1326472 OS Version :Windows ... } ### ### ### ### proc filter_clp {} { global lb global CONFIG set s [$lb curselection] if {[llength $s] != 1} { tk_messageBox -message "Please select exactly one entry" } else { clipboard clear set txt [lindex $CONFIG(clpList) [lindex $s 0]] # IP-Filter: set p1 [string first "Your IP addr" $txt]; # RIPE.net if {$p1 >= 0} { set p1 [string first ": " $txt $p1] set p2 [string first "\n" $txt $p1] #if {$p2 < 0} { set p2 $p1; incr p2 16 } if {$p2 < 0} { set p2 $p1; incr p2 2; set p2 [string first " " $txt $p2] } if {$p2 < 0} { set p2 [string length $txt] } ## wm title . "IP: $p1 $p2"; after 1111; ## debug incr p1 incr p2 -1 set ip [string range $txt $p1 $p2] set cs [clock seconds] #set td [clock format $cs -format "%Y-%m-%d %H:%M:%S" ] set td [clock format $cs -format "%Y-%m-%d %H:%M" ] #clipboard append "IP=$ip" clipboard append "$td $ip " return } # CDex-Filter: set p1 [string first "Disk ID" $txt]; # freedb-Disk-ID if {$p1 >= 0} { set p1 [string first ":" $txt $p1] set p2 [string first "\n" $txt $p1] ## wm title . "CDex $p1 $p2"; after 1111; ## debug incr p1 incr p2 -1 set id1 [string range $txt $p1 $p2] set p1 [string first "Volume ID" $txt]; # CD-Volume-ID set p1 [string first ":" $txt $p1] set p2 [string first "\n" $txt $p1] incr p1 incr p2 -1 set id2 [string range $txt $p1 $p2] clipboard append "DiskID=$id1 V-Id=$id2" return } # Forum-Filter: set p1 [string first "Post subject:" $txt]; # Forum if {$p1 >= 0} { set p1 [string first ":" $txt $p1] set p2 [string first "\n" $txt $p1] ## wm title . "Forum $p1 $p2"; after 1111; ## debug incr p1 incr p2 -1 set txS [string range $txt $p1 $p2] set p1 [string first "Posted:" $txt]; set p1 [string first ":" $txt $p1] set p2 [string first "\n" $txt $p1] incr p1 incr p2 -1 set txD [string range $txt $p1 $p2] clipboard append "Date=$txD Subject=$txS" return } # ...add other filters here... wm title . "filter: no match" after 500 } return } proc diff {} { global lb global CONFIG set s [$lb curselection] if {[llength $s] < 2} { tk_messageBox -message "please select two files" } else { set s1 [lindex $s end] set s2 [lindex $s end-1] set f1 [lindex $CONFIG(clpList) $s1] set f2 [lindex $CONFIG(clpList) $s2] # Todo: process exitcodes>0 that don't indicate errors if {[catch { exec $CONFIG(diff) $f1 $f2 } msg]} { tk_messageBox -title "Error" -icon info \ -message "could not execute diff tool '$CONFIG(diff)'\n \ $msg\n\ Please check installation or change [getrcname]\n\ to specify the diff tool of your choice." } } return } proc finish {} { exit_handler exit } proc build_gui {} { global lb frame .l set lb .l.lb listbox $lb -listvar CONFIG(clpList) -selectmode extended -height 7 -width 50 -yscrollcommand ".l.sb set" scrollbar .l.sb -command "$lb yview" pack $lb -expand 1 -fill both -side left pack .l.sb -fill y -side left pack .l -expand 1 -fill both -padx 5 -pady 5 frame .b button .b.clear -text Clear -command {set CONFIG(clpList) {}} button .b.export -text Export -command {export_clp} button .b.process -text Process -command {process_clp} button .b.filter -text Filter -command {filter_clp} button .b.diff -text Diff -command diff button .b.exit -text Exit -command finish button .b.help -text Help -command { toplevel .help label .help.l -text $usage -justify left -width 60 pack .help.l -expand 1 button .help.b -command {destroy .help} -text " OK " pack .help.b -expand 1 -padx 3 -pady 3 } pack .b.exit .b.help .b.diff .b.filter .b.process .b.export .b.clear \ -side right -padx 3 -pady 3 -ipadx 10 # -side right -padx 5 -pady 5 -ipadx 15 pack .b -fill x wm protocol . WM_DELETE_WINDOW finish wm title . $::progVersion # set minsize to the size of the window after 1sec. # this freezes the automatically set windows size as minimum. after 1000 {catch {wm minsize . [lindex [split [wm geometry .] x+] 0] [lindex [split [wm geometry .] x+] 1]}} } ######################################################### # main # build_gui read_rc scan_clp 1 ====== ---- **Comments** [HJG] 2016-01-25 - I added a new command "filter". It searches thru the text of the selected clip for certain keywords, and returns some extracted text-snippets to the clipboard. Currently, the proc filter_clp is looking for 3 different patterns, let's call them Forum, IP, and CDex. When a block of text from a forum-posting gets copied to the clipboard, that might look like ====== Post subject: Re: Problem. New postPosted: 2016-01-13 14:15 Reply with quote ... ====== Now the filter scans that text and exports back to the clipboard: Date= 2016-01-13 14:15 Subject= Re: Problem. [wm title] is used for brief status-messages. I also tried to make the diff-portion of ClipboardMonitor work with http://www.prestosoft.com/edp_examdiffpro.asp?flm=1%|%ExamDiff%|%. <
> (There is also a free version available on that website)<
> So far, this was only partly successful: that diff-program runs, but returns with an errorcode. <
> I guess Examdiff uses exitcode 0=no diffs found, 1=some diffs found, 2=error, or something like that. [HJG] 2016-02-04: Added another new command, "Process". <
> For now, it just converts the text of the selected entry to lowercase before exporting it to the clipboard, but I have plans to expand this functionality. <> Application | GUI | Desktop