Files

65 lines
3.3 KiB
PowerShell
Raw Permalink Normal View History

# Sends an EVision per-key colour frame (same packets as SignalRGB's EVision plugin)
# Usage: evision_led.ps1 -Leds "0=ff0000,21=00ff00" [-Fill 000000] [-Count 128] [-Seconds 0] [-SoftwareMode]
param(
[string]$Leds = '',
[string]$Fill = '000000',
[int]$Count = 128,
[double]$Seconds = 0,
[switch]$SoftwareMode,
[string]$Match = 'VID_320F&PID_502A&MI_01&COL04'
)
Add-Type @"
using System;
using System.Runtime.InteropServices;
public static class EV {
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
public static extern IntPtr CreateFile(string n, uint a, uint s, IntPtr sa, uint c, uint f, IntPtr t);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool WriteFile(IntPtr h, byte[] b, int n, out int w, IntPtr o);
[DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr h);
}
"@
$dev = Get-PnpDevice -PresentOnly -Class HIDClass | Where-Object { $_.InstanceId -match [regex]::Escape($Match) } | Select-Object -First 1
if (-not $dev) { throw "RGB endpoint $Match not found" }
$path = '\\?\' + ($dev.InstanceId -replace '\\','#') + '#{4d1e55b2-f16f-11cf-88cb-001111000030}'
$h = [EV]::CreateFile($path, [uint32]3221225472, 3, [IntPtr]::Zero, 3, 0, [IntPtr]::Zero)
if ($h -eq [IntPtr]-1) { throw "open failed, error $([Runtime.InteropServices.Marshal]::GetLastWin32Error())" }
function Send([byte[]]$pkt) {
$buf = New-Object byte[] 64; [Array]::Copy($pkt, $buf, [Math]::Min(64, $pkt.Length))
$w = 0
if (-not [EV]::WriteFile($h, $buf, 64, [ref]$w, [IntPtr]::Zero)) { throw "write failed, error $([Runtime.InteropServices.Marshal]::GetLastWin32Error())" }
}
function Rgb([string]$hex) { $hex = $hex.TrimStart('#'); ,([byte[]]@([Convert]::ToByte($hex.Substring(0,2),16), [Convert]::ToByte($hex.Substring(2,2),16), [Convert]::ToByte($hex.Substring(4,2),16))) }
# Build the colour buffer
$data = New-Object byte[] ($Count * 3)
$f = Rgb $Fill
for ($i = 0; $i -lt $Count; $i++) { $data[$i*3] = $f[0]; $data[$i*3+1] = $f[1]; $data[$i*3+2] = $f[2] }
foreach ($e in ($Leds -split ',' | Where-Object { $_ })) {
$idx, $col = $e.Split('=')
if ($idx -match '^(\d+)-(\d+)$') { $range = [int]$Matches[1]..[int]$Matches[2] } else { $range = @([int]$idx) }
$c = Rgb $col
foreach ($i in $range) { if ($i -lt $Count) { $data[$i*3] = $c[0]; $data[$i*3+1] = $c[1]; $data[$i*3+2] = $c[2] } }
}
function SendFrame {
$per = 56
for ($off = 0; $off -lt $data.Length; $off += $per) {
$chunk = New-Object byte[] $per
[Array]::Copy($data, $off, $chunk, 0, [Math]::Min($per, $data.Length - $off))
$pkt = [byte[]](@(0x04, 0, 0, 0x12, $per, ($off -band 0xFF), (($off -shr 8) -band 0xFF), 0) + $chunk)
# checksum = 16-bit sum of bytes 3..63 (matches the plugin's formula)
$sum = 0; for ($k = 3; $k -lt 64; $k++) { $sum += $pkt[$k] }
$pkt[1] = $sum -band 0xFF; $pkt[2] = ($sum -shr 8) -band 0xFF
Send $pkt
Start-Sleep -Milliseconds 1
}
}
try {
if ($SoftwareMode) { Send ([byte[]]@(0x04, 0x8c, 0x00, 0x0b, 0x30, 0x50, 0x01)); Start-Sleep -Milliseconds 20 }
$end = (Get-Date).AddSeconds($Seconds); $n = 0
do { SendFrame; $n++; if ($Seconds -gt 0) { Start-Sleep -Milliseconds 100 } } while ((Get-Date) -lt $end)
"sent $n frame(s), $([Math]::Ceiling($data.Length / 56)) packets each"
} finally { [void][EV]::CloseHandle($h) }