Page 1 of 2

Display ripple effect when mouse click

Posted: 20 Jul 2015, 22:02
by mright
This script can show a little ripple effect when you left/right click the mouse button.
When the mouse is idle for five seconds or you press left control key, display the ripple to indicate the location of the cursor.

Code: Select all

#NoEnv
CoordMode Mouse, Screen
Setup()

~LButton::ShowRipple(LeftClickRippleColor)
~RButton::ShowRipple(RightClickRippleColor)
~LControl Up::ShowRipple(MouseIdleRippleColor)

Setup()
{
    Global
    RippleWinSize := 200
    RippleStep := 10
    RippleMinSize := 10
    RippleMaxSize := RippleWinSize - 20
    RippleAlphaMax := 0x60
    RippleAlphaStep := RippleAlphaMax // ((RippleMaxSize - RippleMinSize) / RippleStep)
    RippleVisible := False
    LeftClickRippleColor := 0xff0000
    RightClickRippleColor := 0x0000ff
    MouseIdleRippleColor := 0x008000
    
    DllCall("LoadLibrary", Str, "gdiplus.dll")
    VarSetCapacity(buf, 16, 0)
    NumPut(1, buf)
    DllCall("gdiplus\GdiplusStartup", UIntP, pToken, UInt, &buf, UInt, 0)
    
    Gui Ripple: -Caption +LastFound +AlwaysOnTop +ToolWindow +Owner +E0x80000
    Gui Ripple: Show, NA, RippleWin
    hRippleWin := WinExist("RippleWin")
    hRippleDC := DllCall("GetDC", UInt, 0)
    VarSetCapacity(buf, 40, 0)
    NumPut(40, buf, 0)
    NumPut(RippleWinSize, buf, 4)
    NumPut(RippleWinSize, buf, 8)
    NumPut(1, buf, 12, "ushort")
    NumPut(32, buf, 14, "ushort")
    NumPut(0, buf, 16)
    hRippleBmp := DllCall("CreateDIBSection", UInt, hRippleDC, UInt, &buf, UInt, 0, UIntP, ppvBits, UInt, 0, UInt, 0)
    DllCall("ReleaseDC", UInt, 0, UInt, hRippleDC)
    hRippleDC := DllCall("CreateCompatibleDC", UInt, 0)
    DllCall("SelectObject", UInt, hRippleDC, UInt, hRippleBmp)
    DllCall("gdiplus\GdipCreateFromHDC", UInt, hRippleDC, UIntP, pRippleGraphics)
    DllCall("gdiplus\GdipSetSmoothingMode", UInt, pRippleGraphics, Int, 4)
    
    MouseGetPos _lastX, _lastY
    SetTimer MouseIdleTimer, 5000
    Return

MouseIdleTimer:
    MouseGetPos _x, _y
    if (_x == _lastX and _y == _lastY)
        ShowRipple(MouseIdleRippleColor, _interval:=20)
    else
        _lastX := _x, _lastY := _y
    Return
}

ShowRipple(_color, _interval:=10)
{
    Global
    if (RippleVisible)
    	Return
    RippleColor := _color
    RippleDiameter := RippleMinSize
    RippleAlpha := RippleAlphaMax
    RippleVisible := True

    MouseGetPos _pointerX, _pointerY
    SetTimer RippleTimer, % _interval
    Return

RippleTimer:
    DllCall("gdiplus\GdipGraphicsClear", UInt, pRippleGraphics, Int, 0)
    if ((RippleDiameter += RippleStep) < RippleMaxSize) {
        DllCall("gdiplus\GdipCreatePen1", Int, ((RippleAlpha -= RippleAlphaStep) << 24) | RippleColor, float, 3, Int, 2, UIntP, pRipplePen)
        DllCall("gdiplus\GdipDrawEllipse", UInt, pRippleGraphics, UInt, pRipplePen, float, 1, float, 1, float, RippleDiameter - 1, float, RippleDiameter - 1)
        DllCall("gdiplus\GdipDeletePen", UInt, pRipplePen)
    }
    else {
        RippleVisible := False
        SetTimer RippleTimer, Off
    }

    VarSetCapacity(buf, 8)
    NumPut(_pointerX - RippleDiameter // 2, buf, 0)
    NumPut(_pointerY - RippleDiameter // 2, buf, 4)
    DllCall("UpdateLayeredWindow", UInt, hRippleWin, UInt, 0, UInt, &buf, Int64p, (RippleDiameter + 5) | (RippleDiameter + 5) << 32, UInt, hRippleDC, Int64p, 0, UInt, 0, UIntP, 0x1FF0000, UInt, 2)
    Return
}

Re: Display ripple effect when mouse click

Posted: 20 Jul 2015, 22:34
by mright
And by the way, I would like to report a strange behavior:
When I was refactoring the previous code, I found that if I rename the variable name "buf" to "temp", then the DllCall("GdiplusStartup"...) function returns an error code 2, which means invalid parameter, this happend to the DllCall("CreateDIBSection",...) call too, but except the name "temp", any other variable name will be ok, is this by design or something?

Re: Display ripple effect when mouse click

Posted: 21 Jul 2015, 03:07
by noname
nice effect :) !

I had the same with "path" variable name the solution is to add #NoEnv at the beginning of your code.

Re: Display ripple effect when mouse click

Posted: 21 Jul 2015, 03:42
by mright
lain wrote:nice effect :) !

