Maybe this is helpful for somebody. I got tons of helf from this forum, so here's some return on investment (if only little). There's probalby also alot of room for improvement, so any feedback is appreciated as well.
Greets.
Code: Select all
; Example
success := ShowInfoGuiUntilNextEvent("Now click on button xy", event:="LClick", &clickX:=0, &clickY:=0, &dragToX:=0, &dragToY:=0, fontColor:="Red", fontSize:=20, bgColor:="AAAAAA", offsetX:=-250, offsetY:=50, guiWidth:=500, timeOut:=10000)
MsgBox("Action was timed out or escaped: " . !success)
return
; shows a transparent info gui that follows the mouse, to tell the user what to do for next mouse click
; - msg: the message to show
; - event: the event that is waited for to make the gui disappear again, can be LClick, LClickOrDrag, LDrag, MClick, MClickOrDrag, MDrag, RClick, RClickOrDrag, RDrag, X = any event
; - fontColor: the color of the text
; - fontSize: the size of the text
; - bgColor: the color of the background. use "AAAAAA" for transparent
; - offsetX/Y: the offset from the mouse pointer
; - guiwidth: the width of the gui in pixels
; - timeOut: time in Milliseconds, before the GUI is dismissed. 0 is never
; returns true if the user clicked, false if escape was pressed
; returns by reference the location where click occurred (clickX and clickY)
ShowInfoGuiUntilNextEvent(msg, event:="LClick", &clickX:=0, &clickY:=0, &dragToX:=0, &dragToY:=0, fontColor:="Red", fontSize:=20, bgColor:="AAAAAA", offsetX:=20, offsetY:=20, guiWidth:=1000, timeOut:=0) {
global showInfoGui := true ; global variables to communicate between functions
global infoGuiQuitEvent := ""
global infoGuiOffsetX := offsetX
global infoGuiOffsetY := offsetY
global infoGuiEvent := event
global infoGuiClickX := 0
global infoGuiClickY := 0
global infoGuiDragToX := 0
global infoGuiDragToY := 0
global infoGuiTimeOutText
startTime := A_TickCount
if WinExist("InfoGuiWinTitle") ; if function is called when a window is being shown - immediatly return
return
; 1) create GUI
InfoGui := Gui("+LastFound +AlwaysOnTop -DPIScale -Caption +ToolWindow +Border", "InfoGuiWinTitle")
InfoGui.BackColor := bgColor, InfoGui.MarginX := "5", InfoGui.MarginY := "5"
InfoGui.SetFont("s12 underline c" . fontColor, "Verdana")
InfoGui.Add("Text", "section", "MyApp User Guidance")
InfoGui.SetFont("s12 norm c" . fontColor, "Verdana")
InfoGui.Add("Text", "x+10", "(hit 'Esc' to chancel)")
if (timeOut > 0)
timeoutTextCtrl := InfoGui.Add("Text", "x+5 vinfoGuiTimeOutText", "- TimeOut in XXX")
InfoGui.SetFont("s" . fontSize . " norm bold c" . fontColor, "Verdana")
InfoGui.Add("Text", "xs y+5 w" . guiWidth, msg)
InfoGui.Show("NoActivate AutoSize")
if (bgColor == "AAAAAA")
WinSetTransColor("AAAAAA", "InfoGuiWinTitle")
; 2) wait for next click or esc to delete gui again - showing timeout if necessary
while (showInfoGui && (((A_TickCount - startTime) < timeOut) || (timeOut == 0)) ) {
if (timeOut > 0) {
timeLeft := Round((timeOut - (A_TickCount - startTime)) / 1000)
timeoutTextCtrl.Value := "- TimeOut in " timeLeft "s"
}
MoveInfoGui()
Sleep(50)
}
; 3) clean up
InfoGui.Destroy()
clickX := infoGuiClickX
clickY := infoGuiClickY
dragToX := infoGuiDragToX
dragToY := infoGuiDragToY
return (infoGuiQuitEvent == event)
}
#HotIf WinExist("InfoGuiWinTitle")
~LButton:: DetectMouseButtonEvent("LButton") ; ~ send LButton also to underlying app
~MButton:: DetectMouseButtonEvent("MButton") ; keep MButton to script - don't want to start annoying autoscroll-mode in Word
~RButton:: DetectMouseButtonEvent("RButton") ; ~ send RButton also to unterlying app
Esc:: QuitInfoGui("Esc")
#HotIf ;WinExist("InfoGuiWinTitle")
; moves the info gui
MoveInfoGui() {
global infoGuiOffsetX, infoGuiOffsetY
CoordMode("Mouse", "Screen")
MouseGetPos(&mx, &my)
wx := mx + infoGuiOffsetX
wy := my + infoGuiOffsetY
WinMove(wx, wy, , , "InfoGuiWinTitle")
; WinMove, InfoGuiBackgroundWinTitle, , %wx%, %wy%
}
; sets the information to quit the gui and what key was the reason (the quit key)
QuitInfoGui(quitEvent) {
global showInfoGui, infoGuiQuitEvent
showInfoGui := false
infoGuiQuitEvent := quitEvent
}
; determines if a leftclick, middleclick or rightclick was a drag
; - buttonName: is either LButton, MButton, RButton
; returns true if it was a drag
; returns false if the click was less than 200ms, or if drags counts as click
DetectMouseButtonEvent(buttonName := "LButton") {
global showInfoGui
global infoGuiDragIsClick
global infoGuiEvent ; the event that is waited for to make the gui disappear again, can be LClick, LClickOrDrag, LDrag, MClick, MClickOrDrag, MDrag, RClick, RClickOrDrag, RDrag
global infoGuiQuitEvent ; the event that triggered quitting the gui
global infoGuiClickX, infoGuiClickY, infoGuiDragToX, infoGuiDragToY ; the coordinates of the event
startTime := A_TickCount
if (infoGuiEvent == "X") {
eventHappened := true
} else if (SubStr(buttonName, 1, 1) == SubStr(infoGuiEvent, 1, 1)) { ; if the event is for the correct button
CoordMode("Mouse", "Screen")
MouseGetPos(&infoGuiClickX, &infoGuiClickY)
while GetKeyState(buttonName, "P") { ; while Button is pressed
MoveInfoGui() ; move info gui as well during drag
Sleep(30) ; ... wait until it is released
}
MouseGetPos(&infoGuiDragToX, &infoGuiDragToY)
wasDrag := duration := (A_TickCount - startTime) > 200 ; a drag is more than 200ms long
switch SubStr(infoGuiEvent, 2) { ; what event was it?
case "Click": eventHappened := !wasDrag
case "Drag": eventHappened := wasDrag
case "ClickOrDrag": eventHappened := true
Default: eventHappened := false
}
} else {
eventHappened := false ; the defined event is for another button -> return false
}
if eventHappened {
showInfoGui := false
infoGuiQuitEvent := infoGuiEvent
}
}