1 (изменено: yalanne, 2015-12-29 15:31:01)

Тема: AHK: Добавление элементов в чужое контекстное меню

Написал такой скрипт:

versionsMenu := "(^Вырезать`nКопировать`nВставить`nУдалить`nВыделить все`n"
             . "|^&Отменить`n`n&Вырезать`n&Копировать`nВст&авить`n&Удалить`n`nВ&ыделить все)"


SetBatchLInes, -1
#Persistent
VarSetCapacity(sString, nSize := 70)

loop
{
	while !(hwnd:= WinExist("ahk_class #32768")) or (listH ~= ":" hwnd ":")
	  DllCall("Sleep",Int,10)true and !WinExist("ahk_class #32768") and listH and (listH := "")
	listH.= ":" hwnd ":"	,listItems:=""
	SendMessage, MN_GETHMENU:=0x1E1, 0, 0
	hMenu := ErrorLevel
	loop % DllCall("GetMenuItemCount", "Uint", hMenu)
	  DllCall("GetMenuString", "Uint", hMenu, "int"
	  , A_Index-1, "str", sString, "int", nSize, "Uint", 0x400) true
	  and (listItems.= ((listItems)? "`n" : "") sString)
	if listItems ~= versionsMenu
	{
	  hSubmenu := DllCall("CreateMenu")
	  DllCall("AppendMenu", Ptr, hMenu, UInt, MF_STRING := 0, UInt, "", Str, "элемент 1")
	  DllCall("AppendMenu", Ptr, hMenu, UInt, MF_POPUP := 0x10, Ptr, hSubmenu, Str, "дочернее меню")
		  DllCall("AppendMenu", Ptr, hSubmenu, UInt, MF_STRING := 0, UInt, "", Str, "элемент 2")
	}
}

  *немного исправил. в 11стр убрал  проверку несуществующей переменной(осталось от старого способа) и в 12стр сделал проверку на полноту переменной. А в общем скрипт работает точно так же.

Он добавляет новые элементы в контекстное меню редактирования текста(правый клик по любому edit полю windows).

+ в такое

http://i.imgur.com/03PTpbV.png

+ и в такое(notepad++)

http://i.imgur.com/hARlYhY.png

В другие не должен.

Как актуальней всего на них действие назначить? Для этого тоже есть api'шка которая просто на клик переходит на метку в скрипте?

И есть ли возможность добавлять свои элементы в контекстное меню google chrome? Там класс идет Chrome_WidgetWin_2 а не #32768. Если его даже указать в моем скрипте в замен то он не может с ними работать, ничего не происходит.

2

Re: AHK: Добавление элементов в чужое контекстное меню

А зачем там бесконечный цикл, не пойму?

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

3 (изменено: yalanne, 2015-12-04 22:05:01)

Re: AHK: Добавление элементов в чужое контекстное меню

Ну без него скрипт будет работать первые 10мс и все. Не будет пытаться найти контекстное меню.
Не использовал winwait потому что там еще hwnd сравнивается что бы на одно меню не лепилось тоже самое после возрата с дочернего(любого).

А хук для конекст меню уж больно крупный по сравнению с этим способом.

4

Re: AHK: Добавление элементов в чужое контекстное меню

Не лучшее решение, по-моему.

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

5

Re: AHK: Добавление элементов в чужое контекстное меню

*Нелучшее.

6 (изменено: Alectric, 2015-12-05 08:44:04)

Re: AHK: Добавление элементов в чужое контекстное меню

OFF:

teadrinker пишет:

А зачем там бесконечный цикл,

Что вы все так боитесь (избегаете) бесконечных циклов, не пойму... если в нем все правильно продумать, то ничего лишнего из ресурсов системы он тратить не будет, даже на старых одно-ядерных "дроволетах".

Win 10 x64
AHK v1.1.33.02
                       Справка тебе в помощь.

7

Re: AHK: Добавление элементов в чужое контекстное меню

Alectric пишет:

если в нем все правильно продумать

Да, но здесь совершаются какие-то действия независимо от того, существует ли целевое окно. Дело даже не в нагрузке на процессор, а в том, что просто некрасиво.

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

8

Re: AHK: Добавление элементов в чужое контекстное меню

becauseim пишет:

*Нелучшее.

+ OFF

На скользкий путь встаете, коллега.

9

Re: AHK: Добавление элементов в чужое контекстное меню

OFF: Не лучшее

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

10 (изменено: yalanne, 2015-12-05 12:45:42)

Re: AHK: Добавление элементов в чужое контекстное меню

Основной Луп практически не совершает частые скачки, идет тормоз на
while
  Sleep 10...
Если условие подходит то выполняется все что идет дальше и скрипт снова натыкается на while.
Да и нагрузка наименьшая, сильных скачков озу нету.

11

Re: AHK: Добавление элементов в чужое контекстное меню

*Луп.

12

Re: AHK: Добавление элементов в чужое контекстное меню

В таком случае внешний цикл лишний, вполне можно было обойтись одним.

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

13 (изменено: yalanne, 2015-12-05 14:30:33)

Re: AHK: Добавление элементов в чужое контекстное меню

