diff --git a/src/multi_clipboard.v2.ahk b/src/multi_clipboard.v2.ahk index 03c777a..5cd0b3b 100644 --- a/src/multi_clipboard.v2.ahk +++ b/src/multi_clipboard.v2.ahk @@ -1,17 +1,18 @@ ;=================================================================================================== ; Multi_Clipboard -; GroggyOtter - 20230502 +; Created by: GroggyOtter +; Creation Date: 20230501 ;=================================================================================================== -; Customizeable multi-clipboard script +; A Customizable multi-clipboard script. ; Allows number bar, numpad, or function keys to be used. ; Modifier keys are used to either copy, paste, or view a key's clipboard ; ; === Usage ======================================================================================== -; Treats a numberset as multiple virtual clipboard that you can copy to, paste from, and display +; Treats a numberset as multiple virtual clipboards that you can copy to, paste from, and display ; Example:input_mode is 1, copy_hotkey is ^, paste_hotkey is 0 = none, 1 = NumPad, 2 = F - ,this.clip_dat[num] := {str:'',bin:Buffer(0)} ; Initialize with an object for string and binary - ,this.make_hotkey(num, prfx) ; Create hotkey + this.backup() ; Backup clipboard to original contents + ,empty := ClipboardAll() ; Save empty ClipboardAll object for clip_dat initialization + ,times := this.input_mode = 2 ? 12 : 10 ; Set loop to 12 if function and 10 for numpad/numbar + loop times { ; Loop once for each number in the set + num := A_Index - (this.input_mode = 2 ? 0 : 1) ; Use index for minus 1 for non-function keys so they start at 0 + ,prfx := !this.input_mode ? '' : (this.input_mode = 1) ? 'Numpad' : 'F' ; Set prefix > 0 = none, 1 = NumPad, 2 = F + ,this.clip_dat[num] := {str:'', bin:empty} ; Initialize with an object for string and binary + ,this.make_hotkey(num, prfx) ; Create hotkey + + this.restore() ; Restore clipboard to original contents } } @@ -77,54 +82,62 @@ class multi_clipboard { ,5,'Clear' ,6,'Right' ,7,'Home' ,8,'Up' ,9,'PgUp') for method, hk_mod in this.mod_map { ; Loop through copy/paste/show methods and mods - obm := ObjBindMethod(this, method, num) ; Make BoundFunc to run when copy/paste/show pressed - ,Hotkey('*' hk_mod prfx num, obm) ; Creates copy/paste/show in both numpad and shift+numpad variants - ,(this.input_mode = 1) ? Hotkey('*' hk_mod prfx num_shift[num], obm) : 0 ; If numpad, make a shift variant hotkey + obm := ObjBindMethod(this, method, num) ; Make BoundFunc to run when copy/paste/show pressed + ,Hotkey('*' hk_mod prfx num, obm) ; Creates copy/paste/show in both numpad and shift+numpad variants + ,(this.input_mode = 1) ? Hotkey('*' hk_mod prfx num_shift[num], obm) : 0 ; If numpad, make a shift variant hotkey } } static copy(index, *) { ; Method to call when copying data - bak := ClipboardAll() ; Backup current clipboard contents - ,A_Clipboard := '' ; Clear clipboard + this.backup() ; Backup current clipboard contents ,SendInput('^c') ; Send copy ,ClipWait(1, 1) ; Wait up to 1 sec for clipboard to contain something ,this.clip_dat[index].bin := ClipboardAll() ; Save string/bin data to clip_dat ,this.clip_dat[index].str := A_Clipboard ; Save string/bin data to clip_dat - ,A_Clipboard := bak ; Finally, restore the original clipboard contents + ,this.restore() ; Restore clipboard to original contents } static paste(index, *) { ; Method to call when pasting saved data - bak := ClipboardAll() ; Backup current clipboard contents + this.backup() ; Backup current clipboard contents ,A_Clipboard := this.clip_dat[index].bin ; Put saved data back onto clipboard ,SendInput('^v') ; Paste loop 10 ; Wait up to 1 second for clipboard to not be in use - Sleep(100) - Until !DllCall('GetOpenClipboardWindow') ; Break if clipboard not in use - A_Clipboard := bak ; Finally, restore the original clipboard contents + Sleep(100) ; Wait 100ms and check again + Until !DllCall('GetOpenClipboardWindow') ; And break if clipboard not in use + this.restore() ; Restore clipboard to original contents + } + + static backup() { ; Backs up and clears clipboard + this._backup := ClipboardAll() + ,A_Clipboard := '' + } + + static restore() { ; Restores clipboard + A_Clipboard := this._backup } static show(index:='', hk:='', *) { ; Method to show contents of clip_dat str := '' ; String to display if (index != '') ; If key not blank, clipboard was specified - str .= this.format_line(index) ; Get that key's clipboard info + str .= this.format_line(index) ; Get that key's clipboard info else ; Else if key was blank, get all clipboards - for index in this.clip_dat ; Loop through clip_dat - str .= this.format_line(index) '`n`n' ; Format each clipboard + for index in this.clip_dat ; Loop through clip_dat + str .= this.format_line(index) '`n`n' ; Format each clipboard - edit_max_char := 64000 - if (StrLen(str) > edit_max_char) - str := SubStr(str, 1, edit_max_char) + edit_max_char := 64000 ; Edit boxes have a max char of around 64000 + if (StrLen(str) > edit_max_char) ; If chars exceeds that + str := SubStr(str, 1, edit_max_char) ; Keep only the first 64000 chars so no error is thrown this.make_gui(RTrim(str, '`n')) ; Trim text and make a gui to display it If this.quick_view ; If quick view is enabled - KeyWait(this.strip_mods(hk)) ; Halt code here until hotkey is released - ,this.destroy_gui() ; Destroy gui after key release + KeyWait(this.strip_mods(hk)) ; Halt code here until hotkey is released + ,this.destroy_gui() ; Destroy gui after key release return } static format_line(index) { ; Formats clipboard text for display - switch this.input_mode { ; Get key type using input_mode + switch this.input_mode { ; Get key input_mode string type case 0: typ := 'Number ' case 1: typ := 'Numpad' case 2: typ := 'F' @@ -151,8 +164,9 @@ class multi_clipboard { ,chr_h := 15 ; Set a char height ,strl := 0 ; Track max str length loop parse str, '`n', '`r' ; Go through each line of the string - n := StrLen(A_LoopField), (n > strl ? strl := n : 0), strr := A_Index ; If length of str > strl, record new max + n := StrLen(A_LoopField), (n > strl ? strl := n : 0), strr := A_Index ; If length of str > strl, record new max + ; Approximate how big the edit box should be w := (strl) * chr_w ; Width = chars wide * char width ,h := (strr + 2) * chr_h ; Height = Rows (+4 scrollbar/padding) * char height ,(h > A_ScreenHeight*0.7) ? h := A_ScreenHeight*0.7 : 0 ; Don't let height exceed 70% screen height @@ -170,17 +184,21 @@ class multi_clipboard { ,goo.OnEvent('Close', (*) => goo.Destroy()) ; On gui close, destroy it ,goo.OnEvent('Escape', (*) => goo.Destroy()) ; On escape press, destroy it ,goo.SetFont('s10 cWhite Bold', 'Consolas') ; Default font size, color, weight, and type + ; Edit box opt := ' ReadOnly -Wrap +0x300000 -WantReturn -WantTab Background' bg_col ; Edit control options ,goo.edit := goo.AddEdit('xm ym w' edt.w ' h' edt.h opt, str) ; Add edit control to gui + ; Copy btn goo.copy := goo.AddButton('xm y+' m ' w' btn.w ' h' btn.h, 'Copy To Clipboard') ; Add an large close button ,goo.copy.OnEvent('Click', (*) => A_Clipboard := goo.edit.value) ; When it's clicked, destroy gui ,goo.copy.Focus() ; Now close button the focused control + ; Close btn - goo.close := goo.AddButton('x+' m ' yp w' btn.w ' h' btn.h, 'Close') ; Add an large close button + goo.close := goo.AddButton('x+' m ' yp w' btn.w ' h' btn.h, 'Close') ; Add an large close button ,goo.close.OnEvent('Click', (*) => goo.Destroy()) ; When it's clicked, destroy gui ,goo.close.Focus() ; Now close button the focused control + ; Finish up obm := ObjBindMethod(this, "WM_MOUSEMOVE") ; Boundfunc to run with OnMessage ,OnMessage(0x200, obm) ; When gui detects mouse movement (0x200), run boundfunc @@ -193,7 +211,7 @@ class multi_clipboard { static WM_MOUSEMOVE(wparam, lparam, msg, hwnd) { ; Function that runs on gui mouse move static WM_NCLBUTTONDOWN := 0xA1 ; Message for left clicking on a window's titlebar if (wparam = 1) ; If Left Mouse is down - PostMessage(WM_NCLBUTTONDOWN, 2,,, "ahk_id " hwnd) ; Tell windows left click is down on the title bar + PostMessage(WM_NCLBUTTONDOWN, 2,,, "ahk_id " hwnd) ; Tell windows left click is down on the title bar } static destroy_gui() { ; Destroys current gui @@ -202,16 +220,16 @@ class multi_clipboard { static strip_mods(txt) { ; Used to remove modifiers from hotkey strings loop parse '^!#+*<>~$' ; Go through each modifier - if SubStr(txt, -1) != A_LoopField ; Last char can't match or the symbol is the literal key - txt := StrReplace(txt, A_LoopField) ; Otherwise remove it + if SubStr(txt, -1) != A_LoopField ; Last char can't match or the symbol is the literal key + txt := StrReplace(txt, A_LoopField) ; Otherwise remove it return txt ; Return neutered hotkey } static verify_mod_map() { ; Warns user of duplicate key assignments for meth1, mod1 in this.mod_map ; Loop through mod_map once for base - for meth2, mod2 in this.mod_map ; Loop again for comparison - if StrCompare(mod1, mod2) && !StrCompare(meth1, meth2) ; If two modifiers match but keys don't - throw Error('Duplicate modifiers found in mod_map', A_ThisFunc ; Throw an error to notify user + for meth2, mod2 in this.mod_map ; Loop again for comparison + if StrCompare(mod1, mod2) && !StrCompare(meth1, meth2) ; If two modifiers match but keys don't + throw Error('Duplicate modifiers found in mod_map', A_ThisFunc ; Throw an error to notify user ,'`n' meth1 ':' mod1 '`n' meth2 ':' mod2) } }