RadMode Tools
v22.27-BV automation scripts and utilities for radiology workflows
How to Use
Complete AutoHotkey v2 script for radiology workflow automation
- 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.
- 2Configure your hotkeys and settings in the setup GUI. The launcher minimizes to the system tray after setup — close it to stop the script.
- 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.
- 4Press Caps + W to restore a previously saved workspace layout and Caps + C to refresh the PowerScribe target.
- 5Press Alt + Z for Break Glass.
- 6Press Ctrl + Alt + S to save workspace layout.
- 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
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(¤tX, ¤tY)
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
648This 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.