+ так?
versionsMenu := "(^Вырезать`nКопировать`nВставить`nУдалить`nВыделить все`n"
             . "|^&Отменить`n`n&Вырезать`n&Копировать`nВст&авить`n&Удалить`n`nВ&ыделить все)"


SetBatchLInes, -1
#Persistent
VarSetCapacity(sString, nSize := 70)

loop
	if !(hwnd:= WinExist("ahk_class #32768")) or (listH ~= ":" hwnd ":")
	  DllCall("Sleep",Int,10)true and !WinExist("ahk_class #32768") and listH and (listH := "")
	  
	Else {
	  listH.= ":" hwnd ":"	,listItems:=""
	  SendMessage, MN_GETHMENU:=0x1E1, 0, 0
	  hMenu := ErrorLevel
	  loop % DllCall("GetMenuItemCount", "Uint", hMenu)
	    DllCall("GetMenuString", "Uint", hMenu, "int"
	    , A_Index-1, "str", sString, "int", nSize, "Uint", 0x400) true
	    and (listItems.= ((listItems)? "`n" : "") sString)
	  if listItems ~= versionsMenu
	  {
	    hSubmenu := DllCall("CreateMenu")
	    DllCall("AppendMenu", Ptr, hMenu, UInt, MF_STRING := 0, UInt, "", Str, "элемент 1")
	    DllCall("AppendMenu", Ptr, hMenu, UInt, MF_POPUP := 0x10, Ptr, hSubmenu, Str, "дочернее меню")
		    DllCall("AppendMenu", Ptr, hSubmenu, UInt, MF_STRING := 0, UInt, "", Str, "элемент 2")
	}
		}

А что насчет моих вопросов то? Как действие прикрутить к своему пункту или как добавить в контекстное меню хрома свой пункт?

14

Re: AHK: Добавление элементов в чужое контекстное меню

Я до воскресенья без компьютера.

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

15 (изменено: teadrinker, 2015-12-09 23:49:58)

Re: AHK: Добавление элементов в чужое контекстное меню

У меня так получилось:

#Persistent
global EVENT_OBJECT_SHOW := 0x8002, WINEVENT_SKIPOWNTHREAD := 1

/*
В функцию передаётся массив.
1-й ключ — название ф-ции, обрабатывающей клик по нашему пункту меню.
2-й ключ — объект, ключи которого должны точно соответствовать названию классов окон, в edit-меню которых добавляем наши пункты,
а значения этих ключей — масиивы со списком названий наших пунктов
*/
AddMyEditMenu( [ "RunMyMenu", { Notepad: ["MyItem1", "MyItem2"], "Notepad++": ["MyItem1", "MyItem2"] } ] )

RunMyMenu(MenuHWND, WindowClass, items)  ; ф-ция, обрабатывающей клик по нашему пункту меню
{
	if ((item := IsMouseOverMyMenu(MenuHWND, items)) = "")
		Return
; здесь должно быть действие в зависимости от класса окна и названия нашего пункта меню
	MsgBox, % WindowClass "`n" item
}

AddMyEditMenu(obj)
{
	Hotkey, ~LButton     , Dummy, On
	Hotkey, ~RButton Up, Dummy, On
	Hotkey, ~AppsKey Up, Dummy, On
	addr := Object(obj)
	OnExit(Func("ReleaseObj").Bind(addr))
	SetWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_SHOW, 0, RegisterCallback("HookProc", "F", 3, addr), 0, 0, WINEVENT_SKIPOWNTHREAD)
}

HookProc(hWinEventHook, event, hwnd)
{
	static hwnd_prev := 0
	IfWinExist, ahk_id %hwnd_prev%
		Return
	
	if (A_ThisHotkey = "~LButton") && !(A_ThisHotkey = "~RButton Up") && !(A_ThisHotkey = "~AppsKey Up")
		Return
	
	WinGetClass, class, ahk_id %hwnd%
	if !(class = "#32768")
		Return
	
	obj := Object(A_EventInfo)
	WinGetClass, class, A
	for k in obj[2]
		(k == class && match := 1)
	if !match
		Return
	
	ControlGetFocus, focus, A
	if !RegExMatch(focus, "^(Edit|Scintilla)\d+")
		Return
	
	AppEndMyMenu(obj[2][class])
	FuncObj := Func(obj[1]).Bind(hwnd, class, obj[2][class])
	Hotkey, ~LButton, % FuncObj, On
	hwnd_prev := hwnd
}

AppEndMyMenu(items)
{
	static MN_GETHMENU := 0x1E1, MF_STRING := 0, MF_SEPARATOR := 0x800
	SendMessage, MN_GETHMENU,,,, ahk_class #32768
	hMenu := ErrorLevel
	DllCall("AppendMenu", Ptr, hMenu, UInt, MF_SEPARATOR, UInt, 0, Str, "")
	for k, item in items
		DllCall("AppendMenu", Ptr, hMenu, UInt, MF_STRING, UInt, "", Str, item)
}

IsMouseOverMyMenu(MenuHWND, items)
{
	MouseGetPos,,, ID
	if !(ID = MenuHWND)
		Return
	
	AccObj := AccObjectFromPoint(child)
	item := AccObj.AccName(child)
	for k, v in items
		if (v == item)
			Return item
}

