Paste second/third.. item from Windows clipboard Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
N1KA
Posts: 18
Joined: 08 Oct 2019, 01:37

Paste second/third.. item from Windows clipboard

Post by N1KA » 28 Jan 2021, 17:02

Windows 10 has Clipboard history feature
• I can copy multiple things
• and paste whichever I want
ctrl+v pastes last one, but I couldn't find any simple way to paste second, third ... items with simple shortcut
without opening clipboard UI with win+v and selecting which one I want to paste

I want to press win+1 or 2 and paste second or third last copied text.
the last solution I thought is to just replicate key combinations with autohotkey but send, {enter} doesn't work for me, normally it works when I press enter

Code: Select all

#1::
send, #v
sleep, 10
send, {Down}
sleep, 10
sendEvent, {enter}
return
Last edited by BoBo on 28 Jan 2021, 17:36, edited 1 time in total.
Reason: Added [code][/code]-tags.

User avatar
mikeyww
Posts: 26935
Joined: 09 Sep 2014, 18:38

Re: Paste second/third.. item from Windows clipboard

Post by mikeyww » 28 Jan 2021, 18:02

Code: Select all

Global clip := []
OnClipboardChange("ClipChanged")

#1::
#2::
#3::
#4::
#5::
#6::
#7::
#8::Send % clip[StrReplace(A_ThisHotkey, "#") + 1]

ClipChanged(Type) {
 clip.InsertAt(1, Clipboard)
 SoundBeep, 1700, 30
 If clip.Count() > 9
  clip.RemoveAt(10)
}

teadrinker
Posts: 4330
Joined: 29 Mar 2015, 09:41
Contact:

Re: Paste second/third.. item from Windows clipboard  Topic is solved

Post by teadrinker » 29 Jan 2021, 02:24

Code: Select all

#1::
#2::
   (new ClipboardHistory).PutHistoryItemIntoClipboard( SubStr(A_ThisHotkey, 2) + 1 )
   Send, ^v
   Return

class ClipboardHistory
{
; https://is.gd/bYyogJ ; Clipboard Class (MSDN)
; https://is.gd/F2lyI0 ; Windows.ApplicationModel.DataTransfer.h (GitHub)
   __New() {
      static IID_IClipboardStatics2 := "{D2AC1B6A-D29F-554B-B303-F0452345FE02}"
      if !(A_OSVersion ~= "^\d") {
         MsgBox, This class requires Windows 10 or later!
         Return
      }
      riid := CLSIDFromString(IID_IClipboardStatics2, _)

      WinStr := new WindowsString("Windows.ApplicationModel.DataTransfer.Clipboard")
      WinStr.CreateInterface(riid, pIClipboardStatics2)
      WinStr := ""

      this.ClipboardStatics2 := new IClipboardStatics2( pIClipboardStatics2 )
   }
   
   __Delete() {
      this.ClipboardStatics2 := ""
   }
   
   IsHistoryEnabled[] {
      get {
         Return this.ClipboardStatics2.IsHistoryEnabled
      }
   }
   
   ClearHistory() {
      Return this.ClipboardStatics2.ClearHistory()
   }
   
   PutHistoryItemIntoClipboard(index) { ; 1 based
      static SetHistoryItemAsContentStatus := ["Success", "AccessDenied", "ItemDeleted"]
      if !pIClipboardHistoryItem := this._GetClipboardHistoryItemByIndex(index)
         Return
      ClipboardHistoryItem := new IClipboardHistoryItem( pIClipboardHistoryItem )
      status := this.ClipboardStatics2.SetHistoryItemAsContent( ClipboardHistoryItem.ptr )
      Return SetHistoryItemAsContentStatus[ status + 1 ]
   }
   
   _GetClipboardHistoryItemByIndex(index) { ; 1 based
      static AsyncStatus  := ["Started", "Completed", "Canceled", "Error"]
      this.ClipboardStatics2.GetHistoryItemsAsync( pIAsyncOperation )
      AsyncOperation := new IAsyncOperation( pIAsyncOperation )
      AsyncOperation.QueryIAsyncInfo(pIAsyncInfo)
      AsyncInfo := new IAsyncInfo( pIAsyncInfo )
      Loop {
         Sleep, 10
         status := AsyncStatus[ AsyncInfo.Status + 1 ]
      } until status != "Started" || status = ""
      if (status != "Completed") {
         MsgBox,, Error, AsyncInfo.Status: "%status%"
         Return
      }
      AsyncOperation.GetResults( pIClipboardHistoryItemsResult )
      ClipboardHistoryItemsResult := new IClipboardHistoryItemsResult( pIClipboardHistoryItemsResult )
      pIReadOnlyList := ClipboardHistoryItemsResult.Items
      ReadOnlyList := new IReadOnlyList( pIReadOnlyList )
      if ( ReadOnlyList.Count < index ) {
         MsgBox, 48, % " ", Index "%index%" exceeds items count!
         Return
      }
      Return pIClipboardHistoryItem := ReadOnlyList.Item[index - 1]
   }
}

class IClipboardStatics2 extends _InterfaceBase
{
   GetHistoryItemsAsync(ByRef pIAsyncOperation) {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "UIntP", pIAsyncOperation)
      this.IsError(A_ThisFunc, hr)
   }
   ClearHistory() {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UIntP", res)
      this.IsError(A_ThisFunc, hr)
      Return res
   }
   SetHistoryItemAsContent(pIClipboardHistoryItem) {
      hr := DllCall(this.VTable(9), "Ptr", this.ptr, "Ptr", pIClipboardHistoryItem, "UIntP", res)
      this.IsError(A_ThisFunc, hr)
      Return res
   }
   IsHistoryEnabled[] {
      get {
         hr := DllCall(this.VTable(10), "Ptr", this.ptr, "UIntP", res)
         this.IsError(A_ThisFunc, hr)
         Return res
      }
   }
}

class IClipboardHistoryItemsResult extends _InterfaceBase
{
   Items[] {
      get {
         hr := DllCall(this.VTable(7), "Ptr", this.ptr, "PtrP", pIReadOnlyList)
         this.IsError(A_ThisFunc, hr)
         Return pIReadOnlyList
      }
   }
}

class IClipboardHistoryItem extends _InterfaceBase ; <— do not delete!
{
}

class IReadOnlyList extends _InterfaceBase
{
   Item[index] {
      get {
         hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Int", index, "PtrP", pInterface)
         this.IsError(A_ThisFunc, hr)
         Return pInterface
      }
   }
   Count[] {
      get {
         hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UIntP", count)
         this.IsError(A_ThisFunc, hr)
         Return count
      }
   }
}

class IAsyncOperation extends _InterfaceBase
{
   QueryIAsyncInfo(ByRef pIAsyncInfo) {
      static IID_IAsyncInfo := "{00000036-0000-0000-C000-000000000046}"
      pIAsyncInfo := ComObjQuery(this.ptr, IID_IAsyncInfo)
   }
   GetResults(ByRef pInterface) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "PtrP", pInterface)
      this.IsError(A_ThisFunc, hr)
   }
}

class IAsyncInfo extends _InterfaceBase
{
   Status[] {
      get {
         hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UIntP", status)
         this.IsError(A_ThisFunc, hr)
         Return status
      }
   }
}

class _InterfaceBase {
   __New(ptr) {
      this.ptr := ptr
   }
   __Delete() {
      ObjRelease(this.ptr)
   }
   VTable(idx) {
      Return NumGet(NumGet(this.ptr + 0) + A_PtrSize*idx)
   }
   IsError(method, result, exc := true) {
      if (result = 0)
         Return 0
      error := StrReplace(method, ".", "::") . " failed.`nResult: "
                              . ( result = "" ? "No result" : SysError(Format("{:#x}", result & 0xFFFFFFFF)) )
                              . "`nErrorLevel: " . ErrorLevel
      if !exc
         Return error
      throw error
   }
}

