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.
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
}
I use autohotkey to insert a text string into a text file.
How can I store the path and the name of that file in a new variable?
Let's say I use this code for inserting a date/time stamp:
::iii:: ; insert a date time stamp
send, ID%A_YYYY%.%A_MM%.%A_DD%.%A_Hour%.%A_Min%.%A_Sec%
return
How can I modify my code to store the path and name of the file I am tagging?
Something like this? :
::iii:: ; insert a date time stamp
send, ID%A_YYYY%.%A_MM%.%A_DD%.%A_Hour%.%A_Min%.%A_Sec%
path = <code for extracting path>
filename = <code for extracting filename>
return
Try
::iii:: ; insert a date time stamp
SendInput, ID%A_YYYY%.%A_MM%.%A_DD%.%A_Hour%.%A_Min%.%A_Sec%{Enter}
SendInput, % GetFilePath_notepad() "`n"
SendInput, % GetFileName_notepad() "`n"
return
GetFilePath_notepad(){
If !WinActive("ahk_class Notepad")
{
MsgBox, Notepad isn't active
return
}
; https://autohotkey.com/docs/commands/ComObjGet.htm
Path := ""
WinGet pid, PID, A
wmi := ComObjGet("winmgmts:")
queryEnum := wmi.ExecQuery(""
. "Select * from Win32_Process where ProcessId=" . pid)
._NewEnum()
If queryEnum[process]
{
Pos := InStr(process.CommandLine, .exe,, 1)
Path := SubStr(process.CommandLine, Pos+6)
}
else
MsgBox, Process not found!
wmi := queryEnum := process := ""
If (Path != "")
return %Path%
else
MsgBox, Path not found!
}
GetFileName_notepad(){
If !WinActive("ahk_class Notepad")
{
MsgBox, Notepad isn't active
return
}
WinGetTitle, WinTitle, A
If (SubStr(WinTitle, -9) = " - Notepad")
FileName := SubStr(WinTitle, 1, -10)
If (SubStr(WinTitle, -8) = " - Editor")
FileName := SubStr(WinTitle, 1, -9)
If (SubStr(FileName, 1, 1) = "*")
FileName := SubStr(FileName, 2)
return %FileName%
}
EDIT:
Insteaf of
SendInput, % GetFilePath_notepad() "`n"
SendInput, % GetFileName_notepad() "`n"
you can use
FilePath := GetFilePath_notepad()
SendInput, %FilePath%{Enter}
FileName := GetFileName_notepad()
SendInput, %FileName%{Enter}
SendInput is faster and more reliable as Send
You can use the WinGet command to get the full path of the currently active window:
WinGet, path, ProcessPath, A
path is the variable in which you store the result of the command.
ProcessPath is a parameter of the command that tells it which information you want to extract, in this case the process path.
A means that you want to get the information of the currently active window.
To get the title of the currently active window you use the WinGetActiveTitle command:
WinGetActiveTitle, thetitle
StringTrimRight is used to remove the " - Notepad" part from the window title.
You can test your code with this:
::iii:: ; insert a date time stamp
send, ID%A_YYYY%.%A_MM%.%A_DD%.%A_Hour%.%A_Min%.%A_Sec%
WinGet, path, ProcessPath, A
WinGetActiveTitle, thetitle
StringTrimRight, thetitle, thetitle ,10
Msgbox, path=%path% `ntitle=%thetitle%
return
I often save files from Chrome to the Downloads folder or My Documents folder.
You have to look for these files later in the folder. Tell me whether it is possible to somehow make it more convenient using the ahk script. By pressing F3 for example, the last file or folder in the current folder is highlighted. How to implement it. Please help me, I'm a new
F3::
SetTitleMatchMode, 2
File := "" ; empty variable
Time := ""
Loop, Files, %A_MyDocuments%\Downloads\*.*, DF ; include files and folders
{
If (A_LoopFileTimeModified >= Time)
{
Time := A_LoopFileTimeModified ; the time the file/folder was last modified
File := A_LoopFileFullPath ; the path and name of the file/folder currently retrieved
}
}
; MsgBox, Last modified file in %A_MyDocuments%\Downloads is`n`n"%File%"
IfWinNotExist Downloads ahk_class CabinetWClass
Run % "explorer.exe /select," . File ; open containing folder and highlight this file/folder
else
{
SplitPath, File, name
MsgBox, Last modified file = "%name%"
WinActivate, Downloads ahk_class CabinetWClass
WinWaitActive, Downloads ahk_class CabinetWClass
; SelectExplorerItem(name) ; or:
SendInput, %name%
}
return
SelectExplorerItem(ItemName) { ; selects the specified item in the active explorer window, if present
; SelectItem -> msdn.microsoft.com/en-us/library/bb774047(v=vs.85).aspx
Window := ""
Static Shell := ComObjCreate("Shell.Application")
For Window In Shell.Windows
try IfWinActive, % "ahk_id " window.HWND
If (Item := Window.Document.Folder.ParseName(ItemName))
Window.Document.SelectItem(Item, 29)
Return (Item ? True : False)
}
https://autohotkey.com/docs/commands/LoopFile.htm
This code figures out the current explorer windows open,
I would like to open the first in the list, and if the list is empty open a
new explorer instead.
I hope to the open/activate the either window at the current mouse position
#e::
list := ""
numberOfwindows := ""
wins := ""
WinGet, id, list, ahk_class CabinetWClass ahk_exe explorer.exe
Loop, %id%
{
numberOfwindows := A_Index
this_ID := id%A_Index%
WinGetTitle, title, ahk_id %this_ID%
wins .= A_Index A_Space title ? A_Index A_Space title "`n" : ""
}
MsgBox, number of explorer windows = %numberOfwindows%`n`n%wins%
return
This solves it. - however it can be optimized, anyone have any suggestions ?
#e::
list := ""
numberOfwindows := ""
wins := ""
WinGet, id, list, ahk_class CabinetWClass ahk_exe explorer.exe
Loop, %id%
{
numberOfwindows := A_Index
this_ID := id%A_Index%
WinGetTitle, title, ahk_id %this_ID%
if (A_Index = 1) { ; if it's the first index of the loop
;MsgBox %title%
win = %title% ; store the title in " win "
}
wins .= A_Index A_Space title ?½½ A_Index A_Space title "`n" : ""
}
IfWinNotExist ahk_class CabinetWClass
{
Run C:\Windows\explorer.exe
win := File Explorer
WinWait, %win% ahk_class CabinetWClass
WinMove, mxpos_new , mypos_new
WinActivate
}
;MsgBox, number of explorer windows = %numberOfwindows%`n`n%wins%
; above msgbox displays number and the names of the windows.
;~ ; we now know the win
; and its title, exe and class.
; we want it's current position.
WinGetPos, X, Y, Width, Height,%win% ahk_class CabinetWClass
;MsgBox, %X%, %Y%, %Width%, %Height%
; and we want the mouse position.
CoordMode, Mouse, Screen ; Coordinates are relative to the desktop (entire screen).
MouseGetPos, mxpos , mypos,
;MsgBox, %mxpos%, %mypos%
mxpos_new := mxpos - (Width / 2)
mypos_new := mypos - (Height / 2)
;MsgBox, %mxpos% %mypos% %Width% %Height% %mxpos_new% %mypos_new%
; activate that specific window
WinWait, %win% ahk_class CabinetWClass
WinMove, mxpos_new , mypos_new
WinActivate
return
I'm trying to find out if there is a "Save As" box open with this WinExist script
if WinExist,Save As,Save As
MsgBox, is there
else
MsgBox, is not there
Your original code is almost correct:
The space between if and WinExist must be removed.
The second parameter of ifWinExist is WinTitle. If the Save As dialog does not contain the text "Save As", you must remove that second parameter. This is the case on my Windows 7 system with English (Australia) regional settings.
Working examples:
; ifWinExist command
ifWinExist, Save As
MsgBox, is there
else
MsgBox, is not there
; if(expression) and WinExist() function
if WinExist("Save As")
MsgBox, is there
else
MsgBox, is not there
You can also combine criteria:
ifWinExist, Save As ahk_class #32770
Assuming it is an OSs' window, I would do something like,
^F1:: ;press Control + F1 to serch the window.
if FindWindow()
msgbox Found
else
msgbox Not Found
Return
FindWindow(strPartOfTitle="Save", strClass="#32770") {
if (hWnd := WinExist("ahk_class " . strClass))
{
WinGetTitle, strWinTitle, ahk_id %hWnd%
if InStr(strWinTitle, strPartOfTitle)
return true
else
return false
}
}