1 (изменено: DD, 2016-06-30 21:32:17)

Тема: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

Для Win7 здорово недостает возможности, как на XP, вызывать контекстное меню активной папки по клику в области верхнего левого угла её окна. Имеется в виду меню, которое было бы выведено для текущей папки уровнем выше, по правой кнопке. Можно ли организовать? В качестве шаблона возможно пригодится  скрипт, который обрабатывает эту часть окна:


GroupAdd, ExplorerGrp, ahk_class CabinetWClass
GroupAdd, ExplorerGrp, ahk_class ExploreWClass

IsCursorInEdge(winTitle := "")
{
  MouseGetPos, ClickX, ClickY, WindowUnderMouseID

  ; WM_NCHITTEST 
  SendMessage, 0x84,, ( ClickY << 16 )|ClickX,, ahk_id %WindowUnderMouseID% 
  WM_NCHITTEST_Result =%ErrorLevel% 
  If WM_NCHITTEST_Result in 3 ; in titlebar enclosed area - top of window 
  {
    TOOLTIP WWWWWWWWWWWWWWWinEdge
    SLEEP 1000
    TOOLTIP
  }
  return ErrorLevel = 2
}
#if IsCursorInEdge("ahk_group ExplorerGrp")
{
  mbutton::
  Return
}
#if


~vkC0 & Esc:: ; tilde + esc
   ExitApp

2

Re: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

Не совсем понимаю смысл. Зачем целиться в верхний левый угол, когда можно просто кликнуть по клиентской области?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

3

Re: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

teadrinker пишет:

Зачем целиться в верхний левый угол

Чтобы не переходить в родительскую папку. (Верхний левый угол — значок окна.)

teadrinker пишет:

, когда можно просто кликнуть по клиентской области?

Это другое меню.

4 (изменено: Drugoy, 2016-06-30 23:27:34)

Re: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

DD пишет:

Для Win7 здорово недостает возможности, как на XP, вызывать контекстное меню активной папки по клику в области верхнего левого угла её окна. Имеется в виду меню, которое было бы выведено для текущей папки уровнем выше, по правой кнопке. Можно ли организовать? В качестве шаблона возможно пригодится  скрипт, который обрабатывает эту часть окна:

А объясните, пожалуйста, скриншотом, а то не понятно.

5

Re: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

OFF: Ещё, как я помню, в IE6 правый щелчок по значку окна вызывал контекстное меню файла для локальных файлов, а для нелокальных — что-то наподобие контекстного меню ярлыка.

6

Re: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

Возможно, тут в конце полезные ссылки: http://rsdn.ru/forum/winapi/3473636.hot.

7

Re: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

Я так и не понял, какое именно меню нужно. Скриншот можете сделать?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

8

Re: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

Это должно происходить?
Пока что без уголков. Просто на lwin.

#Include GetPaths.ahk
#Include ShellContextMenu.ahk

lwin::
if (	ePath := Explorer_GetPath()	) != "ERROR"
	ShellContextMenu(ePath)
Return
+ GetPaths.ahk
;Автор: https://autohotkey.com/board/topic/60985-get-paths-of-selected-items-in-an-explorer-window/

