1

Тема: AHK: Пользовательское контекстное меню

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

#HotkeyInterval 0
GUI, +HwndMyGui
GUI, Add, Button, g1, Мой компьютер
GUI, Add, Button, g2, Программы
GUI, Add, Button, g3, Рабочий стол
GUI, Add, Button, g4, Мои документы
Return

#if WinActive("ahk_id" MyGui)
WheelDown::Send {Right}
WheelUp::Send {Left}
#if

F1:: GUI, Show
F1 up::
Send, {Space}
GUI, Hide
Return

1:
Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
Return
2:
Run, %A_ProgramFiles%
Return
3:
Run, %A_Desktop%
Return
4:
Run, %A_MyDocuments%
Return

2

Re: AHK: Пользовательское контекстное меню

Если внешнее сходство с контекстым меню это наиболее важное условие, то вот скрипт "PopFav":
(хоткеи ^1 и ^2)

; PopFav -- simple popup menu launcher inspired by PopSel

; Sample menus are given in the special commented section below between /* */.
; Two menus are created. Use hotkeys Ctrl-1 and Ctrl-2 to launch them.
; If you want to read menus from another file, change POPFAV_MENU_FILE below.
;
; First line of a menu definition contains a unique Menu Name which identifies
; the menu.  It must be the first instance of this Name in the file.
; Next line with Menu Name ends Menu definition.  Menu Names must conform to
; the rules of AHK variable naming: letters, numbers, and _ only, no spaces.
;
; Within each menu, one line corresponds to one menu item.
; Specify the name of the menu item first, followed by the == string, followed
; by the Target parameter for the Run command.
; See http://www.autohotkey.com/docs/commands/Run.htm for details.
; It's not possible to specify Run parameters other than Target.
;
; To create separator line, omit text after the == string.
; Lines without == are ignored, e.g., blank lines, comments.
;
; Use >> string to create submenu. Only one level sumbenus are possible, that
; is only the first >> string is treated as sumbenu separator.
;
; Once a menu name is defined, use it to create popup menu:
; 1. Call function
;   POPFAV_Create_Menu("MenuName", POPFAV_MENU_FILE)
; 2. Create hotkey
;   {Hotkey}::Menu, MenuName, Show
; See below for examples.

/*
=========== MENU DEFINITIONS =================================================

___________ POPFAV_DEMO_MENU1 ________________________________________________
/Documents and Settings    == C:\Documents and Settings
        folders can open faster if file manager is specified
/Program Files             == explorer.exe %ProgramFiles%
        create separator in main menu
--------==
/%A_Temp%                  == explorer.exe %A_Temp%

        create sumbenu Applications
Applications >> !Notepad.exe  == notepad.exe
Applications >> edit this script in notepad   == notepad.exe %A_ScriptFullPath%
Applications >> !Calc.exe     == Calc.exe
Applications >> !cmd.exe      ==  %comspec% /k cd %A_ScripDir%

        these are examples from AHK help for Run command
AHK help examples >> My Computer        == ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
AHK help examples >> Recycle Bin        == ::{645ff040-5081-101b-9f08-00aa002f954e}
AHK help examples >> ------------------ ==
        Do not escape , in Target string.
AHK help examples >> Display Properties->Settings == rundll32.exe shell32.dll,Control_RunDLL desk.cpl,, 3

        create separator in main menu, this ends previous sumbenu
--------==

        Potential gotchas with deref. Don't use %% unless you have to.
Gotchas >> this menu name: %MenuName%        == %A_Space%
Gotchas >> edit menu definition file in notepad   == notepad.exe %MenuFile%
___________ POPFAV_DEMO_MENU1 ________________________________________________


___________ POPFAV_DEMO_MENU2 ________________________________________________
        links
autohotkey.com          == http://www.autohotkey.com
autohotkey.com/docs     == http://www.autohotkey.com/docs/
google                      == http://www.google.com/webhp?num=100
___________ POPFAV_DEMO_MENU2 ________________________________________________

========= END OF MENU DEFINITIONS ============================================
*/

;;;;; Specify file which contains PopFav menu definitions.
; Menus are defined at the start of this script file between /* */.
POPFAV_MENU_FILE = %A_ScriptFullPath%
; Menus are defined in external file in this script's dir.
; POPFAV_MENU_FILE = %A_ScriptDir%\PopFav.menus

;;;;; Create PopFav menus.  Use menu names defined in menu file.
POPFAV_Create_Menu("POPFAV_DEMO_MENU1", POPFAV_MENU_FILE)
POPFAV_Create_Menu("POPFAV_DEMO_MENU2", POPFAV_MENU_FILE)

;;;;; Create hotkeys which show PopFav menus.
^1::Menu, POPFAV_DEMO_MENU1, Show
^2::Menu, POPFAV_DEMO_MENU2, Show

;;;;; End of PopFav configuration. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
return
;====================== end of auto-execute section ==========================
;=============================================================================


POPFAV_Create_Menu(MenuName, MenuFile) {
; Parse menu definition MenuName from file MenuFile.
; Create menu MenuName and its submenus.
    global
    local pos
    local _left, _right ; parts before and after == separator
    local _left1, _left2 ; parts before and after >> separator
    local OutsideOfMenu = 1
    local SubLev = 0 ; 0 if in main menu, 1 if in submenu
    local SubName ; current submenu item; part before >> with whitespace stripped
    local MenuIdx = 1 ; main menu item index, also a submenu id: %MenuName%%MenuIdx%
    local SubIdx = 1 ; current sumbenu item index, increment after adding to sumbenu

    Loop, Read, %MenuFile%
    {
        ; Skip lines until the first line with MenuName.
        if OutsideOfMenu
        {
            IfInString, A_LoopReadLine, %MenuName%
                OutsideOfMenu = 0
            continue
        }
        ; Second line with MenuName marks the end of menu definition.
        ; Add last submenu, if any, and exit loop.
        IfInString, A_LoopReadLine, %MenuName%
        {
            if SubLev = 1
                Menu, %MenuName%, Add, %SubName%, :%MenuName%%MenuIdx%
            break
        }
        ; We are inside menu definition.
        ; Add menu item to (sub)menu and create global variable containing the
        ; command of this (sub)menu item. Variables are named:
        ;      %MenuName%_cmd%MenuIdx%           --main menu
        ;      %MenuName%%MenuIdx%_cmd%SubIdx%   --submenu
        ; Add menu separator if there is nothing after the first == string.
        ; NOTE: increment (sub)menu item index after adding any item, including
        ; separator or submenu.
        ;
        ; get location of ==
        StringGetPos, pos, A_LoopReadLine, ==
        if pos < 0; ignore line without ==
            continue
        ; get part after ==
        StringTrimLeft, _right, A_LoopReadLine, pos+2
        _right = %_right%  ; strip whitespace
        ; get part before ==
        StringLeft, _left, A_LoopReadLine, pos
        ; resolve any references to variables (assumes that submenu separator cannot be created)
        Transform, _left, deref, %_left%
        _left = %_left%  ; strip whitespace
        ; check for submenu separator
        StringGetPos, pos, _left, >>
        ;;;;;;;;;; there is no submenu, add item to main menu
        if pos < 0
        {
            if SubLev = 1 ; previous submenu ended, add it
            {
                SubLev = 0
                Menu, %MenuName%, Add, %SubName%, :%MenuName%%MenuIdx%
                MenuIdx++
                SubIdx = 1
            }
            if _right =
            {
                Menu, %MenuName%, Add
                MenuIdx++
            }
            else
            {
                Transform, %MenuName%_cmd%MenuIdx%, deref, %_right%
                Menu, %MenuName%, Add, %_left%, POPFAV_MENU_HANDLER
                MenuIdx++
            }
        }
        ;;;;;;;;;; there is a submenu; add item to it
        else
        {
            StringLeft, _left1, _left, pos ; sumbenu name
            _left1 = %_left1%
            StringTrimLeft, _left2, _left, pos+2 ; sumbenu item name
            _left2 = %_left2%
            ;;;;; new submenu after main menu
            if SubLev = 0
            {
                SubLev = 1
                SubName = %_left1%
            }
            ;;;;; another item of previous submenu, nothing changed
            else if _left1 = %SubName%
            {
            }
            ;;;;; new submenu after previous submenu
            else
            {
                ; add previous submenu
                Menu, %MenuName%, Add, %SubName%, :%MenuName%%MenuIdx%
                MenuIdx++
                SubIdx = 1
                ; start building new submenu
                SubName = %_left1%
            }
            ;;;;; add item to sumbenu, add separator if there is nothing after ==
            if _right =
            {
                Menu, %MenuName%%MenuIdx%, Add
                SubIdx++
            }
            else
            {
                Transform, %MenuName%%MenuIdx%_cmd%SubIdx%, deref, %_right%
                Menu, %MenuName%%MenuIdx%, Add, %_left2%, POPFAV_MENU_HANDLER
                SubIdx++
            }
        }
    }
}


POPFAV_MENU_HANDLER:
; Handler for all PopFav menu items.
    ; Fetch variable containing action for selected menu item.
    ; _popfav_cmd contains last menu action: handy for debugging
    _popfav_cmd := %A_ThisMenu%_cmd%A_ThisMenuItemPos%
    Run, %_popfav_cmd%
return

3

Re: AHK: Пользовательское контекстное меню

внешне максимально похожий на контекстное меню

Так а само "готовое меню" чем не устраивает?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

4

Re: AHK: Пользовательское контекстное меню

serzh82saratov, заголовком окна, кнопками. Предпочитаю минималистичные строки. Наверное, было бы даже лучше в виде многострочного тултипа.

5

Re: AHK: Пользовательское контекстное меню

mafckz, подойдет как альтернативный вариант. Но хотелось бы с точностью повторить функционал сценария из первого поста.

6

Re: AHK: Пользовательское контекстное меню

becauseim пишет:

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

Наподобии как здесь с буфером обмена?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

7

Re: AHK: Пользовательское контекстное меню

serzh82saratov, точно не понял, что именно Вы имели в виду. Раскрывающуюся панель по нажатию на MButton либо список, раскрывающийся при нажатии на строку из этой панели. Но, в любом случае, как вариант, думаю, было бы весьма неплохо.

8

Re: AHK: Пользовательское контекстное меню

becauseim пишет:

список, раскрывающийся при нажатии на строку из этой панели

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

9

Re: AHK: Пользовательское контекстное меню

serzh82saratov, да, вполне.

10 (изменено: mafckz, 2016-04-18 02:41:49)

Re: AHK: Пользовательское контекстное меню

#SingleInstance force

#HotkeyInterval 0
GUI, +HwndMyGui -Caption -0x40000
GUI, Margin, -1, -1
GUI, Add, Button, g1, Мой компьютер
GUI, Add, Button, g2 wp, Программы
GUI, Add, Button, g3 wp, Рабочий стол
GUI, Add, Button, g4 wp, Мои документы
Return

#if WinActive("ahk_id" MyGui)
WheelDown::Send {Right}
WheelUp::Send {Left}
#if

F1:: GUI, Show
F1 up::
Send, {Space}
GUI, Hide
Return

1:
Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
Return
2:
Run, %A_ProgramFiles%
Return
3:
Run, %A_Desktop%
Return
4:
Run, %A_MyDocuments%
Return

11 (изменено: becauseim, 2016-04-18 13:39:29)

Re: AHK: Пользовательское контекстное меню

mafckz, Спасибо! А можно ли повторить цветовую схему отображения выделения аналогично контекстному меню? Без разделений строк, выделение серым цветом, без обводки подобной кнопкам.

upd.: Или же подобно выпадающему списку из сценария от serzh82saratov, но в менее контрастных цветах.

12 (изменено: serzh82saratov, 2016-04-18 17:51:15)

Re: AHK: Пользовательское контекстное меню

максимально похожий на контекстное меню.

serzh82saratov, заголовком окна, кнопками. Предпочитаю минималистичные строки. Наверное, было бы даже лучше в виде многострочного тултипа.

Вы наверное меня не так поняли, чем не устраивает стандартное меню:


Menu, MyMenu, Add, Мой компьютер, 1
Menu, MyMenu, Add, Программы, 2
Menu, MyMenu, Add, Рабочий стол, 3
Menu, MyMenu, Add,  Мои документы, 4 
Return


F1:: Menu, MyMenu, Show

1:
	Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
	Return
2:
	Run, %A_ProgramFiles%
	Return
3:
	Run, %A_Desktop%
	Return
4:
	Run, %A_MyDocuments%
	Return
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

13 (изменено: mafckz, 2016-04-18 18:26:38)

Re: AHK: Пользовательское контекстное меню

serzh82saratov, у меня с подобным скриптом не получилось посылать {down} и {up} кручением колесика мышки, т.е. следующий код не работает при открытом меню:

SendLevel, 1
return
WheelDown::SendEvent {down}
WheelUp::SendEvent {up}

Как это можно реализовать?
(Физическое нажатие стрелок на клавиатуре перемещает фокус элементов меню)

14

Re: AHK: Пользовательское контекстное меню

serzh82saratov, спасибо! В общем, это то, что нужно. Но минималистичное GUI подобно представленному Вами было бы еще лучше. Как уже заметил mafckz, не хватает перехода по строкам при прокручивании колесиком мыши.

15 (изменено: serzh82saratov, 2016-04-21 04:13:26)

Re: AHK: Пользовательское контекстное меню

у меня с подобным скриптом не получилось посылать {down} и {up}

Да, во время отображения стандартного меню никакие хоткеи не работают.

минималистичное GUI подобно представленному

Ну если совсем простенькое меню, без отметок, вложенностей и.т.п., то примерно так:


#SingleInstance Force
#NoEnv

List1 := [["Мой компьютер","1"],["Программы","2"],["Рабочий стол","3"],["Мои документы","4"]]
List2 := [["Папка скрипта","OpenDir"],["Редактировать","Edit"],["Как определить имя пункта","Check_name"]]

Menu1 := New Menu(List1, "FFFFFF", "DBDBDB", "2842A0", 210)
Menu2 := New Menu(List2, "5976C5", "2EC001", "FFFFFF", , 24)

Escape:: ExitApp

+1::Menu1.Show()
	
+2::Menu2.Show()

OpenDir:
	Run %A_ScriptDir%
	Return
Edit:
	Run, Edit %A_ScriptFullPath%
	Return
Check_name:
	MsgBox % Menu.Name
	Return
1:
	Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
	Return
2:
	Run, %A_ProgramFiles%
	Return
3:
	Run, %A_Desktop%
	Return
4:
	Run, %A_MyDocuments%
	Return






Class Menu {
	Static oMenu := {}, View, Selection, AllReady, PrCtrl, WaitX, WaitY, Name, Label, XMargin := "  ", YMargin := 30  ; в процентах к размеру текста
	__New(List, bcgColor, hiColor, textColor, Transparent = 255, FontSize = 0) {
		If !Menu.AllReady
			Menu.SetHotkeys(), OnMessage(0x202, this["WM_LBUTTONUP"].Bind(this)), Menu.AllReady := 1
		Gui, New
		Gui, +AlwaysOnTop -DPIScale +hwndhGui +LabelMenuOn -Caption +Border +Owner +E0x08000000
		Menu.oMenu[hGui] := {}, Menu.oMenu[hGui].Items := [], Menu.oMenu[hGui].ItemPos := []
		this.hwnd := hGui, Menu.oMenu[hGui].Obj := this, Menu.oMenu[hGui].List := List
		Menu.oMenu[hGui].bcgColor := bcgColor, Menu.oMenu[hGui].hiColor := hiColor, Menu.oMenu[hGui].textColor := textColor
		Gui, Font, % "q1" . (FontSize ? " s" FontSize : "")
		Gui, Margin, 0, 0
		Gui, Color, %bcgColor%  
		If (Transparent < 255)
		{
			S_DetectHiddenWindows := A_DetectHiddenWindows
			DetectHiddenWindows, On
			WinSet, Transparent, %Transparent%, ahk_id %hGui%
			DetectHiddenWindows, %S_DetectHiddenWindows%
		}
		For k, v in List
		{
			Gui, Add, Text, hwndhDummy hidden, % Menu.XMargin v[1] Menu.XMargin
			GuiControlGet, Pos, Pos, %hDummy%
			maxW := !maxW || PosW > maxW ? PosW : maxW
			maxH := !maxH || PosH > maxH ? PosH : maxH
			DllCall("DestroyWindow", "Ptr", hDummy)
		}
		Gui, Show, Hide w0 h0
		For k, v in List
		{
			Gui, Add, Progress, % (k = 1 ? "x0 y0" : "y+0") " hwndhBack w" maxW " h" maxH + (maxH / 100 * Menu.YMargin) " Background" bcgColor, 0
			Gui, Add, Text, % "xp yp wp hp hwndhText +0x200 BackgroundTrans c" textColor, % Menu.XMargin v[1] Menu.XMargin
			Menu.oMenu[hGui].Items[hText] := {back:hBack,key:k,label:v[2],name:v[1]}
			Menu.oMenu[hGui].Items[hBack] := {text:hText,key:k,label:v[2],name:v[1]}
			Menu.oMenu[hGui].ItemPos[k] := {text:hText,back:hBack}
		}
		Gui, Show, Hide AutoSize, #32768
		Menu.oMenu[hGui].Obj.hwnd
		Return this
	}
	Show(x = "", y = "") {
		Menu.Hide()
		If (x = "" || y = "")
			DllCall("GetCursorPos", "int64P", pt), x := pt << 32 >> 32, y := pt >> 32
		GuiHwnd := Menu.View := this.hwnd
		Menu.Name := Menu.Label := ""
		Menu.GetClientSize(GuiHwnd, w, h)
		Menu.CalculatePopupWindowPosition(sx, sy, w, h, x, y, 4, 4)
		Gui, %GuiHwnd%:Show, NA x%sx% y%sy%
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, 50
	}
	Hide() {
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, Off
		GuiHwnd := Menu.View
		Menu.Color(Menu.oMenu[GuiHwnd].bcgColor, Menu.oMenu[GuiHwnd].Items[Menu.Selection].back)
		Menu.View := Menu.Selection := Menu.PrCtrl := 0, Menu.WaitX := Menu.WaitY := ""
		Try Gui, %GuiHwnd%:Show, Hide
	}
	Select(hwnd = "") {
		hwnd := !hwnd ? Menu.Selection : hwnd
		Try SetTimer, % Menu.Label, -1
		Menu.Hide()
	}
	MouseGet() {
		If (Menu.WaitX != "")
		{
			DllCall("GetCursorPos", "int64P", pt), X := pt << 32 >> 32, Y := pt >> 32
			If (Abs(X - Menu.WaitX) > 1 || Abs(Y - Menu.WaitY) > 1)
				Menu.WaitX := Menu.WaitY := ""
			Else
				Return
		}
		MouseGetPos, , , win, ctrl, 2
		If (win = Menu.View && ctrl && ctrl != Menu.PrCtrl)
		{
			obj := Menu.oMenu[win]
			Menu.Color(obj.bcgColor, obj.Items[Menu.Selection].back)
			Menu.Selection := ctrl
			Menu.Color(obj.hiColor, obj.Items[Menu.Selection].back)
			Menu.Label := obj.Items[ctrl].label
			Menu.Name := obj.Items[ctrl].Name
			Menu.PrCtrl := ctrl
		}
		GuiHwnd := Menu.View
		Try Gui, %GuiHwnd%:+AlwaysOnTop
    }
	Up_Down() {
		obj := Menu.oMenu[Menu.View]
		mi := obj.List.MaxIndex()
		sel := obj.Items[Menu.Selection].key
		new := InStr(A_ThisHotkey, "Up")
		? (!sel || sel = 1 ? mi : sel - 1)
		: (!sel || sel = mi ? 1 : sel + 1)
		Menu.Color(obj.bcgColor, obj.Items[Menu.Selection].back)
		Menu.Selection := obj.ItemPos[new].text
		Menu.Color(obj.hiColor, obj.ItemPos[new].back)
		Menu.Label := obj.Items[Menu.Selection].label
		Menu.Name := obj.Items[Menu.Selection].Name
		Menu.PrCtrl := 0
		DllCall("GetCursorPos", "int64P", pt), Menu.WaitX := pt << 32 >> 32, Menu.WaitY := pt >> 32
    }
	SetHotkeys() {
		#If Menu.View
		#If Menu.View && Menu.Selection
		#If
		Hotkey, IF, Menu.View
		hFunc := ObjBindMethod(this, "MouseIsUnderMenu")
		Hotkey, ~LButton, % hFunc
		Hotkey, ~RButton, % hFunc
		Hotkey, ~MButton, % hFunc
		hFunc := ObjBindMethod(this, "Up_Down")
		Hotkey, *WheelUp, % hFunc
		Hotkey, *WheelDown, % hFunc
		Hotkey, *Up, % hFunc
		Hotkey, *Down, % hFunc
		hFunc := ObjBindMethod(this, "Hide")
		Hotkey, Escape, % hFunc
		Hotkey, IF, Menu.View && Menu.Selection
		hFunc := ObjBindMethod(this, "Select")
		Hotkey, Space, % hFunc
		Hotkey, Enter, % hFunc
		Hotkey, IF
    }
	MouseIsUnderMenu() {
		MouseGetPos, , , win
		If (win != Menu.View)
			Menu.Hide()
    }
	Color(color, hwndback)  {
		GuiControl, +Background%color%, %hwndback%
		GuiControl, +Redraw, %hwndback%
		GuiControl, +Redraw, % Menu.Selection
	}
	WM_LBUTTONUP(w, l, m, h)  {
		Menu.Select(h)
	}
	GetClientSize(hwnd, ByRef W, ByRef H)  {
		VarSetCapacity(pwi, 60, 0), NumPut(60, pwi, 0, "UInt")
		DllCall("GetWindowInfo", "Ptr", hwnd, "UInt", &pwi)
		W := NumGet(pwi, 28, "Int") - NumGet(pwi, 20, "Int")
		H := NumGet(pwi, 32, "Int") - NumGet(pwi, 24, "Int")
	}
	CalculatePopupWindowPosition(byref left, byref top, w, h, x, y, offsetx = 0, offsety = 0)  {
		VarSetCapacity(POINT, 8, 0), VarSetCapacity(structs, 24, 0)
		NumPut(x, POINT, 0, "int"), NumPut(y, POINT, 4, "int")
		NumPut(w + offsetx, structs, 0, "int"), NumPut(h + offsety, structs, 4, "int")
		If !DllCall("CalculatePopupWindowPosition"
			, "ptr", &POINT
			, "ptr", &structs
			, "int", 0
			, "ptr", 0
			, "ptr", &structs + 8)
			Return 0
		left  := NumGet(structs, 8, "int") + offsetx
		top := NumGet(structs, 12, "int") + offsety
		Return 1
	}
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

16 (изменено: Malcev, 2016-04-19 15:15:21)

Re: AHK: Пользовательское контекстное меню

serzh82saratov пишет:

Да, во время отображения стандартного меню никакие хоткеи не работают.

Можно создать еще один скрипт и прописать в нем:

#IfWinExist, ahk_class #32768
WheelDown::down
WheelUp::up
#If

Но у меня почему-то при первом запуске кода из 12 поста не всегда срабатывает передвижение по пунктам меню с помощью нажатия стрелочек верх-вниз. Помогает либо перезапуск скрипта, либо закрытие меню и повторное его появление с помощью f1.
Может у них баг какой-то либо у меня.
Так как в хелпе написано:

Show [, X, Y]: Displays MenuName, allowing the user to select an item with arrow keys, menu shortcuts (underlined letters), or the mouse

17

Re: AHK: Пользовательское контекстное меню

Можно создать еще один скрипт

Таким макаром можно много чего порешать...

#IfWinExist, ahk_class #32768
WheelDown::down
WheelUp::up
#If

Не знаю на счёт IfWinExist, думаю тут правильнее IsWindowVisible. Ну и если уже неактивное окно нашли, то скорее всего ControlSend.

Поправил 15 пост.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

18 (изменено: becauseim, 2016-04-20 03:54:17)

Re: AHK: Пользовательское контекстное меню

Насколько я понял, вариант с классическим контекстным меню отпадает в виду невозможности отправления горячих клавиш при активности данного элемента. Т.е. полностью повторить функционал сценария из первого поста не получится.

В таком случае, вариант сценария из 15-го поста от serzh82saratov подходит отлично, но хотелось бы несколько изменить размеры и цвета интерфейса, в т.ч. величину шрифта и отступы. serzh82saratov, добавьте, пожалуйста, комментарии к тем строкам, где можно изменить перечисленные параметры. Спасибо!

И еще у меня так и не получилось добавить запуск выбранного пункта при отжатии горячей клавиши.

19 (изменено: mafckz, 2016-04-20 11:44:29)

Re: AHK: Пользовательское контекстное меню

becauseim пишет:

... хотелось бы несколько изменить размеры и цвета интерфейса, в т.ч. величину шрифта и отступы. serzh82saratov, добавьте, пожалуйста, комментарии к тем строкам, где можно изменить перечисленные параметры. Спасибо!

И еще у меня так и не получилось добавить запуск выбранного пункта при отжатии горячей клавиши.

#SingleInstance Force
#NoEnv

global MenuSelectedItemLabel  		; содержит метку (label) выделенного элемента меню
global ShowMenuInTheCenter := 1		; 1 для появления меню в центре экрана, иначе 0

List1 := [["Мой компьютер","1"],["Программы","2"],["Рабочий стол","3"],["Мои документы","4"]]
List2 := [["Папка скрипта","OpenDir"],["Редактировать","Edit"],["Как определить имя пункта","Check_name"]]

;_____:= New Menu(<List>, "<цвет общего фона>", "<цвет подсветки-фокус>"," <цвет текста>", <прозрачность меню>, <размер шрифта> )
Menu1 := New Menu(List1, "FFFFFF", "DBDBDB", "2842A0", 210)
Menu2 := New Menu(List2, "5976C5", "2EC001", "FFFFFF", , 12)

Escape:: ExitApp

F1::
	Menu1.Show() 
	KeyWait F1
	Menu1.Hide() 
	if (MenuSelectedItemLabel != "")
		gosub % MenuSelectedItemLabel
	return


+2::Menu2.Show()


OpenDir:
	Run %A_ScriptDir%
	Return
Edit:
	Run, Edit %A_ScriptFullPath%
	Return
Check_name:
	MsgBox % Menu.Name
	Return
1:
	Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
	Return
2:
	Run, %A_ProgramFiles%
	Return
3:
	Run, %A_Desktop%
	Return
4:
	Run, %A_MyDocuments%
	Return






Class Menu {
	Static oMenu := {}, View, Selection, AllReady, PrCtrl, WaitX, WaitY, Name
	__New(List, bcgColor, hiColor, textColor, Transparent = 255, FontSize = 0) {
		If !Menu.AllReady
			Menu.SetHotkeys(), OnMessage(0x202, this["WM_LBUTTONUP"].Bind(this)), Menu.AllReady := 1
		Gui, New
		Gui, +AlwaysOnTop -DPIScale +hwndhGui +LabelMenuOn -Caption +Border +Owner +E0x08000000
		Menu.oMenu[hGui] := {}, Menu.oMenu[hGui].Items := [], Menu.oMenu[hGui].ItemPos := []
		this.hwnd := hGui, Menu.oMenu[hGui].Obj := this, Menu.oMenu[hGui].List := List
		Menu.oMenu[hGui].bcgColor := bcgColor, Menu.oMenu[hGui].hiColor := hiColor, Menu.oMenu[hGui].textColor := textColor
		Gui, Font, % "q1" . (FontSize ? " s" FontSize : "")
		Gui, Margin, 0, 0
		Gui, Color, %bcgColor%
		If (Transparent < 255)
		{
			S_DetectHiddenWindows := A_DetectHiddenWindows
			DetectHiddenWindows, On
			WinSet, Transparent, %Transparent%, ahk_id %hGui%
			DetectHiddenWindows, %S_DetectHiddenWindows%
		}
		For k, v in List
		{
			Gui, Add, Text, hwndhDummy hidden, % "    " v[1] "    "
			GuiControlGet, Pos, Pos, %hDummy%
			maxW := !maxW || PosW > maxW ? PosW : maxW
			maxH := !maxH || PosH > maxH ? PosH : maxH
			DllCall("DestroyWindow", "Ptr", hDummy)
		}
		For k, v in List
		{
			Gui, Add, Progress, % (k = 1 ? "x0 y0" : "y+0") " hwndhBack w" maxW " h" maxH * 2 " Background" bcgColor, 0
			Gui, Add, Text, % "xp yp wp hp hwndhText +0x200 BackgroundTrans c" textColor, % "    " v[1] "    "
			Menu.oMenu[hGui].Items[hText] := {back:hBack,key:k,label:v[2],name:v[1]}
			Menu.oMenu[hGui].Items[hBack] := {text:hText,key:k,label:v[2],name:v[1]}
			Menu.oMenu[hGui].ItemPos[k] := {text:hText,back:hBack}
		}
		Gui, Show, Hide, #32768
		Menu.oMenu[hGui].Obj.hwnd
		Return this
	}
	Show(x = "", y = "") {
		Menu.Hide()
		If (x = "" || y = "")
			DllCall("GetCursorPos", "int64P", pt), x := pt << 32 >> 32, y := pt >> 32
		GuiHwnd := Menu.View := this.hwnd
		Menu.GetClientSize(GuiHwnd, w, h)
		Menu.CalculatePopupWindowPosition(sx, sy, w, h, x, y, 4, 4)
		Gui, %GuiHwnd%:Show, NA x%sx% y%sy%
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, 50
	}
	Hide() {
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, Off
		GuiHwnd := Menu.View
		Menu.Color(Menu.oMenu[GuiHwnd].bcgColor, Menu.oMenu[GuiHwnd].Items[Menu.Selection].back)
		Menu.View := Menu.Selection := Menu.PrCtrl := 0, Menu.WaitX := Menu.WaitY := ""
		Try Gui, %GuiHwnd%:Show, Hide
	}
	Select(hwnd = "") {
		hwnd := !hwnd ? Menu.Selection : hwnd
		Menu.Name := Menu.oMenu[Menu.View].Items[hwnd].Name
		Try SetTimer, % Menu.oMenu[Menu.View].Items[hwnd].label, -1
		Menu.Hide()
	}
	MouseGet() {
		If (Menu.WaitX != "")
		{
			DllCall("GetCursorPos", "int64P", pt), X := pt << 32 >> 32, Y := pt >> 32
			If (Abs(X - Menu.WaitX) > 1 || Abs(Y - Menu.WaitY) > 1)
				Menu.WaitX := Menu.WaitY := ""
			Else
				Return
		}
		MouseGetPos, , , win, ctrl, 2
		If (win = Menu.View && ctrl && ctrl != Menu.PrCtrl)
		{
			obj := Menu.oMenu[win]
			Menu.Color(obj.bcgColor, obj.Items[Menu.Selection].back)
			Menu.Selection := ctrl
			Menu.Color(obj.hiColor, obj.Items[Menu.Selection].back)
			Menu.PrCtrl := ctrl
		}
		GuiHwnd := Menu.View
		Try Gui, %GuiHwnd%:+AlwaysOnTop
    }
	SetHotkeys() {
		#If Menu.View
		#If Menu.View && Menu.Selection
		#If
		Hotkey, IF, Menu.View
		hFunc := ObjBindMethod(this, "MouseIsUnderMenu")
		Hotkey, ~LButton, % hFunc
		Hotkey, ~RButton, % hFunc
		Hotkey, ~MButton, % hFunc
		hFunc := ObjBindMethod(this, "Up_Down")
		Hotkey, WheelUp, % hFunc
		Hotkey, WheelDown, % hFunc
		Hotkey, Up, % hFunc
		Hotkey, Down, % hFunc
		hFunc := ObjBindMethod(this, "Hide")
		Hotkey, Escape, % hFunc
		Hotkey, IF, Menu.View && Menu.Selection
		hFunc := ObjBindMethod(this, "Select")
		Hotkey, Space, % hFunc
		Hotkey, Enter, % hFunc
		Hotkey, IF
    }
	MouseIsUnderMenu() {
		MouseGetPos, , , win
		If (win != Menu.View)
			Menu.Hide()
    }
	Up_Down() {
		obj := Menu.oMenu[Menu.View]
		mi := obj.List.MaxIndex()
		sel := obj.Items[Menu.Selection].key
		new := InStr(A_ThisHotkey, "Up")
		? (!sel || sel = 1 ? mi : sel - 1)
		: (!sel || sel = mi ? 1 : sel + 1)
		Menu.Color(obj.bcgColor, obj.Items[Menu.Selection].back)

		Menu.Selection := obj.ItemPos[new].text
		Menu.Color(obj.hiColor, obj.ItemPos[new].back)
		Menu.PrCtrl := 0
		DllCall("GetCursorPos", "int64P", pt), Menu.WaitX := pt << 32 >> 32, Menu.WaitY := pt >> 32
    }
	Color(color, hwndback)  {
		GuiControl, +Background%color%, %hwndback%
		GuiControl, +Redraw, %hwndback%
		GuiControl, +Redraw, % Menu.Selection
		
		;;;/////////////////
		MenuSelectedItemLabel := Menu.oMenu[Menu.View].Items[Menu.Selection].label	
	}
	WM_LBUTTONUP(w, l, m, h)  {
		Menu.Select(h)
	}
	GetClientSize(hwnd, ByRef W, ByRef H)  {
		VarSetCapacity(pwi, 60, 0), NumPut(60, pwi, 0, "UInt")
		DllCall("GetWindowInfo", "Ptr", hwnd, "UInt", &pwi)
		W := NumGet(pwi, 28, "Int") - NumGet(pwi, 20, "Int")
		H := NumGet(pwi, 32, "Int") - NumGet(pwi, 24, "Int")
	}
	CalculatePopupWindowPosition(byref left, byref top, w, h, x, y, offsetx = 0, offsety = 0)  {
		VarSetCapacity(POINT, 8, 0), VarSetCapacity(structs, 24, 0)
		NumPut(x, POINT, 0, "int"), NumPut(y, POINT, 4, "int")
		NumPut(w + offsetx, structs, 0, "int"), NumPut(h + offsety, structs, 4, "int")
		If !DllCall("CalculatePopupWindowPosition"
			, "ptr", &POINT
			, "ptr", &structs
			, "int", 0
			, "ptr", 0
			, "ptr", &structs + 8)
			Return 0
		if (ShowMenuInTheCenter = 1) {
			left := (A_ScreenWidth - w) // 2
			top := (A_ScreenHeight - h) // 2
		}
		else {
			left := NumGet(structs, 8, "int") + offsetx
			top := NumGet(structs, 12, "int") + offsety
		}
		Return 1
	}
}

UPDATE: Изменил код для появления меню в центре экрана.

20

Re: AHK: Пользовательское контекстное меню

mafckz, Спасибо! Подпишите, пожалуйста, строку, где изменяется положение места появления меню. Т.к. мне сейчас наиболее подходит вариант появления рядом с курсором.

21 (изменено: Malcev, 2016-04-20 15:14:25)

Re: AHK: Пользовательское контекстное меню

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

Не знаю на счёт IfWinExist, думаю тут правильнее IsWindowVisible. Ну и если уже неактивное окно нашли, то скорее всего ControlSend.

Может так и правильней, но у меня так, вроде, работает, кроме повторяющегося глюка при первом вызове меню, который я написал в 16 посту.
PS Подправил, чтоб работало на отжатие.

ScriptManage := {}                       ; создаём объект для управления скриптами
ScriptManage.Run := Func("RunScript")    ; создаём несколько методов
ScriptManage.Terminate := Func("TerminateScript")
OnExit, OnExit
ScriptManage.Run(1)

Menu, MyMenu, Add, Мой компьютер, 1
Menu, MyMenu, Add, Программы, 2
Menu, MyMenu, Add, Рабочий стол, 3
Menu, MyMenu, Add,  Мои документы, 4 
Return


F1:: Menu, MyMenu, Show

1:
	Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
	Return
2:
	Run, %A_ProgramFiles%
	Return
3:
	Run, %A_Desktop%
	Return
4:
	Run, %A_MyDocuments%
	Return


OnExit:
   for k, v in ScriptManage
      if k is integer
         ScriptManage.Terminate(k)
   ExitApp



RunScript(this, n)   ; здесь this — вызывающий объект, n — номер скрипта, который будем запускать
{
   ;*********************** это текст скрипта, который будем запускать ************************
   Text1 =  
   (
      #NoTrayIcon
      SetKeyDelay, 0, 10
      loop
      {
         KeyWait, f1, D
         ControlSend,, {Down}, ahk_class #32768
         KeyWait, f1
         ControlSend,, {Enter}, ahk_class #32768
      }
      #if GetKeyState("f1", "P")
      WheelDown::
      ControlSend,, {Down}, ahk_class #32768
      return
      WheelUp::
      ControlSend,, {Up}, ahk_class #32768
      return
      Esc::return
      Enter::return
      NumpadEnter::return
      LButton::return
      RButton::return
      #If
   )
   ;******************************** ; конец текста скрипта ***********************************
   
   FilePath := A_Temp "\_MyScript_" A_TickCount ".ahk"
   FileAppend, % Text%n%, % FilePath
   Run, % FilePath,,, PID
   DetectHiddenWindows, On
   WinWait, % "ahk_pid" PID
   FileDelete, % FilePath
   this[n] := {PID: PID}  ; сохраняем PID дочернего скрипта в соответствующем ключе вызывающего объекта
}

TerminateScript(this, n)
{
   Process, Close, % this[n].PID
}

22

Re: AHK: Пользовательское контекстное меню

becauseim пишет:

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

Надо будет ещё подумать.

becauseim пишет:

изменить размеры и цвета интерфейса, в т.ч. величину шрифта и отступы.

Так они же указываются при создании меню:

New Menu(List2, "5976C5", "2EC001", "FFFFFF", , 24)

Из этого должно быть понятно где какой параметр:

__New(List, bcgColor, hiColor, textColor, Transparent = 255, FontSize = 0)

При показе можно указатьсвои координаты:

Menu1.Show(111, 222)
becauseim пишет:

И еще у меня так и не получилось добавить запуск выбранного пункта при отжатии горячей клавиши.

В новой редекции добавил.


+1::
	Menu1.Show()
	KeyWait, 1
	Menu1.Hide()
	Try GoSub, % Menu.Label
	Return
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

23 (изменено: serzh82saratov, 2016-04-20 19:11:23)

Re: AHK: Пользовательское контекстное меню

Насколько я понял, вариант с классическим контекстным меню отпадает

Вроде ответ найден:


#SingleInstance Force
#NoEnv
DetectHiddenWindows, On

Menu, MyMenu, Add, Мой компьютер, g1
Menu, MyMenu, Add, Программы, g2
Menu, MyMenu, Add, Рабочий стол, g3
Menu, MyMenu, Add,  Мои документы, g4  
hMyMenu := MenuGetHandle("MyMenu")
PID := DllCall("GetCurrentProcessId")
OnMessage(0x211, "WM_ENTERMENULOOP")
Return

#If WinExist("ahk_class #32768 ahk_pid" PID)
WheelDown::ControlSend, ahk_parent, {Down}
WheelUp::ControlSend, ahk_parent, {Up}
#If

1:: Menu_Show(hMyMenu)
1 Up:: 
	ControlSend, ahk_parent, {Enter}, % "ahk_id" WinExist("ahk_class #32768 ahk_pid" PID)
	Menu_Hide()  
	Return

g1:
	Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
	Return
g2:
	Run, %A_ProgramFiles%
	Return
g3:
	Run, %A_Desktop%
	Return
g4:
	Run, %A_MyDocuments%
	Return
	
WM_ENTERMENULOOP() {
	Return 1
}

Menu_Show(hMenu, mX="", mY="", Flags=0x0) {
	DllCall("GetCursorPos", "int64P", pt)
	mX := (mX = "") ? pt << 32 >> 32 : mX
	mY := (mY = "") ? pt >> 32 : mY
	DllCall("SetForegroundWindow", Ptr, A_ScriptHwnd) 
	DllCall("TrackPopupMenu", Ptr, hMenu, UInt, Flags  
	   , Int, mX, Int, mY, UInt, 0, Ptr, A_ScriptHwnd, UInt, 0)
	PostMessage, 0,0,0,, ahk_id %A_ScriptHwnd%
}

Menu_Hide() { 
	SendMessage, 0x1F,,,, ahk_id %A_ScriptHwnd%
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

24 (изменено: serzh82saratov, 2016-04-21 02:31:18)

Re: AHK: Пользовательское контекстное меню

Menu_Hide можно заменить на ControlSend. В этом варианте окно не деактивируется, но и меню не пропадает при клике не по нему, хотя это не особо требуется в варианте с исчезновением при отпускании клавиши:


#SingleInstance Force
#NoEnv
DetectHiddenWindows, On
OnMessage(0x211, "WM_ENTERMENULOOP") 
PID := DllCall("GetCurrentProcessId")

Menu, MyMenu, Add, Мой компьютер, g1
Menu, MyMenu, Add, Программы, g2
Menu, MyMenu, Add, Рабочий стол, g3
Menu, MyMenu, Add,  Мои документы, g4  
hMyMenu := MenuGetHandle("MyMenu")
Return

#If WinExist("ahk_class #32768 ahk_pid" PID)
Up::
WheelUp::ControlSend, ahk_parent, {Up}
Down::
WheelDown::ControlSend, ahk_parent, {Down}
#If

1:: Menu_Show(hMyMenu)  
1 Up:: ControlSend, ahk_parent, {Enter}, % "ahk_id" WinExist("ahk_class #32768 ahk_pid" PID)
2::ControlSend, ahk_parent, {Esc}, % "ahk_id" WinExist("ahk_class #32768 ahk_pid" PID)   ; Menu Hide 

g1:
	Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
	Return
g2:
	Run, %A_ProgramFiles%
	Return
g3:
	Run, %A_Desktop%
	Return
g4:
	Run, %A_MyDocuments%
	Return
	
WM_ENTERMENULOOP() {
	Return 1
}

Menu_Show(hMenu, mX = "", mY = "", Flags = 0x0) {
	DllCall("GetCursorPos", "int64P", pt)
	mX := (mX = "") ? pt << 32 >> 32 : mX
	mY := (mY = "") ? pt >> 32 : mY
	; DllCall("SetForegroundWindow", Ptr, A_ScriptHwnd)
	DllCall("TrackPopupMenu", Ptr, hMenu, UInt, Flags  
	   , Int, mX, Int, mY, UInt, 0, Ptr, A_ScriptHwnd, UInt, 0)
	; PostMessage, 0, 0, 0, , ahk_id %A_ScriptHwnd%
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

25

Re: AHK: Пользовательское контекстное меню

serzh82saratov, Call to nonexistent function.

hMyMenu := MenuGetHandle("MyMenu")

26

Re: AHK: Пользовательское контекстное меню

К варианту из 19-го поста, при изменении параметра величины шрифта, величина отступа остается неизменной. Мне бы хотелось сделать минимальные отступы. Как это можно сделать? Также у меня не получилось вернуть появление меню к положению курсора.

27

Re: AHK: Пользовательское контекстное меню

becauseim пишет:

serzh82saratov, Call to nonexistent function.

hMyMenu := MenuGetHandle("MyMenu")

Обновите АНК.

becauseim пишет:

К варианту из 19-го поста, при изменении параметра величины шрифта, величина отступа остается неизменной. Мне бы хотелось сделать минимальные отступы. Как это можно сделать? Также у меня не получилось вернуть появление меню к положению курсора.

Не знаю, мой код в 15 посте, в нём меню появляется у курсора. Отступ задаётся в переменной Margin, которая находится в начале класса. Пропишите в ней нужное количество пробелов, или удалите все:

Margin := ""

для минимальных отступов.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

28

Re: AHK: Пользовательское контекстное меню

serzh82saratov пишет:

мой код в 15 посте

Кажется, в него не включена навигация скроллом.

Отступ задаётся в переменной Margin

В таком случае, также необходима возможность настройки величины межстрочного интервала. Мне нравится вариант, реализованный здесь.

29

Re: AHK: Пользовательское контекстное меню

Только сейчас заметил что при первом показе меню из 24 поста, меню не скрывается. Сразу я этого не видел так как скрипты из блокнота запускаются другим скриптом. То есть если запустить из проводника, то при первом показе глюк есть, а если запустить скрипт другим скриптом то глюка нет, и работает как часики. Непонятно отношение метода запуска к работоспобности данного кода.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

30

Re: AHK: Пользовательское контекстное меню

becauseim пишет:

Кажется, в него не включена навигация скроллом.

У меня колесиком пункты меняются.

becauseim пишет:

В таком случае, также необходима возможность настройки величины межстрочного интервала.

Gui, Add, Progress, % (k = 1 ? "x0 y0" : "y+0") " hwndhBack w" maxW " h" maxH * 2 " Background" bcgColor, 0

Тут maxH * 2, это высота строки равна двум размерам текста. Замените например на maxH + 2 для малой высоты строки.

becauseim пишет:

Мне нравится вариант, реализованный здесь.

На HTML не охота писать, хочу повторить тоже самое на АНК.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

31

Re: AHK: Пользовательское контекстное меню

Вообщем ничего не понимаю, но у меня скрипт работает "с первого раза", только если запустить его программно.


#SingleInstance Force
#NoEnv

cmd = %1%
If (cmd != "Start")
{
	Run, "%A_ScriptFullPath%" "Start", %A_ScriptDir%
	ExitApp
}

DetectHiddenWindows, On
OnMessage(0x211, "WM_ENTERMENULOOP")
PID := DllCall("GetCurrentProcessId")

Menu, MyMenu, Add, Мой компьютер, g1
Menu, MyMenu, Add, Программы, g2
Menu, MyMenu, Add, Рабочий стол, g3
Menu, MyMenu, Add,  Мои документы, g4  
hMyMenu := MenuGetHandle("MyMenu")
Return

#If WinExist("ahk_class #32768 ahk_pid" PID)
Up::
WheelUp::ControlSend, ahk_parent, {Up}
Down::
WheelDown::ControlSend, ahk_parent, {Down}
#If

1:: 
	Menu_Show(hMyMenu)
	KeyWait, 1
	Return
	
1 Up:: 
	ControlSend, ahk_parent, {Enter}, % "ahk_id" WinExist("ahk_class #32768 ahk_pid" PID)
	Menu_Hide()
	Return

g1:
	Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
	Return
g2:
	Run, %A_ProgramFiles%
	Return
g3:
	Run, %A_Desktop%
	Return
g4:
	Run, %A_MyDocuments%
	Return
	
WM_ENTERMENULOOP() {
	Return 1
}

Menu_Show(hMenu, mX="", mY="", Flags=0x0) {
	DllCall("GetCursorPos", "int64P", pt)
	mX := (mX = "") ? pt << 32 >> 32 : mX
	mY := (mY = "") ? pt >> 32 : mY
	; DllCall("SetForegroundWindow", Ptr, A_ScriptHwnd) 
	DllCall("TrackPopupMenu", Ptr, hMenu, UInt, Flags  
	   , Int, mX, Int, mY, UInt, 0, Ptr, A_ScriptHwnd, UInt, 0) 
	; PostMessage, 0,0,0,, ahk_id %A_ScriptHwnd% 
}

Menu_Hide() { 
	SendMessage, 0x1F,,,, ahk_id %A_ScriptHwnd%
} 
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

32 (изменено: serzh82saratov, 2016-04-21 04:22:37)

Re: AHK: Пользовательское контекстное меню

В таком случае, также необходима возможность настройки величины межстрочного интервала.

Добавил YMargin в новую редакцию.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

33 (изменено: Malcev, 2016-04-21 13:10:21)

Re: AHK: Пользовательское контекстное меню

У меня код из 31 поста все-равно не всегда срабатывает.
Наверное баг какой-то.

34

Re: AHK: Пользовательское контекстное меню

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

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

35

Re: AHK: Пользовательское контекстное меню

becauseim

Для появления меню возле курсора, нужно в данной строке, поменять значение 1 на 0.

global ShowMenuInTheCenter := 1

36 (изменено: serzh82saratov, 2016-04-22 17:49:44)

Re: AHK: Пользовательское контекстное меню

XMargin и YMargin можно задать отдельно для каждого меню как 7 и 8 параметры.
XMargin задаётся числом пробелов слева и справа от строки, YMargin в процентах к высоте текста. По умолчанию XMargin = 1, YMargin = 1. Ещё небольшие изменения.


#SingleInstance Force
#NoEnv

List1 := [["Мой компьютер","1"],["Программы","2"],["Рабочий стол","3"],["Мои документы","4"]]
List2 := [["Папка скрипта","OpenDir"],["Редактировать","Edit"],["Как определить имя пункта","Check_name"]]

Menu1 := New Menu(List1, "FFFFFF", "DBDBDB", "2842A0", 210)
Menu2 := New Menu(List2, "5976C5", "2EC001", "FFFFFF", , 22)

Escape:: ExitApp

+1::
	Menu1.Show()
	KeyWait, 1
	Menu1.Hide(1)
	Return

+2::Menu2.Show()

OpenDir:
	Run %A_ScriptDir%
	Return
Edit:
	Run, Edit %A_ScriptFullPath%
	Return
Check_name:
	MsgBox % Menu.Name
	Return
1:
	Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
	Return
2:
	Run, %A_ProgramFiles%
	Return
3:
	Run, %A_Desktop%
	Return
4:
	Run, %A_MyDocuments%
	Return






Class Menu {
	Static View, Selection, AllReady, Obj, PrCtrl, WaitX, WaitY, Name, Label
	__New(List, bcgColor, hiColor, textColor, Transparent = 255, FontSize = 0, XMargin = 1, YMargin = 1) {
		If !Menu.AllReady
			Menu.SetHotkeys(), OnMessage(0x202, this["WM_LBUTTONUP"].Bind(this)), Menu.AllReady := 1
		Gui, New
		Gui, +AlwaysOnTop -DPIScale +hwndhGui +LabelMenuOn -Caption +Border +Owner +E0x08000000
		this.hwnd := hGui, this.List := List
		this.bcgColor := bcgColor, this.hiColor := hiColor, this.textColor := textColor
		Gui, Font, % "q1" . (FontSize ? " s" FontSize : "")
		Gui, Margin, 0, 0
		Gui, Color, %bcgColor%
		If (Transparent < 255)
		{
			S_DetectHiddenWindows := A_DetectHiddenWindows
			DetectHiddenWindows, On
			WinSet, Transparent, %Transparent%, ahk_id %hGui%
			DetectHiddenWindows, %S_DetectHiddenWindows%
		}
		S_AutoTrim := A_AutoTrim
		AutoTrim, Off
		Loop % XMargin
			XMarginStr .= " "
		AutoTrim, %S_AutoTrim%
		For k, v in List
		{
			Gui, Add, Text, hwndhDummy hidden, % XMarginStr v[1] XMarginStr
			GuiControlGet, Pos, Pos, %hDummy%
			maxW := !maxW || PosW > maxW ? PosW : maxW
			maxH := !maxH || PosH > maxH ? PosH : maxH
			DllCall("DestroyWindow", "Ptr", hDummy)
		}
		Gui, Show, Hide w0 h0
		For k, v in List
		{
			Gui, Add, Progress, % (k = 1 ? "x0 y0" : "y+0") " hwndhBack w" maxW " h" maxH + (maxH / 100 * YMargin) " Background" bcgColor, 0
			Gui, Add, Text, % "xp yp wp hp hwndhText +0x200 BackgroundTrans c" textColor, % XMarginStr v[1] XMarginStr
			this.Items[hText] := {back:hBack,key:k,Label:v[2],name:v[1]}
			this.Items[hBack] := {text:hText,key:k,Label:v[2],name:v[1]}
			this.ItemPos[k] := {text:hText,back:hBack}
		}
		Gui, Show, Hide AutoSize, #32768
		Return this
	}
	Show(x = "", y = "") {
		Menu.Hide()
		If (x = "" || y = "")
			DllCall("GetCursorPos", "int64P", pt), x := pt << 32 >> 32, y := pt >> 32
		Hwnd := Menu.View := this.hwnd
		Menu.Name := Menu.Label := Menu.PrCtrl := ""
		Menu.GetClientSize(Hwnd, w, h)
		Menu.CalculatePopupWindowPosition(sx, sy, w, h, x, y, 4, 4)
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, 50
		Menu.Obj := this
		Gui, %Hwnd%:Show, NA x%sx% y%sy%
	}
	Hide(Select = 0) {
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, Off
		Hwnd := Menu.View
		this := Menu.Obj
		Menu.Color(this.bcgColor, this.Items[Menu.Selection].back)
		Menu.View := Menu.Selection := 0, Menu.WaitX := Menu.WaitY := Menu.Obj := ""
		Try Gui, %Hwnd%:Show, Hide
		If Select
			Try GoSub, % Menu.Label
	}
	Select(hwnd = "") {
		hwnd := !hwnd ? Menu.Selection : hwnd
		Try SetTimer, % Menu.Label, -1
		Menu.Hide()
	}
	MouseGet() {
		MouseGetPos, , , win, ctrl, 2
		If (Menu.WaitX != "")
		{
			If (win != Menu.View)
				Return
			DllCall("GetCursorPos", "int64P", pt), X := pt << 32 >> 32, Y := pt >> 32
			If (Abs(X - Menu.WaitX) > 1 || Abs(Y - Menu.WaitY) > 1)
				Menu.WaitX := Menu.WaitY := ""
			Else
				Return
		}
		If (win = Menu.View)
		{
			If (ctrl && ctrl != Menu.PrCtrl)
			{
				this := Menu.Obj
				Menu.Color(this.bcgColor, this.Items[Menu.Selection].back)
				Menu.Selection := ctrl
				Menu.Color(this.hiColor, this.Items[Menu.Selection].back)
				Menu.Label := this.Items[ctrl].Label
				Menu.Name := this.Items[ctrl].Name
				Menu.PrCtrl := ctrl
			}
		}
		Else If Menu.Selection
		{
			this := Menu.Obj
			Menu.Color(this.bcgColor, this.Items[Menu.Selection].back)
			Menu.Name := Menu.Label := Menu.PrCtrl := Menu.Selection := ""
		}
		Hwnd := Menu.View
		Try Gui, %Hwnd%:+AlwaysOnTop
    }
	Up_Down() {
		this := Menu.Obj
		mi := this.List.MaxIndex()
		sel := this.Items[Menu.Selection].key
		new := InStr(A_ThisHotkey, "Up")
		? (!sel || sel = 1 ? mi : sel - 1)
		: (!sel || sel = mi ? 1 : sel + 1)
		Menu.Color(this.bcgColor, this.Items[Menu.Selection].back)
		Menu.Selection := this.ItemPos[new].text
		Menu.Color(this.hiColor, this.ItemPos[new].back)
		Menu.Label := this.Items[Menu.Selection].Label
		Menu.Name := this.Items[Menu.Selection].Name
		Menu.PrCtrl := 0
		DllCall("GetCursorPos", "int64P", pt), Menu.WaitX := pt << 32 >> 32, Menu.WaitY := pt >> 32
    }
	SetHotkeys() {
		#If Menu.View
		#If Menu.View && Menu.Selection
		#If
		Hotkey, IF, Menu.View
		hFunc := ObjBindMethod(this, "MouseIsUnderMenu")
		Hotkey, ~*LButton, % hFunc
		Hotkey, ~*RButton, % hFunc
		Hotkey, ~*MButton, % hFunc
		hFunc := ObjBindMethod(this, "Up_Down")
		Hotkey, *WheelUp, % hFunc
		Hotkey, *WheelDown, % hFunc
		Hotkey, *Up, % hFunc
		Hotkey, *Down, % hFunc
		hFunc := ObjBindMethod(this, "Hide")
		Hotkey, Escape, % hFunc
		Hotkey, *LAlt, % hFunc
		Hotkey, *LWin, % hFunc
		Hotkey, IF, Menu.View && Menu.Selection
		hFunc := ObjBindMethod(this, "Select")
		Hotkey, Space, % hFunc
		Hotkey, Enter, % hFunc
		Hotkey, IF
    }
	MouseIsUnderMenu() {
		MouseGetPos, , , win
		If (win != Menu.View)
			Menu.Hide()
    }
	Color(color, hwndback)  {
		GuiControl, +Background%color%, %hwndback%
		GuiControl, +Redraw, %hwndback%
		GuiControl, +Redraw, % Menu.Selection
	}
	WM_LBUTTONUP(w, l, m, h)  {
		If (A_Gui = Menu.View)
			Menu.Select(h)
	}
	GetClientSize(hwnd, ByRef W, ByRef H)  {
		VarSetCapacity(pwi, 60, 0), NumPut(60, pwi, 0, "UInt")
		DllCall("GetWindowInfo", "Ptr", hwnd, "UInt", &pwi)
		W := NumGet(pwi, 28, "Int") - NumGet(pwi, 20, "Int")
		H := NumGet(pwi, 32, "Int") - NumGet(pwi, 24, "Int")
	}
	CalculatePopupWindowPosition(byref left, byref top, w, h, x, y, offsetx = 0, offsety = 0)  {
		VarSetCapacity(POINT, 8, 0), VarSetCapacity(structs, 24, 0)
		NumPut(x, POINT, 0, "int"), NumPut(y, POINT, 4, "int")
		NumPut(w + offsetx, structs, 0, "int"), NumPut(h + offsety, structs, 4, "int")
		If !DllCall("CalculatePopupWindowPosition"
			, "ptr", &POINT
			, "ptr", &structs
			, "int", 0
			, "ptr", 0
			, "ptr", &structs + 8)
			Return 0
		left  := NumGet(structs, 8, "int") + offsetx
		top := NumGet(structs, 12, "int") + offsety
		Return 1
	}
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

37

Re: AHK: Пользовательское контекстное меню

serzh82saratov, в данном случае меню выглядит так, как мне хотелось. Осталось только подобрать цвета. Спасибо!
Добавьте, пожалуйста, к последнему сценарию позиционирование прокручиванием, а также выбор выделенного пункта при отжатии горячей клавиши.

38 (изменено: serzh82saratov, 2016-04-22 17:49:21)

Re: AHK: Пользовательское контекстное меню

Добавьте, пожалуйста, к последнему сценарию позиционирование прокручиванием

Колёсико мыши должно работать уже с первой версии.

выбор выделенного пункта при отжатии горячей клавиши.

Так я уже вам в 22 посте отвечал:

+1::
	Menu1.Show()
	KeyWait, 1
	Menu1.Hide()
	Try GoSub, % Menu.Label
	Return

Немного изменил, если в Hide() указать 1, то будет переход по метке.

+1::
	Menu1.Show()
	KeyWait, 1
	Menu1.Hide(1)
	Return
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

39 (изменено: Malcev, 2016-04-22 22:44:30)

Re: AHK: Пользовательское контекстное меню

Вообщем ничего не понимаю, но у меня скрипт работает "с первого раза", только если запустить его программно.

У меня так работает. Наверное баг. Написал им на оффорум.

DetectHiddenWindows, on
WinActivate, ahk_class AutoHotkey
Menu, MyMenu, Add, Desktop, 1
Menu, MyMenu, Add, Programs, 2
Return
 
F1:: Menu, MyMenu, Show
 
1:
Run, %A_Desktop%
Return
 
2:
Run, %A_ProgramFiles%
Return

40

Re: AHK: Пользовательское контекстное меню

serzh82saratov, А можно ли в последнем варианте изменить цвет обводки меню (или убрать вообще)?
А также, можно ли добавить вложенное меню?

41

Re: AHK: Пользовательское контекстное меню

becauseim пишет:

изменить цвет обводки меню

Нет.

becauseim пишет:

или убрать вообще

В строке

Gui, +AlwaysOnTop -DPIScale +hwndhGui +LabelMenuOn -Caption +Border +Owner +E0x08000000

удалить  +Border.

becauseim пишет:

А также, можно ли добавить вложенное меню?

Это уже сложно.

Malcev пишет:

У меня так работает. Наверное баг.

Так а в чём баг? На первый взгляд в данном случае стандартное поведение.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

42 (изменено: Malcev, 2016-04-23 02:10:55)

Re: AHK: Пользовательское контекстное меню

Баг в том, что судя по хелпу, клавиши - "вверх-вниз" должны срабатывать сразу после комманды:

F1:: Menu, MyMenu, Show

Show [, X, Y]: Displays MenuName, allowing the user to select an item with arrow keys, menu shortcuts (underlined letters), or the mouse

Но без активирования окна при старте они не срабатывают.
То есть, так работают:

DetectHiddenWindows, on
WinActivate, ahk_class AutoHotkey
Menu, MyMenu, Add, Desktop, 1
Menu, MyMenu, Add, Programs, 2
Return
 
F1:: Menu, MyMenu, Show
 
1:
Run, %A_Desktop%
Return
 
2:
Run, %A_ProgramFiles%
Return

А так нет:

Menu, MyMenu, Add, Desktop, 1
Menu, MyMenu, Add, Programs, 2
Return
 
F1:: Menu, MyMenu, Show
 
1:
Run, %A_Desktop%
Return
 
2:
Run, %A_ProgramFiles%
Return

43 (изменено: serzh82saratov, 2016-04-23 02:31:25)

Re: AHK: Пользовательское контекстное меню

А, я потому не понял, что у меня никакой из вариантов не работает с первого раза, а со второго раза работают оба варианта (то есть без разницы). То есть всё также как и в 31 посте например.

WinActivate, ahk_class AutoHotkey

Судя по Remarks к TrackPopupMenu, это должно влиять только на то чтобы клик мышью вне меню скрывал его.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

44 (изменено: Malcev, 2016-04-23 06:07:29)

Re: AHK: Пользовательское контекстное меню

А так?

DetectHiddenWindows, on
SetTitleMatchMode 2
Menu, MyMenu, Add, Desktop, 1
Menu, MyMenu, Add, Programs, 2
Return
 
F1:: 
WinActivate, %A_ScriptName%
Menu, MyMenu, Show
return
 
1:
Run, %A_Desktop%
Return
 
2:
Run, %A_ProgramFiles%
Return

Кстати, по твоей ссылке пишут:

Using shortkeys with TrackPopupMenu
If you are using shortkeys in your popup menu e.g. &About, E&xit then make sure SetForegroundWindow() is called before TrackPopupMenu().
Otherwise when the popup menu is activated pressing the shortkeys (A or x) will have no impact / not work.

45 (изменено: serzh82saratov, 2016-04-23 06:19:48)

Re: AHK: Пользовательское контекстное меню

Всё  также, только со второго раза стрелки работают.
В 31 посте у меня код работает в 100% случаев, а у тебя нет. Непонятно почему по разному, ещё более загадочно какой эффект, у меня, даёт запуск не из проводника...

SetForegroundWindow (это тоже самое что и WinActivate, %A_ScriptName%) не даёт пользы в вопросе со стрелками, оно у меня там кстати закомментировано.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

46

Re: AHK: Пользовательское контекстное меню

Помогите, пожалуйста, установить вызов меню при условии, что была совершениа прокрутка на один шаг (WheelDown) во время удержания ПКМ, а при простом удержании ПКМ без прокрутки выполнялось иное действие. Так происходит вызов меню при удержании ПКМ:

RButton::
   mod =
   SetTimer, RButtonTimer, -150
   KeyWait, RButton
   SetTimer, RButtonTimer, Off
   if !mod
      Send, {RButton}
   Return

RButtonTimer:
   mod = 1
	Menu1.Show()
	KeyWait, RButton
	Menu1.Hide()
	Try GoSub, % Menu.Label
	Return

47

Re: AHK: Пользовательское контекстное меню


#If (mod = "")
WheelDown::WheelDownCounter++
#If

RButton::
   mod =
   WheelDownCounter := 0
   SetTimer, RButtonTimer, -150
   KeyWait, RButton
   SetTimer, RButtonTimer, Off
   if !mod
      Send, {RButton}
   Return

RButtonTimer:
	mod = 1
	if (WheelDownCounter = 1)
	{
		Menu1.Show()
		KeyWait, RButton
		Menu1.Hide()
		Try GoSub, % Menu.Label
	}
	Else 	
		MsgBox иное действие
	Return

А вы не супергерой? Обычному человеку нажать RButton и двинуть WheelDown ровно на один шаг за 150 мс, та ещё задача.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

48

Re: AHK: Пользовательское контекстное меню

serzh82saratov, наверное, Вы неправильно поняли. После зажатия ПКМ на 150 мсек выполняется одно действие. В моем случае это:

Send {vk43}

А если следом выполняется прогрутка, то появляется альтернативное контекстное меню с последующим позиционированием прокруткой.

49

Re: AHK: Пользовательское контекстное меню

Так а как же тут поймешь, если приводите код в котором этого нет, а есть то что я понял.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

50

Re: AHK: Пользовательское контекстное меню

Вообщем и сейчас не ясно чего вы хотите добится.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

51

Re: AHK: Пользовательское контекстное меню

serzh82saratov, Ваш вариант работает верно, кроме одного положения: меню появляется только в том случае, если я успел прокрутить вниз в течение 150 мсек после отправления иного действия. По задумке, этот таймер касается только времени, в течение которого необходимо удерживать ПКМ для вызова иного действия.

52

Re: AHK: Пользовательское контекстное меню

при условии, что была совершениа прокрутка на один шаг (WheelDown) во время удержания ПКМ


Тогда или сразу после движения WheelDown:


#If (mod = "")
WheelDown::WheelDownCounter++
#If

$RButton::
	mod =
	WheelDownCounter := 0
	SetTimer, RButtonTimer, -150
	While (GetKeyState("RButton", "P") && !WheelDownCounter)
		Sleep 10
	if (WheelDownCounter && (mod := 1)) 
	{
		Menu1.Show() 
		KeyWait, RButton 
		Menu1.Hide(1)
	}
	if !mod
		Send, {RButton} 
	Return 

RButtonTimer:
	MsgBox, , , иное действие, 0.1
	Return

Или при отпускании RButton меню не скрыть:

#If (mod = "")
WheelDown::WheelDownCounter++
#If

$RButton::
	mod =
	WheelDownCounter := 0
	SetTimer, RButtonTimer, -150
	KeyWait, RButton 
	if (WheelDownCounter = 1 && (mod := 1)) 
		Menu1.Show() 
	if !mod
		Send, {RButton} 
	Return 

RButtonTimer:
	MsgBox, , , иное действие, 0.1
	Return
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

53 (изменено: serzh82saratov, 2016-04-24 00:49:38)

Re: AHK: Пользовательское контекстное меню

Добавил в координаты показа слово "Center".
Показывает в середине по горизонтали, и 100 сверху:

Menu2.Show("Center", 100)

Ровно посередине:

Menu2.Show("Center", "Center")


#SingleInstance Force
#NoEnv

List1 := [["Мой компьютер","1"],["Программы","2"],["Рабочий стол","3"],["Мои документы","4"]]
List2 := [["Папка скрипта","OpenDir"],["Редактировать","Edit"],["Как определить имя пункта","Check_name"]]

Menu1 := New Menu(List1, "FFFFFF", "DBDBDB", "2842A0", 210, 10)
Menu2 := New Menu(List2, "5976C5", "2EC001", "FFFFFF", , 22)

Escape:: ExitApp

	
+1::
	Menu1.Show()
	KeyWait, 1
	Menu1.Hide(1)
	Return

+2::Menu2.Show("Center", 100)

OpenDir:
	Run %A_ScriptDir%
	Return
Edit:
	Run, Edit %A_ScriptFullPath%
	Return
Check_name:
	MsgBox % Menu.Name
	Return
1:
	Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
	Return
2:
	Run, %A_ProgramFiles%
	Return
3:
	Run, %A_Desktop%
	Return
4:
	Run, %A_MyDocuments%
	Return






Class Menu {
	Static View, Selection, AllReady, Obj, PrCtrl, WaitX, WaitY, Name, Label
	__New(List, bcgColor, hiColor, textColor, Transparent = 255, FontSize = 0, XMargin = 1, YMargin = 1) {
		If !Menu.AllReady
			Menu.SetHotkeys(), OnMessage(0x202, this["WM_LBUTTONUP"].Bind(this)), Menu.AllReady := 1
		Gui, New
		Gui, +AlwaysOnTop -DPIScale +hwndhGui +LabelMenuOn -Caption +Border +Owner +E0x08000000
		this.hwnd := hGui, this.List := List
		this.bcgColor := bcgColor, this.hiColor := hiColor, this.textColor := textColor
		Gui, Font, % "q1" . (FontSize ? " s" FontSize : "")
		Gui, Margin, 0, 0
		Gui, Color, %bcgColor%
		If (Transparent < 255)
		{
			S_DetectHiddenWindows := A_DetectHiddenWindows
			DetectHiddenWindows, On
			WinSet, Transparent, %Transparent%, ahk_id %hGui%
			DetectHiddenWindows, %S_DetectHiddenWindows%
		}
		S_AutoTrim := A_AutoTrim
		AutoTrim, Off
		Loop % XMargin
			XMarginStr .= " "
		AutoTrim, %S_AutoTrim%
		For k, v in List
		{
			Gui, Add, Text, hwndhDummy hidden, % XMarginStr v[1] XMarginStr
			GuiControlGet, Pos, Pos, %hDummy%
			maxW := !maxW || PosW > maxW ? PosW : maxW
			maxH := !maxH || PosH > maxH ? PosH : maxH
			DllCall("DestroyWindow", "Ptr", hDummy)
		}
		Gui, Show, Hide w0 h0
		For k, v in List
		{
			Gui, Add, Progress, % (k = 1 ? "x0 y0" : "y+0") " hwndhBack w" maxW " h" maxH + (maxH / 100 * YMargin) " Background" bcgColor, 0
			Gui, Add, Text, % "xp yp wp hp hwndhText +0x200 BackgroundTrans c" textColor, % XMarginStr v[1] XMarginStr
			this.Items[hText] := {back:hBack,key:k,Label:v[2],name:v[1]}
			this.Items[hBack] := {text:hText,key:k,Label:v[2],name:v[1]}
			this.ItemPos[k] := {text:hText,back:hBack}
		}
		Gui, Show, Hide AutoSize, #32768
		Return this
	}
	Show(x = "", y = "") {
		Menu.Hide()
		Hwnd := Menu.View := this.hwnd
		Menu.Name := Menu.Label := Menu.PrCtrl := ""
		If (x = "" || y = "")
		{
			DllCall("GetCursorPos", "int64P", pt), x := pt << 32 >> 32, y := pt >> 32
			Menu.GetClientSize(Hwnd, w, h)
			Menu.CalculatePopupWindowPosition(x, y, w, h, x, y, 4, 4)
		}
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, 50
		Menu.Obj := this
		Gui, %Hwnd%:Show, NA x%x% y%y% 
	}
	Hide(Select = 0) {
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, Off
		Hwnd := Menu.View
		this := Menu.Obj
		Menu.Color(this.bcgColor, this.Items[Menu.Selection].back)
		Menu.View := Menu.Selection := 0, Menu.WaitX := Menu.WaitY := Menu.Obj := ""
		Try Gui, %Hwnd%:Show, Hide
		If Select
			Try GoSub, % Menu.Label
	}
	Select(hwnd = "") {
		hwnd := !hwnd ? Menu.Selection : hwnd
		Try SetTimer, % Menu.Label, -1
		Menu.Hide()
	}
	Close() {
		Menu.Label := Menu.Name := "", Menu.Hide()
	}
	MouseGet() {
		MouseGetPos, , , win, ctrl, 2
		If (Menu.WaitX != "")
		{
			If (win != Menu.View)
				Return
			DllCall("GetCursorPos", "int64P", pt), X := pt << 32 >> 32, Y := pt >> 32
			If (Abs(X - Menu.WaitX) > 1 || Abs(Y - Menu.WaitY) > 1)
				Menu.WaitX := Menu.WaitY := ""
			Else
				Return
		}
		If (win = Menu.View)
		{
			If (ctrl && ctrl != Menu.PrCtrl)
			{
				this := Menu.Obj
				Menu.Color(this.bcgColor, this.Items[Menu.Selection].back)
				Menu.Selection := ctrl
				Menu.Color(this.hiColor, this.Items[Menu.Selection].back)
				Menu.Label := this.Items[ctrl].Label
				Menu.Name := this.Items[ctrl].Name
				Menu.PrCtrl := ctrl
			}
		}
		Else If Menu.Selection
		{
			this := Menu.Obj
			Menu.Color(this.bcgColor, this.Items[Menu.Selection].back)
			Menu.Name := Menu.Label := Menu.PrCtrl := Menu.Selection := ""
		}
		Hwnd := Menu.View
		Try Gui, %Hwnd%:+AlwaysOnTop
    }
	Up_Down() {
		this := Menu.Obj
		mi := this.List.MaxIndex()
		sel := this.Items[Menu.Selection].key
		new := InStr(A_ThisHotkey, "Up")
		? (!sel || sel = 1 ? mi : sel - 1)
		: (!sel || sel = mi ? 1 : sel + 1)
		Menu.Color(this.bcgColor, this.Items[Menu.Selection].back)
		Menu.Selection := this.ItemPos[new].text
		Menu.Color(this.hiColor, this.ItemPos[new].back)
		Menu.Label := this.Items[Menu.Selection].Label
		Menu.Name := this.Items[Menu.Selection].Name
		Menu.PrCtrl := 0
		DllCall("GetCursorPos", "int64P", pt), Menu.WaitX := pt << 32 >> 32, Menu.WaitY := pt >> 32
    }
	SetHotkeys() {
		#If Menu.View
		#If Menu.View && Menu.Selection
		#If
		Hotkey, IF, Menu.View
		hFunc := ObjBindMethod(this, "Up_Down")
		Hotkey, *$WheelUp, % hFunc
		Hotkey, *$WheelDown, % hFunc
		Hotkey, *$Up, % hFunc
		Hotkey, *$Down, % hFunc
		hFunc := ObjBindMethod(this, "MenuIsUnderMouse")
		Hotkey, ~*$LButton, % hFunc
		Hotkey, ~*$RButton, % hFunc
		Hotkey, ~*MButton, % hFunc
		hFunc := ObjBindMethod(this, "Close")
		Hotkey, *$Escape, % hFunc
		Hotkey, *$LAlt, % hFunc
		Hotkey, *$LWin, % hFunc
		Hotkey, IF, Menu.View && Menu.Selection
		hFunc := ObjBindMethod(this, "Select")
		Hotkey, *$Space, % hFunc
		Hotkey, *$Enter, % hFunc
		Hotkey, IF
    }
	MenuIsUnderMouse() {
		MouseGetPos, , , win
		If (win != Menu.View)
			Menu.Close()
    }
	Color(color, hwndback)  {
		GuiControl, +Background%color%, %hwndback%
		GuiControl, +Redraw, %hwndback%
		GuiControl, +Redraw, % Menu.Selection
	}
	WM_LBUTTONUP(w, l, m, h)  {
		If (A_Gui = Menu.View)
			Menu.Select(h)
	}
	GetClientSize(hwnd, ByRef W, ByRef H)  {
		VarSetCapacity(pwi, 60, 0), NumPut(60, pwi, 0, "UInt")
		DllCall("GetWindowInfo", "Ptr", hwnd, "UInt", &pwi)
		W := NumGet(pwi, 28, "Int") - NumGet(pwi, 20, "Int")
		H := NumGet(pwi, 32, "Int") - NumGet(pwi, 24, "Int")
	}
	CalculatePopupWindowPosition(byref left, byref top, w, h, x, y, offsetx = 0, offsety = 0)  {
		VarSetCapacity(POINT, 8, 0), VarSetCapacity(structs, 24, 0)
		NumPut(x, POINT, 0, "int"), NumPut(y, POINT, 4, "int")
		NumPut(w + offsetx, structs, 0, "int"), NumPut(h + offsety, structs, 4, "int")
		If !DllCall("CalculatePopupWindowPosition"
			, "ptr", &POINT
			, "ptr", &structs
			, "int", 0
			, "ptr", 0
			, "ptr", &structs + 8)
			Return 0
		left  := NumGet(structs, 8, "int") + offsetx
		top := NumGet(structs, 12, "int") + offsety
		Return 1
	}
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

54

Re: AHK: Пользовательское контекстное меню

serzh82saratov, в Вашем препоследнем варианте иное действие совершается при обычном нажатии на ПКМ, а предполагается лишь при удержании ПКМ на 150 мсек. При отпускании ПКМ на выбранном пункте, к сожалению, ничего не происходит.

Попробую перефразировать. При удержании ПКМ на 150 мсек отправляется клавиша "С", после чего начинается ожидание прокручивания вниз. Если прокрутка совершилась, то появляется альтернативное контекстное меню с последующим позиционированием с помощью прокрутки и вызовом действия при отпускании ПКМ. Если после отправления клавиши "С", т.е. иного действия, прокрутка не совершается, а вместо этого нажимается любая другая клавиша включая ЛКМ, то ожидание прокручивания прекращается. Для последующего ожидания прокрутки с целью вызова альтернативного контекстного меню необходимо вновь зажать ПКМ на 150 мсек.

55 (изменено: serzh82saratov, 2016-04-23 20:23:18)

Re: AHK: Пользовательское контекстное меню


#If (mod = 0)
WheelDown::WheelDownCounter++
#If

$RButton::
	WheelDownCounter := 0
	SetTimer, RButtonTimer, -150
	While (GetKeyState("RButton", "P") && !WheelDownCounter)
		Sleep 10
	SetTimer, RButtonTimer, Off 
	mod := 0
	if (WheelDownCounter && (mod := 1)) 
	{
		Menu1.Show() 
		KeyWait, RButton 
		Menu1.Hide(1)
	}
	if (!mod && (mod := 1))
		Send, {RButton}
	Return 

RButtonTimer:
	mod := 0
	MsgBox, , , иное действие, 0.1
	Return 
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

56

Re: AHK: Пользовательское контекстное меню

serzh82saratov, вероятно, у меня где-то ошибка, т.к. при выборе пункта контекстного меню и отпускании ПКМ ничего не происходит. Посмотрите, пожалуйста.


#SingleInstance Force
#NoEnv

List1 := [["Menu1","1"],["Menu2","2"],["Menu3","3"]]
List2 := [["ScriptDir","OpenDir"],["Edit","Edit"],["Как определить имя пункта","Check_name"]]

Menu1 := New Menu(List1, "222222", "075687", "FFFFFF", , 10)
Menu2 := New Menu(List2, "5976C5", "2EC001", "FFFFFF", , 22)

Escape:: ExitApp

#If (mod = 0)
WheelDown::WheelDownCounter++
#If

$RButton::
	WheelDownCounter := 0
	SetTimer, RButtonTimer, -150
	While (GetKeyState("RButton", "P") && !WheelDownCounter)
		Sleep 10
	SetTimer, RButtonTimer, Off 
	mod := 0
	if (WheelDownCounter && (mod := 1)) 
	{
		Menu1.Show() 
		KeyWait, RButton 
		Menu1.Hide(1)
	}
	if (!mod && (mod := 1))
		Send, {RButton}
	Return 

RButtonTimer:
	mod := 0
	ToolTip Send C
	Return 

1:
ToolTip 1
return
2:
ToolTip 2
return
3:
ToolTip 3
return

Class Menu {
	Static View, Selection, AllReady, Obj, PrCtrl, WaitX, WaitY, Name, Label
	__New(List, bcgColor, hiColor, textColor, Transparent = 255, FontSize = 0, XMargin = 1, YMargin = 1) {
		If !Menu.AllReady
			Menu.SetHotkeys(), OnMessage(0x202, this["WM_LBUTTONUP"].Bind(this)), Menu.AllReady := 1
		Gui, New
		Gui, +AlwaysOnTop -DPIScale +hwndhGui +LabelMenuOn -Caption +Owner +E0x08000000
		this.hwnd := hGui, this.List := List
		this.bcgColor := bcgColor, this.hiColor := hiColor, this.textColor := textColor
		Gui, Font, % "q1" . (FontSize ? " s" FontSize : "")
		Gui, Margin, 0, 0
		Gui, Color, %bcgColor%
		If (Transparent < 255)
		{
			S_DetectHiddenWindows := A_DetectHiddenWindows
			DetectHiddenWindows, On
			WinSet, Transparent, %Transparent%, ahk_id %hGui%
			DetectHiddenWindows, %S_DetectHiddenWindows%
		}
		S_AutoTrim := A_AutoTrim
		AutoTrim, Off
		Loop % XMargin
			XMarginStr .= " "
		AutoTrim, %S_AutoTrim%
		For k, v in List
		{
			Gui, Add, Text, hwndhDummy hidden, % XMarginStr v[1] XMarginStr
			GuiControlGet, Pos, Pos, %hDummy%
			maxW := !maxW || PosW > maxW ? PosW : maxW
			maxH := !maxH || PosH > maxH ? PosH : maxH
			DllCall("DestroyWindow", "Ptr", hDummy)
		}
		Gui, Show, Hide w0 h0
		For k, v in List
		{
			Gui, Add, Progress, % (k = 1 ? "x0 y0" : "y+0") " hwndhBack w" maxW " h" maxH + (maxH / 100 * YMargin) " Background" bcgColor, 0
			Gui, Add, Text, % "xp yp wp hp hwndhText +0x200 BackgroundTrans c" textColor, % XMarginStr v[1] XMarginStr
			this.Items[hText] := {back:hBack,key:k,Label:v[2],name:v[1]}
			this.Items[hBack] := {text:hText,key:k,Label:v[2],name:v[1]}
			this.ItemPos[k] := {text:hText,back:hBack}
		}
		Gui, Show, Hide AutoSize, #32768
		Return this
	}
	Show(x = "", y = "") {
		Menu.Hide()
		If (x = "" || y = "")
			DllCall("GetCursorPos", "int64P", pt), x := pt << 32 >> 32, y := pt >> 32
		Hwnd := Menu.View := this.hwnd
		Menu.Name := Menu.Label := Menu.PrCtrl := ""
		Menu.GetClientSize(Hwnd, w, h)
		Menu.CalculatePopupWindowPosition(sx, sy, w, h, x, y, 4, 4)
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, 50
		Menu.Obj := this
		Gui, %Hwnd%:Show, NA x%sx% y%sy%
	}
	Hide() {
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, Off
		Hwnd := Menu.View
		this := Menu.Obj
		Menu.Color(this.bcgColor, this.Items[Menu.Selection].back)
		Menu.View := Menu.Selection := 0, Menu.WaitX := Menu.WaitY := Menu.Obj := ""
		Try Gui, %Hwnd%:Show, Hide
	}
	Select(hwnd = "") {
		hwnd := !hwnd ? Menu.Selection : hwnd
		Try SetTimer, % Menu.Label, -1
		Menu.Hide()
	}
	MouseGet() {
		MouseGetPos, , , win, ctrl, 2
		If (Menu.WaitX != "")
		{
			If (win != Menu.View)
				Return
			DllCall("GetCursorPos", "int64P", pt), X := pt << 32 >> 32, Y := pt >> 32
			If (Abs(X - Menu.WaitX) > 1 || Abs(Y - Menu.WaitY) > 1)
				Menu.WaitX := Menu.WaitY := ""
			Else
				Return
		}
		If (win = Menu.View)
		{
			If (ctrl && ctrl != Menu.PrCtrl)
			{
				this := Menu.Obj
				Menu.Color(this.bcgColor, this.Items[Menu.Selection].back)
				Menu.Selection := ctrl
				Menu.Color(this.hiColor, this.Items[Menu.Selection].back)
				Menu.Label := this.Items[ctrl].Label
				Menu.Name := this.Items[ctrl].Name
				Menu.PrCtrl := ctrl
			}
		}
		Else If Menu.Selection
		{
			this := Menu.Obj
			Menu.Color(this.bcgColor, this.Items[Menu.Selection].back)
			Menu.Name := Menu.Label := Menu.PrCtrl := Menu.Selection := ""
		}
		Hwnd := Menu.View
		Try Gui, %Hwnd%:+AlwaysOnTop
    }
	Up_Down() {
		this := Menu.Obj
		mi := this.List.MaxIndex()
		sel := this.Items[Menu.Selection].key
		new := InStr(A_ThisHotkey, "Up")
		? (!sel || sel = 1 ? mi : sel - 1)
		: (!sel || sel = mi ? 1 : sel + 1)
		Menu.Color(this.bcgColor, this.Items[Menu.Selection].back)
		Menu.Selection := this.ItemPos[new].text
		Menu.Color(this.hiColor, this.ItemPos[new].back)
		Menu.Label := this.Items[Menu.Selection].Label
		Menu.Name := this.Items[Menu.Selection].Name
		Menu.PrCtrl := 0
		DllCall("GetCursorPos", "int64P", pt), Menu.WaitX := pt << 32 >> 32, Menu.WaitY := pt >> 32
    }
	SetHotkeys() {
		#If Menu.View
		#If Menu.View && Menu.Selection
		#If
		Hotkey, IF, Menu.View
		hFunc := ObjBindMethod(this, "MouseIsUnderMenu")
		Hotkey, ~*LButton, % hFunc
		Hotkey, ~*RButton, % hFunc
		Hotkey, ~*MButton, % hFunc
		hFunc := ObjBindMethod(this, "Up_Down")
		Hotkey, *WheelUp, % hFunc
		Hotkey, *WheelDown, % hFunc
		Hotkey, *Up, % hFunc
		Hotkey, *Down, % hFunc
		hFunc := ObjBindMethod(this, "Hide")
		Hotkey, Escape, % hFunc
		Hotkey, *LAlt, % hFunc
		Hotkey, *LWin, % hFunc
		Hotkey, IF, Menu.View && Menu.Selection
		hFunc := ObjBindMethod(this, "Select")
		Hotkey, Space, % hFunc
		Hotkey, Enter, % hFunc
		Hotkey, IF
    }
	MouseIsUnderMenu() {
		MouseGetPos, , , win
		If (win != Menu.View)
			Menu.Hide()
    }
	Color(color, hwndback)  {
		GuiControl, +Background%color%, %hwndback%
		GuiControl, +Redraw, %hwndback%
		GuiControl, +Redraw, % Menu.Selection
	}
	WM_LBUTTONUP(w, l, m, h)  {
		If (A_Gui = Menu.View)
			Menu.Select(h)
	}
	GetClientSize(hwnd, ByRef W, ByRef H)  {
		VarSetCapacity(pwi, 60, 0), NumPut(60, pwi, 0, "UInt")
		DllCall("GetWindowInfo", "Ptr", hwnd, "UInt", &pwi)
		W := NumGet(pwi, 28, "Int") - NumGet(pwi, 20, "Int")
		H := NumGet(pwi, 32, "Int") - NumGet(pwi, 24, "Int")
	}
	CalculatePopupWindowPosition(byref left, byref top, w, h, x, y, offsetx = 0, offsety = 0)  {
		VarSetCapacity(POINT, 8, 0), VarSetCapacity(structs, 24, 0)
		NumPut(x, POINT, 0, "int"), NumPut(y, POINT, 4, "int")
		NumPut(w + offsetx, structs, 0, "int"), NumPut(h + offsety, structs, 4, "int")
		If !DllCall("CalculatePopupWindowPosition"
			, "ptr", &POINT
			, "ptr", &structs
			, "int", 0
			, "ptr", 0
			, "ptr", &structs + 8)
			Return 0
		left  := NumGet(structs, 8, "int") + offsetx
		top := NumGet(structs, 12, "int") + offsety
		Return 1
	}
}

57

Re: AHK: Пользовательское контекстное меню

Если скопировать последнюю версию из 53 то у меня работает.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

58

Re: AHK: Пользовательское контекстное меню

serzh82saratov, Да, работает. Спасибо!
Небольшой момент. Если зажать ПКМ и отпустить без прокручивания, то вызывается стандартное контекстное меню. Необходимо, чтобы после зажатия ПКМ стандартное контекстное меню не вызывалось.

59

Re: AHK: Пользовательское контекстное меню

Так вы же сами изначально прописали:

   if !mod
      Send, {RButton}

Удалите:

	if (!mod && (mod := 1))
		Send, {RButton}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

60

Re: AHK: Пользовательское контекстное меню

Перекопируйте класс из 53, небольшие правки.

Наверное понял что нужно:


#If WheelDownOn
WheelDown::WheelDownCounter++
#If

$RButton::
	WheelDownOn := RButtonLong := WheelDownCounter := 0
	SetTimer, RButtonTimer, -150
	While (GetKeyState("RButton", "P") && !WheelDownCounter)
		Sleep 10
	SetTimer, RButtonTimer, Off
	WheelDownOn := 0
	If WheelDownCounter
	{
		Menu1.Show()
		KeyWait, RButton 
		Menu1.Hide(1)
	}
	If !RButtonLong
		Send, {RButton}
	Return 

RButtonTimer:
	RButtonLong := WheelDownOn := 1
	MsgBox, , , иное действие, 0.1
	Return 
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

61

Re: AHK: Пользовательское контекстное меню

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

При удержании ПКМ на 150 мсек отправляется клавиша "С", после чего начинается ожидание прокручивания вниз. Если прокрутка совершилась, то появляется альтернативное контекстное меню с последующим позиционированием с помощью прокрутки и вызовом действия при отпускании ПКМ. Если после отправления клавиши "С", т.е. иного действия, прокрутка не совершается, а вместо этого нажимается любая другая клавиша включая ЛКМ, или ПКМ просто отжимается, то ожидание прокручивания прекращается, а также отправляется клавиша "V". Для последующего ожидания прокрутки с целью вызова альтернативного контекстного меню необходимо вновь зажать ПКМ на 150 мсек.

62 (изменено: serzh82saratov, 2016-05-07 13:40:43)

Re: AHK: Пользовательское контекстное меню

#If WheelDownOn
WheelDown::WheelDownCounter++
#If

$RButton::
	WheelDownOn := RButtonLong := WheelDownCounter := 0
	SetTimer, RButtonTimer, -150
	While (GetKeyState("RButton", "P") && !WheelDownCounter)
		Sleep 10
	SetTimer, RButtonTimer, Off
	WheelDownOn := 0
	If WheelDownCounter
	{
		Menu1.Show()
		KeyWait, RButton 
		Menu1.Hide(1)
	}
	If !RButtonLong
		Send, {RButton}
	Else If !WheelDownCounter
		MsgBox, , , V, 0.3
	Return 

RButtonTimer:
	RButtonLong := WheelDownOn := 1
	MsgBox, , , C, 0.3
	Return  
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

63

Re: AHK: Пользовательское контекстное меню

serzh82saratov, могли бы Вы добавить параметр, запоминающий положение курсора мыши после удержания ПКМ, чтобы можно было укзать на возвращение указателя в это место при отпускании ПКМ?

В идеале, хотелось бы получить следующий дополнительный функционал:
После удержания ПКМ запоминается положение курсора в переменную (с помощью которой, можно было бы, например, вернуться в эти координаты после отпускания ПКМ), начинается ожидание прокрутки для вызова меню, а также начинается ожидание зажатия ЛКМ на 100 мсек. Если при зажатой ПКМ совершается зажатие ЛКМ, то выполняется:

Send 1
KeyWait {LButton}
Send 2
return

А если происходит простой клик ЛКМ (менее 100 мсек), то выполняется:

Send {LButton}

Несмотря на совершенный клик ЛКМ, ожидание прокрутки для вызова меню продолжается пока зажата ПКМ.

64

Re: AHK: Пользовательское контекстное меню

becauseim пишет:

могли бы Вы добавить параметр, запоминающий положение курсора мыши после удержания ПКМ, чтобы можно было укзать на возвращение указателя в это место при отпускании ПКМ?

Это понял, а дальше много всего, не осилю.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

65

Re: AHK: Пользовательское контекстное меню

serzh82saratov, иными словами, необходимо объединить последний сценарий с другим сценарием,
написанным Вами ранее. Только его необходимо несколько изменить, используя упомянутый желаемый мною параметр, запоминающий положение курсора.


Сейчас он работает следующим образом:

После совершения нажатия ЛКМ, начинается ожидание траектории движения курсора, при направлении курсора вправо от места зажатия отправляется клавиша {а}, при отпускании - {b}. Если влево - то наоборот. Если остается на месте - отправляется {^!+p}.


Хотелось бы иметь усовершенствованный вариант:

После совершения зажатия ЛКМ на 150 мсек, запоминаются координаты положения курсора и начинается ожидание траектории движения курсора, но ничего не отправляется, а при отпускании ЛКМ справа от места зажатия отправляется клавиша {b}, далее отправляется клик в полученные вначале координаты и отправляется клавиша {а}. Если отпускается слева - то наоборот. Если остается на месте - отправляется {^!+p}. Если ЛКМ была отпущена ранее 150 мсек после нажатия, т.е. без зажатия, то работает как обычно (отправлется LButton).


Работа данной горячей клавиши подразумевается при зажатой ПКМ наравне с ожиданием прокрутки для вызова альтернативного контекстного меню.

66

Re: AHK: Пользовательское контекстное меню

Что то как то ещё сложнее для меня стало. В любом случае такое организовывать надо в отдельной функции, никак не в "стандартном классе" меню.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

67

Re: AHK: Пользовательское контекстное меню

serzh82saratov, в данном случае, меню не имеет никакого отношения к описанному. Пересечение лишь в том, что обе горячие клавиши должны работать при зажатой ПКМ. Первое действие срабатывает при прокручивании вниз (вызов меню), а второе (описанное) при зажатии ЛКМ (при уже зажатой ПКМ).

68

Re: AHK: Пользовательское контекстное меню

Частенько такое сообщение вылазит, хотя пользуюсь AutoHotkey_L v1.1.23.05 (Unicode 32-bit) —
http://i78.fastpic.ru/thumb/2016/0506/a7/edf2cd91198ef9309fc3fd04c858b7a7.jpeg

69 (изменено: mafckz, 2016-05-06 11:38:31)

Re: AHK: Пользовательское контекстное меню

DD пишет:

Частенько такое сообщение вылазит

Вроде, такая ошибка происходит при пустых значениях переменных sx и sy.
Потестировал менюшки из последнего кода от serzh82saratov. У меня ошибок не было. При каких условиях (положение мыши и т.п.) она появляется?

70

Re: AHK: Пользовательское контекстное меню

Выводится независимо от условий, всегда и стабильно.

71

Re: AHK: Пользовательское контекстное меню

DD вы зыпускаете этот:

+ код

#SingleInstance Force
#NoEnv

List1 := [["Мой компьютер","g1"],["Программы","g2"],["Рабочий стол","g3"],["Мои документы","g4"]]
List2 := [["Папка скрипта","OpenDir"],["Редактировать","Edit"],["Как определить имя пункта","Check_name",{B:"FFDE8A",H:"E66C4F",T:"000000"}]]

Menu1 := New Menu(List1, "FFFFFF", "DBDBDB", "2842A0", 210, 10)
Menu2 := New Menu(List2, "5976C5", "2EC001", "FFFFFF", , 22)

Escape:: ExitApp


1::
	Menu1.Show()
	KeyWait, 1
	Menu1.Hide(1)
	Return

2::Menu2.Show("Center", 100, "W")

OpenDir:
	Run %A_ScriptDir%
	Return
Edit:
	Run, Edit %A_ScriptFullPath%
	Return
Check_name:
	MsgBox % Menu.Name
	Return
g1:
	Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
	Return
g2:
	Run, %A_ProgramFiles%
	Return
g3:
	Run, %A_Desktop%
	Return
g4:
	Run, %A_MyDocuments%
	Return






Class Menu {
	Static View, Selection, AllReady, Obj, PrCtrl, WaitX, WaitY, Name, Label
	__New(List, bcgColor, hiColor, textColor, Transparent = 255, FontSize = 0, XMargin = 1, YMargin = 1) {
		If !Menu.AllReady
			Menu.SetHotkeys(), OnMessage(0x202, this["WM_LBUTTONUP"].Bind(this)), Menu.AllReady := 1
		Gui, New
		Gui, +AlwaysOnTop -DPIScale +hwndhGui +LabelMenuOn -Caption +Border +Owner +E0x08000000
		this.hwnd := hGui, this.List := List
		Gui, Font, % "q1" . (FontSize ? " s" FontSize : "")
		Gui, Margin, 0, 0
		Gui, Color, %bcgColor%
		S_AutoTrim := A_AutoTrim
		AutoTrim, Off
		Loop % XMargin
			XMarginStr .= " "
		this.XMarginStr := XMarginStr 
		AutoTrim, %S_AutoTrim%
		this.GetMaxSize(List, maxW, maxH)
		Gui, Show, Hide w0 h0
		For k, v in List
		{
			_bcgColor := v[3].B != "" ? v[3].B : bcgColor, _textColor := v[3].T != "" ? v[3].T : textColor, _hiColor := v[3].H != "" ? v[3].H : hiColor 
			Gui, Add, Progress, % (k = 1 ? "x0 y0" : "y+0") " hwndhBack w" maxW " h" maxH + (maxH / 100 * YMargin) " Background" _bcgColor, 0
			Gui, Add, Text, % "xp yp wp hp hwndhText +0x200 BackgroundTrans c" _textColor, % XMarginStr v[1] XMarginStr
			this.Items[hText] := {back:hBack,key:k,Label:v[2],name:v[1],bcgColor:_bcgColor,hiColor:_hiColor,textColor:_textColor}
			this.Items[hBack] := {text:hText,key:k,Label:v[2],name:v[1],bcgColor:_bcgColor,hiColor:_hiColor,textColor:_textColor}
			this.ItemPos[k] := {text:hText,back:hBack}
		}
		Gui, Show, Hide AutoSize, #32768
		S_DetectHiddenWindows := A_DetectHiddenWindows
		DetectHiddenWindows, On
		If (Transparent < 255)
			WinSet, Transparent, %Transparent%, ahk_id %hGui%
		WinGetPos, , , Width, Height, ahk_id %hGui%
		this.Width := Width, this.Height := Height
		DetectHiddenWindows, %S_DetectHiddenWindows%
		Return this
	}
	Show(x = 0, y = 0, Relative = "M", hWin = 0) {
		Menu.Hide()
		Hwnd := Menu.View := this.hwnd
		Menu.Name := Menu.Label := Menu.PrCtrl := ""
		If Relative = S
			sx := x, sy := y
		Else
		{
			If Relative = W
			{
				WinGetPos, wx, wy, ww, wh, % (hWin ? "ahk_id" hWin : "A")
				ix := wx + (x = "Center" ? ((ww // 2) - (this.Width // 2)) : x) 
				iy := wy + (y = "Center" ? ((wh // 2) - (this.Height // 2)) : y)
			}
			Else If Relative = M
			{
				DllCall("GetCursorPos", "int64P", pt), ix := pt << 32 >> 32, iy := pt >> 32 
				ix += (x = "Center" ? -(this.Width // 2) : x) 
				iy += (y = "Center" ? -(this.Height // 2) : y)
			}		
			Menu.GetClientSize(Hwnd, w, h)
			Menu.CalculatePopupWindowPosition(sx, sy, w, h, ix, iy) 
		}
		Gui, %Hwnd%:Show, NA AutoSize x%sx% y%sy% 
		
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, 10
		Menu.Obj := this
	}
	Hide(Select = 0) {
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, Off
		Hwnd := Menu.View
		this := Menu.Obj
		item := this.Items[Menu.Selection]
		Menu.Color(item.bcgColor, item.back)
		Menu.View := Menu.Selection := 0, Menu.WaitX := Menu.WaitY := Menu.Obj := ""
		Try Gui, %Hwnd%:Show, Hide
		If Select
			Try GoSub, % Menu.Label
	}
	GetMaxSize(Items, ByRef maxW, ByRef maxH) {  
		For k, v in Items
		{
			Gui, Add, Text, hwndhDummy hidden, % this.XMarginStr v[1] this.XMarginStr
			GuiControlGet, Pos, Pos, %hDummy%
			maxW := !maxW || PosW > maxW ? PosW : maxW
			maxH := !maxH || PosH > maxH ? PosH : maxH
			DllCall("DestroyWindow", "Ptr", hDummy)
		}
	}
	NewText(Index, Text) {  
		hText := this.ItemPos[Index].text
		GuiControl, , %hText%, % this.XMarginStr Text this.XMarginStr
		this.Items[hText].name := Text
		this.Items[this.ItemPos[Index].back].name := Text
	}
	Select(hwnd = "") {
		hwnd := !hwnd ? Menu.Selection : hwnd
		Try SetTimer, % Menu.Label, -1
		Menu.Hide()
	}
	Close() {
		Menu.Label := Menu.Name := "", Menu.Hide()
	}
	MouseGet() {
		MouseGetPos, , , win, ctrl, 2
		If (Menu.WaitX != "")
		{
			If (win != Menu.View)
				Return
			DllCall("GetCursorPos", "int64P", pt), X := pt << 32 >> 32, Y := pt >> 32
			If (Abs(X - Menu.WaitX) > 1 || Abs(Y - Menu.WaitY) > 1)
				Menu.WaitX := Menu.WaitY := ""
			Else
				Return
		}
		If (win = Menu.View)
		{
			If (ctrl && ctrl != Menu.PrCtrl)
			{
				this := Menu.Obj
				item := this.Items[Menu.Selection]
				Menu.Color(item.bcgColor, item.back)
				Menu.Selection := ctrl
				item := this.Items[Menu.Selection]
				Menu.Color(item.hiColor, item.back)
				Menu.Label := item.Label
				Menu.Name := item.Name
				Menu.PrCtrl := ctrl
			}
		}
		Else If Menu.Selection
		{
			this := Menu.Obj
			item := this.Items[Menu.Selection]
			Menu.Color(item.bcgColor, item.back)
			Menu.Name := Menu.Label := Menu.PrCtrl := Menu.Selection := ""
		}
		Hwnd := Menu.View
		Try Gui, %Hwnd%:+AlwaysOnTop
    }
	Up_Down() {
		this := Menu.Obj
		mi := this.List.MaxIndex()
		sel := this.Items[Menu.Selection].key
		new := InStr(A_ThisHotkey, "Up")
		? (!sel || sel = 1 ? mi : sel - 1)
		: (!sel || sel = mi ? 1 : sel + 1)
		item := this.Items[Menu.Selection]
		Menu.Color(item.bcgColor, item.back)
		Menu.Selection := this.ItemPos[new].text
		item := this.Items[Menu.Selection]
		Menu.Color(item.hiColor, item.back)
		Menu.Label := item.Label
		Menu.Name := item.Name
		Menu.PrCtrl := 0
		DllCall("GetCursorPos", "int64P", pt), Menu.WaitX := pt << 32 >> 32, Menu.WaitY := pt >> 32
    }
	SetHotkeys() {
		#If Menu.View
		#If Menu.View && Menu.Selection
		#If
		Hotkey, IF, Menu.View
		hFunc := ObjBindMethod(this, "Up_Down")
		If !Menu.NotWheel
		{
			Hotkey, *$WheelUp, % hFunc
			Hotkey, *$WheelDown, % hFunc
		}
		Hotkey, *$Up, % hFunc
		Hotkey, *$Down, % hFunc
		hFunc := ObjBindMethod(this, "MenuIsUnderMouse")
		Hotkey, ~*$LButton, % hFunc
		Hotkey, ~*$RButton, % hFunc
		Hotkey, ~*MButton, % hFunc
		hFunc := ObjBindMethod(this, "Close")
		Hotkey, *$Escape, % hFunc
		Hotkey, *$LAlt, % hFunc
		Hotkey, *$LWin, % hFunc
		Hotkey, IF, Menu.View && Menu.Selection
		hFunc := ObjBindMethod(this, "Select")
		Hotkey, *$Space, % hFunc
		Hotkey, *$Enter, % hFunc
		Hotkey, IF
    }
	MenuIsUnderMouse() {
		MouseGetPos, , , win
		If (win != Menu.View)
			Menu.Close()
    }
	Color(color, hwndback)  {
		GuiControl, +Background%color%, %hwndback%
		GuiControl, +Redraw, %hwndback%
		GuiControl, +Redraw, % Menu.Selection
	}
	WM_LBUTTONUP(w, l, m, h)  {
		If (A_Gui = Menu.View)
			Menu.Select(h)
	}
	GetClientSize(hwnd, ByRef W, ByRef H)  {
		VarSetCapacity(pwi, 60, 0), NumPut(60, pwi, 0, "UInt")
		DllCall("GetWindowInfo", "Ptr", hwnd, "UInt", &pwi)
		W := NumGet(pwi, 28, "Int") - NumGet(pwi, 20, "Int")
		H := NumGet(pwi, 32, "Int") - NumGet(pwi, 24, "Int")
	}
	CalculatePopupWindowPosition(byref left, byref top, w, h, x, y, offsetx = 0, offsety = 0)  {
		VarSetCapacity(POINT, 8, 0), VarSetCapacity(structs, 24, 0)
		NumPut(x, POINT, 0, "int"), NumPut(y, POINT, 4, "int")
		NumPut(w + offsetx, structs, 0, "int"), NumPut(h + offsety, structs, 4, "int")
		If !DllCall("CalculatePopupWindowPosition"
			, "ptr", &POINT
			, "ptr", &structs
			, "int", 0
			, "ptr", 0
			, "ptr", &structs + 8)
			Return 0
		left  := NumGet(structs, 8, "int") + offsetx
		top := NumGet(structs, 12, "int") + offsety
		Return 1
	}
} 

и при нажатии на 1 или 2 у вас всегда ошибка?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

72

Re: AHK: Пользовательское контекстное меню

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

отдельный параметр, запоминающий положение курсора мыши после удержания ПКМ, чтобы можно было укзать на возвращение указателя в это место при отпускании ПКМ?

73

Re: AHK: Пользовательское контекстное меню

Много размыто, например - почему ПКМ, если пользователь может назначить любую кнопку. При отпускании где, на меню, не на меню, везде, только если выбран пункт, или не выбран, или всегда...

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

74 (изменено: becauseim, 2016-05-07 00:19:50)

Re: AHK: Пользовательское контекстное меню

serzh82saratov, наверное, я забежал немного вперед и сам немного запутался. Положение курсора необходимо запомнить в тот момент, когда происходит прокручивание, т.е. непосредственно перед вызовом альтернативного контекстного меню. А отправление MouseClick в эти координаты подразумевается в момент отпускания ПКМ, т.е. перед выполнением действий выбранного пункта.

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

75

Re: AHK: Пользовательское контекстное меню

serzh82saratov пишет:

всегда ошибка?

Так и есть.

76 (изменено: serzh82saratov, 2016-05-15 12:14:31)

Re: AHK: Пользовательское контекстное меню

Добавил отнсительность координат:
Третий параметр "W" - относительно активного окна (4 параметром можно указать хэндл нужного окна), "S" - относительно экрана, "M" - относительно мыши.
Показывает в середине по горизонтали, и 100 сверху относительно активного окна:

Menu2.Show("Center", 100, "W")

Если 5 параметром указать 1, то при выборе пункта мышь сначала вернётся в координаты на момент вызова меню, если 2 то вернётся и кликнет.
Можно задать пункту свои цвета указав 3 параметром массив:

{B:"FFDE8A",H:"E66C4F",T:"000000"}

B - фон, H - подсветка, T - текст. См. пример ниже, второе меню.
Если какой то из них не указан, берётся из общего для меню.

Можно в последствии изменить текст пункта указав его индекс, ширина меню при этом не изменится.

Menu1.NewText(1, "новый текст")   ; 1 пункт

Можно запретить колёсико мыши, если например меню вызывается по средней кнопке или колёсику.

Menu.NotWheel := 1   ; указать перед созданием меню первого меню

#SingleInstance Force
#NoEnv

List1 := [["Мой компьютер","g1"],["Программы","g2"],["Рабочий стол","g3"],["Мои документы","g4"]]
List2 := [["Папка скрипта","OpenDir"],["Редактировать","Edit"],["Как определить имя пункта","Check_name",{B:"FFDE8A",H:"E66C4F",T:"000000"}]]

Menu1 := New Menu(List1, "FFFFFF", "DBDBDB", "2842A0", 210, 10)
Menu2 := New Menu(List2, "5976C5", "2EC001", "FFFFFF", , 22)

Escape:: ExitApp


1::
	Menu1.Show()
	KeyWait, 1
	Menu1.Hide(1)
	Return

2::Menu2.Show("Center", 100, "S",, 1)

OpenDir:
	Run %A_ScriptDir%
	Return
Edit:
	Run, Edit %A_ScriptFullPath%
	Return
Check_name:
	MsgBox % Menu.Name
	Return
g1:
	Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
	Return
g2:
	Run, %A_ProgramFiles%
	Return
g3:
	Run, %A_Desktop%
	Return
g4:
	Run, %A_MyDocuments%
	Return






Class Menu {
	Static View, Selection, AllReady, Obj, PrCtrl, WaitX, WaitY, Name, Label
	__New(List, bcgColor, hiColor, textColor, Transparent = 255, FontSize = 0, XMargin = 1, YMargin = 1) {
		If !Menu.AllReady
			Menu.SetHotkeys(), OnMessage(0x202, this["WM_LBUTTONUP"].Bind(this)), Menu.AllReady := 1
		Gui, New
		Gui, +AlwaysOnTop -DPIScale +hwndhGui +LabelMenuOn -Caption +Border +Owner +E0x08000000
		this.hwnd := hGui, this.List := List
		Gui, Font, % "q1" . (FontSize ? " s" FontSize : "")
		Gui, Margin, 0, 0
		Gui, Color, %bcgColor%
		S_AutoTrim := A_AutoTrim
		AutoTrim, Off
		Loop % XMargin
			XMarginStr .= " "
		this.XMarginStr := XMarginStr 
		AutoTrim, %S_AutoTrim%
		this.GetMaxSize(List, maxW, maxH)
		Gui, Show, Hide w0 h0
		For k, v in List
		{
			_bcgColor := v[3].B != "" ? v[3].B : bcgColor, _textColor := v[3].T != "" ? v[3].T : textColor, _hiColor := v[3].H != "" ? v[3].H : hiColor 
			Gui, Add, Progress, % (k = 1 ? "x0 y0" : "y+0") " hwndhBack w" maxW " h" maxH + (maxH / 100 * YMargin) " Background" _bcgColor, 0
			Gui, Add, Text, % "xp yp wp hp hwndhText +0x200 BackgroundTrans c" _textColor, % XMarginStr v[1] XMarginStr
			this.Items[hText] := {back:hBack,key:k,Label:v[2],name:v[1],bcgColor:_bcgColor,hiColor:_hiColor,textColor:_textColor}
			this.Items[hBack] := {text:hText,key:k,Label:v[2],name:v[1],bcgColor:_bcgColor,hiColor:_hiColor,textColor:_textColor}
			this.ItemPos[k] := {text:hText,back:hBack}
		}
		Gui, Show, Hide AutoSize, #32768
		S_DetectHiddenWindows := A_DetectHiddenWindows
		DetectHiddenWindows, On
		If (Transparent < 255)
			WinSet, Transparent, %Transparent%, ahk_id %hGui%
		WinGetPos, , , Width, Height, ahk_id %hGui%
		this.Width := Width, this.Height := Height
		DetectHiddenWindows, %S_DetectHiddenWindows%
		Return this
	}
	Show(x = 0, y = 0, Relative = "M", hWin = 0, SaveMouse = 0) {
		Menu.Close()
		Hwnd := Menu.View := this.hwnd
		If SaveMouse
			DllCall("GetCursorPos", "int64P", pt), this.SaveMouseX := pt << 32 >> 32, this.SaveMouseY := pt >> 32
		this.SaveMouse := SaveMouse
		Menu.Name := Menu.Label := Menu.PrCtrl := ""
		If Relative = S
			sx := x, sy := y
		Else
		{
			If Relative = W
			{
				WinGetPos, wx, wy, ww, wh, % (hWin ? "ahk_id" hWin : "A")
				ix := wx + (x = "Center" ? ((ww // 2) - (this.Width // 2)) : x) 
				iy := wy + (y = "Center" ? ((wh // 2) - (this.Height // 2)) : y)
			}
			Else If Relative = M
			{
				DllCall("GetCursorPos", "int64P", pt), ix := pt << 32 >> 32, iy := pt >> 32 
				ix += (x = "Center" ? -(this.Width // 2) : x)
				iy += (y = "Center" ? -(this.Height // 2) : y)
			}		
			Menu.GetClientSize(Hwnd, w, h) 
			Menu.CalculatePopupWindowPosition(sx, sy, w, h, ix, iy)  
		}
		Gui, %Hwnd%:Show, NA AutoSize x%sx% y%sy% 
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, 10
		Menu.Obj := this
	}
	Hide(Select = 0) { 
		hFunc := ObjBindMethod(this, "MouseGet")
		SetTimer, % hFunc, Off
		Hwnd := Menu.View
		this := Menu.Obj
		item := this.Items[Menu.Selection]
		Menu.Color(item.bcgColor, item.back)
		If this.SaveMouse
			DllCall("SetCursorPos", "Uint", this.SaveMouseX, "Uint", this.SaveMouseY)
		If this.SaveMouse = 2
			Click
		Menu.View := Menu.Selection := 0, Menu.WaitX := Menu.WaitY := Menu.Obj := ""
		Try Gui, %Hwnd%:Show, Hide
		If Select
			Try GoSub, % Menu.Label
	}
	GetMaxSize(Items, ByRef maxW, ByRef maxH) {  
		For k, v in Items
		{
			Gui, Add, Text, hwndhDummy hidden, % this.XMarginStr v[1] this.XMarginStr
			GuiControlGet, Pos, Pos, %hDummy%
			maxW := !maxW || PosW > maxW ? PosW : maxW
			maxH := !maxH || PosH > maxH ? PosH : maxH
			DllCall("DestroyWindow", "Ptr", hDummy)
		}
	}
	NewText(Index, Text) {  
		hText := this.ItemPos[Index].text
		GuiControl, , %hText%, % this.XMarginStr Text this.XMarginStr
		this.Items[hText].name := Text
		this.Items[this.ItemPos[Index].back].name := Text
	}
	Select() {
		Menu.Hide(1)
	}
	Close() {
		this := Menu.Obj, this.SaveMouse := 0
		Menu.Label := Menu.Name := "", Menu.Hide()
	}
	MouseGet() {
		MouseGetPos, , , win, ctrl, 2
		If (Menu.WaitX != "")
		{
			If (win != Menu.View)
				Return
			DllCall("GetCursorPos", "int64P", pt), X := pt << 32 >> 32, Y := pt >> 32
			If (Abs(X - Menu.WaitX) > 1 || Abs(Y - Menu.WaitY) > 1)
				Menu.WaitX := Menu.WaitY := ""
			Else
				Return
		}
		If (win = Menu.View)
		{
			If (ctrl && ctrl != Menu.PrCtrl)
			{
				this := Menu.Obj
				item := this.Items[Menu.Selection]
				Menu.Color(item.bcgColor, item.back)
				Menu.Selection := ctrl
				item := this.Items[Menu.Selection]
				Menu.Color(item.hiColor, item.back)
				Menu.Label := item.Label
				Menu.Name := item.Name
				Menu.PrCtrl := ctrl
			}
		}
		Else If Menu.Selection
		{
			this := Menu.Obj
			item := this.Items[Menu.Selection]
			Menu.Color(item.bcgColor, item.back)
			Menu.Name := Menu.Label := Menu.PrCtrl := Menu.Selection := ""
		}
		Hwnd := Menu.View
		Try Gui, %Hwnd%:+AlwaysOnTop
    }
	Up_Down() {
		this := Menu.Obj
		mi := this.List.MaxIndex()
		sel := this.Items[Menu.Selection].key
		new := InStr(A_ThisHotkey, "Up")
		? (!sel || sel = 1 ? mi : sel - 1)
		: (!sel || sel = mi ? 1 : sel + 1)
		item := this.Items[Menu.Selection]
		Menu.Color(item.bcgColor, item.back)
		Menu.Selection := this.ItemPos[new].text
		item := this.Items[Menu.Selection]
		Menu.Color(item.hiColor, item.back)
		Menu.Label := item.Label
		Menu.Name := item.Name
		Menu.PrCtrl := 0
		DllCall("GetCursorPos", "int64P", pt), Menu.WaitX := pt << 32 >> 32, Menu.WaitY := pt >> 32
    }
	SetHotkeys() {
		#If Menu.View
		#If Menu.View && Menu.Selection
		#If
		Hotkey, IF, Menu.View
		hFunc := ObjBindMethod(this, "Up_Down")
		If !Menu.NotWheel
		{
			Hotkey, *$WheelUp, % hFunc
			Hotkey, *$WheelDown, % hFunc
		}
		Hotkey, *$Up, % hFunc
		Hotkey, *$Down, % hFunc
		hFunc := ObjBindMethod(this, "MenuIsUnderMouse")
		Hotkey, ~*$LButton, % hFunc
		Hotkey, ~*$RButton, % hFunc
		Hotkey, ~*$MButton, % hFunc
		hFunc := ObjBindMethod(this, "Close")
		Hotkey, *$Escape, % hFunc
		Hotkey, $Escape, % hFunc
		Hotkey, *$LAlt, % hFunc
		Hotkey, *$LWin, % hFunc
		Hotkey, IF, Menu.View && Menu.Selection
		hFunc := ObjBindMethod(this, "Select")
		Hotkey, *$Space, % hFunc
		Hotkey, *$Enter, % hFunc
		Hotkey, IF
    }
	MenuIsUnderMouse() {
		MouseGetPos, , , win
		If (win != Menu.View)
			Menu.Close()
    }
	Color(color, hwndback)  {
		GuiControl, +Background%color%, %hwndback%
		GuiControl, +Redraw, %hwndback%
		GuiControl, +Redraw, % Menu.Selection
	}
	WM_LBUTTONUP(w, l, m, h)  {
		If (A_Gui = Menu.View)
			Menu.Select()
	}
	GetClientSize(hwnd, ByRef W, ByRef H)  {
		VarSetCapacity(pwi, 60, 0), NumPut(60, pwi, 0, "UInt")
		DllCall("GetWindowInfo", "Ptr", hwnd, "UInt", &pwi)
		W := NumGet(pwi, 28, "Int") - NumGet(pwi, 20, "Int")
		H := NumGet(pwi, 32, "Int") - NumGet(pwi, 24, "Int")
	}
	CalculatePopupWindowPosition(byref left, byref top, w, h, x, y, offsetx = 0, offsety = 0)  {
		VarSetCapacity(point, 8, 0), VarSetCapacity(structs, 24, 0)
		NumPut(x, point, 0, "int"), NumPut(y, point, 4, "int")
		NumPut(w + offsetx, structs, 0, "int"), NumPut(h + offsety, structs, 4, "int")
		If !DllCall("CalculatePopupWindowPosition"
			, "ptr", &point
			, "ptr", &structs
			, "int", 0
			, "ptr", 0
			, "ptr", &structs + 8)
			Return 0
		left  := NumGet(structs, 8, "int") + offsetx
		top := NumGet(structs, 12, "int") + offsety
		Return 1
	}
} 
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

77

Re: AHK: Пользовательское контекстное меню

becauseim может просто:

serzh82saratov пишет:

Если 5 параметром указать 1, то при выборе пункта мышь сначала вернётся в координаты на момент вызова меню.

becauseim пишет:

отправление MouseClick  в эти координаты подразумевается

Опять не понятно MouseClick или MouseMove?

DD я заметил что в заголовке окна с ошибкой, у вас то чего у меня никогда не было, у меня там всегда только имя скрипта.
Попробуйте показ меню относительно экрана, окна и мыши Show(10, 10, "M"). Надо побольше вводных чтобы понять почему именно у вас не работает.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

78 (изменено: DD, 2016-05-07 15:35:35)

Re: AHK: Пользовательское контекстное меню

serzh82saratov, в заголовке окна с ошибкой у меня тоже значится имя скрипта, которое, тем не менее, не при чем, потому что менял по-всякому.

Сейчас вывод работает по клавише «2», но если подставить для любой из клавиш Show(10, 10, "M") (вот так: 1::Menu2.Show(10, 10, "M") или 2::Menu2.Show(10, 10, "M")) — та же ошибка.

79

Re: AHK: Пользовательское контекстное меню

У меня кстати XP SP2, может в этом дело?

80

Re: AHK: Пользовательское контекстное меню

serzh82saratov, работает! В последней редакции перед выбором пункта курсор возвращается в координаты вызова меню, если установить соответствующий параметр. Думал, что получится самостоятельно извлечь этот параметр для добавления в другой Ваш сценарий, но задача оказалось сложной. Помогите, пожалуйста, ее решить в соседней ветке.

81

Re: AHK: Пользовательское контекстное меню

DD пишет:

У меня кстати XP SP2, может в этом дело?

Да, CalculatePopupWindowPosition не работает в ХР.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

82 (изменено: becauseim, 2016-05-14 18:09:18)

Re: AHK: Пользовательское контекстное меню

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

upd.: a вообще, было бы удобнее, если можно было включать или исключать возвращение курсора к месту вызова в зависимости от выбранного пункта меню. Например, добавить соответсвующий параметр в переменные.

...
List1 := [["Мой компьютер","g1", "Возвращать"],["Программы","g2", "Не возвращать"]]
...

83

Re: AHK: Пользовательское контекстное меню

becauseim пишет:

А как можно совершить клик в эти координаты отдельным действием?

Это добавил.

becauseim пишет:

upd.: a вообще, было бы удобнее, если можно было включать или исключать возвращение курсора к месту вызова в зависимости от выбранного пункта меню. Например, добавить соответсвующий параметр в переменные.

Можно конечно всё что угодно добавить, но можно и самому, указать просто возвращать мышь, а кликать или не кликать уже из подпрограммы выбранного пункта.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

84

Re: AHK: Пользовательское контекстное меню

serzh82saratov пишет:

Это добавил.

Открыл, но не нашел переменные координат.

85

Re: AHK: Пользовательское контекстное меню

Какие переменные? Там просто вместо 1, 2 пятым параметром.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

86

Re: AHK: Пользовательское контекстное меню

serzh82saratov, не знаю, насколько ясно я выразился. В общем, догадался:


...
		Menu1.Show("Right", 10, "M",, 1)
		MouseGetPos, MenuRunX, MenuRunY
...

87 (изменено: becauseim, 2016-05-15 00:37:54)

Re: AHK: Пользовательское контекстное меню

serzh82saratov, после последней редакции заменил код, начиная с Class Menu , но не смотря на то, что у меня
Menu1.Show("Right", 10, "M",, 1), меню появляется в левом нижнем углу экрана. Что я сделал неправильно?

88

Re: AHK: Пользовательское контекстное меню

Это я не то добавил, попробуйте ещё раз.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

89

Re: AHK: Пользовательское контекстное меню

becauseim пишет:

Menu1.Show("Right", 10, "M",, 1)

А что тут значит Right?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

90

Re: AHK: Пользовательское контекстное меню

serzh82saratov,

Error: Invalid option

Gui, %Hwnd%:Show, NA AutoSize x%sx% y%sy% 

91

Re: AHK: Пользовательское контекстное меню

serzh82saratov пишет:

А что тут значит Right?

В предыдущей редакции меню появлялось по центру. Наугад поменял Center на Right, и вроде исправилось.

92

Re: AHK: Пользовательское контекстное меню

Error: Invalid option

Поправил.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

93

Re: AHK: Пользовательское контекстное меню

becauseim пишет:

В предыдущей редакции меню появлялось по центру. Наугад поменял Center на Right, и вроде исправилось.

Любой текст кроме "Center" эквивалентен нулю.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

94 (изменено: becauseim, 2016-05-17 11:43:46)

Re: AHK: Пользовательское контекстное меню

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



#If WheelDownOn
WheelDown::WheelDownCounter++
#If

$RButton::
	WheelDownOn := RButtonLong := WheelDownCounter := 0
	SetTimer, RButtonTimer, -150
	While (GetKeyState("RButton", "P") && !WheelDownCounter)
		Sleep 10
	SetTimer, RButtonTimer, Off
	WheelDownOn := 0
	If WheelDownCounter
	{
		Send {vk56}^!+{k} ; отправить V+Ctrl+Alt+Shift+K перед вызовом меню
		Menu1.Show("Center", 10, "M",, 2) ; 1 - mousemove, 2 - mouseclick
		;~ MouseGetPos, MenuRunX, MenuRunY
		KeyWait, RButton
		Menu1.Hide(1)
	}
	If !RButtonLong
		Send, {RButton}
	Else If !WheelDownCounter
		SendInput {vk56}
	Return 
	
RButtonTimer:
	RButtonLong := WheelDownOn := 1
   SendInput {vk43}
	Return

95

Re: AHK: Пользовательское контекстное меню

Да, с кликом наверное не получится, он деактивирует меню.

becauseim пишет:

Может, метод вызова меню, который испоьзуется в моем случае, не полностью соответствует последней редакции сценария?

Тут я даже непонимаю как оно должно появится. Нажимаем RButton и потом ждём когда его отпустят.

While (GetKeyState("RButton", "P")

И далее блок.

		Menu1.Show("Center", 10, "M",, 2) ; 1 - mousemove, 2 - mouseclick
		;~ MouseGetPos, MenuRunX, MenuRunY
		KeyWait, RButton
		Menu1.Hide(1)

Где KeyWait уже не ждёт, соответственно меню сразу исчезает.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

96 (изменено: becauseim, 2016-05-17 12:33:09)

Re: AHK: Пользовательское контекстное меню

serzh82saratov, забыл часть кода, добавил.

Да, с кликом наверное не получится, он деактивирует меню.

Т.е. деактивирует до момента выбора пункта меню? Значит, использовать версию, где подразумевается только перемещение указателя на исходную позицию и в начале того пункта меню, где это необходимо, добавить MouseClick, Left?

upd.: Насколько мне стало ясным, скрипт начинает некорректно работать, если я указываю пятым параметром значение 2, т.е. кликать мышью перед началом действия выбранного пункта. Т.е. буду использовать предыдущую редакцию, т.к. все равно нет необходимости в клике всегда, а только для некоторых пунктов меню.

97

Re: AHK: Пользовательское контекстное меню

Да, всё верно, вместо MouseClick, Left можно просто Click.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui