Что нового

Создать контекстное меню без GUI

Suppir

Продвинутый
Сообщения
967
Репутация
62
Добрый день!

Подскажите, как создать контекстное меню по клику средней клавиши мышки, если у программы нет GUI?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,670
Репутация
2,463
Код:
#include <Constants.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>
#include <GUIMenu.au3>
#include <Misc.au3>
#include <Timers.au3>

Global $hUser32Dll = DllOpen('User32.dll')
Global $iHideMenuDelay = 10

Global $iKey = 04

While 1
	If _IsPressed($iKey, $hUser32Dll) Then
		_ShowPopupMenu_Proc()
	Else
		Sleep(100)
	EndIf
WEnd

Func _ShowPopupMenu_Proc()
	Local $hDlg, $cDummy, $nContextMenu, $hContextMenu, $nHide_MItem, $nExit_MItem, $hTimer, $aMousePos, $nResult
	
	$hDlg = GUICreate('', 1, 1, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW); Create our temporary GUI
	
	$cDummy = GUICtrlCreateDummy(); Create a dummy control to hang a context menu on
	
	$nContextMenu = GUICtrlCreateContextMenu($cDummy); Create the context menu
	$hContextMenu = GUICtrlGetHandle($nContextMenu)
	
	$nHide_MItem = GUICtrlCreateMenuItem('Hide', $nContextMenu)
	$nShowMsg_MItem = GUICtrlCreateMenuItem('Show some message', $nContextMenu)
	GUICtrlCreateMenuItem('', $nContextMenu)
	$nExit_MItem = GUICtrlCreateMenuItem('Exit', $nContextMenu)
	
	GUISetState(@SW_SHOW, $hDlg)
	
	$hTimer = _Timer_SetTimer($hDlg, $iHideMenuDelay, '_CheckHoverMenu_Proc')
	
	$aMousePos = MouseGetPos()
	$nResult = _GUICtrlMenu_TrackPopupMenu($hContextMenu, $hDlg, $aMousePos[0] - 27, $aMousePos[1] - 12, 1, 1, 2)
	
	_Timer_KillTimer($hDlg, $hTimer)
	
	Switch $nResult
		Case $nShowMsg_MItem
			MsgBox(64, 'Title', 'My Message')
		Case $nHide_MItem
			;hm... it's already hidden :D
		Case $nExit_MItem
			DllClose($hUser32Dll)
			Exit
	EndSwitch
	
	GUIDelete($hDlg)
EndFunc

Func _CheckHoverMenu_Proc($hWnd, $Msg, $iIDTimer, $dwTime)
	Local $stPoint = DllStructCreate('int X;int Y')
	Local $aMousePos = MouseGetPos()
	
	DllStructSetData($stPoint, 'X', $aMousePos[0])
	DllStructSetData($stPoint, 'Y', $aMousePos[1])
	
	Local $hWndFromPoint = _WinAPI_WindowFromPoint($stPoint)
	
	If _WinAPI_GetClassName($hWndFromPoint) <> '#32768' Then
		Send('{ESC}')
	EndIf
EndFunc
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Спасибо! Все работает.
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Creator, вот такой вопрос еще возник.

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

Код:
$comments[0][0] = $upperComment
$comments[0][1] = $pattern
$comments[1][0] = $upperComment1
$comments[1][1] = $pattern1
...


Всего в массиве от 4 до 10 (максимум) элементов в первом измерении и 2 элемента во втором измерении.

Вопрос в следующем. Как в создаваемом контекстном меню создать элементы меню, у которых будет надпись = $comments[0][0], а если кликнуть по меню, то выскакивает Msg с текстом = $comments[0][1] ?
 

MnM

Post-Hardcore
Сообщения
679
Репутация
90
Suppir
Так?
Код:
#include <Constants.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>
#include <GUIMenu.au3>
#include <Misc.au3>
#include <Timers.au3>
Global $hUser32Dll = DllOpen('User32.dll')
Global $iHideMenuDelay = 10
Global $Comments[4][2]
$Comments[0][0]="1"
$Comments[0][1]="Еденица"
$Comments[1][0]="2"
$Comments[1][1]="Двойка"
$Comments[2][0]="3"
$Comments[2][1]="Тройка"
$Comments[3][0]="4"
$Comments[3][1]="Четверка"
;Заполнять массив лучше всего при его создании или в цикле for...to...next
Global $iKey = 04
While 1
    If _IsPressed($iKey, $hUser32Dll) Then
        _ShowPopupMenu_Proc()
    Else
        Sleep(100)
    EndIf
WEnd
Func _ShowPopupMenu_Proc()
    Local $hDlg, $cDummy, $nContextMenu, $hContextMenu, $nHide_MItem, $nExit_MItem, $hTimer, $aMousePos, $nResult
	Local $aMenuItem[4]
    $hDlg = GUICreate('', 1, 1, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW)
    $cDummy = GUICtrlCreateDummy()
    $nContextMenu = GUICtrlCreateContextMenu($cDummy)
    $hContextMenu = GUICtrlGetHandle($nContextMenu)
	For $i=0 To UBound($Comments)-1
		$aMenuItem[$i]=GUICtrlCreateMenuItem($Comments[$i][0],$nContextMenu)
	Next
    $nExit_MItem = GUICtrlCreateMenuItem('Exit', $nContextMenu)
    GUISetState(@SW_SHOW, $hDlg)
    $hTimer = _Timer_SetTimer($hDlg, $iHideMenuDelay, '_CheckHoverMenu_Proc')
    $aMousePos = MouseGetPos()
    $nResult = _GUICtrlMenu_TrackPopupMenu($hContextMenu, $hDlg, $aMousePos[0] - 27, $aMousePos[1] - 12, 1, 1, 2)
    _Timer_KillTimer($hDlg, $hTimer)
    Switch $nResult
		Case $aMenuItem[3]
			MsgBox(64,"",$Comments[3][1])
		Case $aMenuItem[2]
			MsgBox(64,"",$Comments[2][1])
		Case $aMenuItem[1]
			MsgBox(64,"",$Comments[1][1])
		Case $aMenuItem[0];Определение нажатого меню в массиве как то можно сократить, но вылетело из головы=(
			MsgBox(64,"",$Comments[0][1])
        Case $nExit_MItem
            DllClose($hUser32Dll)
            Exit
    EndSwitch
    GUIDelete($hDlg)
EndFunc
Func _CheckHoverMenu_Proc($hWnd, $Msg, $iIDTimer, $dwTime)
    Local $stPoint = DllStructCreate('int X;int Y')
    Local $aMousePos = MouseGetPos()
    DllStructSetData($stPoint, 'X', $aMousePos[0])
    DllStructSetData($stPoint, 'Y', $aMousePos[1])
    Local $hWndFromPoint = _WinAPI_WindowFromPoint($stPoint)
    If _WinAPI_GetClassName($hWndFromPoint) <> '#32768' Then
        Send('{ESC}')
    EndIf
EndFunc

CreatoR спасибо за пример то же=)
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
MnM, а если элементов не 4, а от 4 до 10 штук? Потому что массив $Comments генерируется каждый раз при вызове меню и там могут быть разные элементы, разное количество.

Тогда как лучше написать?


Добавлено:
Сообщение автоматически объединено:

Параметр $iHideMenuDelay мне пришлось увеличивать до 100, иначе клик по меню в половине случаев не срабатывал.
 

MnM

Post-Hardcore
Сообщения
679
Репутация
90
Suppir
С костыльками, но с динамическим массивом пунктов меню вполне работает
Код:
#include <Constants.au3>
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <WinAPI.au3>
#include <GUIMenu.au3>
#include <Misc.au3>
#include <Timers.au3>
Global $hUser32Dll = DllOpen('User32.dll')
Global $iHideMenuDelay = 10
Global $Comments[5][2],$IDmenu
$Comments[0][0]="1"
$Comments[0][1]="Еденица"
$Comments[1][0]="2"
$Comments[1][1]="Двойка"
$Comments[2][0]="3"
$Comments[2][1]="Тройка"
$Comments[3][0]="4"
$Comments[3][1]="Четверка"
$Comments[4][0]="5"
$Comments[4][1]="Пятерка"
;Заполнять массив лучше всего при его создании или в цикле for...to...next
Global $iKey = 04
While 1
    If _IsPressed($iKey, $hUser32Dll) Then
        _ShowPopupMenu_Proc()
    Else
        Sleep(100)
    EndIf
WEnd
Func _ShowPopupMenu_Proc()
    Local $hDlg, $cDummy, $nContextMenu, $nHide_MItem, $nExit_MItem, $hTimer, $aMousePos, $nResult
	Global $aMenuItem[UBound($Comments)],$hContextMenu
    $hDlg = GUICreate('', 1, 1, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW)
    $cDummy = GUICtrlCreateDummy()
    $nContextMenu = GUICtrlCreateContextMenu($cDummy)
    $hContextMenu = GUICtrlGetHandle($nContextMenu)
	For $i=0 To UBound($Comments)-1
		$aMenuItem[$i]=GUICtrlCreateMenuItem($Comments[$i][0],$nContextMenu,-1,1)
	Next
    $nExit_MItem = GUICtrlCreateMenuItem('Exit', $nContextMenu)
	GUIRegisterMsg($wm_menuselect,"__MenuSelect")
    GUISetState(@SW_SHOW, $hDlg)
    $hTimer = _Timer_SetTimer($hDlg, $iHideMenuDelay, '_CheckHoverMenu_Proc')
    $aMousePos = MouseGetPos()
    $nResult = _GUICtrlMenu_TrackPopupMenu($hContextMenu, $hDlg, $aMousePos[0] - 27, $aMousePos[1] - 12, 1, 1,2)
    _Timer_KillTimer($hDlg, $hTimer)
    Switch $nResult
		Case $aMenuItem[0] To $aMenuItem[UBound($aMenuItem)-1]
			MsgBox(64,'',$Comments[$IDmenu][1])
        Case $nExit_MItem
            DllClose($hUser32Dll)
            Exit
    EndSwitch
    GUIDelete($hDlg)
EndFunc
Func __MenuSelect($hWnd,$Msg,$wParam,$lParam)
	If $lParam=$hContextMenu Then
		Local $id=BitAND($wParam,0xFFFF)
		Switch $id
			Case $aMenuItem[0] To $aMenuItem[UBound($aMenuItem)-1]
				For $i=0 To UBound($aMenuItem)-1
					If $id=$aMenuItem[$i] Then
						$IDmenu=$i
						ExitLoop
					EndIf
				Next
		EndSwitch
	EndIf
EndFunc
Func _CheckHoverMenu_Proc($hWnd, $Msg, $iIDTimer, $dwTime)
    Local $stPoint = DllStructCreate('int X;int Y')
    Local $aMousePos = MouseGetPos()
    DllStructSetData($stPoint, 'X', $aMousePos[0])
    DllStructSetData($stPoint, 'Y', $aMousePos[1])
    Local $hWndFromPoint = _WinAPI_WindowFromPoint($stPoint)
    If _WinAPI_GetClassName($hWndFromPoint) <> '#32768' Then
        Send('{ESC}')
    EndIf
EndFunc
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Я что-то не пойму. Написал свой код, практически такой же:

Код:
Func _ShowPopupMenu_Proc()
    Local $hDlg, $cDummy, $nContextMenu, $nHide_MItem, $nExit_MItem, $hTimer, $aMousePos, $nResult
    Global $aMenuItem[UBound($Comments)],$hContextMenu
    $hDlg = GUICreate('', 1, 1, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW)
    $cDummy = GUICtrlCreateDummy()
    $nContextMenu = GUICtrlCreateContextMenu($cDummy)
    $hContextMenu = GUICtrlGetHandle($nContextMenu)
    For $i=0 To UBound($Comments)-1
        $aMenuItem[$i]=GUICtrlCreateMenuItem($Comments[$i][0],$nContextMenu,-1,1)
    Next
    $nExit_MItem = GUICtrlCreateMenuItem('Exit', $nContextMenu)
    GUIRegisterMsg($wm_menuselect,"__MenuSelect")
    GUISetState(@SW_SHOW, $hDlg)
    $hTimer = _Timer_SetTimer($hDlg, 70, '_CheckHoverMenu_Proc')
    $aMousePos = MouseGetPos()
    $nResult = _GUICtrlMenu_TrackPopupMenu($hContextMenu, $hDlg, $aMousePos[0] - 27, $aMousePos[1] - 12, 1, 1,2)
    _Timer_KillTimer($hDlg, $hTimer)
    Switch $nResult
        Case $aMenuItem[0] To $aMenuItem[UBound($aMenuItem)-1]
            MsgBox(64,'',$Comments[$IDmenu][1])
        Case $nExit_MItem
            DllClose($hUser32Dll)
            Exit
    EndSwitch
    GUIDelete($hDlg)
EndFunc

Func __MenuSelect($hWnd,$Msg,$wParam,$lParam)
    If $lParam=$hContextMenu Then
        Local $id=BitAND($wParam,0xFFFF)
        Switch $id
            Case $aMenuItem[0] To $aMenuItem[UBound($aMenuItem)-1]
                For $i=0 To UBound($aMenuItem)-1
                    If $id=$aMenuItem[$i] Then
                        $IDmenu=$i
                        ExitLoop
                    EndIf
                Next
        EndSwitch
    EndIf
EndFunc


Func _CheckHoverMenu_Proc($hWnd, $Msg, $iIDTimer, $dwTime)
    Local $stPoint = DllStructCreate('int X;int Y')
    Local $aMousePos = MouseGetPos()
    DllStructSetData($stPoint, 'X', $aMousePos[0])
    DllStructSetData($stPoint, 'Y', $aMousePos[1])
    Local $hWndFromPoint = _WinAPI_WindowFromPoint($stPoint)
    If _WinAPI_GetClassName($hWndFromPoint) <> '#32768' Then
        Send('{ESC}')
    EndIf
EndFunc


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


Добавлено:
Сообщение автоматически объединено:

А, все, разобрался. У меня хоткей Esc был забит на выход из программы. Этот хоткей конфликтовал с
Код:
If _WinAPI_GetClassName($hWndFromPoint) <> '#32768' Then
        Send('{ESC}')
    EndIf
 
Верх