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 := "v22.27-BV" ; Bare Number Picklists
13global INI_FILE := "rad_helper_settings.ini"
14
15; --- User Variables (Runtime) ---
16global USER := ""
17global PASS := ""
18global BV_PASS := ""
19global KEEPAWAKE := 0
20global TRACKBALL_SCROLL := 1
21global DEBUG_MODE := 0
22
23; --- Advanced Settings (Loaded from INI) ---
24global BTG_TAB_DELAY := 80
25global BTG_POPUP_DELAY := 500
26global SCROLL_THRESHOLD := 15
27global SCROLL_LOCK_RATIO := 2.0
28
29; --- Marker Customization ---
30global MARKER_SIZE := 5
31global MARKER_COLOR := "FF0000"
32global MARKER_ALPHA := 180
33
34; --- Reliability Settings ---
35SetKeyDelay 10, 10
36global LOGIN_STEP_DELAY := 150
37
38; --- Window Titles & Layout Apps ---
39global EPIC_TITLE := "Prod"
40global PS := "PowerScribe"
41global VISAGE := "Visage"
42global VISAGE_LOGIN := "Client Login ahk_class Qt51510QWindowIcon"
43
44global WORKSPACE_APPS := [
45 {name: "PowerScribe", disp: "PowerScribe", title: "360 ahk_exe Nuance.PowerScribe360.exe", enabled: 1},
46 {name: "Epic", disp: "Epic", title: "Epic ahk_exe wfica32.exe", enabled: 1},
47 {name: "VisageBrowser", disp: "Vis Browser", title: "Study Browser", enabled: 1},
48 {name: "VisageNavigator", disp: "Vis Nav", title: "Study Navigator", enabled: 1},
49 {name: "Chrome", disp: "Chrome", title: "ahk_exe chrome.exe", enabled: 1},
50 {name: "VisageWorklist", disp: "Vis Worklist", title: "Worklist", enabled: 1}
51]
52
53global RADSMODE := false
54global MarkerGui := unset
55
56; ==============================================================================
57; Initialization
58; ==============================================================================
59LoadSettings()
60CreateCursorMarker()
61
62; ==============================================================================
63; Main GUI
64; ==============================================================================
65myGui := Gui()
66myGui.Title := "Radiology Helper " . VERSION
67myGui.BackColor := "FBFBFB"
68myGui.SetFont("s10", "Segoe UI")
69
70; --- Login Section ---
71myGui.Add("GroupBox", "x20 y10 w460 h115", "Login Credentials")
72
73myGui.Add("Text", "x40 y35 w70 h25 +0x200", "Username:")
74Edit1 := myGui.Add("Edit", "x115 y35 w130 h25", USER)
75myGui.Add("Text", "x255 y35 w70 h25 +0x200", "Password:")
76Edit2 := myGui.Add("Edit", "x330 y35 w110 h25 +Password", PASS)
77
78myGui.Add("Text", "x40 y75 w70 h25 +0x200", "BV Pass:")
79Edit3 := myGui.Add("Edit", "x115 y75 w130 h25 +Password", BV_PASS)
80
81; --- Action Button ---
82LaunchButton := myGui.Add("Button", "x20 y140 w260 h50 +Default", "Launch Visage System")
83LaunchButton.OnEvent("Click", LaunchButtonHandler)
84LaunchButton.SetFont("s11 bold")
85
86; --- Config Button ---
87ConfigButton := myGui.Add("Button", "x290 y140 w190 h50", "Advanced Config")
88ConfigButton.OnEvent("Click", OpenConfigMenu)
89
90; --- Options Section ---
91CheckBox1 := myGui.Add("CheckBox", "x40 y200 w150 h25 Checked" . KEEPAWAKE, "Prevent Sleep")
92CheckBox2 := myGui.Add("CheckBox", "x220 y200 w240 h25 Checked" . TRACKBALL_SCROLL, "Hold CapsLock to scroll")
93CheckBox3 := myGui.Add("CheckBox", "x40 y225 w150 h25 Checked" . DEBUG_MODE, "Debug Mode")
94
95CheckBox1.OnEvent("Click", UpdateGlobals)
96CheckBox2.OnEvent("Click", UpdateGlobals)
97CheckBox3.OnEvent("Click", UpdateGlobals)
98
99; --- Workspace Layout Section ---
100myGui.Add("GroupBox", "x20 y260 w460 h120", "Workspace Layout (Multi-Monitor)")
101
102Chk_PS := myGui.Add("CheckBox", "x30 y285 w140 h20 Checked" . WORKSPACE_APPS[1].enabled, "PowerScribe")
103Chk_Epic := myGui.Add("CheckBox", "x180 y285 w130 h20 Checked" . WORKSPACE_APPS[2].enabled, "Epic")
104Chk_VisB := myGui.Add("CheckBox", "x320 y285 w140 h20 Checked" . WORKSPACE_APPS[3].enabled, "Vis Browser")
105
106Chk_VisN := myGui.Add("CheckBox", "x30 y315 w140 h20 Checked" . WORKSPACE_APPS[4].enabled, "Vis Nav")
107Chk_Chrome := myGui.Add("CheckBox", "x180 y315 w130 h20 Checked" . WORKSPACE_APPS[5].enabled, "Chrome")
108Chk_VisW := myGui.Add("CheckBox", "x320 y315 w140 h20 Checked" . WORKSPACE_APPS[6].enabled, "Vis Worklist")
109
110Btn_SaveLayout := myGui.Add("Button", "x120 y345 w100 h25", "Save Layout")
111Btn_RestLayout := myGui.Add("Button", "x240 y345 w100 h25", "Restore Layout")
112
113; Link GUI controls to the array for dynamic text updates
114WORKSPACE_APPS[1].ctrl := Chk_PS
115WORKSPACE_APPS[2].ctrl := Chk_Epic
116WORKSPACE_APPS[3].ctrl := Chk_VisB
117WORKSPACE_APPS[4].ctrl := Chk_VisN
118WORKSPACE_APPS[5].ctrl := Chk_Chrome
119WORKSPACE_APPS[6].ctrl := Chk_VisW
120
121Chk_PS.OnEvent("Click", UpdateLayoutGlobals)
122Chk_Epic.OnEvent("Click", UpdateLayoutGlobals)
123Chk_VisB.OnEvent("Click", UpdateLayoutGlobals)
124Chk_VisN.OnEvent("Click", UpdateLayoutGlobals)
125Chk_Chrome.OnEvent("Click", UpdateLayoutGlobals)
126Chk_VisW.OnEvent("Click", UpdateLayoutGlobals)
127Btn_SaveLayout.OnEvent("Click", SaveWorkspace)
128Btn_RestLayout.OnEvent("Click", RestoreWorkspace)
129
130; --- Divider ---
131myGui.Add("Text", "x20 y390 w460 h2 0x10")
132
133; --- Reference Guide ---
134myGui.SetFont("s9", "Segoe UI")
135RefGroup := myGui.Add("GroupBox", "x20 y400 w460 h235", "Quick Reference Guide")
136
137; Column 1: Global
138myGui.SetFont("s9 w700")
139myGui.Add("Text", "x40 y420 w180", "Global Shortcuts")
140myGui.SetFont("s9 w400")
141myGui.Add("Text", "x40 y440 w200", "Caps + f : Rads Mode ON")
142myGui.Add("Text", "x40 y460 w200", "Caps + d : Rads Mode OFF")
143myGui.Add("Text", "x40 y480 w200", "Caps + w : Restore Layout")
144myGui.Add("Text", "x40 y500 w200", "Caps + c : Refresh PS Target")
145myGui.Add("Text", "x40 y520 w200", "Ctrl + Alt + s : Save Layout")
146myGui.Add("Text", "x40 y540 w200", "Alt + z : Fast Break Glass")
147myGui.Add("Text", "x40 y560 w200", "Shift + Caps : Toggle CapsLock")
148
149; Column 2: Rads Mode
150myGui.SetFont("s9 w700")
151myGui.Add("Text", "x260 y420 w180", "Rads Mode (Vim-Style)")
152myGui.SetFont("s9 w400")
153myGui.Add("Text", "x260 y440 w200", "d : Toggle Dictation")
154myGui.Add("Text", "x260 y460 w200", "h : Save Draft (F9)")
155myGui.Add("Text", "x260 y480 w200", "f / g : Next / Prev Field")
156myGui.Add("Text", "x260 y500 w200", "s / a : Backspace / Enter")
157myGui.Add("Text", "x260 y520 w200", "1 - 5 : Pick List Choice")
158
159; Logic Note
160myGui.SetFont("s8 italic c555555")
161myGui.Add("Text", "x40 y590 w420", "Logic Note: Logins utilize a clipboard-injection method to instantly paste credentials, bypassing standard keystroke lag.")
162
163; Footer
164myGui.SetFont("s8 c777777")
165myGui.Add("Text", "x20 y640 w460 Center", "Note: Red dot indicator appears when Rads Mode is active.")
166
167UpdateLayoutDetection() ; Set initial UI state
168myGui.Show("w500 h670")
169
170; ==============================================================================
171; Cursor Marker Logic
172; ==============================================================================
173CreateCursorMarker() {
174 global MarkerGui, MARKER_SIZE, MARKER_COLOR, MARKER_ALPHA
175 if IsSet(MarkerGui)
176 MarkerGui.Destroy()
177 MarkerGui := Gui("+AlwaysOnTop -Caption +ToolWindow +E0x20")
178 MarkerGui.BackColor := MARKER_COLOR
179 D := MARKER_SIZE
180 WinSetRegion("0-0 W" D " H" D " R" D "-" D, MarkerGui.Hwnd)
181 MarkerGui.Opt("+LastFound")
182 WinSetTransparent(MARKER_ALPHA, MarkerGui.Hwnd)
183}
184
185UpdateMarkerPos() {
186 global RADSMODE, MarkerGui, MARKER_SIZE
187 if (RADSMODE) {
188 MouseGetPos(&mX, &mY)
189 MarkerGui.Show("x" (mX + 12) " y" (mY + 12) " w" MARKER_SIZE " h" MARKER_SIZE " NoActivate")
190 } else {
191 MarkerGui.Hide()
192 }
193}
194
195; ==============================================================================
196; Advanced Config Menu
197; ==============================================================================
198OpenConfigMenu(*) {
199 advGui := Gui()
200 advGui.Title := "Advanced Configuration"
201 advGui.SetFont("s9", "Segoe UI")
202
203 advGui.Add("GroupBox", "x10 y10 w380 h100", "Rads Mode Indicator (Dot)")
204 advGui.Add("Text", "x30 y35 w100 h20", "Dot Size (px):")
205 Ctrl_Size := advGui.Add("Edit", "x130 y32 w60 h20 Number", MARKER_SIZE)
206 advGui.Add("Text", "x210 y35 w80 h20", "Hex Color:")
207 Ctrl_Color := advGui.Add("Edit", "x290 y32 w80 h20", MARKER_COLOR)
208 advGui.Add("Text", "x30 y65 w100 h20", "Opacity (0-255):")
209 Ctrl_Alpha := advGui.Add("Edit", "x130 y62 w60 h20 Number", MARKER_ALPHA)
210
211 advGui.Add("GroupBox", "x10 y120 w380 h130", "Workflow Settings")
212 advGui.Add("Text", "x30 y145 w150 h20", "Tab Delay (ms):")
213 Ctrl_TabDelay := advGui.Add("Edit", "x240 y142 w80 h20 Number", BTG_TAB_DELAY)
214 advGui.Add("Text", "x30 y175 w150 h20", "Scroll Sensitivity:")
215 Ctrl_Sens := advGui.Add("Edit", "x240 y172 w80 h20 Number", SCROLL_THRESHOLD)
216 advGui.Add("Text", "x30 y205 w150 h20", "Axis Lock Ratio:")
217 Ctrl_Lock := advGui.Add("Edit", "x240 y202 w80 h20", SCROLL_LOCK_RATIO)
218
219 SaveBtn := advGui.Add("Button", "x90 y270 w100 h30", "Save")
220 CancelBtn := advGui.Add("Button", "x200 y270 w100 h30", "Cancel")
221 SaveBtn.OnEvent("Click", SaveHandler)
222 CancelBtn.OnEvent("Click", (*) => advGui.Destroy())
223 advGui.Show()
224
225 SaveHandler(*) {
226 global BTG_TAB_DELAY, SCROLL_THRESHOLD, SCROLL_LOCK_RATIO
227 global MARKER_SIZE, MARKER_COLOR, MARKER_ALPHA
228 MARKER_SIZE := Ctrl_Size.Value
229 MARKER_COLOR := Ctrl_Color.Value
230 MARKER_ALPHA := Ctrl_Alpha.Value
231 BTG_TAB_DELAY := Ctrl_TabDelay.Value
232 SCROLL_THRESHOLD := Ctrl_Sens.Value
233 SCROLL_LOCK_RATIO := Number(Ctrl_Lock.Value)
234 SaveSettings()
235 CreateCursorMarker()
236 advGui.Destroy()
237 MsgBox("Settings Saved!", "Configuration", "Iconi T1")
238 }
239}
240
241; ==============================================================================
242; INI Persistence Functions
243; ==============================================================================
244LoadSettings() {
245 global BTG_TAB_DELAY, SCROLL_THRESHOLD, SCROLL_LOCK_RATIO
246 global MARKER_SIZE, MARKER_COLOR, MARKER_ALPHA, WORKSPACE_APPS
247 if FileExist(INI_FILE) {
248 try {
249 BTG_TAB_DELAY := IniRead(INI_FILE, "Citrix", "TabDelay", 80)
250 SCROLL_THRESHOLD := IniRead(INI_FILE, "Physics", "Sensitivity", 15)
251 SCROLL_LOCK_RATIO := IniRead(INI_FILE, "Physics", "AxisLock", 2.0)
252 MARKER_SIZE := IniRead(INI_FILE, "Marker", "Size", 5)
253 MARKER_COLOR := IniRead(INI_FILE, "Marker", "Color", "FF0000")
254 MARKER_ALPHA := IniRead(INI_FILE, "Marker", "Alpha", 180)
255
256 for app in WORKSPACE_APPS {
257 app.enabled := IniRead(INI_FILE, "LayoutSettings", app.name . "_Enabled", 1)
258 }
259 }
260 }
261}
262
263SaveSettings() {
264 global WORKSPACE_APPS
265 IniWrite(BTG_TAB_DELAY, INI_FILE, "Citrix", "TabDelay")
266 IniWrite(SCROLL_THRESHOLD, INI_FILE, "Physics", "Sensitivity")
267 IniWrite(SCROLL_LOCK_RATIO, INI_FILE, "Physics", "AxisLock")
268 IniWrite(MARKER_SIZE, INI_FILE, "Marker", "Size")
269 IniWrite(MARKER_COLOR, INI_FILE, "Marker", "Color")
270 IniWrite(MARKER_ALPHA, INI_FILE, "Marker", "Alpha")
271
272 for app in WORKSPACE_APPS {
273 IniWrite(app.enabled, INI_FILE, "LayoutSettings", app.name . "_Enabled")
274 }
275}
276
277; ==============================================================================
278; GUI Handlers & Detection
279; ==============================================================================
280UpdateGlobals(*) {
281 global USER := Edit1.Value, PASS := Edit2.Value, BV_PASS := Edit3.Value
282 global KEEPAWAKE := CheckBox1.Value
283 global TRACKBALL_SCROLL := CheckBox2.Value, DEBUG_MODE := CheckBox3.Value
284}
285
286UpdateLayoutGlobals(*) {
287 global WORKSPACE_APPS
288 WORKSPACE_APPS[1].enabled := Chk_PS.Value
289 WORKSPACE_APPS[2].enabled := Chk_Epic.Value
290 WORKSPACE_APPS[3].enabled := Chk_VisB.Value
291 WORKSPACE_APPS[4].enabled := Chk_VisN.Value
292 WORKSPACE_APPS[5].enabled := Chk_Chrome.Value
293 WORKSPACE_APPS[6].enabled := Chk_VisW.Value
294 SaveSettings()
295}
296
297UpdateLayoutDetection() {
298 global WORKSPACE_APPS
299 for app in WORKSPACE_APPS {
300 if WinExist(app.title) {
301 if !InStr(app.ctrl.Text, "(Active)")
302 app.ctrl.Text := app.disp . " (Active)"
303 } else {
304 if !InStr(app.ctrl.Text, "(Off)")
305 app.ctrl.Text := app.disp . " (Off)"
306 }
307 }
308}
309
310LaunchButtonHandler(*) {
311 LaunchVisage()
312 myGui.Minimize()
313}
314CloseHandler(*) => ExitApp()
315
316; ==============================================================================
317; Workspace Layout Core Logic
318; ==============================================================================
319SaveWorkspace(*) {
320 global INI_FILE, WORKSPACE_APPS
321 savedList := ""
322
323 for app in WORKSPACE_APPS {
324 if (app.enabled && WinExist(app.title)) {
325 minMax := WinGetMinMax(app.title)
326
327 if (minMax == -1) {
328 WinRestore(app.title)
329 Sleep(50)
330 }
331
332 WinGetPos(&X, &Y, &W, &H, app.title)
333
334 IniWrite(X, INI_FILE, "Layout_" . app.name, "X")
335 IniWrite(Y, INI_FILE, "Layout_" . app.name, "Y")
336 IniWrite(W, INI_FILE, "Layout_" . app.name, "W")
337 IniWrite(H, INI_FILE, "Layout_" . app.name, "H")
338 IniWrite(minMax == 1 ? 1 : 0, INI_FILE, "Layout_" . app.name, "Maximized")
339
340 if (minMax == -1) {
341 WinMinimize(app.title)
342 }
343 savedList .= app.disp . ", "
344 }
345 }
346
347 if (savedList != "") {
348 ToolTip("Saved Layout: " . RTrim(savedList, ", "))
349 } else {
350 ToolTip("No enabled apps detected to save.")
351 }
352 SetTimer () => ToolTip(), -3000
353}
354
355RestoreWorkspace(*) {
356 global INI_FILE, WORKSPACE_APPS
357 restoredList := ""
358
359 for app in WORKSPACE_APPS {
360 if (app.enabled && WinExist(app.title)) {
361 try {
362 X := IniRead(INI_FILE, "Layout_" . app.name, "X", "")
363 if (X == "")
364 continue
365
366 Y := IniRead(INI_FILE, "Layout_" . app.name, "Y")
367 W := IniRead(INI_FILE, "Layout_" . app.name, "W")
368 H := IniRead(INI_FILE, "Layout_" . app.name, "H")
369 isMax := IniRead(INI_FILE, "Layout_" . app.name, "Maximized")
370
371 WinRestore(app.title)
372 Sleep(50)
373 WinMove(X, Y, W, H, app.title)
374
375 if (app.name == "Epic") {
376 Sleep(100)
377 }
378
379 if (isMax == 1) {
380 WinMaximize(app.title)
381 }
382 restoredList .= app.disp . ", "
383 }
384 }
385 }
386
387 if (restoredList != "") {
388 ToolTip("Restored Layout: " . RTrim(restoredList, ", "))
389 } else {
390 ToolTip("No layouts restored.")
391 }
392 SetTimer () => ToolTip(), -3000
393}
394
395; ==============================================================================
396; Core Logic
397; ==============================================================================
398SetTimer StopSleep, 100000
399SetTimer UpdateMarkerPos, 100
400SetTimer UpdateLayoutDetection, 2000
401
402LaunchVisage() {
403 if WinExist(VISAGE) {
404 WinActivate(VISAGE)
405 return
406 }
407 if WinExist(VISAGE_LOGIN) {
408 VisageLoginSequence()
409 return
410 }
411 targetLnk := ""
412 loop files A_Desktop "\*Visage*.lnk" {
413 targetLnk := A_LoopFileFullPath
414 break
415 }
416 if (targetLnk == "") {
417 loop files A_DesktopCommon "\*Visage*.lnk" {
418 targetLnk := A_LoopFileFullPath
419 break
420 }
421 }
422 if (targetLnk) {
423 Run(targetLnk)
424 } else {
425 fallbackPath := "C:\Program Files\Visage Imaging\Visage 7.1\bin\arch-Win\vsclient.exe"
426 if FileExist(fallbackPath) {
427 Run(fallbackPath)
428 } else {
429 MsgBox("Could not find Visage executable.", "Error", "Icon!")
430 return
431 }
432 }
433 if WinWait(VISAGE_LOGIN,, 20) {
434 VisageLoginSequence()
435 }
436}
437
438VisageLoginSequence() {
439 global VISAGE_LOGIN, LOGIN_STEP_DELAY
440 global Edit1, Edit2
441
442 if !WinExist(VISAGE_LOGIN)
443 return
444 WinActivate(VISAGE_LOGIN)
445 if !WinWaitActive(VISAGE_LOGIN,, 3)
446 return
447
448 local safeUser := Edit1.Value
449 local safePass := Edit2.Value
450
451 SetKeyDelay 10, 10
452
453 WinGetPos(,, &winW, &winH, VISAGE_LOGIN)
454 oldMode := A_CoordModeMouse
455 CoordMode "Mouse", "Window"
456
457 MouseMove(winW * 0.60, winH * 0.40)
458 Sleep(LOGIN_STEP_DELAY)
459 Click()
460 Sleep(LOGIN_STEP_DELAY)
461
462 ClipSaved := ClipboardAll()
463
464 SendEvent("^a{Delete}")
465 Sleep(LOGIN_STEP_DELAY)
466 A_Clipboard := ""
467 A_Clipboard := "VISAGE.NYUMC.ORG"
468 ClipWait(1)
469 Send("^v")
470 Sleep(LOGIN_STEP_DELAY + 50)
471 SendEvent("{Tab}")
472 Sleep(LOGIN_STEP_DELAY)
473
474 SendEvent("^a{Delete}")
475 Sleep(LOGIN_STEP_DELAY)
476 A_Clipboard := ""
477 A_Clipboard := safeUser
478 ClipWait(1)
479 Send("^v")
480 Sleep(LOGIN_STEP_DELAY + 50)
481 SendEvent("{Tab}")
482 Sleep(LOGIN_STEP_DELAY)
483
484 A_Clipboard := ""
485 A_Clipboard := safePass
486 ClipWait(1)
487 Send("^v")
488 Sleep(LOGIN_STEP_DELAY + 200)
489
490 SendEvent("{Enter}")
491
492 Sleep(150)
493 A_Clipboard := ClipSaved
494
495 CoordMode "Mouse", oldMode
496}
497
498; --- Fast Break Glass (Clipboard Injection) ---
499fastBreakGlass(*) {
500 global BTG_TAB_DELAY, Edit2
501
502 ClipSaved := ClipboardAll()
503
504 A_Clipboard := ""
505 A_Clipboard := "Provision"
506 ClipWait(1)
507 Send("^v")
508 Sleep(BTG_TAB_DELAY + 50)
509
510 Send("{Tab}")
511 Sleep(BTG_TAB_DELAY)
512 Send("{Tab}")
513 Sleep(BTG_TAB_DELAY)
514
515 A_Clipboard := ""
516 A_Clipboard := Edit2.Value
517 ClipWait(1)
518 Send("^v")
519 Sleep(BTG_TAB_DELAY + 50)
520
521 Send("!a")
522
523 Sleep(150)
524 A_Clipboard := ClipSaved
525}
526
527loginSite() {
528 global Edit1, Edit2
529
530 ClipSaved := ClipboardAll()
531
532 A_Clipboard := ""
533 A_Clipboard := Edit1.Value
534 ClipWait(1)
535 Send("^v")
536 Sleep(200)
537 Send("{Tab}")
538 Sleep(200)
539
540 A_Clipboard := ""
541 A_Clipboard := Edit2.Value
542 ClipWait(1)
543 Send("^v")
544 Sleep(200)
545 Send("{Enter}")
546
547 Sleep(150)
548 A_Clipboard := ClipSaved
549}
550
551; --- Bellevue Remote Desktop Login ---
552loginBellevue(*) {
553 global Edit3
554 KeyWait("Alt")
555 KeyWait("b")
556 Sleep(100)
557 SetKeyDelay 40, 40
558 SendEvent("{Raw}" Edit3.Value)
559 Sleep(200)
560 SendEvent("{Enter}")
561}
562
563; ==============================================================================
564; CAPSLOCK & MODIFIER HOTKEYS
565; ==============================================================================
566
567; --- Shift + CapsLock toggles the actual uppercase state ---
568+CapsLock::CapsLock
569
570; --- CapsLock intercepts ---
571#HotIf TRACKBALL_SCROLL
572 $CapsLock::TrackballScroll()
573#HotIf
574
575; --- Disable standard CapsLock press if Trackball scroll is off ---
576#HotIf !TRACKBALL_SCROLL
577 $CapsLock::return
578#HotIf
579
580; --- Custom Rads Mode Modifiers ---
581#HotIf GetKeyState("CapsLock", "P")
582 f:: enableRadsMode()
583 d:: exitRadsMode()
584 w:: RestoreWorkspace()
585 c:: ForceRefreshControl()
586#HotIf
587
588; ==============================================================================
589; CAPSLOCK SCROLL
590; ==============================================================================
591TrackballScroll(*) {
592 global SCROLL_THRESHOLD, SCROLL_LOCK_RATIO
593 oldMode := A_CoordModeMouse
594 CoordMode "Mouse", "Screen"
595 MouseGetPos(&startX, &startY)
596 bankX := 0, bankY := 0
597 Loop {
598 if !GetKeyState("CapsLock", "P")
599 break
600 MouseGetPos(¤tX, ¤tY)
601 moveX := currentX - startX, moveY := currentY - startY
602 if (moveX != 0 || moveY != 0) {
603 DllCall("SetCursorPos", "int", startX, "int", startY)
604 }
605 bankX += moveX, bankY += moveY
606 absX := Abs(bankX), absY := Abs(bankY)
607 if (absX > (absY * SCROLL_LOCK_RATIO)) {
608 if (absX >= SCROLL_THRESHOLD) {
609 ticks := Integer(absX / SCROLL_THRESHOLD)
610 direction := (bankX > 0) ? "{WheelRight}" : "{WheelLeft}"
611 Loop ticks
612 Send(direction)
613 bankX := Mod(bankX, SCROLL_THRESHOLD), bankY := 0
614 }
615 } else if (absY > absX) {
616 if (absY >= SCROLL_THRESHOLD) {
617 ticks := Integer(absY / SCROLL_THRESHOLD)
618 direction := (bankY > 0) ? "{WheelDown}" : "{WheelUp}"
619 Loop ticks
620 Send(direction)
621 bankY := Mod(bankY, SCROLL_THRESHOLD), bankX := 0
622 }
623 }
624 Sleep(5)
625 }
626 CoordMode "Mouse", oldMode
627}
628
629; ==============================================================================
630; UTILS & HOTKEYS
631; ==============================================================================
632GetTargetControl(forceRefresh := false) {
633 global PS
634
635 largestArea := 0
636 bestControl := ""
637
638 try {
639 ctrlList := WinGetControls(PS)
640 for ctrl in ctrlList {
641 if InStr(ctrl, "RICHEDIT") {
642 try {
643 ; Ensure the control is visible
644 if ControlGetVisible(ctrl, PS) {
645 ControlGetPos(&x, &y, &w, &h, ctrl, PS)
646
647 ; Filter out phantom formatting buffers
648 if (w > 20 && h > 20) {
649 area := w * h
650 if (area > largestArea) {
651 largestArea := area
652 bestControl := ctrl
653 }
654 }
655 }
656 } catch {
657 continue
658 }
659 }
660 }
661 }
662
663 return bestControl
664}
665
666ActivateAndSend(key, targetSpecificControl := true) {
667 global PS
668 if !WinExist(PS)
669 return
670
671 ; [ANTI-DEADLOCK FAST PATH]
672 ; Uses SendEvent for improved reliability with Nuance/Dragon hooks
673 if WinActive(PS) {
674 SendEvent(key)
675 return
676 }
677
678 ; Slow path (if clicking back into PS from Epic/Visage)
679 WinActivate(PS)
680 if !WinWaitActive(PS,, 1)
681 return
682 Sleep(50)
683
684 if targetSpecificControl {
685 target := GetTargetControl()
686 if (target) {
687 try {
688 if (ControlGetFocus(PS) != target) {
689 ControlFocus(target, PS)
690 }
691 }
692 }
693 }
694
695 SendEvent(key)
696}
697
698StopSleep(*) {
699 if (KEEPAWAKE) {
700 SendEvent("{F15}")
701 }
702}
703
704pick(num) {
705 global PS
706 MouseGetPos &startX, &startY
707 CoordMode "Mouse", "Client"
708 heightRow := 17
709 if WinExist(PS) {
710 try {
711 for ctrl in WinGetControls(PS) {
712 try {
713 txt := ControlGetText(ctrl, PS)
714 } catch {
715 continue
716 }
717 if (txt == "Pick List Choices") {
718 ControlGetPos(&x, &y, &w, &h, ctrl, PS)
719 targetY := y + Integer(heightRow/2) + (heightRow * num)
720 targetX := x + 20
721 if !WinActive(PS) {
722 WinActivate(PS)
723 WinWaitActive(PS,, 1)
724 }
725 Click(targetX, targetY)
726 Sleep(50)
727 Click(targetX, targetY)
728 CoordMode "Mouse", "Screen"
729 MouseMove(startX, startY)
730 Sleep(50)
731 ActivateAndSend("{Tab}", true)
732 return
733 }
734 }
735 }
736 }
737 CoordMode "Mouse", "Screen"
738}
739
740; -- Common Rads Logic --
741toggleDictation(*) {
742 static lastToggle := 0
743
744 ; Debounce to prevent double-triggers
745 if (A_TickCount - lastToggle < 500) {
746 return
747 }
748 lastToggle := A_TickCount
749
750 ; Routes through ActivateAndSend to ensure PowerScribe is targeted,
751 ; passing 'false' so it skips searching for a specific text control.
752 ActivateAndSend("{F4}", false)
753}
754
755saveDraft(*) => ActivateAndSend("{F9}", false)
756nextField(*) => ActivateAndSend("{Tab}", true)
757prevField(*) => ActivateAndSend("+{Tab}", true)
758backspace(*) => ActivateAndSend("{Backspace}", true)
759newLine(*) => ActivateAndSend("{Enter}", true)
760
761enableRadsMode(*) {
762 global RADSMODE := true
763 GetTargetControl(true) ; Automatically flush and re-target when entering Rads Mode
764}
765exitRadsMode(*) {
766 global RADSMODE := false
767}
768
769ForceRefreshControl(*) {
770 GetTargetControl(true)
771 ToolTip("PowerScribe Target Refreshed")
772 SetTimer () => ToolTip(), -1500
773}
774
775; -- Global Hotkeys --
776!z:: fastBreakGlass()
777!p:: loginSite()
778
779!b:: loginBellevue()
780
781^!s:: SaveWorkspace()
782
783#HotIf RADSMODE
784 r::LButton
785 e::MButton
786 w::RButton
787 $d:: toggleDictation()
788 $h:: saveDraft()
789 $f:: nextField()
790 $g:: prevField()
791 $s:: backspace()
792 $a:: newLine()
793 $q:: Send("^w")
794
795 ; -- Pick List Hotkeys --
796 $1:: (WinActive(PS) ? pick(1) : Send("1"))
797 $2:: (WinActive(PS) ? pick(2) : Send("2"))
798 $3:: (WinActive(PS) ? pick(3) : Send("3"))
799 $4:: (WinActive(PS) ? pick(4) : Send("4"))
800 $5:: (WinActive(PS) ? pick(5) : Send("5"))
801
802 $z:: (WinActive(PS) ? "" : Send("z"))
803 $x:: (WinActive(PS) ? "" : Send("x"))
804 $c:: (WinActive(PS) ? "" : Send("c"))
805 $v:: (WinActive(PS) ? "" : Send("v"))
806#HotIf
807This 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.