#1
@XYZ
Frequency direct input + small window with a 5-item history
I am currently using this, but as it is for research purposes,
no support is provided.
・This code runs on AutoHotkey v2.
https://www.autohotkey.com/v2/
・Place the file in the same folder as PERSEUS, giving it an appropriate
name (e.g., "perseussmallwindow.ahk"—the ".ahk" file extension is required).
・Running this file will launch PERSEUS, followed by the appearance of a
small window. When you enter a number (a frequency), it is buffered and
stored internally until you press the Enter key to confirm. Once the Enter
key is pressed, the software will tune to the specified frequency.
・You can also tune to a frequency by clicking the corresponding button in
the small window's history list.
・To hide the small window, press "Shift + Ctrl + H." Pressing the same key
combination again will make the window reappear.
#Requires AutoHotkey v2.0
#SingleInstance Force
SetDefaultMouseSpeed 0 ; Move the mouse instantly.
SetTitleMatchMode "RegEx"
global FreqBuffer := ""
global FreqHistory := [] ; Array to store frequency history (Max 5 items)
global HistoryButtons := []
global PerseusGui := ""
;*** BEGIN of the PLAYBACK parameter section ***
global playback_step := 10 ; seconds
global playback_minutes := 5
global playback_seconds := 0
global playback_bar_start := 180
global playback_bar_end := 1011
global playback_bar_vpos := 603
global playback_position := playback_bar_start
global playback_last_timestamp := 0
PlaybackJump(seconds)
{
return (playback_bar_end - playback_bar_start) / (((playback_minutes * 60) + playback_seconds) / seconds)
}
;*** END of the PLAYBACK parameter section ***
sendBufferToFreqWnd(unitKey := "")
{
global FreqBuffer, FreqHistory
if (FreqBuffer = "") {
Click(100, 245, 2)
if !WinWait("ahk_class #32770",, 2)
return
if !WinActive("ahk_class #32770")
WinActivate("ahk_class #32770")
Click(110, 45)
Send("{Space}{BS}")
return
}
; Add frequency to history (Max 5 items)
unitStr := (unitKey = "m") ? " MHz" : " kHz"
fullFreqStr := FreqBuffer . unitStr
AddFreqToHistory(fullFreqStr, FreqBuffer, unitKey)
CoordMode("Mouse", "Screen")
MouseGetPos(&cxpos, &cypos)
CoordMode("Mouse", "Window")
Click(100, 245, 2)
if !WinWait("ahk_class #32770",, 2) {
FreqBuffer := ""
return
}
ControlFocus("Edit1", "ahk_class #32770")
ControlClick("Edit1", "ahk_class #32770",,,, "LEFT")
if !WinActive("ahk_class #32770")
WinActivate("ahk_class #32770")
Click(110, 45)
SendText(FreqBuffer)
FreqBuffer := ""
if (unitKey = "k" || unitKey = "Enter") {
Click(64, 184)
Click(104, 186)
} else if (unitKey = "m") {
Click(33, 184)
Click(104, 186)
}
CoordMode("Mouse", "Screen")
Click(cxpos, cypos, 0)
CoordMode("Mouse", "Window")
return
}
; Safe background mouse operation function
UnnoticeableClick(xpos, ypos, attr := "", clicks := 1)
{
perseusWin := "Perseus ahk_class (Afx:400000:2028:|Afx:00400000:2028:)"
if WinExist(perseusWin) && !WinActive(perseusWin)
{
WinActivate(perseusWin)
Sleep(50)
}
CoordMode("Mouse", "Screen")
MouseGetPos(&cxpos, &cypos)
CoordMode("Mouse", "Window")
; Branching click operations based on attributes (e.g., "WD", "WU")
if (attr = "WD") {
Click(xpos, ypos, "WheelDown", clicks)
} else if (attr = "WU") {
Click(xpos, ypos, "WheelUp", clicks)
} else {
Click(xpos, ypos, clicks)
}
CoordMode("Mouse", "Screen")
Click(cxpos, cypos, 0)
CoordMode("Mouse", "Window")
return
}
; Exit program logic
ExitPerseusAndScript()
{
UnnoticeableClick(1010, 12)
ExitApp()
}
; Toggle GUI logic
ToggleGui()
{
global PerseusGui
if (PerseusGui) {
if DllCall("IsWindowVisible", "Ptr", PerseusGui.Hwnd)
PerseusGui.Hide()
else
PerseusGui.Show("NoActivate")
}
}
; Activate Perseus if it isn't already active
perseusWin := "Perseus ahk_class (Afx:400000:2028:|Afx:00400000:2028:)"
if WinExist(perseusWin)
{
WinActivate(perseusWin)
WinWaitActive(perseusWin,, 2)
}
else
{
try {
Run("Perseus",,, &NewPID)
ProcessSetPriority("Realtime", NewPID)
WinWait(perseusWin)
WinActivate(perseusWin)
WinWaitActive(perseusWin,, 3)
} catch {
MsgBox("Can't find the Perseus program.`n`nCheck PerseusKeyboard and the Perseus software`nare located in the same directory.")
ExitApp()
}
}
; --- Automatically click Noise Limiter (n key) ON right after startup ---
Sleep(800)
UnnoticeableClick(969, 402)
; -------------------------------------------------------------------------
; ==============================================================================
; PERSEUS GUI Companion Panel Creation
; ==============================================================================
PerseusGui := Gui("+AlwaysOnTop -Caption +Owner", "PERSEUS Companion")
PerseusGui.BackColor := "181825"
; Enable window dragging by clicking anywhere on the panel
OnMessage(0x0201, WM_LBUTTONDOWN)
WM_LBUTTONDOWN(wParam, lParam, msg, hwnd) {
if (hwnd = PerseusGui.Hwnd)
PostMessage(0xA1, 2,,, PerseusGui.Hwnd)
}
; Header Title
PerseusGui.SetFont("s9 bold c89B4FA", "Segoe UI")
PerseusGui.Add("Text", "x10 y8 w200 h20 Center", "PERSEUS SDR")
; Shortcut control buttons
PerseusGui.SetFont("s8 bold cCDD6F4", "Segoe UI")
PerseusGui.Add("Button", "x10 y32 w96 h24", "Hide (Shift+Ctrl+H)").OnEvent("Click", (*) => ToggleGui())
PerseusGui.Add("Button", "x114 y32 w96 h24", "EXIT (Shift+Q)").OnEvent("Click", (*) => ExitPerseusAndScript())
; Frequency History Group (Top 5)
PerseusGui.SetFont("s8 cCDD6F4", "Segoe UI")
PerseusGui.Add("GroupBox", "x8 y62 w204 h150 c45475A", " Freq History (Top 5) ")
Loop 5 {
yPos := 80 + ((A_Index - 1) * 26)
btn := PerseusGui.Add("Button", "x16 y" . yPos . " w188 h22 Hidden", "")
btn.OnEvent("Click", OnHistoryBtnClick)
HistoryButtons.Push(btn)
}
; Relative positioning based on Perseus main window coordinates (X+750, Y+30)
if WinExist(perseusWin)
{
WinGetPos(&pX, &pY,,, perseusWin)
targetX := pX + 750
targetY := pY + 30
PerseusGui.Show("x" . targetX . " y" . targetY . " w220 h220 NoActivate")
}
else
{
PerseusGui.Show("x750 y30 w220 h220 NoActivate")
}
; --- Frequency History Management Functions ---
AddFreqToHistory(labelStr, val, unitKey) {
global FreqHistory, HistoryButtons
for idx, item in FreqHistory {
if (item.label = labelStr) {
FreqHistory.RemoveAt(idx)
break
}
}
FreqHistory.InsertAt(1, {label: labelStr, val: val, unitKey: unitKey})
if (FreqHistory.Length > 5)
FreqHistory.Pop()
for i, btn in HistoryButtons {
if (i <= FreqHistory.Length) {
btn.Text := FreqHistory[i].label
btn.Visible := true
} else {
btn.Visible := false
}
}
}
; Open frequency input window directly and send frequency when history button is clicked
OnHistoryBtnClick(btn, *) {
global FreqHistory, FreqBuffer
for i, item in FreqHistory {
if (btn.Text = item.label) {
perseusWin := "Perseus ahk_class (Afx:400000:2028:|Afx:00400000:2028:)"
if WinExist(perseusWin)
WinActivate(perseusWin)
FreqBuffer := item.val
sendBufferToFreqWnd(item.unitKey)
break
}
}
}
; --- Global Hotkeys ---
+^h::ToggleGui() ; Shift + Ctrl + H to Hide/Show panel
#HotIf WinActive("Perseus ahk_class (Afx:400000:2028:|Afx:00400000:2028:)")
;*** Frequency Control ***
Left::Click(192, 309)
Right::Click(987, 308)
Up::Click(587, 290, "WheelDown")
Down::Click(587, 290, "WheelUp")
PgDn::
{
Loop 10 {
UnnoticeableClick(587, 290, "WD")
Sleep(1)
}
}
Delete::
{
Loop 10 {
UnnoticeableClick(587, 290, "WU")
Sleep(1)
}
}
[::UnnoticeableClick(135, 295)
]::UnnoticeableClick(150, 295)
-::UnnoticeableClick(130, 333)
_::UnnoticeableClick(155, 334)
/::
NumpadDiv::UnnoticeableClick(133, 152)
*::
NumpadMult::UnnoticeableClick(157, 152)
t::
+t::UnnoticeableClick(227, 309)
w::
+w::UnnoticeableClick(263, 309)
b::
+b::UnnoticeableClick(518, 403)
End::
n::
+n::UnnoticeableClick(969, 402)
0::
Numpad0::global FreqBuffer := FreqBuffer . "0"
1::
Numpad1::global FreqBuffer := FreqBuffer . "1"
2::
Numpad2::global FreqBuffer := FreqBuffer . "2"
3::
Numpad3::global FreqBuffer := FreqBuffer . "3"
4::
Numpad4::global FreqBuffer := FreqBuffer . "4"
5::
Numpad5::global FreqBuffer := FreqBuffer . "5"
6::
Numpad6::global FreqBuffer := FreqBuffer . "6"
7::
Numpad7::global FreqBuffer := FreqBuffer . "7"
8::
Numpad8::global FreqBuffer := FreqBuffer . "8"
9::
Numpad9::global FreqBuffer := FreqBuffer . "9"
Enter::
NumpadEnter::sendBufferToFreqWnd("Enter")
m::
+m::
{
if (FreqBuffer != "") {
sendBufferToFreqWnd("m")
} else {
UnnoticeableClick(1002, 405)
}
}
k::
+k::
{
if (FreqBuffer != "") {
sendBufferToFreqWnd("k")
} else {
UnnoticeableClick(380, 546)
}
}
l::
+L::
NumPadSub::UnnoticeableClick(408, 353)
u::
+U::
NumPadAdd::UnnoticeableClick(455, 353)
a::
+A::UnnoticeableClick(204, 353)
s::
+S::UnnoticeableClick(259, 353)
+c::
c::UnnoticeableClick(310, 353)
r::
+R::UnnoticeableClick(362, 353)
f::
+F::UnnoticeableClick(508, 353)
d::
+D::UnnoticeableClick(561, 353)
e::
+E::UnnoticeableClick(594, 353)
j::
+j::UnnoticeableClick(562, 458)
y::
+y::UnnoticeableClick(260, 546)
h::
+h::UnnoticeableClick(300, 546)
g::
+g::UnnoticeableClick(340, 546)
x::
+x::UnnoticeableClick(23, 422)
Home::UnnoticeableClick(300, 310)
;Wave file change
z::
+z::
{
global playback_position, playback_last_timestamp
UnnoticeableClick(playback_bar_end, playback_bar_vpos)
playback_position := playback_bar_start
playback_last_timestamp := A_TickCount
Sleep(1000)
}
;*** PLAYBACK hotkey section ***
Tab::
{
global playback_last_timestamp, playback_position
playback_current_timestamp := A_TickCount
if (playback_last_timestamp = 0 || playback_last_timestamp > playback_current_timestamp)
playback_last_timestamp := playback_current_timestamp
playback_position += PlaybackJump((playback_current_timestamp - playback_last_timestamp) / 1000)
playback_last_timestamp := playback_current_timestamp
if (playback_position > (playback_bar_end - 1))
playback_position := playback_bar_start + Mod(playback_position - playback_bar_start, playback_bar_end - playback_bar_start)
playback_position += PlaybackJump(playback_step)
if (playback_position > (playback_bar_end - 1))
playback_position := playback_bar_start
UnnoticeableClick(playback_position, playback_bar_vpos)
Sleep(100)
}
+Tab::
{
global playback_last_timestamp, playback_position
playback_current_timestamp := A_TickCount
if (playback_last_timestamp = 0 || playback_last_timestamp > playback_current_timestamp)
playback_last_timestamp := playback_current_timestamp
playback_position += PlaybackJump((playback_current_timestamp - playback_last_timestamp) / 1000)
playback_last_timestamp := playback_current_timestamp
if (playback_position > (playback_bar_end - 1))
playback_position := playback_bar_start + Mod(playback_position - playback_bar_start, playback_bar_end - playback_bar_start)
if (playback_position > (playback_bar_start + PlaybackJump(1))) {
playback_position -= PlaybackJump(playback_step)
if (playback_position < playback_bar_start)
playback_position := playback_bar_start
UnnoticeableClick(playback_position, playback_bar_vpos)
}
Sleep(100)
}
^Tab::
{
global playback_step, playback_minutes, playback_seconds
IB1 := InputBox("Step (in seconds)", "PLAYBACK", "W160 H130", playback_step)
if (IB1.Result = "Cancel")
return
if !IsInteger(IB1.Value) || Number(IB1.Value) <= 0 {
MsgBox("Step invalid", "Error", 0x10)
return
}
playback_step := Number(IB1.Value)
IB2 := InputBox("Minutes", "PLAYBACK", "W160 H130", playback_minutes)
if (IB2.Result = "Cancel")
return
if !IsInteger(IB2.Value) || Number(IB2.Value) < 0 || Number(IB2.Value) > 59 {
MsgBox("Minutes invalid", "Error", 0x10)
return
}
playback_minutes := Number(IB2.Value)
IB3 := InputBox("Seconds", "PLAYBACK", "W160 H130", playback_seconds)
if (IB3.Result = "Cancel")
return
if !IsInteger(IB3.Value) || Number(IB3.Value) < 0 || Number(IB3.Value) > 59 {
MsgBox("Seconds invalid", "Error", 0x10)
return
}
playback_seconds := Number(IB3.Value)
}
;Close Perseus and the script
+q::
!F4::
{
ExitPerseusAndScript()
}
#HotIf
#HotIf WinActive("Frequency ahk_class #32770")
Enter::
NumpadEnter::
k::
+k::
{
Click(64, 184)
Click(104, 186)
}
m::
+m::
{
Click(33, 184)
Click(104, 186)
}
#HotIf