class WindowsString {
   __New(string, isHandle := false) {
      if isHandle
         this.hString := string
      else {
         DllCall("Combase\WindowsCreateString", "WStr", string, "UInt", StrLen(string), "PtrP", hString)
         this.hString := hString
      }
   }
   __Delete() {
      DllCall("Combase\WindowsDeleteString", "Ptr", this.hString)
   }
   Get() {
      pBuff := DllCall("Combase\WindowsGetStringRawBuffer", "Ptr", this.hString, "UIntP", len, "Ptr")
      Return StrGet(pBuff, len, "UTF-16")
   }
   CreateInterface(riid, ByRef pInterface) {
      hr := DllCall("Combase\RoGetActivationFactory", "Ptr", this.hString, "Ptr", riid, "PtrP", pInterface)
      if (hr != 0)
         throw SysError(hr)
   }
}

CLSIDFromString(IID, ByRef CLSID) {
   VarSetCapacity(CLSID, 16, 0)
   if hr := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", &CLSID, "UInt")
      throw "CLSIDFromString failed. Error: " . Format("{:#x}", hr)
   Return &CLSID
}

SysError(ErrorNum = "")
{ 
   static flag := (FORMAT_MESSAGE_ALLOCATE_BUFFER := 0x100) | (FORMAT_MESSAGE_FROM_SYSTEM := 0x1000)
   (ErrorNum = "" && ErrorNum := A_LastError)
   DllCall("FormatMessage", "UInt", flag, "UInt", 0, "UInt", ErrorNum, "UInt", 0, "PtrP", pBuff, "UInt", 512, "Str", "")
   Return (str := StrGet(pBuff)) ? str : ErrorNum
}

N1KA
Posts: 18
Joined: 08 Oct 2019, 01:37

Re: Paste second/third.. item from Windows clipboard

Post by N1KA » 30 Jan 2021, 16:29

teadrinker wrote:
29 Jan 2021, 02:24

Code: Select all

#1::
#2::
   (new ClipboardHistory).PutHistoryItemIntoClipboard( SubStr(A_ThisHotkey, 2) + 1 )
   Send, ^v
   Return

class ClipboardHistory
{
; https is.gd /bYyogJ  Broken Link for safety ; Clipboard Class (MSDN)
; https is.gd /F2lyI0  Broken Link for safety ; Windows.ApplicationModel.DataTransfer.h (GitHub)
   __New() {
      static IID_IClipboardStatics2 := "{D2AC1B6A-D29F-554B-B303-F0452345FE02}"
      if !(A_OSVersion ~= "^\d") {
         MsgBox, This class requires Windows 10 or later!
         Return
      }
      riid := CLSIDFromString(IID_IClipboardStatics2, _)

      WinStr := new WindowsString("Windows.ApplicationModel.DataTransfer.Clipboard")
      WinStr.CreateInterface(riid, pIClipboardStatics2)
      WinStr := ""

      this.ClipboardStatics2 := new IClipboardStatics2( pIClipboardStatics2 )
   }
   
   __Delete() {
      this.ClipboardStatics2 := ""
   }
   
   IsHistoryEnabled[] {
      get {
         Return this.ClipboardStatics2.IsHistoryEnabled
      }
   }
   
   ClearHistory() {
      Return this.ClipboardStatics2.ClearHistory()
   }
   
   PutHistoryItemIntoClipboard(index) { ; 1 based
      static SetHistoryItemAsContentStatus := ["Success", "AccessDenied", "ItemDeleted"]
      if !pIClipboardHistoryItem := this._GetClipboardHistoryItemByIndex(index)
         Return
      ClipboardHistoryItem := new IClipboardHistoryItem( pIClipboardHistoryItem )
      status := this.ClipboardStatics2.SetHistoryItemAsContent( ClipboardHistoryItem.ptr )
      Return SetHistoryItemAsContentStatus[ status + 1 ]
   }
   
