; Clipser ; Copyright (c) 2005 by Decarlo L. ; this program may only be used under the 110 SGPL License ; v1.2.4 ; fixed clip menu reset issues: item compounding, OnClipboardChange buffer effect ; v1.2.3 ; added restore of system clipboard after Clipser paste ; fixed first item duplicate-checking to allow subsets ; added ability for consecutive Paste, supporting Space, Backspace, Enter, Comma ; added skip of filepath/URL caching for items over 99 lines to improve speed ; fixed bug of Undo when clip menu appears ; v1.2.2 description: ; multiclipboard utility. ; menu view (Shift.Ctrl.v.c), ; cycling view (Shift.Ctrl.v, hold modifiers, then v/c for forward/back), ; efficient clipboard switching (double-press LCtrl, then tap/hold), ; composite text clipboard simultaneous with any selected clipboard, ; automatic caching of any copied (or cut) texts, ; automatic checking of duplicate items, ; item-copied indicator, ; alphabetic/chronological clip menu listing, ; automatic saving of clipboards on exit of program or changing of clip ring, ; view/edit all items (toggle Shift.Ctrl.c), ; delete selected items/replace list (Shift.Ctrl.c, hold, then right-click in dialog), ; automatic caching of copied files 10 Mb or less, ; automatic caching of filepathNames and website URL's to specified clipboard, ; support for configurable cut, copy, paste hotkeys ; clipboard naming and other configurable settings (hold Ctrl.C or Alt.L) ; help dialog (right-click dialog after holding Shift.Ctrl.c / Ctrl.C / Alt.L) ; add: auto-capture to specified clipboard when window/program is foreground/open ; add: support for pictures and other non-text objects ; add: option for automatic-advance in multiple Paste ; add: ListBox mode to DeleteSelect ; history, recent topmost: ; added limit setting for automatic delete in file cache ; added option to normalize filecache names from source-naming default ; added support for configurable hotkey option for cut, copy, paste ; added auto-capture of filepathNames and website URL's to specified clipboard ; added ability to backward wrap for in-text scrolling of clip list ; fixed some array handling due to clipboard switching ; added clip# indicator when switching clipboards ; completed remaining list routines to handle clipboard switching ; added updating of clip# index when clipboard is switched ; added automatic saving of clipboards prior to loading new clipboard ring ; fixed issues related to empty clipboard ring ; fixed item checking for last item stored ; fixed item checking regarding subsets of copied items ; fixed item checking on initial entry after clipboard is switched ; modified item checking to handle when custom clipboard is not <composite> ; fixed list handling when max clip limit is reached ; fixed duplicate-item checking of initial element ; fixed menu display issues of item sorting, initial item, and reverse indexing ; added automatic save/load of last clipboard ring ; added settings gui and .ini file for clipboard names and other settingsDownload Clipser (67 K)
Here are the functions used (included in the download).
RunW(app, secToWait=30) ; Run,WinWait,WinActivate,WinWaitActive { Run, %app%,,, appPID ; must be PID, not ID WinWait ahk_pid %appPID%,, %secToWait% WinActivate WinWaitActive,,, %secToWait% ; default 30 sec maximum ifWinNotActive ahk_pid %appPID% Msgbox, Target application window did not activate within %secToWait% sec.`n`nThe originating thread may cause problems if it continues. return } SplashText(title="", timeout="", width="", height="", text="") ; default timeout 700 { SplashTextOn, %Width%, %Height%, %Title%, %Text% if timeout = sleep 700 else if timeout = 0 ; leave on until replaced or turned off later RETURN else sleep %timeout% SplashTextOff return } StringR(in, charsToKeep, charsToTrim="") { StringRight, out, in, %charsToKeep% if charsToTrim StringTrimRight, out, out, %charsToTrim% return out } StringM(in, StartChar, Count, L="") { if L = L StringMid, Out, in, %StartChar%, %Count%, L else StringMid, Out, in, %StartChar%, %Count% return out } StringL(in, charsToKeep, charsToTrim="", trimInitialWhitespace="") { global recurse_StringL_out StringLeft, out, in, %charsToKeep% if charsToTrim StringTrimLeft, out, out, %charsToTrim% if trimInitialWhitespace { recurse_StringL_out = %out% Loop % StrLen(out) { if Contains( StringL(recurse_StringL_out, 1), A_Space . "," . A_Tab . ",`n,`r,`v,`f" ) ; if first char is space recurse_StringL_out := StringL(recurse_StringL_out, StrLen(recurse_StringL_out), 1) ; trim first char else BREAK } } if trimInitialWhitespace return recurse_StringL_out else return out } In( a, b ) ; If a in b list. For b, use "var1 [, var2, ...]" { Loop, Parse, b, `,, %A_Space%%A_Tab% if a = %A_LoopField% Return 1 } Contains( a, b ) ; If a contains any element in b list "var1[,var2,...]" do not use spaces/tabs. ; modifying this to handle spaces/tabs in b list, will make it incompatible with StringL whitespace-trim. { Loop, Parse, b, `, ;, %A_Space%%A_Tab% ifInString, a, %A_LoopField% Return 1 } GuiControlGet(Subcommand="", ControlID="", Param4="") ; use prefix 2:, 37:, etc in first param if needed { GuiControlGet, OutputVar, %Subcommand%, ControlID, Param4 return OutputVar } NotInString(a,b) { IfNotInString, a, %b% ; 2nd param of IfInString defaults to a literal return 1 } KeyWait(str, hotkey="") ; default is string, not hotkey label ; this accepts strings and hotkey labels. do not use commas; spaces/tabs optional { str_orig := str if hotkey ; parse hotkey label { StringReplace, str, str, ^, Ctrl`, StringReplace, str, str, #, LWin`,RWin`, StringReplace, str, str, !, Alt`, StringReplace, str, str, +, Shift`, StringReplace, str, str, %A_Space%&%A_Space%, `, if StringR(str, 2) = ",," { StringTrimRight, str, str, 1 str := str . "`," } ; msgbox,,, %str_orig% =`n`n%str%, 2 Loop, Parse, str, `,, %A_Space%%A_Tab% Keywait % A_LoopField } else Loop, Parse, str,, %A_Space%%A_Tab% Keywait % A_LoopField } HotkeyStrCode(str, codeToString = "") { if codeToString { StringReplace, str, str, +, % " Shift ", all StringReplace, str, str, ^, % " Ctrl ", all StringReplace, str, str, #, % " Win ", all StringReplace, str, str, !, % " Alt ", all } else { StringReplace, str, str, LShift, +, all StringReplace, str, str, RShift, +, all StringReplace, str, str, Shift, +, all StringReplace, str, str, LCtrl, ^, all StringReplace, str, str, RCtrl, ^, all StringReplace, str, str, Ctrl, ^, all StringReplace, str, str, LWin, #, all StringReplace, str, str, RWin, #, all StringReplace, str, str, Win, #, all StringReplace, str, str, LAlt, !, all StringReplace, str, str, RAlt, !, all StringReplace, str, str, Alt, !, all } return str } Sort(ByRef varName, options="", separator="") ; option DØ = ability to sort on every char { if separator = separator = ¤ ifInString, options, DØ { StringReplace, options, options, DØ varNameLength := StrLen(varName) Loop, Parse, varName { ifNotInString, notRepeated, %A_LoopField% { notRepeated = %notRepeated%%A_LoopField% if (A_Index = varNameLength) varName1 = %varName1%%A_LoopField% else varName1 = %varName1%%A_LoopField%%separator% } } if StringR(varName1, 1) = "¤" varName1 := StringR(varName1, 260, 1) Sort varName1, D%separator% Sort varName1, options StringReplace, varName1, varName1, ¤,, all varName = %varName1% ; ByRef changes original } else Sort, varName, options return varName }