Command Palette

Search for a command to run...

Back to AutoHotkey Tools

RadMode Tools

v22.27-BV automation scripts and utilities for radiology workflows

How to Use

Complete AutoHotkey v2 script for radiology workflow automation

  1. 1Download the RadMode.ahk script and RadMode.exe runner, then place them in the same folder. Double-click the Runner (.exe) to launch — a setup GUI window will appear.
  2. 2Configure your hotkeys and settings in the setup GUI. The launcher minimizes to the system tray after setup — close it to stop the script.
  3. 3Press Caps + F to enter Rads Mode and Caps + D to exit. Dictation shortcuts and number hotkeys (1–5) are active only when Rads Mode is enabled.
  4. 4Press Caps + W to restore a previously saved workspace layout and Caps + C to refresh the PowerScribe target.
  5. 5Press Alt + Z for Break Glass.
  6. 6Press Ctrl + Alt + S to save workspace layout.
  7. 7Press Alt + P for site login and Alt + B for Bellevue remote desktop login.

Quick Reference

Key shortcuts — full list available in the script GUI

Global Shortcuts

Caps LockTrackball Scroll (Hold)
Alt + PLogin site
Alt + BLogin Bellevue RDP
Alt + ZBreak Glass
Ctrl + Alt + SSave workspace layout
Caps + FEnable Rads Mode
Caps + DExit Rads Mode
Caps + WRestore workspace layout
Caps + CRefresh PS target
Shift + CapsToggle CapsLock

Rads Mode — Dictation

DToggle dictation
HSave draft (F9)
FNext field
GPrevious field
SBackspace
ANew line
QClose window (Ctrl+W)

Mouse & Pick Lists

RLeft click
EMiddle click
WRight click
1–5Pick list in PowerScribe / type digit elsewhere

Visage viewer:

Z, X, C, VSend to Visage

Download Files

Both files are required — place them in the same folder

