Help converting OnScreen Display function to v2

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
User avatar
Grendahl
Posts: 170
Joined: 30 Sep 2013, 08:21

Help converting OnScreen Display function to v2

Post by Grendahl » 27 Jan 2023, 20:18

I've got a function from AHK v1.1 that pops up text in an on screen display, and I'm having a bear of a time getting it translated to AHK v2.

Anyone able to assist?

V1.1 code:

Code: Select all

; Function to show OSD text
OSD(Text, Color:="Lime", Size:=24, TimeInSec:=3) {
Progress, y75 B ZH0 FM%Size% CWBlack CT%Color%,,%Text%, OSD, ;https://www.autohotkey.com/docs/commands/Progress.htm
WinSet, TransColor, Black, OSD
If(TimeInSec=0)
	Return
SetTimer, RemoveProgressBar, % TimeInSec * 1000
Return
RemoveProgressBar:
	SetTimer, RemoveProgressBar, Off
	Progress, Off
Return
}
What I've got so far is throwing errors, but here's where I am at with it:

Code: Select all

; Function to show OSD text
OSD(Text, Color:="Lime", Size:=24, TimeInSec:=3) {
	;Progress, y75 B ZH0 FM%Size% CWBlack CT%Color%,,%Text%, OSD, ;https://www.autohotkey.com/docs/commands/Progress.htm
	Progress ("y75 B ZH0 FM" Size " CWBlack CT" Color,,Text, "OSD",) ;https://www.autohotkey.com/docs/commands/Progress.htm
	WinSet(TransColor, "Black", "OSD")
	If(TimeInSec=0)
		Return
	;SetTimer, RemoveProgressBar, % TimeInSec * 1000
	SetTimer RemoveProgressBar, TimeInSec*1000
	Return
	RemoveProgressBar()
	{
		SetTimer RemoveProgressBar, Off
		Progress(Off)
	}
}

User avatar
mikeyww
Posts: 26602
Joined: 09 Sep 2014, 18:38

Re: Help converting OnScreen Display function to v2

Post by mikeyww » 27 Jan 2023, 21:26

Hello,

If you would like to use v2, then you would need to use v2 syntax and v2 functions. It's just a fact. The documentation is available at the Web site.

Code: Select all

; Function to show OSD text
#Requires AutoHotkey v2.0
OSD("TEST", "Lime", Size := 24, TimeInSec := 1)

OSD(Text, Color := "Lime", Size := 24, TimeInSec := 3) {
 gui1 := Gui('+AlwaysOnTop -Caption')
 gui1.SetFont('s' Size)
 gui1.BackColor := 'Black'
 gui1.AddText('c' Color, Text)
 gui1.Show('y75')
 WinSetTransColor 'Black', gui1.Hwnd
 SetTimer () => gui1.Hide(), -1000 * TimeInSec
}

Insaid
Posts: 22
Joined: 03 Jan 2024, 06:33

Re: Help converting OnScreen Display function to v2

Post by Insaid » 26 Feb 2024, 10:07

Hi,

I am using this function in my code but I need a single GUI to exist at a time. That is, if I call the OSD function with a time of 10 seconds and after 5 seconds I create another one with a different text, right now they overlap.

I'm looking for that, regardless of the time left, if I call the function again it will be replaced by the one that is already being displayed.

Any idea how to do it?

I have tried with the Hwnd parameter but I don't know how to refer to the one I have already created.

Thanks to all.

User avatar
Grendahl
Posts: 170
Joined: 30 Sep 2013, 08:21

Re: Help converting OnScreen Display function to v2

Post by Grendahl » 26 Feb 2024, 12:02

do a gui close before you call it the second time

Insaid
Posts: 22
Joined: 03 Jan 2024, 06:33

Re: Help converting OnScreen Display function to v2

Post by Insaid » 26 Feb 2024, 12:24

How do I know which gui I should close?

In general, it closes by itself when the seconds indicated in the parameter pass.

User avatar
mikeyww
Posts: 26602
Joined: 09 Sep 2014, 18:38

Re: Help converting OnScreen Display function to v2

Post by mikeyww » 26 Feb 2024, 12:39

Code: Select all

; Function to show OSD text
#Requires AutoHotkey v2.0
F3::OSD("TEST", "Lime", Size := 24, TimeInSec := 3)
F4::OSD("xxxxxxxxxxx", "Lime", Size := 24, TimeInSec := 1)

OSD(Text, Color := "Lime", Size := 24, TimeInSec := 3) {
 Global gui1
 Try gui1.Destroy
 gui1 := Gui('+AlwaysOnTop -Caption')
 gui1.SetFont('s' Size)
 gui1.BackColor := 'Black'
 gui1.AddText('c' Color, Text)
 gui1.Show('y75')
 WinSetTransColor 'Black', gui1.Hwnd
 SetTimer () => gui1.Hide(), -1000 * TimeInSec
}

Insaid
Posts: 22
Joined: 03 Jan 2024, 06:33

Re: Help converting OnScreen Display function to v2

Post by Insaid » 26 Feb 2024, 13:50

@mikeyww You always help me a lot. Thank you very much for all the doubts solved. Your solutions works fine.

I take this opportunity to ask a couple of extra questions.

I want the Gui to have rounded corners because I am showing a transparent background:

Code: Select all

WinSetTransparent 150, OSDGui.Hwnd
But I can't manage to use WinSetRegion correctly.

I'm also trying to make it tight at the bottom right regardless of the number of rows the text has. I manage to align the gui correctly when it is just a sentence but not when there are line breaks because I don't know the height of the gui before it is displayed.

Any idea how to solve this?

User avatar
mikeyww
Posts: 26602
Joined: 09 Sep 2014, 18:38

Re: Help converting OnScreen Display function to v2

Post by mikeyww » 26 Feb 2024, 14:31

To round all four corners, you might need to use Gdip or a similar technique. I have not done it; you could search the forum.

Code: Select all

; This script gets a GUI's height
#Requires AutoHotkey v2.0
g := Gui('-DPIScale', 'GUI height')
g.SetFont 's20'
g.BackColor := 'Black'
window := g.AddText('cWhite w300 Center')
client := g.AddText('cWhite wp   Center')
g.Show 'Hide'
g.GetPos(,,, &windowHeight)
g.GetClientPos(,,, &clientHeight)
window.Text := 'Window: ' windowHeight
client.Text := 'Client: ' clientHeight
g.Show

XMCQCX
Posts: 225
Joined: 14 Oct 2020, 23:44

Re: Help converting OnScreen Display function to v2

Post by XMCQCX » 26 Feb 2024, 16:17

@Insaid
rounded corners, at the bottom right.

Code: Select all

#SingleInstance Force
#Requires AutoHotkey v2.0

g := Gui('-Caption')
g.SetFont('s30')
g.Add('Text',, 'GUI with rounded corners`npositioned at the bottom right.')
FrameShadow(g.hwnd)

g.Show('Hide')
WinGetPos(,, &gW, &gH, g)
g.Show('x' A_ScreenWidth - gW - 15 'y' A_ScreenHeight - gH - 75)
SetTimer((*) => ExitApp(), -5000)

; Credits Klark92
; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=29117&hilit=FrameShadow

FrameShadow(hwnd)
{
    DllCall("dwmapi.dll\DwmIsCompositionEnabled", "int*", &dwmEnabled:=0)
    
    if !dwmEnabled {
        DllCall("user32.dll\SetClassLongPtr", "ptr", hwnd, "int", -26, "ptr", DllCall("user32.dll\GetClassLongPtr", "ptr", hwnd, "int", -26) | 0x20000)
    }
    else {
        /*
		VarSetCapacity(_MARGINS,16)
		NumPut(1,&_MARGINS,0,"UInt")
		NumPut(1,&_MARGINS,4,"UInt")
		NumPut(1,&_MARGINS,8,"UInt")
		NumPut(1,&_MARGINS,12,"UInt")
        */
        margins := Buffer(16, 0)    
        NumPut("int", 1, "int", 1, "int", 1, "int", 1, margins) ; <= converted from v1 above. I'm not sure about this.

        DllCall("dwmapi.dll\DwmSetWindowAttribute", "ptr", hwnd, "Int", 2, "Int*", 2, "Int", 4)
        DllCall("dwmapi.dll\DwmExtendFrameIntoClientArea", "ptr", hwnd, "ptr", margins)
    }
}

User avatar
mikeyww
Posts: 26602
Joined: 09 Sep 2014, 18:38

Re: Help converting OnScreen Display function to v2

Post by mikeyww » 26 Feb 2024, 16:22

Excellent! :) :thumbup: :wave:

Insaid
Posts: 22
Joined: 03 Jan 2024, 06:33

Re: Help converting OnScreen Display function to v2

Post by Insaid » 27 Feb 2024, 05:03

Thank you all for your help. Now it does just what I wanted.

I have merged both codes together to keep all the functionality.

If the function is called without parameters it will disappear the message that is visible even if the timer is not finished.

Code: Select all

#SingleInstance Force
#Requires AutoHotkey v2.0

OSD("Test 1", , , TimeInSec := 100)
Sleep 3000
OSD("Multiline`nMultiline`nMultiline`n", "White", Size := 24, TimeInSec := 5)
Sleep 3000
OSD("Differents colors", "Red", Size := 24, TimeInSec := 5)
Sleep 3000
OSD()

OSD(Text := "", Color := "White", Size := 24, TimeInSec := 3) {
	Global OSDGui
	Try OSDGui.Destroy

	If (Text = "") 
		TimeInSec := 0.01

	OSDGui := Gui("+AlwaysOnTop -Caption +ToolWindow" )
	OSDGui.SetFont('s' Size)
	OSDGui.BackColor := "Black"
	OSDGui.AddText('c' Color, Text)
        FrameShadow(OSDGui.hwnd)
        OSDGui.Show('Hide')
        WinGetPos(,, &gW, &gH, OSDGui)
        WinSetTransparent 150, OSDGui.Hwnd
        OSDGui.BackColor := "Black"

        OSDGui.Show("NoActivate x" A_ScreenWidth - gW - 15 "y" A_ScreenHeight - gH - 75) ;right
        ;OSDGui.Show("x20 y" A_ScreenHeight - gH - 75) ;left
        SetTimer () => OSDGui.Hide(), -1000 * TimeInSec
}

; Credits Klark92
; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=29117&hilit=FrameShadow

FrameShadow(hwnd)
{
    DllCall("dwmapi.dll\DwmIsCompositionEnabled", "int*", &dwmEnabled:=0)

    if !dwmEnabled {
        DllCall("user32.dll\SetClassLongPtr", "ptr", hwnd, "int", -26, "ptr", DllCall("user32.dll\GetClassLongPtr", "ptr", hwnd, "int", -26) | 0x20000)
    }
    else {
        /*
		VarSetCapacity(_MARGINS,16)
		NumPut(1,&_MARGINS,0,"UInt")
		NumPut(1,&_MARGINS,4,"UInt")
		NumPut(1,&_MARGINS,8,"UInt")
		NumPut(1,&_MARGINS,12,"UInt")
        */
        margins := Buffer(16, 0)
        NumPut("int", 1, "int", 1, "int", 1, "int", 1, margins) ; <= converted from v1 above. I'm not sure about this.

        DllCall("dwmapi.dll\DwmSetWindowAttribute", "ptr", hwnd, "Int", 2, "Int*", 2, "Int", 4)
        DllCall("dwmapi.dll\DwmExtendFrameIntoClientArea", "ptr", hwnd, "ptr", margins)
    }
}

User avatar
mikeyww
Posts: 26602
Joined: 09 Sep 2014, 18:38

Re: Help converting OnScreen Display function to v2

Post by mikeyww » 27 Feb 2024, 05:23

You can remove that line if you wish.

As you have written into your script, your function starts a timer but does not halt the script or cause it to sleep.

The period elapsed is 3 seconds rather than 5 because you sleep for 3 seconds, and at that point, the function is immediately called again, and does what it is programmed to do. This is true for each of the calls and not just the last one.

You can learn how a timer works via the documentation.
Period: If omitted and the timer does not exist, it will be created with a period of 250. If omitted and the timer already exists, it will be reset at its former period unless Priority is specified. Otherwise, the absolute value of this parameter is used as the approximate number of milliseconds that must pass before the timer is executed. The timer will be automatically reset.
What the script does:
Regardless of the time left, if I call the function again it will be replaced by the one that is already being displayed.

Insaid
Posts: 22
Joined: 03 Jan 2024, 06:33

Re: Help converting OnScreen Display function to v2

Post by Insaid » 27 Feb 2024, 14:53

Thank you for your comments.

I know what you're saying. The purpose of sleep is only for testing. In this way it is seen that the notifications do not overlap but rather the previous one is destroyed regardless of the time left.

Post Reply

Return to “Ask for Help (v2)”