0

When pressing "Ctr+C" while selecting some files in the explorer, their paths are saved in the clipboard and when later pressing "Ctr+V" the files are pasted. For an AutoHotkey script I need to edit these paths in the clipboard, so the explorer pastes other files in the location of the "Ctr+V" press. So for example I want to select the file "A.txt" in "C:\Folder1" with "Ctr+C", then activate the AutoHotkey script to change the stored information in the clipboard of "A.txt" to the information about another file "B.txt", so when pressing "Ctr+V" in "C:\Folder2" the explorer copies "B.txt" instead of "A.txt".

But I have no idea how the paths of "Ctr+C" are exactly stored in the clipboard and I found no useful documentation. Different programms to access the content of the clipboard give one of the three results: 1) [Absolute nothing] 2) "C://A.txt" 3) "file:///C:/A.txt". But when editing the clipboard to "C://B.txt" or "file:///C:/B.txt" I got no reaction of the file explorer when using "Ctr+V".

So how are the paths of copied files exactly stored in the clipboard and with which programm I could edit them?

Edit: Following expamle to explain exactly what my goal is: Suppose I have a file "A.txt" in path 1, which I want to move to path 2 and another file "B.txt" in path 3, which I want to move to path 4. The normal procedure would be:

1) Copy "A.txt" with "Ctr+C" in path 1.

2) Paste "A.txt" with "Ctr+V" in path 2.

3) Copy "B.txt" with "Ctr+C" in path 3.

4) Paste "B.txt" with "Ctr+V" in path 4.

The goal of my AutoHotkey script is to allow the following alternative:

1) Copy "A.txt" with "Ctr+C+1" in path 1.

2) Copy "B.txt" with "Ctr+C+2" in path 2.

3) Paste "A.txt" with "Ctr+V+1" in path 1.

4) Paste "B.txt" wiht "Ctr+V+2" in path 2.

At first glance it might seem unnecessary, but when organising a lot of files in more complex system, it would be really convenient for me. Ideally, it should also work when I add "C.txt", "D.txt", ... to be saved in the third/fourth/... clipboard slot and even when instead of "A.txt" I want to store multiple files in one clipboard slot; later I also want to implement "Ctr+X+[n]" to cut files.

I experimented a lot and was able to save the different paths of the files from the clipboard to AutoHotkey variables. But now I have to load the paths, which are stored in the AutoHotkey variables back to the clipboard, so the corresponding files are pasted with the explorer.

So just for an example: My AutoHotkey script detects the keyboard input "Ctr+C+1" while I select A.txt in the file explorer, then sends the computer the shorcut "Ctr+C" to store the path of A.txt in the clipboard and finally saves this path as "C:/A.txt" in the AutoHotkey varibale "clip1". Then I select B.txt in the file explorer, press "Ctr+C+2", so the AutoHotkey script presses "Ctr+C" to get the file paths into the Windows clipboard and then saves ít as "C:/B.txt" in "clip2". Now I press "Ctr+V+1", so the AutoHotkey script should write the path from the variable "clip1" back in the Windows, then press "Ctr+V" to paste the file in the explorer. But the really problem is now, that it is not enough to just edit the Windows clipboard to "C:/A.txt". Then so the explorer doesnt react to the input "Ctr+V", for which he should paste the file. So, the Windows clipboard has to be edited in another format, like for example "#explorer_file:///C:/A.txt" (just a complete stupid guess, since I have no idea how it looks). I need to find this format, so my AutoHotkey script can edit the currently saved paths to another paths.