   _GetClipboardHistoryItemByIndex(index) { ; 1 based
      static AsyncStatus  := ["Started", "Completed", "Canceled", "Error"]
      this.ClipboardStatics2.GetHistoryItemsAsync( pIAsyncOperation )
      AsyncOperation := new IAsyncOperation( pIAsyncOperation )
      AsyncOperation.QueryIAsyncInfo(pIAsyncInfo)
      AsyncInfo := new IAsyncInfo( pIAsyncInfo )
      Loop {
         Sleep, 10
         status := AsyncStatus[ AsyncInfo.Status + 1 ]
      } until status != "Started" || status = ""
      if (status != "Completed") {
         MsgBox,, Error, AsyncInfo.Status: "%status%"
         Return
      }
      AsyncOperation.GetResults( pIClipboardHistoryItemsResult )
      ClipboardHistoryItemsResult := new IClipboardHistoryItemsResult( pIClipboardHistoryItemsResult )
      pIReadOnlyList := ClipboardHistoryItemsResult.Items
      ReadOnlyList := new IReadOnlyList( pIReadOnlyList )
      if ( ReadOnlyList.Count < index ) {
         MsgBox, 48, % " ", Index "%index%" exceeds items count!
         Return
      }
      Return pIClipboardHistoryItem := ReadOnlyList.Item[index - 1]
   }
}

class IClipboardStatics2 extends _InterfaceBase
{
   GetHistoryItemsAsync(ByRef pIAsyncOperation) {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "UIntP", pIAsyncOperation)
      this.IsError(A_ThisFunc, hr)
   }
   ClearHistory() {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UIntP", res)
      this.IsError(A_ThisFunc, hr)
      Return res
   }
   SetHistoryItemAsContent(pIClipboardHistoryItem) {
      hr := DllCall(this.VTable(9), "Ptr", this.ptr, "Ptr", pIClipboardHistoryItem, "UIntP", res)
      this.IsError(A_ThisFunc, hr)
      Return res
   }
   IsHistoryEnabled[] {
      get {
         hr := DllCall(this.VTable(10), "Ptr", this.ptr, "UIntP", res)
         this.IsError(A_ThisFunc, hr)
         Return res
      }
   }
}

class IClipboardHistoryItemsResult extends _InterfaceBase
{
   Items[] {
      get {
         hr := DllCall(this.VTable(7), "Ptr", this.ptr, "PtrP", pIReadOnlyList)
         this.IsError(A_ThisFunc, hr)
         Return pIReadOnlyList
      }
   }
}

class IClipboardHistoryItem extends _InterfaceBase ; <— do not delete!
{
}

class IReadOnlyList extends _InterfaceBase
{
   Item[index] {
      get {
         hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Int", index, "PtrP", pInterface)
         this.IsError(A_ThisFunc, hr)
         Return pInterface
      }
   }
   Count[] {
      get {
         hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UIntP", count)
         this.IsError(A_ThisFunc, hr)
         Return count
      }
   }
}

class IAsyncOperation extends _InterfaceBase
{
   QueryIAsyncInfo(ByRef pIAsyncInfo) {
      static IID_IAsyncInfo := "{00000036-0000-0000-C000-000000000046}"
      pIAsyncInfo := ComObjQuery(this.ptr, IID_IAsyncInfo)
   }
   GetResults(ByRef pInterface) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "PtrP", pInterface)
      this.IsError(A_ThisFunc, hr)
   }
}

class IAsyncInfo extends _InterfaceBase
{
   Status[] {
      get {
         hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UIntP", status)
         this.IsError(A_ThisFunc, hr)
         Return status
      }
   }
}

class _InterfaceBase {
   __New(ptr) {
      this.ptr := ptr
   }
   __Delete() {
      ObjRelease(this.ptr)
   }
   VTable(idx) {
      Return NumGet(NumGet(this.ptr + 0) + A_PtrSize*idx)
   }
   IsError(method, result, exc := true) {
      if (result = 0)
         Return 0
      error := StrReplace(method, ".", "::") . " failed.`nResult: "
                              . ( result = "" ? "No result" : SysError(Format("{:#x}", result & 0xFFFFFFFF)) )
                              . "`nErrorLevel: " . ErrorLevel
      if !exc
         Return error
      throw error
   }
}