Explorer_GetPath(hwnd="")
{
	if !(window := Explorer_GetWindow(hwnd))
		return ErrorLevel := "ERROR"
	if (window="desktop")
		return A_Desktop
	path := window.LocationURL
	path := RegExReplace(path, "ftp://.*@","ftp://")
	StringReplace, path, path, file:///
	StringReplace, path, path, /, \, All 
	
	; thanks to polyethene
	Loop
		If RegExMatch(path, "i)(?<=%)[\da-f]{1,2}", hex)
			StringReplace, path, path, `%%hex%, % Chr("0x" . hex), All
		Else Break
	return path
}
Explorer_GetAll(hwnd="")
{
	return Explorer_Get(hwnd)
}
Explorer_GetSelected(hwnd="")
{
	return Explorer_Get(hwnd,true)
}

Explorer_GetWindow(hwnd="")
{
	; thanks to jethrow for some pointers here
    WinGet, process, processName, % "ahk_id" hwnd := hwnd? hwnd:WinExist("A")
    WinGetClass class, ahk_id %hwnd%
	
	if (process!="explorer.exe")
		return
	if (class ~= "(Cabinet|Explore)WClass")
	{
		for window in ComObjCreate("Shell.Application").Windows
			if (window.hwnd==hwnd)
				return window
	}
	else if (class ~= "Progman|WorkerW") 
		return "desktop" ; desktop found
}
Explorer_Get(hwnd="",selection=false)
{
	if !(window := Explorer_GetWindow(hwnd))
		return ErrorLevel := "ERROR"
	if (window="desktop")
	{
		ControlGet, hwWindow, HWND,, SysListView321, ahk_class Progman
		if !hwWindow ; #D mode
			ControlGet, hwWindow, HWND,, SysListView321, A
		ControlGet, files, List, % ( selection ? "Selected":"") "Col1",,ahk_id %hwWindow%
		base := SubStr(A_Desktop,0,1)=="\" ? SubStr(A_Desktop,1,-1) : A_Desktop
		Loop, Parse, files, `n, `r
		{
			path := base "\" A_LoopField
			IfExist %path% ; ignore special icons like Computer (at least for now)
				ret .= path "`n"
		}
	}
	else
	{
		if selection
			collection := window.document.SelectedItems
		else
			collection := window.document.Folder.Items
		for item in collection
			ret .= item.path "`n"
	}
	return Trim(ret,"`n")
}
+ ShellContextMenu.ahk
;Автор: https://autohotkey.com/board/topic/20376-invoking-directly-contextmenu-of-files-and-folders/

ShellContextMenu( sPath, win_hwnd = 0 )
{
   if ( !sPath  )
      return
   if !win_hwnd
   {
      Gui,SHELL_CONTEXT:New, +hwndwin_hwnd
      Gui,Show
   }
   
   If sPath Is Not Integer
      DllCall("shell32\SHParseDisplayName", "Wstr", sPath, "Ptr", 0, "Ptr*", pidl, "Uint", 0, "Uint*", 0)
      ;This function is the preferred method to convert a string to a pointer to an item identifier list (PIDL).
   else
      DllCall("shell32\SHGetFolderLocation", "Ptr", 0, "int", sPath, "Ptr", 0, "Uint", 0, "Ptr*", pidl)
   DllCall("shell32\SHBindToParent", "Ptr", pidl, "Ptr", GUID4String(IID_IShellFolder,"{000214E6-0000-0000-C000-000000000046}"), "Ptr*", pIShellFolder, "Ptr*", pidlChild)
   ;IShellFolder->GetUIObjectOf
   DllCall(VTable(pIShellFolder, 10), "Ptr", pIShellFolder, "Ptr", 0, "Uint", 1, "Ptr*", pidlChild, "Ptr", GUID4String(IID_IContextMenu,"{000214E4-0000-0000-C000-000000000046}"), "Ptr", 0, "Ptr*", pIContextMenu)
   ObjRelease(pIShellFolder)
   CoTaskMemFree(pidl)
   
   hMenu := DllCall("CreatePopupMenu")
   ;IContextMenu->QueryContextMenu
   ;http://msdn.microsoft.com/en-us/library/bb776097%28v=VS.85%29.aspx
   DllCall(VTable(pIContextMenu, 3), "Ptr", pIContextMenu, "Ptr", hMenu, "Uint", 0, "Uint", 3, "Uint", 0x7FFF, "Uint", 0x100)   ;CMF_EXTENDEDVERBS
   ComObjError(0)
      global pIContextMenu2 := ComObjQuery(pIContextMenu, IID_IContextMenu2:="{000214F4-0000-0000-C000-000000000046}")
      global pIContextMenu3 := ComObjQuery(pIContextMenu, IID_IContextMenu3:="{BCFCE0A0-EC17-11D0-8D10-00A0C90F2719}")
   e := A_LastError ;GetLastError()
   ComObjError(1)
   if (e != 0)
      goTo, StopContextMenu
   Global   WPOld:= DllCall("SetWindowLongPtr", "Ptr", win_hwnd, "int",-4, "Ptr",RegisterCallback("WindowProc"),"UPtr")
   DllCall("GetCursorPos", "int64*", pt)
   DllCall("InsertMenu", "Ptr", hMenu, "Uint", 0, "Uint", 0x0400|0x800, "Ptr", 2, "Ptr", 0)
   DllCall("InsertMenu", "Ptr", hMenu, "Uint", 0, "Uint", 0x0400|0x002, "Ptr", 1, "Ptr", &sPath)

   idn := DllCall("TrackPopupMenuEx", "Ptr", hMenu, "Uint", 0x0100|0x0001, "int", pt << 32 >> 32, "int", pt >> 32, "Ptr", win_hwnd, "Uint", 0)

   /*
   typedef struct _CMINVOKECOMMANDINFOEX {
   DWORD   cbSize;          0
   DWORD   fMask;           4
   HWND    hwnd;            8
   LPCSTR  lpVerb;          8+A_PtrSize
   LPCSTR  lpParameters;    8+2*A_PtrSize
   LPCSTR  lpDirectory;     8+3*A_PtrSize
   int     nShow;           8+4*A_PtrSize
   DWORD   dwHotKey;        12+4*A_PtrSize
   HANDLE  hIcon;           16+4*A_PtrSize
   LPCSTR  lpTitle;         16+5*A_PtrSize
   LPCWSTR lpVerbW;         16+6*A_PtrSize
   LPCWSTR lpParametersW;   16+7*A_PtrSize
   LPCWSTR lpDirectoryW;    16+8*A_PtrSize
   LPCWSTR lpTitleW;        16+9*A_PtrSize
   POINT   ptInvoke;        16+10*A_PtrSize
   } CMINVOKECOMMANDINFOEX, *LPCMINVOKECOMMANDINFOEX;
   http://msdn.microsoft.com/en-us/library/bb773217%28v=VS.85%29.aspx
   */
   struct_size  :=  16+11*A_PtrSize
   VarSetCapacity(pici,struct_size,0)
   NumPut(struct_size,pici,0,"Uint")         ;cbSize
   NumPut(0x4000|0x20000000|0x00100000,pici,4,"Uint")   ;fMask
   NumPut(win_hwnd,pici,8,"UPtr")       ;hwnd
   NumPut(1,pici,8+4*A_PtrSize,"Uint")       ;nShow
   NumPut(idn-3,pici,8+A_PtrSize,"UPtr")     ;lpVerb
   NumPut(idn-3,pici,16+6*A_PtrSize,"UPtr")  ;lpVerbW
   NumPut(pt,pici,16+10*A_PtrSize,"Uptr")    ;ptInvoke
   
   DllCall(VTable(pIContextMenu, 4), "Ptr", pIContextMenu, "Ptr", &pici)   ; InvokeCommand

   DllCall("GlobalFree", "Ptr", DllCall("SetWindowLongPtr", "Ptr", win_hwnd, "int", -4, "Ptr", WPOld,"UPtr"))
   DllCall("DestroyMenu", "Ptr", hMenu)
StopContextMenu:
   ObjRelease(pIContextMenu3)
   ObjRelease(pIContextMenu2)
   ObjRelease(pIContextMenu)
   pIContextMenu2:=pIContextMenu3:=WPOld:=0
   Gui,SHELL_CONTEXT:Destroy
   return idn
}
WindowProc(hWnd, nMsg, wParam, lParam)
{
   Global   pIContextMenu2, pIContextMenu3, WPOld
   If   pIContextMenu3
   {    ;IContextMenu3->HandleMenuMsg2
      If   !DllCall(VTable(pIContextMenu3, 7), "Ptr", pIContextMenu3, "Uint", nMsg, "Ptr", wParam, "Ptr", lParam, "Ptr*", lResult)
         Return   lResult
   }
   Else If   pIContextMenu2
   {    ;IContextMenu2->HandleMenuMsg
      If   !DllCall(VTable(pIContextMenu2, 6), "Ptr", pIContextMenu2, "Uint", nMsg, "Ptr", wParam, "Ptr", lParam)
         Return   0
   }
   Return   DllCall("user32.dll\CallWindowProcW", "Ptr", WPOld, "Ptr", hWnd, "Uint", nMsg, "Ptr", wParam, "Ptr", lParam)
}
VTable(ppv, idx)
{
   Return   NumGet(NumGet(1*ppv)+A_PtrSize*idx)
}
GUID4String(ByRef CLSID, String)
{
   VarSetCapacity(CLSID, 16,0)
   return DllCall("ole32\CLSIDFromString", "wstr", String, "Ptr", &CLSID) >= 0 ? &CLSID : ""
}
CoTaskMemFree(pv)
{
   Return   DllCall("ole32\CoTaskMemFree", "Ptr", pv)
}
+ DD

9 (изменено: DD, 2016-07-01 01:47:48)

Re: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

wisgest пишет:

OFF: Ещё, как я помню, в IE6 правый щелчок по значку окна вызывал контекстное меню файла для локальных файлов, а для нелокальных — что-то наподобие контекстного меню ярлыка.

Точно, я и забыл)) Тоже было удобно, тоже материализовать не худо б))

teadrinker пишет:

Я так и не понял, какое именно меню нужно. Скриншот можете сделать?

Это стандартное меню со скриншота, только не для «DMDE», а для «Program Files», которое можно было бы там же вызвать, без необходимости перехода в родительскую папку:
http://i62.fastpic.ru/thumb/2016/0701/a6/a17d659d4a4523326bbd0c2b83307aa6.jpeg

yalanne пишет:

Это должно происходить?

Спасибо, да. К коду возможно ещё IE прикрутить?

10

Re: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

Теперь я не понимаю что за контекстное меню ie надо.

11

Re: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

Это то же самое внешнее меню, вот так оно показывалось на XP:

http://i80.fastpic.ru/thumb/2016/0701/98/491f27ce83614f3211788c6d58c6c098.jpeg

12 (изменено: yalanne, 2016-07-02 00:40:29)

Re: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

Вот скрипт. Видит клик по иконке в шапке и вместо стандартного системного меню открывает как у дочернего по правому клику.
С папками скорость нормальная, а вот с приложениями чуток тормозит(сек 2) почему то. Тормоза на финальной функции ShellContextMenu.

#Include GetPaths.ahk
#Include ShellContextMenu.ahk

CoordMode,Mouse,Screen

#if GetClickIconTitle()
LButton::
RButton::
	WinGetClass,ClassActive,A
	
	if ClassActive ~= "(Cabinet|Explore)WClass"
	{
		if (	ePath := Explorer_GetPath()	) = "ERROR"
			Return
	}
	Else
	{
		WinGet,PidFocusWin,Pid,A
		for process in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process")
			if process.ProcessId = PidFocusWin
			{
				ePath := process.ExecutablePath
				break
			}
	}
	
	
	ShellContextMenu( ePath )
	Return
	
#if

GetClickIconTitle()
{
	Local x,y,id
	Static WM_NCHITTEST := 0x84,	HTSYSMENU := 0x3
	MouseGetPos,x,y,id
	SendMessage,% WM_NCHITTEST,,x|(y<<16),,ahk_id %id%
	if (ErrorLevel = HTSYSMENU)
		return True
}

Самая длительная пауза в строке:

DllCall(VTable(pIContextMenu, 3), "Ptr", pIContextMenu, "Ptr", hMenu, "Uint", 0, "Uint", 3, "Uint", 0x7FFF, "Uint", 0x100)   ;CMF_EXTENDEDVERBS

Кто знает что сделать для оптимизации?

+ DD

13 (изменено: DD, 2016-07-02 01:45:05)

Re: AHK: Контекстное меню активной папки по клику в её верхнем левом углу

Спасибо большое, стало жутко удобно)) Добавил обработку пути в IE.

+ открыть спойлер
#Include GetPaths.ahk
#Include ShellContextMenu.ahk

CoordMode,Mouse,Screen

#if GetClickIconTitle()
LButton::
RButton::
	WinGetClass,ClassActive,A
	
	if ClassActive ~= "(Cabinet|Explore)WClass"
	{
		if (	ePath := Explorer_GetPath()	) = "ERROR"
			Return
	}
	Else
	{
		WinGet,PidFocusWin,Pid,A
		for process in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process")
			if process.ProcessId = PidFocusWin
			{
				ePath := process.ExecutablePath
				break
			}
	}

	If WinActive("ahk_class IEFrame")
	{
		ret:=doc:=markup:=pat:="n/a" 
 
		If IsObject(ret:=HTMLGetObjectIEFrame("ahk_class IEFrame")) 
		And (markup:=(doc:=ret.document).documentElement.innerHTML, pat:="si).*?<title>(.*)?</title>.*") 
		{ 
			;MsgBox, 262208, % "Title:", % RegExReplace(markup, pat, "$1") ;, 1.5 
			;MsgBox, 262208, % "Path:", % doc.URL ;, 1.5 
			ttlName:=RegExReplace(markup, pat, "$1")
			ePath:=doc.URL
		} 
		Else MsgBox, 262160, % "Oops!", % "An error has occured! ("ret ")", 1.5 
	}

	
	ShellContextMenu( ePath )
	Return
	
#if

GetClickIconTitle()
{
	Local x,y,id
	Static WM_NCHITTEST := 0x84,	HTSYSMENU := 0x3
	MouseGetPos,x,y,id
	SendMessage,% WM_NCHITTEST,,x|(y<<16),,ahk_id %id%
	if (ErrorLevel = HTSYSMENU)
		return True
}

; http://l.autohotkey.net/docs/commands/ComObjQuery.htm 
; http://www.autohotkey.com/board/topic/47052-basic-webpage-controls-with-javascript-com-tutorial 
HTMLGetObjectIEFrame(winTitle:="ahk_class IEFrame", instance:=1) 
{ 
	Static msg:=DllCall("RegisterWindowMessage", "Str", "WM_HTML_GETOBJECT", "UInt") 
		, IID1:="{332C4425-26CB-11D0-B483-00C04FD90119}" ; IID_IHTMLDocument2 
		, IID2:="{0002DF05-0000-0000-C000-000000000046}" ; IID_IWebBrowserApp 
		, VT_DISPATCH:=9 
		, F_OWNVALUE:=1 
 
	SendMessage, msg,,, % "Internet Explorer_Server"instance, % winTitle 
	If % ErrorLevel!="FAIL" And (lResult:=ErrorLevel, VarSetCapacity(GUID, 16, 0)) 
	If DllCall("ole32\CLSIDFromString", "Str", IID1 
		, "Ptr", &GUID 
		, "UInt")=0 
	If DllCall("oleacc\ObjectFromLresult", "Ptr", lResult 
		, "Ptr", &GUID 
		, "Ptr", 0 
		, "Ptr*", pDoc 
		, "UInt")=0 
	Return, ComObject(VT_DISPATCH, ComObjQuery(pDoc, IID2, IID2), F_OWNVALUE) 
		, ObjRelease(pDoc) 
	Return, ErrorLevel 
}