AutoHotkey Script
.ahk
RadMode.ahk
Download Script
Executable Runner
.exe
RadMode.exe
Download Runner
Full RadMode Automation Script
View the complete source code or copy it to your clipboard
1#Requires Autohotkey v2
2#SingleInstance Force
3CoordMode "ToolTip", "Screen"
4CoordMode "Mouse", "Screen" 
5CoordMode "Pixel", "Screen" 
6SetTitleMatchMode 2
7
8; ==============================================================================
9; Version & Configuration Defaults
10; Author: Ryan Cummings
11; ==============================================================================
12global VERSION := "v23.1"
13global INI_FILE := "rad_helper_settings.ini"
14
15global KEEPAWAKE := 0
16global TRACKBALL_SCROLL := 1
17global DEBUG_MODE := 0
18
19; --- Advanced Settings (Loaded from INI) ---
20global SCROLL_THRESHOLD := 15     
21global SCROLL_LOCK_RATIO := 2.0   
22
23; --- Marker Customization ---
24global MARKER_SIZE := 5           
25global MARKER_COLOR := "FF0000"   
26global MARKER_ALPHA := 180        
27
28; --- Reliability Settings ---
29SetKeyDelay 10, 10
30
31; --- Window Titles & Layout Apps ---
32; Window criteria are deliberately based on stable executable/class identifiers,
33; never a live patient/study title, PID, or HWND.
34global EPIC_TITLE := "ahk_exe wfica32.exe ahk_class Transparent Windows Client"
35global PS := "PowerScribe"
36
37global WORKSPACE_APPS := [
38    {name: "PowerScribe", disp: "PowerScribe", title: "360 ahk_exe Nuance.PowerScribe360.exe", enabled: 1},
39    {name: "Epic", disp: "Epic", title: EPIC_TITLE, enabled: 1},
40    {name: "Pacs", disp: "PACS", title: "ahk_exe mp.exe ahk_class WindowsForms10.Window.8.app.0.297b065_r58_ad1", enabled: 1},
41    {name: "Worklist", disp: "Worklist", title: "ahk_exe Worklist.exe ahk_class WindowsForms10.Window.8.app.0.134c08f_r11_ad1", enabled: 1}
42]
43
44global RADSMODE := false
45global MarkerGui := unset
46
47; ==============================================================================
48; Initialization
49; ==============================================================================
50LoadSettings() 
51CreateCursorMarker()
52
53; ==============================================================================
54; Main GUI
55; ==============================================================================
56myGui := Gui()
57myGui.Title := "Radiology Helper " . VERSION
58myGui.BackColor := "FBFBFB"
59myGui.SetFont("s10", "Segoe UI")
60
61; --- Login Section ---
62; --- Config Button ---
63ConfigButton := myGui.Add("Button", "x20 y15 w460 h35", "Advanced Config")
64ConfigButton.OnEvent("Click", OpenConfigMenu)
65
66; --- Options Section ---
67CheckBox1 := myGui.Add("CheckBox", "x40 y65 w150 h25 Checked" . KEEPAWAKE, "Prevent Sleep")
68CheckBox2 := myGui.Add("CheckBox", "x220 y65 w240 h25 Checked" . TRACKBALL_SCROLL, "Hold CapsLock to scroll")
69CheckBox3 := myGui.Add("CheckBox", "x40 y90 w150 h25 Checked" . DEBUG_MODE, "Debug Mode")
70
71CheckBox1.OnEvent("Click", UpdateGlobals)
72CheckBox2.OnEvent("Click", UpdateGlobals)
73CheckBox3.OnEvent("Click", UpdateGlobals)
74
75; --- Workspace Layout Section ---
76myGui.Add("GroupBox", "x20 y130 w460 h95", "Workspace Layout (Multi-Monitor)")
77
78Chk_PS := myGui.Add("CheckBox", "x30 y155 w140 h20 Checked" . WORKSPACE_APPS[1].enabled, "PowerScribe")
79Chk_Epic := myGui.Add("CheckBox", "x180 y155 w130 h20 Checked" . WORKSPACE_APPS[2].enabled, "Epic")
80Chk_Pacs := myGui.Add("CheckBox", "x320 y155 w140 h20 Checked" . WORKSPACE_APPS[3].enabled, "PACS")
81
82Chk_Worklist := myGui.Add("CheckBox", "x30 y180 w140 h20 Checked" . WORKSPACE_APPS[4].enabled, "Worklist")
83
84Btn_SaveLayout := myGui.Add("Button", "x200 y180 w110 h25", "Save Layout")
85Btn_RestLayout := myGui.Add("Button", "x325 y180 w125 h25", "Restore Layout")
86
87; Link GUI controls to the array for dynamic text updates
88WORKSPACE_APPS[1].ctrl := Chk_PS
89WORKSPACE_APPS[2].ctrl := Chk_Epic
90WORKSPACE_APPS[3].ctrl := Chk_Pacs
91WORKSPACE_APPS[4].ctrl := Chk_Worklist
92
93Chk_PS.OnEvent("Click", UpdateLayoutGlobals)
94Chk_Epic.OnEvent("Click", UpdateLayoutGlobals)
95Chk_Pacs.OnEvent("Click", UpdateLayoutGlobals)
96Chk_Worklist.OnEvent("Click", UpdateLayoutGlobals)
97Btn_SaveLayout.OnEvent("Click", SaveWorkspace)
98Btn_RestLayout.OnEvent("Click", RestoreWorkspace)
99
100; --- Divider ---
101myGui.Add("Text", "x20 y235 w460 h2 0x10")
102
103; --- Reference Guide ---
104myGui.SetFont("s9", "Segoe UI")
105RefGroup := myGui.Add("GroupBox", "x20 y245 w460 h235", "Quick Reference Guide")
106
107; Column 1: Global
108myGui.SetFont("s9 w700")
109myGui.Add("Text", "x40 y265 w180", "Global Shortcuts")
110myGui.SetFont("s9 w400")
111myGui.Add("Text", "x40 y285 w200", "Caps + f : Rads Mode ON")
112myGui.Add("Text", "x40 y305 w200", "Caps + d : Rads Mode OFF")
113myGui.Add("Text", "x40 y325 w200", "Caps + w : Restore Layout")
114myGui.Add("Text", "x40 y345 w200", "Caps + c : Refresh PS Target")
115myGui.Add("Text", "x40 y365 w200", "Ctrl + Alt + s : Save Layout")
116myGui.Add("Text", "x40 y385 w200", "Shift + Caps : Toggle CapsLock")
117myGui.Add("Text", "x40 y425 w200", "Ctrl + Alt + i : Insert comparison date")
118
119; Column 2: Rads Mode
120myGui.SetFont("s9 w700")
121myGui.Add("Text", "x260 y265 w180", "Rads Mode (Vim-Style)")
122myGui.SetFont("s9 w400")
123myGui.Add("Text", "x260 y285 w200", "d : Toggle Dictation")
124myGui.Add("Text", "x260 y305 w200", "h : Save Draft (F9)")
125myGui.Add("Text", "x260 y325 w200", "f / g : Next / Prev Field")
126myGui.Add("Text", "x260 y345 w200", "s / a : Backspace / Enter")
127myGui.Add("Text", "x260 y365 w200", "1 - 5 : Pick List Choice")
128
129; Logic Note
130myGui.SetFont("s8 italic c555555")
131myGui.Add("Text", "x40 y450 w420", "Comparison: hover a prior-report entry, then press Ctrl + Alt + i.")
132
133; Footer
134myGui.SetFont("s8 c777777")
135myGui.Add("Text", "x20 y490 w460 Center", "Note: Red dot indicator appears when Rads Mode is active.")
136
137UpdateLayoutDetection() ; Set initial UI state
138myGui.Show("w500 h520")
139
140; ==============================================================================
141; Cursor Marker Logic
142; ==============================================================================
143CreateCursorMarker() {
144    global MarkerGui, MARKER_SIZE, MARKER_COLOR, MARKER_ALPHA
145    if IsSet(MarkerGui)
146        MarkerGui.Destroy()
147    MarkerGui := Gui("+AlwaysOnTop -Caption +ToolWindow +E0x20") 
148    MarkerGui.BackColor := MARKER_COLOR
149    D := MARKER_SIZE
150    WinSetRegion("0-0 W" D " H" D " R" D "-" D, MarkerGui.Hwnd)
151    MarkerGui.Opt("+LastFound")
152    WinSetTransparent(MARKER_ALPHA, MarkerGui.Hwnd)
153}
154
155UpdateMarkerPos() {
156    global RADSMODE, MarkerGui, MARKER_SIZE
157    if (RADSMODE) {
158        MouseGetPos(&mX, &mY)
159        MarkerGui.Show("x" (mX + 12) " y" (mY + 12) " w" MARKER_SIZE " h" MARKER_SIZE " NoActivate")
160    } else {
161        MarkerGui.Hide()
162    }
163}
164
165; ==============================================================================
166; Advanced Config Menu
167; ==============================================================================
168OpenConfigMenu(*) {
169    advGui := Gui()
170    advGui.Title := "Advanced Configuration"
171    advGui.SetFont("s9", "Segoe UI")
172
173    advGui.Add("GroupBox", "x10 y10 w380 h100", "Rads Mode Indicator (Dot)")
174    advGui.Add("Text", "x30 y35 w100 h20", "Dot Size (px):")
175    Ctrl_Size := advGui.Add("Edit", "x130 y32 w60 h20 Number", MARKER_SIZE)
176    advGui.Add("Text", "x210 y35 w80 h20", "Hex Color:")
177    Ctrl_Color := advGui.Add("Edit", "x290 y32 w80 h20", MARKER_COLOR)
178    advGui.Add("Text", "x30 y65 w100 h20", "Opacity (0-255):")
179    Ctrl_Alpha := advGui.Add("Edit", "x130 y62 w60 h20 Number", MARKER_ALPHA)
180
181    advGui.Add("GroupBox", "x10 y120 w380 h100", "Trackball Scroll")
182    advGui.Add("Text", "x30 y145 w150 h20", "Scroll Sensitivity:")
183    Ctrl_Sens := advGui.Add("Edit", "x240 y142 w80 h20 Number", SCROLL_THRESHOLD)
184    advGui.Add("Text", "x30 y175 w150 h20", "Axis Lock Ratio:")
185    Ctrl_Lock := advGui.Add("Edit", "x240 y172 w80 h20 Number", SCROLL_LOCK_RATIO)
186
187    SaveBtn := advGui.Add("Button", "x90 y240 w100 h30", "Save")
188    CancelBtn := advGui.Add("Button", "x200 y240 w100 h30", "Cancel")
189    SaveBtn.OnEvent("Click", SaveHandler)
190    CancelBtn.OnEvent("Click", (*) => advGui.Destroy())
191    advGui.Show()
192
193    SaveHandler(*) {
194        global SCROLL_THRESHOLD, SCROLL_LOCK_RATIO
195        global MARKER_SIZE, MARKER_COLOR, MARKER_ALPHA
196        MARKER_SIZE := Ctrl_Size.Value
197        MARKER_COLOR := Ctrl_Color.Value
198        MARKER_ALPHA := Ctrl_Alpha.Value
199        SCROLL_THRESHOLD := Ctrl_Sens.Value
200        SCROLL_LOCK_RATIO := Number(Ctrl_Lock.Value) 
201        SaveSettings() 
202        CreateCursorMarker()
203        advGui.Destroy()
204        MsgBox("Settings Saved!", "Configuration", "Iconi T1")
205    }
206}
207
208; ==============================================================================
209; INI Persistence Functions
210; ==============================================================================
211LoadSettings() {
212    global SCROLL_THRESHOLD, SCROLL_LOCK_RATIO
213    global MARKER_SIZE, MARKER_COLOR, MARKER_ALPHA, WORKSPACE_APPS
214    if FileExist(INI_FILE) {
215        try {
216            SCROLL_THRESHOLD := IniRead(INI_FILE, "Physics", "Sensitivity", 15)
217            SCROLL_LOCK_RATIO := IniRead(INI_FILE, "Physics", "AxisLock", 2.0)
218            MARKER_SIZE := IniRead(INI_FILE, "Marker", "Size", 5)
219            MARKER_COLOR := IniRead(INI_FILE, "Marker", "Color", "FF0000")
220            MARKER_ALPHA := IniRead(INI_FILE, "Marker", "Alpha", 180)
221            
222            for app in WORKSPACE_APPS {
223                app.enabled := IniRead(INI_FILE, "LayoutSettings", app.name . "_Enabled", 1)
224            }
225        }
226    }
227}
228
229SaveSettings() {
230    global WORKSPACE_APPS
231    IniWrite(SCROLL_THRESHOLD, INI_FILE, "Physics", "Sensitivity")
232    IniWrite(SCROLL_LOCK_RATIO, INI_FILE, "Physics", "AxisLock")
233    IniWrite(MARKER_SIZE, INI_FILE, "Marker", "Size")
234    IniWrite(MARKER_COLOR, INI_FILE, "Marker", "Color")
235    IniWrite(MARKER_ALPHA, INI_FILE, "Marker", "Alpha")
236    
237    for app in WORKSPACE_APPS {
238        IniWrite(app.enabled, INI_FILE, "LayoutSettings", app.name . "_Enabled")
239    }
240}
241
242; ==============================================================================
243; GUI Handlers & Detection
244; ==============================================================================
245UpdateGlobals(*) {
246    global KEEPAWAKE := CheckBox1.Value
247    global TRACKBALL_SCROLL := CheckBox2.Value, DEBUG_MODE := CheckBox3.Value
248}
249
250UpdateLayoutGlobals(*) {
251    global WORKSPACE_APPS
252    WORKSPACE_APPS[1].enabled := Chk_PS.Value
253    WORKSPACE_APPS[2].enabled := Chk_Epic.Value
254    WORKSPACE_APPS[3].enabled := Chk_Pacs.Value
255    WORKSPACE_APPS[4].enabled := Chk_Worklist.Value
256    SaveSettings()
257}
258
259UpdateLayoutDetection() {
260    global WORKSPACE_APPS
261    for app in WORKSPACE_APPS {
262        if WinExist(app.title) {
263            if !InStr(app.ctrl.Text, "(Active)")
264                app.ctrl.Text := app.disp . " (Active)"
265        } else {
266            if !InStr(app.ctrl.Text, "(Off)")
267                app.ctrl.Text := app.disp . " (Off)"
268        }
269    }
270}
271
272; ==============================================================================
273; Workspace Layout Core Logic
274; ==============================================================================
275SaveWorkspace(*) {
276    global INI_FILE, WORKSPACE_APPS
277    savedList := ""
278
279    for app in WORKSPACE_APPS {
280        if (app.enabled && WinExist(app.title)) {
281            minMax := WinGetMinMax(app.title)
282            
283            if (minMax == -1) {
284                WinRestore(app.title)
285                Sleep(50)
286            }
287
288            WinGetPos(&X, &Y, &W, &H, app.title)
289
290            IniWrite(X, INI_FILE, "Layout_" . app.name, "X")
291            IniWrite(Y, INI_FILE, "Layout_" . app.name, "Y")
292            IniWrite(W, INI_FILE, "Layout_" . app.name, "W")
293            IniWrite(H, INI_FILE, "Layout_" . app.name, "H")
294            IniWrite(minMax == 1 ? 1 : 0, INI_FILE, "Layout_" . app.name, "Maximized")
295
296            if (minMax == -1) {
297                WinMinimize(app.title)
298            }
299            savedList .= app.disp . ", "
300        }
301    }
302    
303    if (savedList != "") {
304        ToolTip("Saved Layout: " . RTrim(savedList, ", "))
305    } else {
306        ToolTip("No enabled apps detected to save.")
307    }
308    SetTimer () => ToolTip(), -3000
309}
310
311RestoreWorkspace(*) {
312    global INI_FILE, WORKSPACE_APPS
313    restoredList := ""
314    
315    for app in WORKSPACE_APPS {
316        if (app.enabled && WinExist(app.title)) {
317            try {
318                X := IniRead(INI_FILE, "Layout_" . app.name, "X", "")
319                if (X == "")
320                    continue
321                    
322                Y := IniRead(INI_FILE, "Layout_" . app.name, "Y")
323                W := IniRead(INI_FILE, "Layout_" . app.name, "W")
324                H := IniRead(INI_FILE, "Layout_" . app.name, "H")
325                isMax := IniRead(INI_FILE, "Layout_" . app.name, "Maximized")
326
327                WinRestore(app.title)
328                Sleep(50) 
329                WinMove(X, Y, W, H, app.title)
330                
331                if (app.name == "Epic") {
332                    Sleep(100)
333                }
334
335                if (isMax == 1) {
336                    WinMaximize(app.title)
337                }
338                restoredList .= app.disp . ", "
339            }
340        }
341    }
342    
343    if (restoredList != "") {
344        ToolTip("Restored Layout: " . RTrim(restoredList, ", "))
345    } else {
346        ToolTip("No layouts restored.")
347    }
348    SetTimer () => ToolTip(), -3000
349}
350
351; ==============================================================================
352; Core Logic
353; ==============================================================================
354SetTimer StopSleep, 100000
355SetTimer UpdateMarkerPos, 100 
356SetTimer UpdateLayoutDetection, 2000 
357
358; ==============================================================================
359; CAPSLOCK & MODIFIER HOTKEYS
360; ==============================================================================
361
362; --- Shift + CapsLock toggles the actual uppercase state ---
363+CapsLock::CapsLock
364
365; --- CapsLock intercepts ---
366#HotIf TRACKBALL_SCROLL
367    $CapsLock::TrackballScroll()
368#HotIf
369
370; --- Disable standard CapsLock press if Trackball scroll is off ---
371#HotIf !TRACKBALL_SCROLL
372    $CapsLock::return 
373#HotIf
374
375; --- Custom Rads Mode Modifiers ---
376#HotIf GetKeyState("CapsLock", "P")
377    f:: enableRadsMode()
378    d:: exitRadsMode()
379    w:: RestoreWorkspace()
380    c:: ForceRefreshControl()
381#HotIf
382
383; ==============================================================================
384; CAPSLOCK SCROLL
385; ==============================================================================
386TrackballScroll(*) {
387    global SCROLL_THRESHOLD, SCROLL_LOCK_RATIO
388    oldMode := A_CoordModeMouse
389    CoordMode "Mouse", "Screen"
390    MouseGetPos(&startX, &startY)
391    bankX := 0, bankY := 0
392    Loop {
393        if !GetKeyState("CapsLock", "P")
394            break
395        MouseGetPos(&currentX, &currentY)
396        moveX := currentX - startX, moveY := currentY - startY
397        if (moveX != 0 || moveY != 0) {
398            DllCall("SetCursorPos", "int", startX, "int", startY)
399        }
400        bankX += moveX, bankY += moveY
401        absX := Abs(bankX), absY := Abs(bankY)
402        if (absX > (absY * SCROLL_LOCK_RATIO)) {
403            if (absX >= SCROLL_THRESHOLD) {
404                ticks := Integer(absX / SCROLL_THRESHOLD)
405                direction := (bankX > 0) ? "{WheelRight}" : "{WheelLeft}"
406                Loop ticks
407                    Send(direction)
408                bankX := Mod(bankX, SCROLL_THRESHOLD), bankY := 0
409            }
410        } else if (absY > absX) {
411            if (absY >= SCROLL_THRESHOLD) {
412                ticks := Integer(absY / SCROLL_THRESHOLD)
413                direction := (bankY > 0) ? "{WheelDown}" : "{WheelUp}"
414                Loop ticks
415                    Send(direction)
416                bankY := Mod(bankY, SCROLL_THRESHOLD), bankX := 0
417            }
418        }
419        Sleep(5)
420    }
421    CoordMode "Mouse", oldMode
422}
423
424; ==============================================================================
425; UTILS & HOTKEYS
426; ==============================================================================
427GetTargetControl(forceRefresh := false) {
428    global PS
429    
430    largestArea := 0
431    bestControl := ""
432    
433    try {
434        ctrlList := WinGetControls(PS)
435        for ctrl in ctrlList {
436            if InStr(ctrl, "RICHEDIT") {
437                try {
438                    ; Ensure the control is visible
439                    if ControlGetVisible(ctrl, PS) {
440                        ControlGetPos(&x, &y, &w, &h, ctrl, PS)
441                        
442                        ; Filter out phantom formatting buffers
443                        if (w > 20 && h > 20) {
444                            area := w * h
445                            if (area > largestArea) {
446                                largestArea := area
447                                bestControl := ctrl
448                            }
449                        }
450                    }
451                } catch {
452                    continue 
453                }
454            }
455        }
456    }
457    
458    return bestControl
459}
460
461ActivateAndSend(key, targetSpecificControl := true, literalText := false) {
462    global PS
463    if !WinExist(PS)
464        return
465        
466    ; [ANTI-DEADLOCK FAST PATH]
467    ; Uses SendEvent for improved reliability with Nuance/Dragon hooks
468    if WinActive(PS) {
469        literalText ? SendText(key) : SendEvent(key)
470        return
471    }
472    
473    ; Slow path (if returning to PowerScribe from another application)
474    WinActivate(PS)
475    if !WinWaitActive(PS,, 1)
476        return
477    Sleep(50)
478    
479    if targetSpecificControl {
480        target := GetTargetControl()
481        if (target) {
482            try {
483                if (ControlGetFocus(PS) != target) {
484                    ControlFocus(target, PS)
485                }
486            }
487        }
488    }
489    
490    literalText ? SendText(key) : SendEvent(key)
491}
492
493StopSleep(*) {
494    if (KEEPAWAKE) {
495        SendEvent("{F15}")
496    }
497}
498
499pick(num) {
500    global PS
501    MouseGetPos &startX, &startY
502    CoordMode "Mouse", "Client" 
503    heightRow := 17
504    if WinExist(PS) {
505        try {
506            for ctrl in WinGetControls(PS) {
507                try {
508                    txt := ControlGetText(ctrl, PS)
509                } catch {
510                    continue
511                }
512                if (txt == "Pick List Choices") {
513                    ControlGetPos(&x, &y, &w, &h, ctrl, PS)
514                    targetY := y + Integer(heightRow/2) + (heightRow * num)
515                    targetX := x + 20
516                    if !WinActive(PS) {
517                        WinActivate(PS)
518                        WinWaitActive(PS,, 1)
519                    }
520                    Click(targetX, targetY)
521                    Sleep(50)
522                    Click(targetX, targetY)
523                    CoordMode "Mouse", "Screen"
524                    MouseMove(startX, startY)
525                    Sleep(50)
526                    ActivateAndSend("{Tab}", true)
527                    return
528                }
529            }
530        }
531    }
532    CoordMode "Mouse", "Screen"
533}
534
535; -- Common Rads Logic --
536toggleDictation(*) {
537    static lastToggle := 0
538    
539    ; Debounce to prevent double-triggers
540    if (A_TickCount - lastToggle < 500) {
541        return 
542    }
543    lastToggle := A_TickCount
544    
545    ; Routes through ActivateAndSend to ensure PowerScribe is targeted,
546    ; passing 'false' so it skips searching for a specific text control.
547    ActivateAndSend("{F4}", false)
548}
549
550saveDraft(*)       => ActivateAndSend("{F9}", false)
551nextField(*)       => ActivateAndSend("{Tab}", true)
552prevField(*)       => ActivateAndSend("+{Tab}", true)
553backspace(*)       => ActivateAndSend("{Backspace}", true)
554newLine(*)         => ActivateAndSend("{Enter}", true)
555
556enableRadsMode(*) {
557    global RADSMODE := true
558    GetTargetControl(true) ; Automatically flush and re-target when entering Rads Mode
559}
560exitRadsMode(*) {
561    global RADSMODE := false
562}
563
564ForceRefreshControl(*) {
565    GetTargetControl(true)
566    ToolTip("PowerScribe Target Refreshed")
567    SetTimer () => ToolTip(), -1500
568}
569
570GetHoveredTooltipText() {
571    ; PowerScribe's hover text is expected to be a standard Windows tooltip
572    ; window. WinSpy will usually miss it because it closes when the inspector
573    ; gains focus, but the hotkey can read it without moving focus or the mouse.
574    for tooltipHwnd in WinGetList("ahk_class tooltips_class32") {
575        try {
576            if !DllCall("IsWindowVisible", "ptr", tooltipHwnd)
577                continue
578            tooltipText := Trim(WinGetText("ahk_id " tooltipHwnd))
579            if (tooltipText != "")
580                return tooltipText
581        }
582    }
583    return ""
584}
585
586ExtractComparisonDate(text) {
587    ; Accept the PowerScribe tooltip format shown in the worklist, e.g.
588    ; "7/30/2026 1:30 AM", as well as dates without a displayed time.
589    if !RegExMatch(text, "\\b(\\d{1,2})[/-](\\d{1,2})[/-](\\d{2,4})\\b", &match)
590        return ""
591
592    month := Integer(match[1])
593    day := Integer(match[2])
594    year := Integer(match[3])
595    if (year < 100)
596        year += 2000
597    if (month < 1 || month > 12 || day < 1 || day > 31)
598        return ""
599    return Format("{:02}/{:02}/{:04}", month, day, year)
600}
601
602InsertComparisonDate(*) {
603    tooltipText := GetHoveredTooltipText()
604    if (tooltipText = "") {
605        MsgBox("No readable PowerScribe hover text was found.`n`nKeep the cursor over a prior-report entry until its date tooltip is visible, then press Ctrl + Alt + i without clicking elsewhere.", "RadMode Comparison Date", "Icon!")
606        return
607    }
608
609    comparisonDate := ExtractComparisonDate(tooltipText)
610    if (comparisonDate = "") {
611        MsgBox("The hover text did not contain a valid date.`n`nText read: " tooltipText, "RadMode Comparison Date", "Icon!")
612        return
613    }
614
615    ActivateAndSend("Comparison: " comparisonDate ".", true, true)
616    ToolTip("Inserted comparison date: " comparisonDate)
617    SetTimer () => ToolTip(), -2000
618}
619
620; -- Global Hotkeys --
621^!s:: SaveWorkspace()
622^!i:: InsertComparisonDate()
623
624#HotIf RADSMODE
625    r::LButton
626    e::MButton
627    w::RButton
628    $d:: toggleDictation()
629    $h:: saveDraft()
630    $f:: nextField()
631    $g:: prevField()
632    $s:: backspace()
633    $a:: newLine()
634    $q:: Send("^w")
635    
636    ; -- Pick List Hotkeys --
637    $1:: (WinActive(PS) ? pick(1) : Send("1")) 
638    $2:: (WinActive(PS) ? pick(2) : Send("2")) 
639    $3:: (WinActive(PS) ? pick(3) : Send("3")) 
640    $4:: (WinActive(PS) ? pick(4) : Send("4")) 
641    $5:: (WinActive(PS) ? pick(5) : Send("5"))
642
643    $z:: (WinActive(PS) ? "" : Send("z"))
644    $x:: (WinActive(PS) ? "" : Send("x"))
645    $c:: (WinActive(PS) ? "" : Send("c"))
646    $v:: (WinActive(PS) ? "" : Send("v"))
647#HotIf
648

This is the full source code of the RadMode.ahk file. You can copy this into a new .ahk file or download the file directly using the button above.