class WindowsString {
   __New(string, isHandle := false) {
      if isHandle
         this.hString := string
      else {
         DllCall("Combase\WindowsCreateString", "WStr", string, "UInt", StrLen(string), "PtrP", hString)
         this.hString := hString
      }
   }
   __Delete() {
      DllCall("Combase\WindowsDeleteString", "Ptr", this.hString)
   }
   Get() {
      pBuff := DllCall("Combase\WindowsGetStringRawBuffer", "Ptr", this.hString, "UIntP", len, "Ptr")
      Return StrGet(pBuff, len, "UTF-16")
   }
   CreateInterface(riid, ByRef pInterface) {
      hr := DllCall("Combase\RoGetActivationFactory", "Ptr", this.hString, "Ptr", riid, "PtrP", pInterface)
      if (hr != 0)
         throw SysError(hr)
   }
}

CLSIDFromString(IID, ByRef CLSID) {
   VarSetCapacity(CLSID, 16, 0)
   if hr := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", &CLSID, "UInt")
      throw "CLSIDFromString failed. Error: " . Format("{:#x}", hr)
   Return &CLSID
}

SysError(ErrorNum = "")
{ 
   static flag := (FORMAT_MESSAGE_ALLOCATE_BUFFER := 0x100) | (FORMAT_MESSAGE_FROM_SYSTEM := 0x1000)
   (ErrorNum = "" && ErrorNum := A_LastError)
   DllCall("FormatMessage", "UInt", flag, "UInt", 0, "UInt", ErrorNum, "UInt", 0, "PtrP", pBuff, "UInt", 512, "Str", "")
   Return (str := StrGet(pBuff)) ? str : ErrorNum
}
hooly crap maan this works the way I wanted without opening or closing clipboard history, thank you a lot

N1KA
Posts: 18
Joined: 08 Oct 2019, 01:37

Re: Paste second/third.. item from Windows clipboard

Post by N1KA » 30 Jan 2021, 16:36

mikeyww wrote:
28 Jan 2021, 18:02

Code: Select all

Global clip := []
OnClipboardChange("ClipChanged")

#1::
#2::
#3::
#4::
#5::
#6::
#7::
#8::Send % clip[StrReplace(A_ThisHotkey, "#") + 1]

ClipChanged(Type) {
 clip.InsertAt(1, Clipboard)
 SoundBeep, 1700, 30
 If clip.Count() > 9
  clip.RemoveAt(10)
}
thank you for responce, it works but it doesnot take copied values from my windows clipboard, but gets the job done, on win+3 writes "IsHistoryEnabled", anyways thank you for answer, @teadrinker replied code that works exactly as I needed.

User avatar
mikeyww
Posts: 26935
Joined: 09 Sep 2014, 18:38

Re: Paste second/third.. item from Windows clipboard

Post by mikeyww » 30 Jan 2021, 17:16

OK, good to hear! It worked when I tested it, but good if you found a solution. Best wishes.

justcop
Posts: 5
Joined: 25 Jan 2019, 08:33

Re: Paste second/third.. item from Windows clipboard

Post by justcop » 16 Aug 2022, 04:51

I'd love to use the code for this to save the status of the clipboard history, [then do some stuff,] and then recover the saved clipboard history so that anything I've done to the clipboard in the interim period is "forgotten".

I'm sure the code for this is in here somewhere but whilst I've got myself pretty good at AHK in the last couple of years classes and dll calls are still over my head so I'm struggling to know where to begin in creating this, which I'm sure is simple from the existing functions.

wetware05
Posts: 750
Joined: 04 Dec 2020, 16:09

Re: Paste second/third.. item from Windows clipboard

Post by wetware05 » 16 Aug 2022, 05:36

hi.
My development took several months. viewtopic.php?t=92963 The code is not good. Many processes can be improved. There are quite a few clipboard utilities created with AhotHotkey.

Some of them: Cl3-master, LintaList, Clipboard Master, Clipjump_x64, Deluxe Clipboard, ReClip, MultiClip, Custom Clipboard...

Post Reply

Return to “Ask for Help (v1)”