I had the same with "path" variable name the solution is to add #NoEnv at the beginning of your code.
Thank you very much! I never thought that environment variables would affect script code.

Re: Display ripple effect when mouse click

Posted: 21 Jul 2015, 03:43
by jNizM
But there is a problem with multi-monitor...

Re: Display ripple effect when mouse click

Posted: 21 Jul 2015, 08:23
by Relayer
This submission packs some of the nuts and bolts in a dll. I believe it is similar but I have not run yours yet.

http://ahkscript.org/boards/viewtopic.p ... trl#p16261

Relayer

Re: Display ripple effect when mouse click

Posted: 24 Jul 2015, 12:26
by gwarble
cool effect... i think you need "coordmode, mouse, screen" or something because it only positions correctly on a full screen window... on a smaller window it "ripples" in the position from the screen top left corner relative to the windows top left corner if that makes sense... that could also be the multi monitor problem

Re: Display ripple effect when mouse click

Posted: 24 Jul 2015, 12:47
by sobuj53
Really cool effect but I'm having some issue like, in Notepad window the ripple effect doesn't correctly shows the mouse ripple effect it also happens in any autohokey generated GUI window. In those instance the mouse ripple happens in different position than actual mouse pointer position. But thanks for your great work :)

Re: Display ripple effect when mouse click

Posted: 24 Jul 2015, 22:43
by boiler
Yes, adding CoordMode, Mouse, Screen as the first line of the script solves the multiple monitor and the other issues for me. Neat script.

Re: Display ripple effect when mouse click

Posted: 25 Jul 2015, 01:17
by sobuj53
Thank you very much, that solves everything :bravo:

Re: Display ripple effect when mouse click

Posted: 17 Sep 2016, 00:18
by SashaChernykh
I'm sorry, that possible separate effect, when I make double-click left mouse button?

Thanks.

Re: Display ripple effect when mouse click

Posted: 15 Oct 2017, 14:30
by robodesign
very nice.... how to make the liner thicker? [never mind; found it]

How to reverse the animation? I would like it reversed for right-click.

Re: Display ripple effect when mouse click

Posted: 18 Oct 2017, 03:53
by Drugwash
Here you are, Marius. I've added the ability to modify the idle timer and the pen width besides reverse animation switch:

Code: Select all

; by mright at  https://autohotkey.com/boards/viewtopic.php?f=6&t=8963&p=176651#p176651
; modded by Drugwash 2017.10.18 for reverse animation, variable idle timer, variable pen width
#NoEnv
#SingleInstance Force
#KeyHistory 0
ListLines Off
SetBatchLines, -1
SetKeyDelay, -1, -1
SetMouseDelay, -1
SetWinDelay, -1
SetControlDelay, -1
CoordMode Mouse, Screen
Setup()

~LButton::ShowRipple(LeftClickRippleColor)
~RButton::ShowRipple(RightClickRippleColor,, 1)
~LControl Up::ShowRipple(MouseIdleRippleColor)