I hope that explains all confusion about this confusing problem.

  • [Combinations of three or more keys](https://www.autohotkey.com/docs/Hotkeys.htm#combo) (Ctr+C+1 etc) are not supported. – user3419297 Dec 24 '19 at 21:03

1 Answers1

1

I'd use something like this:

#NoEnv
#SingleInstance Force

; Create a GUI with checkboxes to save the path of the last copied files and 
; copy/move selected items to another directory opened in explorer:

OnClipboardChange("files_copied")
return

files_copied(type){
    global
    If  (type == 1)  ; the Clipboard contains text or files copied
    {
        ; https://autohotkey.com/board/topic/150291-detect-clipboard-contents-as-text-file-etc/#entry735751
        If (DllCall("IsClipboardFormatAvailable", "uint", 15))  ; the Clipboard contains files
        {
            ToolTip, file(s) copied
            Gui, destroy
            Gui, Color, ControlColor, Black
            Gui, Font, CDefault, Lucida Console
            Gui,  Add, Button,   x30 y5 w100 h26 gCopy ,Copy
            Gui,  Add, Button,   x230 y5 w100 h26 gMove ,Move
            Gui,  Add, CheckBox, x20 y50 vCh200 gCheckAll   cYellow, Select All
            Gui,  Add, CheckBox, x20 y75 vCh201 gUnCheckAll cYellow, De-Select All
            Loop, Parse, Clipboard, `n, `r
            {
                y_pos := 100 + (A_Index * 25)
                Gui,  Add, CheckBox, x20 y%y_pos%  vCh%A_Index% cYellow, %A_LoopField%
                I := A_Index ; number of copied files
            }
            Gui_height := 125+I*25
            Gui,  Show, x100 y5 w400 h%Gui_height%, Files copied ; comment out this line if you want to only show the Gui after pressing F1
            Sleep 1000
            ToolTip
        }
    }
}

; Press F1 to show the Gui if it's hidden
F1:: Gui,  Show
; or If the command in the above function is commented out
; F1:: Gui,  Show, x100 y5 w400 h%Gui_height%, Files copied

CheckAll:
Loop, %I%
    GuiControl,, Ch%A_Index%, 1
GuiControl,, Ch200, 1
GuiControl,, Ch201, 0
return

UnCheckAll:
Loop, %I%
    GuiControl,, Ch%A_Index%, 0
GuiControl,, Ch200, 0
GuiControl,, Ch201, 1
return

Copy:
Gui, submit, nohide
If !WinExist("ahk_class CabinetWClass") ; explorer
{
    MsgBox, No explorer window exists
    return
}
WinActivate, ahk_class CabinetWClass
WinWaitActive, ahk_class CabinetWClass, ,2
If (ErrorLevel)
{
    MsgBox, explorer could not be activated
    return
}
ExplorerPath := GetActiveExplorerPath()
Loop %I%
{
    GuiControlGet, checked,, Ch%A_Index%, Value
    If (checked = 1) ; if the control is checked
    {
        GuiControlGet, file,, Ch%A_Index%, Text
        FileCopy, %file%, %ExplorerPath%\, 1  ; overwrite existing files
    }
}
return

Move:
Gui, submit, nohide
If !WinExist("ahk_class CabinetWClass") ; explorer
{
    MsgBox, No explorer window exists
    return
}
WinActivate, ahk_class CabinetWClass
WinWaitActive, ahk_class CabinetWClass, ,2
If (ErrorLevel)
{
    MsgBox, explorer could not be activated
    return
}
ExplorerPath := GetActiveExplorerPath()
MsgBox, 262180, Move Files, Are you sure you want to move the selected files to`n`n%ExplorerPath%?
IfMsgBox No
    return
New_Clipboard := ""
Loop %I%
{
    GuiControlGet, checked,, Ch%A_Index%, Value
    If (checked = 1) ; if the control is checked
    {
        GuiControlGet, file,, Ch%A_Index%, Text
        FileMove, %file%, %ExplorerPath%\, 1  ; overwrite existing files
    }
    else
    {
        GuiControlGet, file,, Ch%A_Index%, Text
        New_Clipboard .= file . "`n" ; concatenate the outputs
    }
}
If (New_Clipboard = "")
    Gui, destroy
else
    ClipboardSetFiles(New_Clipboard, DropEffect := "Copy")
return

GuiClose:
Gui,  Hide
return  

; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=69925
GetActiveExplorerPath()
{
    explorerHwnd := WinActive("ahk_class CabinetWClass")
    if (explorerHwnd)
    {
        for window in ComObjCreate("Shell.Application").Windows
        {
            if (window.hwnd==explorerHwnd)
            {
                return window.Document.Folder.Self.Path
            }
        }
    }
}

; https://autohotkey.com/boards/viewtopic.php?p=63914#p63914
ClipboardSetFiles(FilesToSet, DropEffect := "Copy") {
   ; FilesToSet - list of fully qualified file pathes separated by "`n" or "`r`n"
   ; DropEffect - preferred drop effect, either "Copy", "Move" or "" (empty string)
   Static TCS := A_IsUnicode ? 2 : 1 ; size of a TCHAR
   Static PreferredDropEffect := DllCall("RegisterClipboardFormat", "Str", "Preferred DropEffect")
   Static DropEffects := {1: 1, 2: 2, Copy: 1, Move: 2}
   ; Count files and total string length
   TotalLength := 0
   FileArray := []
   Loop, Parse, FilesToSet, `n, `r
   {
      If (Length := StrLen(A_LoopField))
         FileArray.Push({Path: A_LoopField, Len: Length + 1})
      TotalLength += Length
   }
   FileCount := FileArray.Length()
   If !(FileCount && TotalLength)
      Return False
   ; Add files to the clipboard
   If DllCall("OpenClipboard", "Ptr", A_ScriptHwnd) && DllCall("EmptyClipboard") {
      ; HDROP format 
      ; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
      hDrop := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 20 + (TotalLength + FileCount + 1) * TCS, "UPtr")
      pDrop := DllCall("GlobalLock", "Ptr" , hDrop)
      Offset := 20
      NumPut(Offset, pDrop + 0, "UInt")         ; DROPFILES.pFiles = offset of file list
      NumPut(!!A_IsUnicode, pDrop + 16, "UInt") ; DROPFILES.fWide = 0 --> ANSI, fWide = 1 --> Unicode
      For Each, File In FileArray
         Offset += StrPut(File.Path, pDrop + Offset, File.Len) * TCS
      DllCall("GlobalUnlock", "Ptr", hDrop)
      DllCall("SetClipboardData","UInt", 0x0F, "UPtr", hDrop) ; 0x0F = CF_HDROP
      ; Preferred DropEffect format 
      If (DropEffect := DropEffects[DropEffect]) {
         ; Write Preferred DropEffect structure to clipboard to switch between copy/cut operations
         ; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
         hMem := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 4, "UPtr")
         pMem := DllCall("GlobalLock", "Ptr", hMem)
         NumPut(DropEffect, pMem + 0, "UChar")
         DllCall("GlobalUnlock", "Ptr", hMem)
         DllCall("SetClipboardData", "UInt", PreferredDropEffect, "Ptr", hMem)
      }
      DllCall("CloseClipboard")
      Return True
   }
   Return False
}
user3419297
  • 9,537
  • 2
  • 15
  • 24