ggps.psm1

# Required assemblies for cursor coordinates and Windows messaging
Add-Type -AssemblyName System.Windows.Forms, System.Drawing -ErrorAction SilentlyContinue

# Safe P/Invoke registration: compiles Win32 mouse_event if not already registered in this AppDomain
if (-not ([System.Management.Automation.PSTypeName]'Win32Functions.Win32MouseEvent').Type) {
    $mouseEventSignature = @'
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, UIntPtr dwExtraInfo);
'@

    Add-Type -MemberDefinition $mouseEventSignature -Name 'Win32MouseEvent' -Namespace 'Win32Functions' | Out-Null
}

function gg {
    <#
    .SYNOPSIS
        Simulates subtle mouse clicks to prevent idle timeouts and session lockouts.

    .DESCRIPTION
        Monitors mouse cursor coordinates and sends left-click down/up events with randomized delays.
        Automatically stops if any key is pressed or if significant mouse movement is detected.

    .PARAMETER MinDelayMs
        Minimum delay in milliseconds between mouse down and up events. Default is 125 ms.

    .PARAMETER MaxDelayMs
        Maximum delay in milliseconds between mouse down and up events. Default is 501 ms.

    .PARAMETER MovementThreshold
        Maximum allowed mouse movement in pixels before the loop exits. Default is 5 pixels.

    .EXAMPLE
        gg
        Runs the keep-alive loop with default intervals (125-501ms) and 5px threshold.

    .EXAMPLE
        gg -MinDelayMs 200 -MaxDelayMs 600 -MovementThreshold 10
        Runs with custom delay range and 10px sensitivity threshold.
    #>

    [CmdletBinding()]
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')]
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingEmptyCatchBlock', '')]
    param (
        [Parameter()]
        [int]$MinDelayMs = 125,

        [Parameter()]
        [int]$MaxDelayMs = 501,

        [Parameter()]
        [int]$MovementThreshold = 5
    )

    $iX = [System.Windows.Forms.Cursor]::Position.X
    $iY = [System.Windows.Forms.Cursor]::Position.Y

    Write-Host "Press any key or move the mouse excessively to stop."

    while ($true) {
        # Check for keyboard input to cancel
        try {
            if ([Console]::KeyAvailable) {
                $null = [Console]::ReadKey($true)
                Write-Host "`nstopped"
                break
            }
        } catch [System.InvalidOperationException] {
            # Non-interactive / redirected console
            $null = $_
        }

        # Check for physical mouse movement by user
        $cMX = [System.Windows.Forms.Cursor]::Position.X
        $cMY = [System.Windows.Forms.Cursor]::Position.Y
        if ([Math]::Abs($cMX - $iX) -gt $MovementThreshold -or [Math]::Abs($cMY - $iY) -gt $MovementThreshold) {
            Write-Host "`nexcessive mouse movement"
            break
        }

        # 0x0002 = MOUSEEVENTF_LEFTDOWN, 0x0004 = MOUSEEVENTF_LEFTUP
        [Win32Functions.Win32MouseEvent]::mouse_event(0x00000002, 0, 0, 0, [UIntPtr]::Zero)
        Start-Sleep -Milliseconds (Get-Random -Minimum $MinDelayMs -Maximum $MaxDelayMs)
        [Win32Functions.Win32MouseEvent]::mouse_event(0x00000004, 0, 0, 0, [UIntPtr]::Zero)
        Start-Sleep -Milliseconds (Get-Random -Minimum $MinDelayMs -Maximum $MaxDelayMs)
    }
}

# Export functions for the PowerShell session
Export-ModuleMember -Function 'gg'

# Run 'gg' on module import unless running in non-interactive CI or explicitly bypassed
if (-not $env:CI -and -not $env:GGPS_SKIP_AUTO_RUN) {
    gg
}