Code: Select all
;==================================================================================================
;AUTHOR : https://www.xyplorer.com/xyfc/viewtopic.php?t=25763
;Function : Rock-click (Left-Mouse-Down + Right-Mouse-Click) run custom menu (Supports Desktop, Explorer, XYplorer)
;Created : 2023-02-28
;Modified : 2023-03-03
;Version : v1.2
;==================================================================================================
#Requires AutoHotkey v2.0.2
#HotIf MouseIsOver("ahk_class Progman") || MouseIsOver("ahk_class WorkerW") || MouseIsOver("ahk_class CabinetWClass") || MouseIsOver("ahk_class ThunderRT6FormDC")
MouseIsOver(WinTitle) {
MouseGetPos ,, &Win
return WinExist(WinTitle " ahk_id " Win)
}
; Get our own HWND (we have no visible window)
G_OwnHWND := A_ScriptHwnd + 0
; Get messages back from XYplorer
OnMessage(0x4a, Receive_WM_COPYDATA)
xyPath := "D:\XYplorer2\XYplorer.exe" ; XY path
if !FileExist(xyPath)
{
TrayTip xyPath, "XYplorer path does not exist!"
;ExitApp
}
exHwnd := ""
selMenu:="", selPos:="", selItem:=""
;==================================================================================================
; Create a popup menu
;==================================================================================================
; Create main menu
MyMenu := Menu()
MyMenu.Name := "Main menu" ; Used to show which menu is selected
; Add menu item
MyMenu.Add "Focus in XYplorer", MenuHandler
if FileExist(xyPath)
MyMenu.SetIcon("Focus in XYplorer", xyPath) ; Add icon to first menu item if icon file exists
MyMenu.Add "Item 2", MenuHandler ; Add a second menu item
MyMenu.Add ; Add a separator line
; Add submenu
Submenu1 := Menu()
Submenu1.Name := "Submenu1" ; Used to show which menu is selected
; Add items to submenu
Submenu1.Add "Submenu item 1", MenuHandler
Submenu1.Add "Submenu item 2", MenuHandler
; Create a submenu in the main menu
MyMenu.Add "Submenu", Submenu1
MyMenu.Add ; Add a separator line
MyMenu.Add "Item 3", MenuHandler ; Add a third menu item
MyMenu.Default := "Focus in XYplorer"
; Global selected
MenuHandler(Item, ItemPos, MyMenu) {
;MsgBox "You selected " Item " (position " ItemPos " in " MyMenu.Name ")"
global selMenu:=MyMenu.Name, selPos:=ItemPos, selItem:=Item ; Global varibles
}
;==================================================================================================
; Rock-click (Left-Mouse-Down + Right-Mouse-Click) run custom menu
;==================================================================================================
~LButton & RButton Up:: ; Left-Mouse-Down + Right-Mouse-Click
{
if WinActive("ahk_class ThunderRT6FormDC") ; If in the XY window
{
MouseGetPos(&fX, &fY, &fID, &fWin)
WinGetPos(&dX, &dY, &dW, &dH, "ahk_class ThunderRT6FormDC")
If(fX > 300 && fX < dW-235 && fY > 100 && fY < dH-60) { ; Hover area: 300 is the width of the tree and 235 is the width of the Catalog or Preview pane, 100 is the height above the column header and 60 is the height of the status bar
xyHwnd := GetxyHwnd()
Send_WM_COPYDATA(xyHwnd, '::`#1400') ; Send the script to XY
}
else Send("{RButton}")
return
}
else ;if WinActive("ahk_class Progman") || WinActive("ahk_class CabinetWClass") ; If on the desktop, Explorer, pop up the custom menu
{
MouseGetPos ,, &Win
global exHwnd := Win || WinExist('A') ; Get HWND of the active window
global selected := explorerGetSel(exHwnd) ; Get desktop, explorer selected items
MyMenu.Show ; Display menu
;MyMenu.Show(1000, 800) ; Display menu at
}
if(!selItem || !exHwnd) ; Return if no menu item is selected
return
;==================================================================================================
; Perform different actions
;==================================================================================================
switch selItem
{
case "Focus in XYplorer":
if(!selected || selected == "ERROR")
{
TrayTip "Nothing selected!", , 1
return
}
if (xyHwnd := GetxyHwnd()) { ; If xy is running
WinActivate("ahk_id " xyHwnd) ; Active XY window
Send_WM_COPYDATA(xyHwnd, '::tab`("new"`, gpc`("' selected '"`, "path"`)`)`; selectitems "' selected '"') ; Send the script to XY
} else {
Run xyPath ' /feed=|::tab("new"`, gpc("' selected '"`, "path"))`; goto "' selected '"|' ; If XY is not running, run XY and run the script
WinWaitActive WinExist("ahk_class ThunderRT6FormDC") ; Waiting to activate the window
sleep 3000
WinActivate("ahk_class ThunderRT6FormDC")
}
case "Item 2":
MsgBox "You selected " selItem " (position " selPos " in " selMenu ")"
case "Submenu item 1":
MsgBox "You selected " selItem " (position " selPos " in " selMenu ")"
case "Submenu item 2":
MsgBox "You selected " selItem " (position " selPos " in " selMenu ")"
case "Item 3":
MsgBox "You selected " selItem " (position " selPos " in " selMenu ")"
default:
Msgbox "Hello!"
}
global selMenu:="", selPos:="", selItem:=""
return
}
;==================================================================================================
; Desktop, Explore get functions
;==================================================================================================
; Get the selected items, excluding shortcut item on the desktop
/*
selNoDeskLnk := explorerGet(exHwnd,true)
if(selNoDeskLnk != "ERROR" && selNoDeskLnk)
msgbox selNoDeskLnk
; Get the selected items
explorerSel := explorerGetSel(exHwnd)
if(explorerSel != "ERROR" && explorerSel)
msgbox explorerSel
*/
explorerGetSel(exHwnd, selection := True)
{
hwWindow := ''
ret := ""
Switch window := explorerGetWindow(exHwnd)
{
Case '':
Return 'ERROR'
Case 'desktop':
Try hwWindow := ControlGetHwnd('SysListView321', 'ahk_class Progman')
hwWindow := hwWindow || ControlGetHwnd('SysListView321', 'ahk_id ' exHwnd)
Loop Parse ListViewGetContent((selection ? 'Selected' : '') ' Col1', hwWindow), '`n', '`r'
{
SplitPath A_LoopField, , , &ext ; Get ext
if(!ext && !DirExist(A_Desktop '\' A_LoopField)) ; Get the target of the shortcut, and stack to the variable ret, if there is no ext and not a folder
{
shortcut := A_Desktop '\' A_LoopField ".lnk"
if !fileExist(shortcut)
shortcut := A_DesktopCommon '\' A_LoopField ".lnk"
FileGetShortcut shortcut, &OutTarget
ret .= OutTarget '`n'
} else { ; If it is a file or a folder, stack to the varibles ret
ret .= A_Desktop '\' A_LoopField '`n'
}
}
Default: ; If it is not on the desktop, stack to the variable ret
For item in selection ? window.document.selectedItems : window.document.Folder.Items
ret .= item.path '`n'
}
Return Trim(ret, '`n')
}
; All items, excluding desktop shortcut items
/*
items := explorerGet(exHwnd, false)
if(items != "ERROR" && items)
msgbox items
*/
explorerGet(exHwnd,selection:=false)
{
hwWindow := ''
ret := ""
Switch window := explorerGetWindow(exHwnd)
{
Case '':
Return 'ERROR'
Case 'desktop':
Try hwWindow := ControlGetHwnd('SysListView321', 'ahk_class Progman')
hwWindow := hwWindow || ControlGetHwnd('SysListView321', 'ahk_id ' exHwnd)
Loop Parse ListViewGetContent((selection ? 'Selected' : '') ' Col1', hwWindow), '`n', '`r'
{
If FileExist(A_Desktop '\' A_LoopField) ; ignore special icons like Computer (at least for now)
ret .= A_Desktop '\' A_LoopField '`n'
}
Default:
For item in selection ? window.document.selectedItems : window.document.Folder.Items
ret .= item.path '`n'
}
Return Trim(ret, '`n')
}
; If it is on the desktop
explorerGetWindow(exHwnd)
{
class := WinGetClass(exHwnd := exHwnd || WinExist('A'))
Switch
{
Case WinGetProcessName(exHwnd) != 'explorer.exe': Return
Case class ~= 'Progman|WorkerW': Return 'desktop'
Case class ~= '(Cabinet|Explore)WClass':
For window in ComObject('Shell.Application').Windows
Try If window.hwnd = exHwnd
Return window
}
}
;==================================================================================================
; XYplorer Send and Get functions
;==================================================================================================
XY_Get(bAll:=false, bSelection:=false)
{
xyQueryScript := '::if (!' bAll ' && !' bSelection ') {$return = "<curpath>"`;} elseif (' bAll ') {$return = listpane(, , , "<crlf>")`;} elseif (' bSelection ') {$return = get("SelectedItemsPathNames", "<crlf>")`;} copydata ' G_OwnHWND ', "$return", 2`;'
if xyHwnd := GetXYHWND()
Send_WM_COPYDATA(xyHwnd, xyQueryScript)
return dataReceived
}
GetXYHWND() {
static xyClass := 'ahk_class ThunderRT6FormDC'
if hwnd := WinActive(xyClass)
return hwnd
else if WinExist(xyClass)
return WinGetList(xyClass)[1]
}
Send_WM_COPYDATA(xyHwnd, message) {
if !(xyHwnd)
return
size := StrLen(message)
COPYDATA := Buffer(A_PtrSize * 3)
NumPut("Ptr", 4194305, COPYDATA, 0)
NumPut("UInt", size * 2, COPYDATA, A_PtrSize)
NumPut("Ptr", StrPtr(message), COPYDATA, A_PtrSize * 2)
return DllCall("User32.dll\SendMessageW", "Ptr", xyHwnd, "UInt", 74, "Ptr", 0, "Ptr", COPYDATA, "Ptr")
}
Receive_WM_COPYDATA(wParam, lParam, *) {
global dataReceived := StrGet(
NumGet(lParam + 2 * A_PtrSize, 'Ptr'), ; COPYDATASTRUCT.lpData, ptr to a str presumably
NumGet(lParam + A_PtrSize, 'UInt') / 2 ; COPYDATASTRUCT.cbData, count bytes of lpData, /2 to get count chars in unicode str
)
}