Setup()
{
    Global
    RippleWinSize := 200
    RippleStep := 10
    RippleMinSize := 10
    RippleMaxSize := RippleWinSize - 20
    RippleAlphaMax := 0x60
    RippleAlphaStep := RippleAlphaMax // ((RippleMaxSize - RippleMinSize) / RippleStep)
    RippleVisible := False
    LeftClickRippleColor := 0xff0000
    RightClickRippleColor := 0x0000ff
    MouseIdleRippleColor := 0x008000
    MouseIdleTimer := 5000
    PenWidth := 3
    Rev := 0
    
    DllCall("LoadLibrary", Str, "gdiplus.dll")
    VarSetCapacity(buf, 16, 0)
    NumPut(1, buf)
    DllCall("gdiplus\GdiplusStartup", UIntP, pToken, UInt, &buf, UInt, 0)
    
    Gui Ripple: -Caption +LastFound +AlwaysOnTop +ToolWindow +Owner +E0x80000
    Gui Ripple: Show, NA, RippleWin
    hRippleWin := WinExist("RippleWin")
    hRippleDC := DllCall("GetDC", UInt, 0)
    VarSetCapacity(buf, 40, 0)
    NumPut(40, buf, 0)
    NumPut(RippleWinSize, buf, 4)
    NumPut(RippleWinSize, buf, 8)
    NumPut(1, buf, 12, "ushort")
    NumPut(32, buf, 14, "ushort")
    NumPut(0, buf, 16)
    hRippleBmp := DllCall("CreateDIBSection", UInt, hRippleDC, UInt, &buf, UInt, 0, UIntP, ppvBits, UInt, 0, UInt, 0)
    DllCall("ReleaseDC", UInt, 0, UInt, hRippleDC)
    hRippleDC := DllCall("CreateCompatibleDC", UInt, 0)
    DllCall("SelectObject", UInt, hRippleDC, UInt, hRippleBmp)
    DllCall("gdiplus\GdipCreateFromHDC", UInt, hRippleDC, UIntP, pRippleGraphics)
    DllCall("gdiplus\GdipSetSmoothingMode", UInt, pRippleGraphics, Int, 4)
    
    MouseGetPos _lastX, _lastY
    SetTimer MouseIdleTimer, %MouseIdleTimer%
    Return

MouseIdleTimer:
    MouseGetPos _x, _y
    if (_x == _lastX and _y == _lastY)
        ShowRipple(MouseIdleRippleColor, _interval:=20)
    else
        _lastX := _x, _lastY := _y
    Return
}