AccObjectFromPoint(ByRef _idChild_ = "", x = "", y = "")
{
	static VT_DISPATCH := 9, h := DllCall("LoadLibrary", Str, "oleacc", Ptr)
	
	(x = "" || y = "") ? DllCall("GetCursorPos", Int64P, pt) : pt := x & 0xFFFFFFFF | y << 32

	VarSetCapacity(varChild, 8 + 2*A_PtrSize, 0)
	if	DllCall("oleacc\AccessibleObjectFromPoint", Int64, pt, PtrP, pAcc, Ptr, &varChild) = 0
		Return ComObjEnwrap(VT_DISPATCH, pAcc, 1), _idChild_ := NumGet(varChild, 8, "UInt")
}
	
SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags)
{
   return DllCall("SetWinEventHook", UInt, eventMin , UInt, eventMax , Ptr, hmodWinEventProc
				, Ptr, lpfnWinEventProc , UInt, idProcess , UInt, idThread, UInt, dwFlags, Ptr)
}

Dummy()
{
	Return
}

ReleaseObj(addr)
{
	ObjRelease(addr)
}

Наверно, можно упростить ещё как-то. Жаль, у меня не хватает знаний, чтоб добавить иконку в свой пункт меню, информация о ней, по-видимому, должна быть в адресном пространстве процесса, которому принадлежит меню. С Хромом вряд ли получится, там нестандартное меню.

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

16

Re: AHK: Добавление элементов в чужое контекстное меню

Есть дурацкий момент с дочерними пунктами, то что если одно и тоже меню вызвать несколько раз(наводить и убирать курсор с элемента), у них hwnd разный но он сохраняет изменения от предыдущего hwnd.
видео.

p.s В некотором роде у меня более расширенный вариант получился. Можно конкретно задать точное меню в которое может быть добавлено, а не во все подряд меню notepad++ добавлять. А так два способа можно объединить.

17

Re: AHK: Добавление элементов в чужое контекстное меню

yalanne пишет:

Есть дурацкий момент с дочерними пунктами

Это да, не заметил, надо исправить.

yalanne пишет:

Можно конкретно задать точное меню в которое может быть добавлено, а не во все подряд меню notepad++ добавлять.

Не совсем понял. Какие там меню ещё есть?

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

18

Re: AHK: Добавление элементов в чужое контекстное меню

versionsMenu := "(^Убрать 1-й стиль`nУбрать 2-й стиль`nУбрать 3-й стиль`nУбрать 4-й стиль`nУбрать 5-й стиль)"


SetBatchLInes, -1
#Persistent
VarSetCapacity(sString, nSize := 70)

loop
	if !(hwnd:= WinExist("ahk_class #32768")) or (listH ~= ":" hwnd ":")
	  DllCall("Sleep",Int,10)true and !WinExist("ahk_class #32768") and listH and (listH := "")
	  
	Else {
	  listH.= ":" hwnd ":"	,listItems:=""
	  SendMessage, MN_GETHMENU:=0x1E1, 0, 0
	  hMenu := ErrorLevel
	  loop % DllCall("GetMenuItemCount", "Uint", hMenu)
	    DllCall("GetMenuString", "Uint", hMenu, "int"
	    , A_Index-1, "str", sString, "int", nSize, "Uint", 0x400) true
	    and (listItems.= ((listItems)? "`n" : "") sString)
	  if listItems ~= versionsMenu
	  {
	    hSubmenu := DllCall("CreateMenu")
	    DllCall("AppendMenu", Ptr, hMenu, UInt, MF_STRING := 0, UInt, "", Str, "элемент 1")
	    DllCall("AppendMenu", Ptr, hMenu, UInt, MF_POPUP := 0x10, Ptr, hSubmenu, Str, "дочернее меню")
		    DllCall("AppendMenu", Ptr, hSubmenu, UInt, MF_STRING := 0, UInt, "", Str, "элемент 2")
	}
		}

Например так:
http://i.imgur.com/Sm36JU4.png
Если подходит к шаблону то вставляется иначе не вставляется.

19

Re: AHK: Добавление элементов в чужое контекстное меню

Так не работает же? Где обработка нажатия?

yalanne пишет:

Если подходит к шаблону то вставляется иначе не вставляется.

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

yalanne пишет:

Есть дурацкий момент с дочерними пунктами

Исправил.

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

20

Re: AHK: Добавление элементов в чужое контекстное меню

Плохо, оказывается, исправил, так правильно:

#Persistent
/*
В функцию передаётся массив.
1-й ключ — название ф-ции, обрабатывающей клик по нашему пункту меню.
2-й ключ — объект, ключи которого должны точно соответствовать названию классов окон, в edit-меню которых добавляем наши пункты,
а значения этих ключей — масиивы со списком названий наших пунктов
*/
AddMyEditMenu( [ "RunMyMenu", { Notepad: ["MyItem1", "MyItem2"], "Notepad++": ["Item1", "Item2"] } ] )

RunMyMenu(MenuHWND, WindowClass, items)  ; ф-ция, обрабатывающей клик по нашему пункту меню
{
	if ((item := IsMouseOverMyMenu(MenuHWND, items)) = "")
		Return
; здесь должно быть действие в зависимости от класса окна и названия нашего пункта меню
	MsgBox, % WindowClass "`n" item
}

AddMyEditMenu(obj)
{
	static event := EVENT_OBJECT_SHOW := 0x8002, WINEVENT_SKIPOWNTHREAD := 1
	Hotkey, ~LButton   , Dummy, On
	Hotkey, ~RButton Up, Dummy, On
	Hotkey, ~AppsKey Up, Dummy, On
	addr := Object(obj)
	OnExit(Func("ReleaseObj").Bind(addr))
	SetWinEventHook(event, event, 0, RegisterCallback("HookProc", "F", 3, addr), 0, 0, WINEVENT_SKIPOWNTHREAD)
}

HookProc(hWinEventHook, event, hwnd)
{
	static hwnd_prev := 0
	IfWinExist, ahk_id %hwnd_prev%
		Return
	
	if (A_ThisHotkey = "~LButton") && !(A_ThisHotkey = "~RButton Up") && !(A_ThisHotkey = "~AppsKey Up")
		Return
	
	WinGetClass, class, ahk_id %hwnd%
	if !(class = "#32768")
		Return
	
	obj := Object(A_EventInfo)
	WinGetClass, class, A
	for k in obj[2]
		(k == class && match := 1)
	if !match
		Return
	
	ControlGetFocus, focus, A
	if !RegExMatch(focus, "^(Edit|Scintilla)\d+")
		Return
	
	AppendMyMenu(obj[2][class])
	FuncObj := Func(obj[1]).Bind(hwnd, class, obj[2][class])
	Hotkey, ~LButton, % FuncObj, On
	hwnd_prev := hwnd
}

AppendMyMenu(items)
{
	static MN_GETHMENU := 0x1E1, MF_STRING := 0, MF_SEPARATOR := 0x800
	SendMessage, MN_GETHMENU,,,, ahk_class #32768
	hMenu := ErrorLevel
	DllCall("AppendMenu", Ptr, hMenu, UInt, MF_SEPARATOR, UInt, 0, Str, "")
	for k, item in items
		DllCall("AppendMenu", Ptr, hMenu, UInt, MF_STRING, UInt, "", Str, item)
}

IsMouseOverMyMenu(MenuHWND, items)
{
	MouseGetPos,,, ID
	if !(ID = MenuHWND)
		Return
	
	AccObj := AccObjectFromPoint(child)
	item := AccObj.AccName(child)
	for k, v in items
		if (v == item)
			Return item
}

AccObjectFromPoint(ByRef _idChild_ = "", x = "", y = "")
{
	static VT_DISPATCH := 9, h := DllCall("LoadLibrary", Str, "oleacc", Ptr)
	
	(x = "" || y = "") ? DllCall("GetCursorPos", Int64P, pt) : pt := x & 0xFFFFFFFF | y << 32

	VarSetCapacity(varChild, 8 + 2*A_PtrSize, 0)
	if	DllCall("oleacc\AccessibleObjectFromPoint", Int64, pt, PtrP, pAcc, Ptr, &varChild) = 0
		Return ComObjEnwrap(VT_DISPATCH, pAcc, 1), _idChild_ := NumGet(varChild, 8, "UInt")
}
	
SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags)
{
   return DllCall("SetWinEventHook", UInt, eventMin , UInt, eventMax , Ptr, hmodWinEventProc
				, Ptr, lpfnWinEventProc , UInt, idProcess , UInt, idThread, UInt, dwFlags, Ptr)
}

Dummy()
{
	Return
}

ReleaseObj(addr)
{
	ObjRelease(addr)
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

21 (изменено: yalanne, 2015-12-10 16:21:33)

Re: AHK: Добавление элементов в чужое контекстное меню

Смог сделать без acc, используя апишки для меню.
Определяет клик по элементу, а так же должен работать на любом языке windows так как вместо имени элемента используется wid для поиска нужного меню.

Global versionsMenuWID := "(^"
				 . "42001:42002:42005:42006:42007:42020:0" ;notepad++
				 . "|^"
				 . "772:0:768:769:770:771:0:177:0" ; windows
				 . ")"

#Persistent
SetWinEventHook(0x6, 0x6, 0, RegisterCallback("HookProc", "F"), 0, 0, 0)
VarSetCapacity(sString, nSize := 70)

SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags)
{
   return DllCall("SetWinEventHook", UInt, eventMin , UInt, eventMax , Ptr, hmodWinEventProc
            , Ptr, lpfnWinEventProc , UInt, idProcess , UInt, idThread, UInt, dwFlags, Ptr)
}

HookProc(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime)
{
	Static savesWid
	WinExist("ahk_class #32768")
	SendMessage, MN_GETHMENU:=0x1E1, 0, 0
	hMenu := ErrorLevel,	listItemsWid:=""
	loop % DllCall("GetMenuItemCount", "Uint", hMenu)
		listItemsWid .= ((listItemsWid) ? ":" : "") DllCall("GetMenuItemID", "Uint", hMenu, "int", A_Index-1)
	maxWid := listItemsWid
	sort,maxWid,n r d:
	maxWid := (StrSplit(maxWid,":")[1])
	nextWid := maxWid << 4
	savesWid .= ((savesWid) ? "|" : "") nextWid
	if (listItemsWid ~= versionsMenuWID)
	{
		DllCall("AppendMenu", Ptr, hMenu, UInt,0, UInt, nextWid := nextWid+1, Str, "элемент 1")
		DllCall("AppendMenu", Ptr, hMenu, UInt,0, UInt, nextWid := nextWid+1, Str, "элемент 2")
	
	}
	
}

