Files
2026-07-13 13:39:12 +08:00

100 lines
3.0 KiB
PowerShell

# OmniRoute tray icon for Windows using NotifyIcon (zero binary, AV-safe)
# IPC: stdin JSON commands, stdout JSON events
param([string]$IconPath, [string]$Tooltip)
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$ErrorActionPreference = "Stop"
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::InputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$script:notifyIcon = New-Object System.Windows.Forms.NotifyIcon
if ($IconPath -and (Test-Path $IconPath)) {
if ($IconPath.ToLower().EndsWith('.ico')) {
$script:notifyIcon.Icon = New-Object System.Drawing.Icon($IconPath)
} else {
# Accepts .png and other bitmap formats via GDI+ handle conversion
$bitmap = New-Object System.Drawing.Bitmap($IconPath)
$handle = $bitmap.GetHicon()
$script:notifyIcon.Icon = [System.Drawing.Icon]::FromHandle($handle)
$bitmap.Dispose()
}
} else {
$script:notifyIcon.Icon = [System.Drawing.SystemIcons]::Application
}
$script:notifyIcon.Text = $Tooltip
$script:notifyIcon.Visible = $true
$script:menu = New-Object System.Windows.Forms.ContextMenuStrip
$script:notifyIcon.ContextMenuStrip = $script:menu
$script:items = @()
function Write-Event($obj) {
$json = $obj | ConvertTo-Json -Compress
[Console]::Out.WriteLine($json)
[Console]::Out.Flush()
}
function Add-MenuItem($index, $title, $enabled) {
$item = New-Object System.Windows.Forms.ToolStripMenuItem
$item.Text = $title
$item.Enabled = $enabled
$idx = $index
$item.Add_Click({ Write-Event @{ type = "click"; index = $idx } }.GetNewClosure())
$script:menu.Items.Add($item) | Out-Null
$script:items += $item
}
function Update-MenuItem($index, $title, $enabled) {
if ($index -lt $script:items.Count) {
$script:items[$index].Text = $title
$script:items[$index].Enabled = $enabled
}
}
function Set-Tooltip($text) {
if ($text.Length -gt 63) { $text = $text.Substring(0, 63) }
$script:notifyIcon.Text = $text
}
# Read commands from stdin on a timer to keep the Windows message loop alive
$reader = [Console]::In
$script:running = $true
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 100
$timer.Add_Tick({
while ($reader.Peek() -ge 0) {
$line = $reader.ReadLine()
if ($null -eq $line) {
$script:notifyIcon.Visible = $false
[System.Windows.Forms.Application]::Exit()
return
}
try {
$cmd = $line | ConvertFrom-Json
switch ($cmd.type) {
"setMenu" {
$script:menu.Items.Clear()
$script:items = @()
for ($i = 0; $i -lt $cmd.items.Count; $i++) {
$it = $cmd.items[$i]
Add-MenuItem $i $it.title $it.enabled
}
}
"updateItem" { Update-MenuItem $cmd.index $cmd.title $cmd.enabled }
"setTooltip" { Set-Tooltip $cmd.text }
"quit" {
$script:notifyIcon.Visible = $false
[System.Windows.Forms.Application]::Exit()
}
}
} catch {}
}
})
$timer.Start()
Write-Event @{ type = "ready" }
[System.Windows.Forms.Application]::Run()