ShowRipple(_color, _interval:=10, _rs:=0)
{
    Global
    if (RippleVisible)
    	Return
    RippleColor := _color
    RippleDiameter := _rs ? RippleMaxSize : RippleMinSize
    RippleAlpha := RippleAlphaMax
    RippleVisible := True
    Rev := _rs

    MouseGetPos _pointerX, _pointerY
    SetTimer RippleTimer, % _interval
    Return

RippleTimer:
    DllCall("gdiplus\GdipGraphicsClear", UInt, pRippleGraphics, Int, 0)
    RippleDiameter := Rev ? RippleDiameter - RippleStep : RippleDiameter + RippleStep
    if (Rev && (RippleDiameter > RippleMinSize)) OR (!Rev && (RippleDiameter < RippleMaxSize)) {
        DllCall("gdiplus\GdipCreatePen1", Int, ((RippleAlpha -= RippleAlphaStep) << 24) | RippleColor, float, PenWidth, Int, 2, UIntP, pRipplePen)
        DllCall("gdiplus\GdipDrawEllipse", UInt, pRippleGraphics, UInt, pRipplePen, float, 1, float, 1, float, RippleDiameter - 1, float, RippleDiameter - 1)
        DllCall("gdiplus\GdipDeletePen", UInt, pRipplePen)
    }
    else {
        RippleVisible := False
        SetTimer RippleTimer, Off
    }

    VarSetCapacity(buf, 8)
    NumPut(_pointerX - RippleDiameter // 2, buf, 0)
    NumPut(_pointerY - RippleDiameter // 2, buf, 4)
    DllCall("UpdateLayeredWindow", UInt, hRippleWin, UInt, 0, UInt, &buf, Int64p, (RippleDiameter + 5) | (RippleDiameter + 5) << 32, UInt, hRippleDC, Int64p, 0, UInt, 0, UIntP, 0x1FF0000, UInt, 2)
    Return
}


Re: Display ripple effect when mouse click

Posted: 18 Oct 2017, 07:31
by robodesign
Thank you very much Drugwash.

The main problem is that I cannot integrate it into my script, at least I failed to do so...

KeyPress uses Hotkey command to bind to the mouse buttons and this one, labels. If I invoke ShowRipple() function from different threads, other than ~LButton, it does not work.

got any suggestions? I thought of implementing visual mouse clicks in another way, without this script, because of this.

Best regards, Marius

Re: Display ripple effect when mouse click

Posted: 18 Oct 2017, 12:21
by Drugwash
I'll have to check that tomorrow, time allowing; right now I'm exhausted, been working in the garden all day.
In the mean time make sure you have

Code: Select all

CoordMode Mouse, Screen
Setup()
in the autoexec section of HotkeyOSD and nothing else interferes with that CoordMode and with any of the global variables declared in Setup(). Also make sure you call ShowRipple() with a valid color as first parameter and maybe call it on a timer right before exiting the hotkey command, like SetTimer, showRipple, -1 where showRipple is a label that actually calls ShowRipple().

Just noticed the script doesn't invoke GdiplusShutdown before exit.

Re: Display ripple effect when mouse click

Posted: 19 Oct 2017, 13:03
by Reloaded
Pretty Cool ! :)

Re: Display ripple effect when mouse click

Posted: 13 Sep 2021, 16:53
by asenx
Drugwash wrote:
18 Oct 2017, 03:53
Here you are, Marius. I've added the ability to modify the idle timer and the pen width besides reverse animation switch:

Code: Select all

; by mright at  https://autohotkey.com/boards/viewtopic.php?f=6&t=8963&p=176651#p176651
; modded by Drugwash 2017.10.18 for reverse animation, variable idle timer, variable pen width
#NoEnv
#SingleInstance Force
#KeyHistory 0
ListLines Off
SetBatchLines, -1
SetKeyDelay, -1, -1
SetMouseDelay, -1
SetWinDelay, -1
SetControlDelay, -1
CoordMode Mouse, Screen
Setup()

~LButton::ShowRipple(LeftClickRippleColor)
~RButton::ShowRipple(RightClickRippleColor,, 1)
~LControl Up::ShowRipple(MouseIdleRippleColor)

Setup()
{
    Global
    RippleWinSize := 200
    RippleStep := 10
    RippleMinSize := 10
    RippleMaxSize := RippleWinSize - 20
    RippleAlphaMax := 0x60
    RippleAlphaStep := RippleAlphaMax // ((RippleMaxSize - RippleMinSize) / RippleStep)
    RippleVisible := False
    LeftClickRippleColor := 0xff0000
    RightClickRippleColor := 0x0000ff
    MouseIdleRippleColor := 0x008000
    MouseIdleTimer := 5000
    PenWidth := 3
    Rev := 0
    
    DllCall("LoadLibrary", Str, "gdiplus.dll")
    VarSetCapacity(buf, 16, 0)
    NumPut(1, buf)
    DllCall("gdiplus\GdiplusStartup", UIntP, pToken, UInt, &buf, UInt, 0)
    
    Gui Ripple: -Caption +LastFound +AlwaysOnTop +ToolWindow +Owner +E0x80000
    Gui Ripple: Show, NA, RippleWin
    hRippleWin := WinExist("RippleWin")
    hRippleDC := DllCall("GetDC", UInt, 0)
    VarSetCapacity(buf, 40, 0)
    NumPut(40, buf, 0)
    NumPut(RippleWinSize, buf, 4)
    NumPut(RippleWinSize, buf, 8)
    NumPut(1, buf, 12, "ushort")
    NumPut(32, buf, 14, "ushort")
    NumPut(0, buf, 16)
    hRippleBmp := DllCall("CreateDIBSection", UInt, hRippleDC, UInt, &buf, UInt, 0, UIntP, ppvBits, UInt, 0, UInt, 0)
    DllCall("ReleaseDC", UInt, 0, UInt, hRippleDC)
    hRippleDC := DllCall("CreateCompatibleDC", UInt, 0)
    DllCall("SelectObject", UInt, hRippleDC, UInt, hRippleBmp)
    DllCall("gdiplus\GdipCreateFromHDC", UInt, hRippleDC, UIntP, pRippleGraphics)
    DllCall("gdiplus\GdipSetSmoothingMode", UInt, pRippleGraphics, Int, 4)
    
    MouseGetPos _lastX, _lastY
    SetTimer MouseIdleTimer, %MouseIdleTimer%
    Return

MouseIdleTimer:
    MouseGetPos _x, _y
    if (_x == _lastX and _y == _lastY)
        ShowRipple(MouseIdleRippleColor, _interval:=20)
    else
        _lastX := _x, _lastY := _y
    Return
}

ShowRipple(_color, _interval:=10, _rs:=0)
{
    Global
    if (RippleVisible)
    	Return
    RippleColor := _color
    RippleDiameter := _rs ? RippleMaxSize : RippleMinSize
    RippleAlpha := RippleAlphaMax
    RippleVisible := True
    Rev := _rs

    MouseGetPos _pointerX, _pointerY
    SetTimer RippleTimer, % _interval
    Return

RippleTimer:
    DllCall("gdiplus\GdipGraphicsClear", UInt, pRippleGraphics, Int, 0)
    RippleDiameter := Rev ? RippleDiameter - RippleStep : RippleDiameter + RippleStep
    if (Rev && (RippleDiameter > RippleMinSize)) OR (!Rev && (RippleDiameter < RippleMaxSize)) {
        DllCall("gdiplus\GdipCreatePen1", Int, ((RippleAlpha -= RippleAlphaStep) << 24) | RippleColor, float, PenWidth, Int, 2, UIntP, pRipplePen)
        DllCall("gdiplus\GdipDrawEllipse", UInt, pRippleGraphics, UInt, pRipplePen, float, 1, float, 1, float, RippleDiameter - 1, float, RippleDiameter - 1)
        DllCall("gdiplus\GdipDeletePen", UInt, pRipplePen)
    }
    else {
        RippleVisible := False
        SetTimer RippleTimer, Off
    }

    VarSetCapacity(buf, 8)
    NumPut(_pointerX - RippleDiameter // 2, buf, 0)
    NumPut(_pointerY - RippleDiameter // 2, buf, 4)
    DllCall("UpdateLayeredWindow", UInt, hRippleWin, UInt, 0, UInt, &buf, Int64p, (RippleDiameter + 5) | (RippleDiameter + 5) << 32, UInt, hRippleDC, Int64p, 0, UInt, 0, UIntP, 0x1FF0000, UInt, 2)
    Return
}

Do you know why your script spontaneously draws circles even without a mouse click?

Re: Display ripple effect when mouse click

Posted: 13 Sep 2021, 16:59
by asenx
@Drugwash Also, if you double-click, the script can't interrupt the animation of the first click and start the second one.

Re: Display ripple effect when mouse click

Posted: 13 Sep 2021, 17:56
by sofista
asenx wrote:
13 Sep 2021, 16:53
Do you know why your script spontaneously draws circles even without a mouse click?
From the first post of this same thread: "When the mouse is idle for five seconds or you press left control key, display the ripple to indicate the location of the cursor."

Re: Display ripple effect when mouse click

Posted: 14 Sep 2021, 03:21
by Drugwash
asenx wrote:
13 Sep 2021, 16:59
@Drugwash Also, if you double-click, the script can't interrupt the animation of the first click and start the second one.
My apologies, it's been a long time since last working on this. I believe a better version has been implemented in @robodesign's Keypress OSD.

On a related note, in Linux under Wine after latest updates this script behaves much worse than before - not that it ever worked correctly anyway - so it would be quite hard if not impossible for me to try and fix this script now. :(
asenx wrote:
13 Sep 2021, 16:53
Do you know why your script spontaneously draws circles even without a mouse click?
As @sofista mentioned above there is an idle timer that kicks in. If you don't want that you can simply comment out this line:
SetTimer MouseIdleTimer, %MouseIdleTimer%