Last active
March 26, 2022 04:59
-
-
Save jadient/1b1478f59f6308c2ea451bdb35f964fb to your computer and use it in GitHub Desktop.
Simple Clipboard History for Windows
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; ClipHist4 - ClipBoard History using AutoHotkey | |
;; | |
;; From: | |
;; https://tinyurl.com/cliphist4 | |
;; | |
;; Based on: | |
;; https://www.autohotkey.com/board/topic/87650-clipboard-history-menu-decrementing-numbered-circular-buckets/ | |
;; with customizations and modernization | |
;; | |
;; About ClipHist4: | |
;; - Stores up to 10 items of clipboard history | |
;; - Popup menu for clipboard history, controllable with keyboard or mouse | |
;; - Hotkeys for the 3 most recent clipboard items | |
;; - Displays tooltip on copy to clipboard | |
;; - Compatible with emacs and putty | |
;; | |
;; Limitations: | |
;; - Text-only | |
;; | |
;; Hotkeys: | |
;; Ctrl-1 to paste the most recent clipboard item | |
;; Ctrl-2 to paste previous item on clipboad | |
;; Ctrl-3 to paste item before that | |
;; Ctrl-4 to show clipboard history as a popup menu | |
;; | |
;; Clipboard history management: | |
;; - if copied text is already in the history, it will be moved to the top of the history | |
;; rather than duplicating the item | |
;; - on menu selection via mouse, if the shift key is down | |
;; the selected item is moved to the top of the list | |
;; | |
^1:: PasteClipItem(1) ;; send current (top) clipboard item | |
^2:: PasteClipItem(2) ;; send previous clipboard item | |
^3:: PasteClipItem(3) ;; send the one before that | |
^4:: ShowClipHistMenu() ;; who can remember past 3? show a menu! | |
ShowClipHistMenu() | |
{ | |
global ClipList | |
;; remove previous menu | |
Menu, ClipboardHistory, Add | |
Menu, ClipboardHistory, DeleteAll | |
;; create new menu items | |
Loop % ClipList.Length() | |
{ | |
;; clean the text for use in the menu | |
MenuText := StrReplace(ClipList[A_Index], "`n", "|") | |
MenuText := RegExReplace(MenuText, "[[:blank:]]+", " ") | |
MenuText := SubStr(MenuText, 1, 64) | |
;; 0x00b7 - unicode middle dot: https://unicodeplus.com/U+00B7 | |
MenuLabel := "&" . Chr(64+A_Index) . " " . Chr(0x00b7) . " " | |
;; label menu items starting with 'A' for keyboard access | |
Menu, ClipboardHistory, Add, % MenuLabel . MenuText, PasteClipFromMenu | |
} | |
;; a hint of blue for menu background: https://tinyurl.com/d0e0f0 | |
Menu, ClipboardHistory, Color, d0e0f0 | |
;; show menu near current cursor position | |
Menu, ClipboardHistory, Show, % A_CaretX, % A_CaretY + 16 | |
} | |
HandleClipboardChange(Type) | |
{ | |
If (Type != 1) | |
return | |
global ClipList | |
;; replace CRLF by LF | |
Text := StrReplace(Clipboard, "`r`n", "`n") | |
;; check if text is already in the history list | |
ClipListIndex := HasVal(ClipList, Text) | |
if (ClipListIndex > 0) | |
ClipList.RemoveAt(ClipListIndex) | |
;; add item to the top of the history list | |
ClipList.InsertAt(1, Text) | |
ShowTooltip(ClipList[1]) | |
;; enforce max number of items | |
ClipList.RemoveAt(ClipList.Max+1) | |
} | |
;; from https://tinyurl.com/HasVal | |
HasVal(haystack, needle) | |
{ | |
for index, value in haystack | |
if (value == needle) | |
return index | |
return 0 | |
} | |
ShowTooltip(Text) | |
{ | |
;; show no more than the first 80 characters | |
Tooltip % SubStr(Text, 1, 80) . "..." | |
; display tooltip for 1 second | |
Sleep 1000 | |
Tooltip | |
} | |
PasteClipFromMenu(ItemName, ItemPos, MenuName) | |
{ | |
global ClipList | |
PasteText(ClipList[ItemPos]) | |
;; move item top top of list, if shift key is down | |
if (ItemPos > 1 && GetKeyState("Shift")) | |
{ | |
ClipList.InsertAt(1, ClipList[ItemPos]) | |
ClipList.RemoveAt(ItemPos+1) | |
} | |
} | |
PasteClipItem(index) | |
{ | |
global ClipList | |
PasteText(ClipList[index]) | |
} | |
PasteText(Text) | |
{ | |
;; faster method, but it's a hack: | |
;; | |
;; (1) save current contents of clipboard | |
;; (2) put text into the clipboard | |
;; (3) send hotkey that will paste the text | |
;; (4) restore the clipboard | |
;; | |
;; Our own clipboard handler must be disabled during these operations. | |
;; If anyone else is listening to the clipboard, this will confuse them. | |
;; | |
;; if this doesn't work, replace with this: | |
;; SetKeyDelay,0 | |
;; SendRaw % Text | |
;; | |
If WinActive("ahk_class Emacs") ;; any Emacs users out there? | |
PasteKey := "^y" ;; send C-y for emacs "yank" | |
Else | |
PasteKey := "+{Ins}" ;; same as ^v, but +{Ins} also works with putty | |
ClipSaved := ClipboardAll ;; save the clipboard | |
;; disable our clipboard listener | |
OnClipboardChange("HandleClipboardChange", 0) | |
Clipboard := Text ;; put text in the clipboard | |
Sleep 100 ;; delay (to increase reliability - rdpclip) | |
Send % PasteKey ;; send keystroke to paste | |
Clipboard := ClipSaved ;; restore the clipboard | |
Sleep 100 ;; delay (to increase reliability) | |
;; restore our clipboard listener | |
OnClipboardChange("HandleClipboardChange", 1) | |
} | |
;; the OnClipboardChange label is deprecated, but it's quite useful here | |
OnClipboardChange: | |
global ClipList | |
if (IsObject(ClipList) ) | |
;; our registered clipboard handler will be triggered | |
return | |
;; first time here, perform initialization | |
ClipList := [] | |
;; max number of items in history | |
ClipList.Max := 10 | |
;; handle the clipboard event, just this one time | |
HandleClipboardChange(A_EventInfo) | |
;; next clipboard event will be handled using the newer mechanism | |
OnClipboardChange("HandleClipboardChange") | |
return |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment