pixelsearch Posted Wednesday at 09:11 AM Posted Wednesday at 09:11 AM (edited) Hi everybody This script displays a big MessageBox having a height higher than @DesktopHeight While the MessageBox is displayed, you can "navigate" inside it like this : * Mouse Left-click drag : to move the window up and down (displaying a new panel of lines) * Mouse Right-click : to display the window at its initial position * Up key * Down key * PageUp Key (Fn + up key on some laptops) * PageDown Key (Fn + down key on some laptops) * Home Key (Fn + left key on some laptops) * End Key (Fn + right key on some laptops) The 6 keyboard keys allow to navigate inside the window. Click on a button (placed at top of the window) to make your choice. All this could have been scripted more easily using a GUI, an Edit control containing the text to display, plus the buttons to choose from, but I just wanted to try it using a native MessageBox expandcollapse popup#include <APISysConstants.au3> ; $GCL_HCURSOR #include <ButtonConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <Misc.au3> #include <MsgBoxConstants.au3> #include <StaticConstants.au3> #include <WinAPIRes.au3> ; _WinAPI_LoadCursor() #include <WinAPISysWin.au3> ; _WinAPI_SetClassLongEx() #include <WindowsConstants.au3> Opt("MustDeclareVars", 1) ;0=no, 1=require pre-declaration Global $g_hGUI, $g_hDLL = DllOpen("user32.dll") Global $g_aCaption, $g_sTitle Example() ;=========================================== Func Example() $g_hGUI = GUICreate("Big MsgBox example", 400, 200) GUICtrlCreateLabel("Number of lines in MsgBox (2 - 1588)", 10, 20, 180, 20, $SS_SUNKEN) Local $idNbLines = GUICtrlCreateInput("200", 200, 20, 35, 20, BitOR($GUI_SS_DEFAULT_INPUT, $ES_NUMBER)), $iNbLines GUICtrlSetLimit($idNbLines, 4) Local $idMsgBox = GUICtrlCreateButton("Big MsgBox", 10, 60, 100, 25, $BS_DEFPUSHBUTTON) Local $idExit = GUICtrlCreateButton("Exit", 10, 110, 100, 25) GUISetState() While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idExit ExitLoop Case $idMsgBox Local $iRet = Prepare_MsgBox(GUICtrlRead($idNbLines)) If $iRet Then MsgBox($MB_TOPMOST, "Big MsgBox return value", $iRet, 0, $g_hGUI) GUICtrlSetState($idNbLines, $GUI_FOCUS) EndSwitch WEnd DllClose($g_hDLL) EndFunc ;==>Example ;=========================================== Func Prepare_MsgBox(Const $iNbLines) If $iNbLines < 2 Or $iNbLines > 1588 Then MsgBox($MB_TOPMOST, "Error", "Enter a number of lines between 2 and 1588", 0, $g_hGUI) Return ; 0 EndIf Local $sTxt = "Line 1 : first line" & @crlf For $i = 2 To $iNbLines - 1 $sTxt &= "Line " & $i & @crlf Next $sTxt &= "Line " & $iNbLines & " : last line" Dim $g_aCaption[3] = ["Cancel", "Try Again", "Continue"] $g_sTitle = "MsgBox with 3 buttons" Local $iChoice = _MsgBox(BitOr($MB_CANCELTRYCONTINUE, $MB_TOPMOST), $g_sTitle, $sTxt, 0, $g_hGUI) ;~ Dim $g_aCaption[2] = ["Yes", "No"] ;~ $g_sTitle = "MsgBox with 2 buttons" ;~ Local $iChoice = _MsgBox(BitOr($MB_YESNO, $MB_TOPMOST), $g_sTitle, $sTxt, 0, $g_hGUI) ;~ Dim $g_aCaption[1] = ["OK"] ;~ $g_sTitle = "MsgBox with 1 button" ;~ Local $iChoice = _MsgBox(BitOr($MB_OK, $MB_TOPMOST), $g_sTitle, $sTxt, 0, $g_hGUI) Return $iChoice EndFunc ;==>Prepare_MsgBox ;=========================================== Func _MsgBox($iFlag, $g_sTitle, $sText, $iTimeOut = 0, $hWnd = 0) GUIRegisterMsg($WM_HELP , "WM_HELP") Local $hTimerProc = DllCallbackRegister('_MsgBoxTimerProc', 'none', 'hwnd;uint;uint_ptr;dword') Local $iTimerID = _WinAPI_SetTimer(0, 0, 10, DllCallbackGetPtr($hTimerProc)) Local $iChoice = MsgBox($iFlag, $g_sTitle, $sText, $iTimeOut, $hWnd) _WinAPI_KillTimer(0, $iTimerID) DllCallbackFree($hTimerProc) GUIRegisterMsg($WM_HELP, "") Return $iChoice EndFunc ;==>_MsgBox ;=========================================== Func _MsgBoxTimerProc($hWnd, $iMsg, $iTimerID, $iTime) If WinExists($g_sTitle) Then _WinAPI_KillTimer(0, $iTimerID) Local $hMsgBox = WinGetHandle($g_sTitle) Local $aPosMsgBox = WinGetPos($hMsgBox) Local $bTooHigh = ($aPosMsgBox[3] > @DesktopHeight + 15) ? True : False If $bTooHigh Then Local $aPosButton, $aPosStatic = ControlGetPos($hMsgBox, "", "Static1") ; the text area For $i = 0 To Ubound($g_aCaption) - 1 ControlSetText($hMsgBox, "", "Button" & ($i + 1), $g_aCaption[$i]) $aPosButton = ControlGetPos($hMsgBox, "", "Button" & ($i + 1)) WinMove(ControlGetHandle($hMsgBox, "", "Button" & ($i + 1)), "", $aPosButton[0], $aPosStatic[1]) Next WinMove(ControlGetHandle($hMsgBox, "", "Static1"), "", $aPosStatic[0], $aPosStatic[1] + $aPosButton[3] + 10) _WinAPI_RedrawWindow($hMsgBox) ; +++ Send("{F1}") ; => Func WM_HELP Else For $i = 0 To Ubound($g_aCaption) - 1 ControlSetText($hMsgBox, "", "Button" & ($i + 1), $g_aCaption[$i]) Next EndIf EndIf EndFunc ;==>_MsgBoxTimerProc ;============================================== Func WM_HELP($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam If WinExists($g_sTitle) Then ; MessageBox window always exists at this stage Local $hMsgBox = WinGetHandle($g_sTitle) Local $aPosMsgBox = WinGetPos($hMsgBox), $aPosMsgBox_Init = $aPosMsgBox Local $aWinPos, $aMPos, $aMPosOld Local $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZEALL) ; $OCR_SIZENS ok too Local $iPrev = _WinAPI_SetClassLongEx($hMsgBox, $GCL_HCURSOR, $hCursor) ; see "147c.au3" HotKeySet("{SPACE}", "_Space") While 1 If WinActive($hMsgBox) Then Select Case _IsPressed("01", $g_hDLL) ; "01" = Left mouse button $aMPosOld = MouseGetPos() While _IsPressed("01", $g_hDLL) $aMPos = MouseGetPos() If $aMPos[1] <> $aMPosOld[1] Then $aWinpos = WinGetPos($hMsgBox) If ($aMPos[0] - 1 > $aWinpos[0]) And ($aMPos[0] + 1 < $aWinpos[0] + $aWinpos[2]) Then WinMove($hMsgBox, "", Default, $aWinpos[1] + ($aMPos[1] - $aMPosOld[1])) $aMPosOld = $aMPos EndIf EndIf Sleep(10) Wend Case _IsPressed("02", $g_hDLL) ; Right mouse button WinMove($hMsgBox, "", $aPosMsgBox_Init[0], $aPosMsgBox_Init[1]) Case _IsPressed("21", $g_hDLL) ; PageUp Key While _IsPressed("21", $g_hDLL) Sleep(10) Wend $aPosMsgBox = WinGetPos($hMsgBox) WinMove( $hMsgBox, "", Default, ($aPosMsgBox[1] + @DesktopHeight > 0) ? 0 : $aPosMsgBox[1] + @DesktopHeight ) Case _IsPressed("22", $g_hDLL) ; PageDown Key While _IsPressed("22", $g_hDLL) Sleep(10) Wend $aPosMsgBox = WinGetPos($hMsgBox) WinMove( $hMsgBox, "", Default, _ ($aPosMsgBox[3] + $aPosMsgBox[1] - @DesktopHeight < @DesktopHeight + 15) ? @DesktopHeight - $aPosMsgBox[3] : $aPosMsgBox[1] - @DesktopHeight ) Case _IsPressed("23", $g_hDLL) ; End Key $aPosMsgBox = WinGetPos($hMsgBox) WinMove($hMsgBox, "", Default, @DesktopHeight - $aPosMsgBox[3]) Case _IsPressed("24", $g_hDLL) ; Home Key WinMove($hMsgBox, "", Default, 0) Case _IsPressed("26", $g_hDLL) ; Up Key $aPosMsgBox = WinGetPos($hMsgBox) WinMove($hMsgBox, "", Default, ($aPosMsgBox[1] + 12 > 0) ? 0 : $aPosMsgBox[1] + 12) Case _IsPressed("28", $g_hDLL) ; Down Key $aPosMsgBox = WinGetPos($hMsgBox) WinMove( $hMsgBox, "", Default, _ ($aPosMsgBox[3] + $aPosMsgBox[1] - 12 < @DesktopHeight) ? @DesktopHeight - $aPosMsgBox[3] : $aPosMsgBox[1] - 12 ) EndSelect EndIf If Not BitAND(WinGetState($hMsgBox), $WIN_STATE_VISIBLE) Then ; one of MsgBox buttons was clicked ExitLoop EndIf Sleep(10) WEnd HotKeySet("{SPACE}") _WinAPI_SetClassLongEx($hMsgBox, $GCL_HCURSOR, $iPrev) ; needed, or cursor $OCR_SIZEALL will show... in final MsgBox from main loop EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_HELP ;============================================== Func _Space() HotKeySet("{SPACE}") ; deactivate Hotkey If WinActive($g_sTitle) Then HotKeySet("{SPACE}", "_DoNothing") ; this part to avoid a MsgBox button being triggered, when Spacebar key is pressed too long. While _IsPressed("20", $g_hDLL) ; Spacebar key Sleep(10) Wend Else Send("{SPACE}") EndIf HotKeySet("{SPACE}", "_Space") ; reactivate Hotkey EndFunc ;==>_Space ;============================================== Func _DoNothing() EndFunc ;==>_DoNothing Edited Wednesday at 09:19 AM by pixelsearch typo Musashi, funkey, CYCho and 1 other 4 "I think you are searching a bug where there is no bug..."
funkey Posted yesterday at 06:33 AM Posted yesterday at 06:33 AM Thank you. Works great. Only thing is visual issue at last line for me. But no problem. BR funkey pixelsearch 1 Programming today is a race between software engineers striving tobuild bigger and better idiot-proof programs, and the Universetrying to produce bigger and better idiots.So far, the Universe is winning.
pixelsearch Posted just now Author Posted just now Thanks to you guys, who found an interest in this experimental script @funkey tomorrow I'll be able to run the script on a Win11 laptop, to see if the little visual issue you described will show there (does it appear on your side each time you run the script ?) Meanwhile, I'm trying to add a few useful _IsPressed() keys inside Func WM_HELP() For example, in a MsgBox, one press on Right key (or on Tab) should focus the button on the right of the actual focused button. In the pic of my preceding post, the "Cancel" button should then be "unfocused" and the "Try again" button should be focused : Unfortunately, in the doctored MessageBox from the script, nothing happens when you press the Right key ! The beginning of the solution could be scripted like this : Case _IsPressed("27", $g_hDLL) ; Right key (nearly same code for Tab key = 09) While _IsPressed("27", $g_hDLL) Sleep(10) Wend Local $iCtrlGetFocus = StringRight(ControlGetFocus($hMsgBox), 1) ; 1/2/3 (last char of "Button1"/"Button2"/"Button3") Local $iCtrlSetFocus = $iCtrlGetFocus < Ubound($g_aCaption) ? $iCtrlGetFocus + 1 : 1 ControlFocus($hMsgBox, "", "Button" & $iCtrlSetFocus) ; correct display after window change. How to improve it ? 1) But that's not enough. If you insert the 7 preceding lines in the script (inside the While 1 loop of Func Help) then run the script, press one time the Right key, then... the focus doesn't change : it is still on the 'Cancel' button BUT now if you select manually another window, then back to the MsgBox window, you'll see that the focus IS correct ('Try again') . So the question is : what should be done easily to "refresh" the MsgBox so it displays correctly the new focused button ? Because swapping manually windows to refresh the focus isn't user friendly at all, _WinAPI_RedrawWindow or _WinAPI_SetWindowPos don't seem to help here (tested) . So if someone got a simple solution for this "focused button refresh", I'll take it, thanks. 2) In fact I just found a working solution for this "non refreshment" issue, based on $BS_DEFPUSHBUTTON : if we remove it from the button that doesn't have the focus anymore ('Cancel') and add it to the button having the focus ('Try again') then the display of the new focused button is always correct. So if no new idea appears during the week-end, then I'll add the $BS_DEFPUSHBUTTON part in the script, at the beginning of the week (taking care of Left key too etc...) Thanks for reading and have a great week-end everybody "I think you are searching a bug where there is no bug..."
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now