#if WinExist("ahk_class #32768")
~lbutton::
SendMessage, MN_GETHMENU:=0x1E1, 0, 0
hMenu := ErrorLevel
wId_focused := ""
; задача этого loop'а получить элемент меню который находится в данный момент в фокусе.
loop % DllCall("GetMenuItemCount", "ptr", hMenu) ; смотрим весь контекстный список(несчитая дочерних)
  VarSetCapacity(MENUITEMINFO, A_PtrSize=8 ? (Size:=80) : (Size:=48), 0) ; win 64x или 32x
  and NumPut(Size, MENUITEMINFO, 0) ;cbSize = Size. Первый параметр структуры, В нем задается размер который равен тому что было определено выше.
  and NumPut(1, MENUITEMINFO, 4) ;fMask = MIIM_STATE. Второй параметр структуры, В нем указывается то что маска стуктуры будет fState.
  and DllCall("GetMenuItemInfo", "UInt", hMenu, "UInt", (A_index-1), "UInt", 1, "UInt", &MENUITEMINFO) ; получаем информацию о элементе меню.
Until (NumGet(MENUITEMINFO,12) & 0x80) ; fState четвертый параметр структуры, если fState содержит MFS_HILITE значит этот элемент в фокусе.
  and (wId_focused := DllCall("GetMenuItemID", "Uint", hMenu, "int", A_Index-1)) ; Если строка выше истина, то конец цикла и установка переменной wId_focused которая содержит wID элемента меню.

 if wId_focused = 704673
	msgbox Нажат Элемент 1 в notepad++
 if wId_focused = 704674
	msgbox Нажат Элемент 2 в notepad++
 if wId_focused = 524305
	msgbox нажат элемент 1 в windows.
 if wId_focused = 524306
	msgbox нажат элемент 2 в windows.
return
#if

А вот второй скрипт, он вспомогательный. С помощью него можно определить wID элемента который в фокусе или вывести весь список wID'ов родительского меню.

#if WinExist("ahk_class #32768")
^1:: ; ctrl+1 Получение wid элемента который в фокусе.
SendMessage, MN_GETHMENU:=0x1E1, 0, 0
hMenu := ErrorLevel
wId_focused := ""
loop % DllCall("GetMenuItemCount", "ptr", hMenu) ; смотрим весь контекстный список(несчитая дочерних)
  VarSetCapacity(MENUITEMINFO, A_PtrSize=8 ? (Size:=80) : (Size:=48), 0) ; win 64x или 32x
  and NumPut(Size, MENUITEMINFO, 0) ;cbSize = Size. Первый параметр структуры, В нем задается размер который равен тому что было определено выше.
  and NumPut(1, MENUITEMINFO, 4) ;fMask = MIIM_STATE. Второй параметр структуры, В нем указывается то что маска стуктуры будет fState.
  and DllCall("GetMenuItemInfo", "UInt", hMenu, "UInt", (A_index-1), "UInt", 1, "UInt", &MENUITEMINFO) ; получаем информацию о элементе меню.
Until (NumGet(MENUITEMINFO,12) & 0x80) ; fState четвертый параметр структуры, если fState содержит MFS_HILITE значит этот элемент в фокусе.
  and (wId_focused := DllCall("GetMenuItemID", "Uint", hMenu, "int", A_Index-1)) ; Если строка выше истина, то конец цикла и установка переменной wId_focused которая содержит wID элемента меню.

tooltip % wId_focused
return

^2:: ; ctrl+2 получение списка wid
	WinExist("ahk_class #32768")
	SendMessage, MN_GETHMENU:=0x1E1, 0, 0
	hMenu := ErrorLevel,	listItemsWid:=""
	loop % DllCall("GetMenuItemCount", "Uint", hMenu)
		listItemsWid .= ((listItemsWid) ? ":" : "") DllCall("GetMenuItemID", "Uint", hMenu, "int", A_Index-1)
	tooltip % listItemsWid

Со временем сделаю удобные функции для работы с чужими меню.

Тестировал на win 10 64x и win 7 64x.
p.s если у своей кнопки задать wid уже существующей, эта кнопка будет делать то же самое действие если даже этот элемент  находится в другом месте этого приложения.

22

Re: AHK: Добавление элементов в чужое контекстное меню

Идея интересная, но пока оформлена не очень, в таком виде пользоваться неудобно.

yalanne пишет:

А вот второй скрипт, он вспомогательный.

У меня не работает на пунктах, имеющих дочернее меню. Неправильные размерности (Int и Ptr).

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

23

Re: AHK: Добавление элементов в чужое контекстное меню

И кстати, такое оформление:

yalanne пишет:
loop % DllCall("GetMenuItemCount", "ptr", hMenu) ; смотрим весь контекстный список(несчитая дочерних)
  VarSetCapacity(MENUITEMINFO, A_PtrSize=8 ? (Size:=80) : (Size:=48), 0) ; win 64x или 32x
  and NumPut(Size, MENUITEMINFO, 0) ;cbSize = Size. Первый параметр структуры, В нем задается размер который равен тому что было определено выше.
  and NumPut(1, MENUITEMINFO, 4) ;fMask = MIIM_STATE. Второй параметр структуры, В нем указывается то что маска стуктуры будет fState.
  and DllCall("GetMenuItemInfo", "UInt", hMenu, "UInt", (A_index-1), "UInt", 1, "UInt", &MENUITEMINFO) ; получаем информацию о элементе меню.
Until (NumGet(MENUITEMINFO,12) & 0x80) ; fState четвертый параметр структуры, если fState содержит MFS_HILITE значит этот элемент в фокусе.
  and (wId_focused := DllCall("GetMenuItemID", "Uint", hMenu, "int", A_Index-1)) ; Если строка выше истина, то конец цикла и установка переменной wId_focused которая содержит wID элемента меню.

это адъ, читать совершенно невозможно. Уместить максимальное количество знаков на единицу площади — достоинство небольшое. Советую перейти на классический способ оформления кода (см. мой пример).

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

24

Re: AHK: Добавление элементов в чужое контекстное меню

teadrinker пишет:

Неправильные размерности (Int и Ptr).

DllCall("GetMenuItemInfo", ... ,"Ptr", &MENUITEMINFO) а в этом случае правильно использовать Ptr?

25

Re: AHK: Добавление элементов в чужое контекстное меню

В этом — да, но вообще в каждом случае лучше смотреть описание параметров winapi-функции в MSDN, там указан тип данных каждого параметра, а каждый тип данных имеет конкретную размерность (тоже можно посмотреть в MSDN).

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

26

Re: AHK: Добавление элементов в чужое контекстное меню

Спасибо за скрипт, я давно ищу способ добавлять свои пункты в контекстное меню.
Но у меня появился вопрос. Мне требуется выделять мышкой текст и обрабатывать его добавленным в контекстное меню пунктом. Не могу понять как мне получить в переменную выделенный текст, почему то эмуляция нажатия Ctrl-C командой Send текст в буфер не копирует.
Подскажите пожалуйста как правильно получить выделенный текст??

27

Re: AHK: Добавление элементов в чужое контекстное меню

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

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

28

Re: AHK: Добавление элементов в чужое контекстное меню

teadrinker пишет:

Если вам не нужно было бы добавлять текст в меню, то вы бы знали, как его получить?

Я получал текст в переменную эмуляцией нажатия Ctrl-C командой Send, текст помещался в буфер и я копировал его в переменную.
Но здесь, добавляя действие в свой элемент контекстное меню, как я уже писал, команда "Send, ^{vk43}" выделенный текст в буфер почему то не копирует.
Да, можно сначала скопировать нужный текст в буфер, потом нажать пр.кнопку мышки и выбрать там свой пункт, код которого выполнит нужные действия, но я хотел объединить эти два действия.

29

Re: AHK: Добавление элементов в чужое контекстное меню

Единственное, что приходит в голову, это что перед посылом Ctrl+C нужно убедиться, что целевое окно активно, и контрол, в котором выделен текст, находится в фокусе.

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

30

Re: AHK: Добавление элементов в чужое контекстное меню

А можно ли менять позицию элемента не перерисовывая все меню?
Вот например мелкий скрипт:

lwin::
pos = 1


	VarSetCapacity(sString, nSize := 70)
	listItemsWid := []
	WinExist("ahk_class #32768")
	SendMessage, MN_GETHMENU:=0x1E1, 0, 0
	hMenu := ErrorLevel


	loop % DllCall("GetMenuItemCount", "Uint", hMenu)
	{
		DllCall("GetMenuString", "Uint", hMenu, "int", A_Index-1, "str", sString, "int", nSize, "Uint", 0x400)
		listItemsWid.Insert( [DllCall("GetMenuItemID", "Uint", hMenu, "int", A_Index-1) , sString] )
	}
	
	listItemsWid.Insert(pos,[80000,"Элемент1"])
	for i,k in listItemsWid
	DllCall("RemoveMenu", "Ptr", hMenu, "Uint", 0, "Uint",0x400)
	for i,k in listItemsWid
	if k[1]
	  DllCall("AppendMenu", Ptr, hMenu, UInt,0x0, UInt, k[1], Str, k[2])
	else if (k[1] = 0)
	  DllCall("AppendMenu", Ptr, hMenu, UInt,0x800, UInt, 0, Str, "")
	else if (k[1] = -1)
	  DllCall("AppendMenu", Ptr, hMenu, UInt,0x10, UInt, 0, Str, "")

Тут можно выбрать позицию элемента, но при этом надо вообще все пункты сохранять в память, а так же стили и пути дочерних меню. Пока что сохранения стилей и путей к дочерним меню нет. Это все муторно. Есть ли простой способ выбрать позицию пункта??

31

Re: AHK: Добавление элементов в чужое контекстное меню

Так есть же InsertMenu и InsertMenuItem.

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

32

Re: AHK: Добавление элементов в чужое контекстное меню

MIIM_STRING := 0x40
MIIM_ID := 0x2
lwin::
	pos := 0
	name := "Элемент 1"
	wid := 80000
	
	
	WinExist("ahk_class #32768")
	SendMessage, MN_GETHMENU:=0x1E1, 0, 0
	hMenu := ErrorLevel

   ;64-bit или 32-bit
   VarSetCapacity(MENUITEMINFO, size := 4*4 + A_PtrSize*8, 0)
   
   ; MENUITEMINFO.cbSize = size
   NumPut(size, MENUITEMINFO)
   
   ; MENUITEMINFO.fMask = MIIM_STRING
   NumPut(MIIM_STRING, &MENUITEMINFO + 4)
   
   ; Получаем длину имени пункта
   TextLength := StrLen(name)
   
   ; создаем буфер для текста.
   VarSetCapacity(TextBuff, TextLength * (A_IsUnicode ? 2 : 1), 0)
   NumPut(&TextBuff, &MENUITEMINFO + 4*4 + A_PtrSize*5)
   NumPut(++TextLength, &MENUITEMINFO + 4*4 + A_PtrSize*6)
   StrPut(name,&TextBuff)
   
   
   ; Установка wid для элемента
   NumPut(MIIM_ID,MENUITEMINFO + 4)
   NumPut(wid,MENUITEMINFO,16)
   
   ; добавление пункта.
   DllCall("InsertMenuItem", Ptr, hMenu, UInt,  pos, UInt, true, Ptr, &MENUITEMINFO)

А как в структуре MENUITEMINFO задать id у элемента? Что то не получается.

33

Re: AHK: Добавление элементов в чужое контекстное меню

А что вот эта строка делает?

NumPut(MIIM_ID,MENUITEMINFO + 4)
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

34 (изменено: yalanne, 2015-12-21 00:21:47)

Re: AHK: Добавление элементов в чужое контекстное меню

Задает маску 0x1 для структуры. В MENUITEMINFO сначала надо же задать маску что бы установить\получить информацию.
А так на вид эти две строчки не чего не делают которые как бы устанавливают wid. Скорей всего не правильно делаю.

35

Re: AHK: Добавление элементов в чужое контекстное меню

Для NumPut есть два формата:

NumPut(MIIM_ID, &MENUITEMINFO + 4)

или

NumPut(MIIM_ID, MENUITEMINFO, 4)

fMask

    Type: UINT

    Indicates the members to be retrieved or set. This member can be one or more of the following values.

Нам нужно в данном случае показать в маске, что устанавливаются два параметра: MIIM_ID = 0x2 и MIIM_STRING = 0x40. Это делается сразу для обоих параметров:

NumPut(MIIM_ID|MIIM_STRING, &MENUITEMINFO + 4)
MIIM_STRING := 0x40
MIIM_ID := 0x2
lwin::
	pos := 0
	name := "Элемент 1"
	wid := 80000
	
	
	WinExist("ahk_class #32768")
	SendMessage, MN_GETHMENU:=0x1E1, 0, 0
	hMenu := ErrorLevel

	;64-bit или 32-bit
	VarSetCapacity(MENUITEMINFO, size := 4*4 + A_PtrSize*8, 0)

	; MENUITEMINFO.cbSize = size
	NumPut(size, MENUITEMINFO)

	; MENUITEMINFO.fMask = MIIM_STRING
	NumPut(MIIM_ID|MIIM_STRING, &MENUITEMINFO + 4)

	; Получаем длину имени пункта
	TextLength := StrLen(name)

	; создаем буфер для текста.
	VarSetCapacity(TextBuff, TextLength * (A_IsUnicode ? 2 : 1), 0)
	NumPut(&TextBuff, &MENUITEMINFO + 4*4 + A_PtrSize*5)
	NumPut(++TextLength, &MENUITEMINFO + 4*4 + A_PtrSize*6)
	StrPut(name,&TextBuff)


	; Установка wid для элемента
	NumPut(wid,MENUITEMINFO,16)

	; добавление пункта.
	DllCall("InsertMenuItem", Ptr, hMenu, UInt,  pos, UInt, true, Ptr, &MENUITEMINFO)
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

36

Re: AHK: Добавление элементов в чужое контекстное меню

Только стоит ли заморачиваться с придумыванием своего id для строки меню? Есть ли стопроцентная гарантия, что мы ни с чем не пересечёмся? По-моему, вполне можно ориентироваться на позицию пункта либо на его текст.

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

37 (изменено: yalanne, 2015-12-21 00:58:09)

Re: AHK: Добавление элементов в чужое контекстное меню

teadrinker пишет:

Есть ли стопроцентная гарантия, что мы ни с чем не пересечёмся?

Ну да есть, но с другой стороны это может быть полезным, например такая тема вроде была что бы создать свое меню и там что  бы элементы были как ярлыки из другого массивного меню с кучей дочерних(о sony vegas вроде тема была.), так сказать избранные пункты которые часто используются.

А так да легче без id, используя позицию и имя.

38

Re: AHK: Добавление элементов в чужое контекстное меню

yalanne пишет:

Ну да есть

Чтобы она была, нам придётся сначала исследовать все пункты всех меню данного приложения. А иначе наш код будет некорректным.

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

39

Re: AHK: Добавление элементов в чужое контекстное меню

С позицией не так уж и просто тоже, например сразу 2 элемента на позицию 1 добавить, у второго уже будет позиция 2. Надо будет прогонять через цикл массив содержащий лист элементов которые будут добавлены и установить позицию + 1 всем.

+ Кстати нашел все таки способ свой id устанавливать.
MIIM_STRING := 0x40
MIIM_ID := 0x2
lwin::
k := ["Элемент1",0,1 + 0xFFFFFF]

	WinExist("ahk_class #32768")
	SendMessage, MN_GETHMENU:=0x1E1, 0, 0
	hMenu := ErrorLevel

	;64-bit или 32-bit
    VarSetCapacity(MENUITEMINFO, size := 4*4 + A_PtrSize*8, 0)
   
    ; MENUITEMINFO.cbSize = size
    NumPut(size, MENUITEMINFO)
	
	; MENUITEMINFO.fMask = MIIM_STRING
	; MENUITEMINFO.fMask = MIIM_ID
	NumPut(MIIM_STRING|MIIM_ID, &MENUITEMINFO + 4)

	; Получаем длину имени пункта
	TextLength := StrLen(k[1])

	; создаем буфер для текста.
	VarSetCapacity(TextBuff, TextLength * (A_IsUnicode ? 2 : 1), 0)
	NumPut(&TextBuff, &MENUITEMINFO + 4*4 + A_PtrSize*5)
	NumPut(++TextLength, &MENUITEMINFO + 4*4 + A_PtrSize*6)
	StrPut(k[1],&TextBuff)
	
	; MENUITEMINFO.wID 
	NumPut( k[3] ,MENUITEMINFO,4*4,"UInt")
		
	; добавление пункта.
	DllCall("InsertMenuItem", Ptr, hMenu, UInt,  k[2], UInt, true, Ptr, &MENUITEMINFO)
	
	; обновить окно меню, что бы убрать визуальные баги.
	WinSet,Redraw

Если по id определять клик, скрипту будет не важна позиция и не будет лишнего поиска.

Тем более id'шник может быть в диапазоне  0 - FFFFFFFF  сложно будет попасть в чужой если брать последние цифры, да и если есть попадание то можно будет просто на пару тысяч больше меньше поставить.
например когда будет функция для удобного создания, если в параметре не указывать id, то присваивается скриптом, если в чужой попало то задаем в вручную.
А еще в этом случае будет удобно если наоборот надо попасть в чужой намеренно.

У винды в общем около 0x8000 и 0x300 id'шники находятся, у notepad++ 0x40000.

40

Re: AHK: Добавление элементов в чужое контекстное меню

А почему просто по тексту пункта не определять?

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

41

Re: AHK: Добавление элементов в чужое контекстное меню

Ну например если есть с одинаковым именем.

42

Re: AHK: Добавление элементов в чужое контекстное меню

А зачем с одинаковым делать? Вероятность, что ID одинаковый получится, больше, т.к. все названия видны, а ID — нет.

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

43

Re: AHK: Добавление элементов в чужое контекстное меню

Ну можно две отдельные функции сделать, одна будет ориентироваться  по имени вторая же по id и кому как удобней будет.

44

Re: AHK: Добавление элементов в чужое контекстное меню

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

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

45

Re: AHK: Добавление элементов в чужое контекстное меню

Я сейчас функцию пишу для создания группы радиобоксов элементов меню, все имеют одинаковое имя:D , а так да можно каждому индивидуально установить.

46

Re: AHK: Добавление элементов в чужое контекстное меню

По-моему, с ID — это будет усложнение для пользователя, проще оговорить, что названия не должны пересекаться.

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

47 (изменено: yalanne, 2016-01-20 13:01:47)

Re: AHK: Добавление элементов в чужое контекстное меню

Кто нибудь знает где можно посмотреть спец. стили для контекстного меню  в windows 10?
это меню так же имеет класс #32768.
http://i.imgur.com/8x1ds0c.gif

Пункт здесь так же добавляется через InsertMenuItem.

48

Re: AHK: Добавление элементов в чужое контекстное меню

А что такое спец. стили?

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

49

Re: AHK: Добавление элементов в чужое контекстное меню

Ну может это не так называется, Но у каждого элемента есть свои стили(заблокирован, не заблокирован, Имеет галочку или нет,галочка-точка, элемент в фокусе и тд.). Раз это тот же класс контекстного меню что и предыдущих windows, значит там просто добавлены новые стили которые есть исключительно в win 10. Которые отвечают за цвет букв и их размер.

50

Re: AHK: Добавление элементов в чужое контекстное меню

Предполагаю, что в 10 так же, как и в 7, fState в MENUITEMINFO. Нет?

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

51

Re: AHK: Добавление элементов в чужое контекстное меню

Возможно, надо будет попробовать методом тыка поискать. А так вроде же все равно где то это должно быть описано быть.

52

Re: AHK: Добавление элементов в чужое контекстное меню

Здесь.

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

53

Re: AHK: Добавление элементов в чужое контекстное меню

О 10 винде там не чего не сказано, да и fState не нашел нечего что бы повлияло на установку белого цвета.

54

Re: AHK: Добавление элементов в чужое контекстное меню

Если не сказано, значит ничего не изменилось. А что за установка белого цвета?

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