Hey all, probably use this forum to munge together documentation, but at least here's the working script.
I use WinXP as my primary OS at work, however I'm a Unix SA so I use terminal windows of one sort or another *alot*. This script is the answer to my wanting to spend less time typing when configuring a cluster.
Default output mode is character at a time. With this setting the script maxes out at 4 outputs on my 2.1Ghz Core 2 laptop (T7400) at my best typing speed. If I slow it down of course it can go to the 10 maximum outputs the script is written for. There's a few hackish things I did to get around speed limitations, and probably a few stupid things too.
How to use: Run the script! Click the + button, click on a window you want to send output to (I use putty). Repeat as necessary to add your terminals to the list. Click in the input box and type away.
To change input mode, click the 3rd statusbar entry (says Char Input). To edit macros click the 2nd statusbar entry (says Run macros), get out of edit mode by clicking again.
If you need to remove a window click - . You don't need to remove a window to interact with it seperately, just click the window you want to fiddle with and go to it. Just remember that when you start typing in Cluster Control again, all the windows in the list get what you're typing.
Things that don't work: CapsLock when you're in Char input mode.
Multi-modifier keys, Alt Modifier keys, and modified non-printables in Char input mode. Typing too fast in Char input mode.
Suggestions/comments/etc ?
Code:
IniFile = ClusterControl.ini
WinTitle = Cluster Control
PickDelay = 15
LocX = Center
LocY = Center
InStyle = Line
MacroMode = Run
TermCount = 0
TermMax = 10
Loop %TermMax%
Terms%A_Index% = 0
HitEnter = 0
LastInSize = 0
NewInSize = 0
NoMacEdit = 1
EditMe := ""
MyEditTitle = Edit Macro
GoSub ReadIni
Gui 1:Add, Edit, x6 y7 w530 h20 -WantReturn +WantTab +WantCtrlA vTheInput gGotInput,
Gui 1:Add, Button, x6 y37 w50 h20 v1 gDoMacro, %MacroButt1%
Gui 1:Add, Button, x66 y37 w50 h20 v2 gDoMacro, %MacroButt2%
Gui 1:Add, Button, x126 y37 w50 h20 v3 gDoMacro, %MacroButt3%
Gui 1:Add, Button, x186 y37 w50 h20 v4 gDoMacro, %MacroButt4%
Gui 1:Add, Button, x246 y37 w50 h20 v5 gDoMacro, %MacroButt5%
Gui 1:Add, Button, x306 y37 w50 h20 v6 gDoMacro, %MacroButt6%
Gui 1:Add, Button, x366 y37 w50 h20 v7 gDoMacro, %MacroButt7%
Gui 1:Add, Button, x426 y37 w50 h20 v8 gDoMacro, %MacroButt8%
Gui 1:Add, Button, x486 y37 w20 h20 vAdd gDoAdd, +
Gui 1:Add, Button, x516 y37 w20 h20 vRem gDoRem, -
GuiControl Disable, Rem
Gui 1:Add, Button, x527 y37 w0 h0 gDoSend Default, Send
Gui 1:Add, StatusBar, gStatusBar
SB_SetParts(400, 80, 65)
SB_SetText("You need to add windows to the " . WinTitle . " list (click +)", 1)
SB_SetText("`t" . MacroMode . " Macros", 2)
SB_SetText("`t" . InStyle . " Input", 3)
Gui 1:+OwnDialogs
Gui 1:Show, x%LocX% y%LocY% AutoSize, %WinTitle%
GroupAdd MyApp, %WinTitle%
Return
GuiClose:
GuiEscape:
GoSub SaveIni
ExitApp
Return
StatusBar:
if (A_GuiEvent != "Normal")
Return
SetTimer WipeStatus1, -10000
if (A_EventInfo = 2) {
if (MacroMode = "Run") {
MacroMode = Edit
SB_SetText("`t" . MacroMode . " Macros", 2)
} else {
MacroMode = Run
SB_SetText("`t" . MacroMode . " Macros", 2)
}
SB_SetText("Click a macro button to " . MacroMode . " the macro.", 1)
} else if (A_EventInfo = 3) {
if (InStyle = "Line") {
InStyle = Char
SB_SetText("`t" . InStyle . " Input", 3)
SetKeyDelay -1, -1
GuiControl Text, TheInput,
} else {
InStyle = Line
SB_SetText("`t" . InStyle . " Input", 3)
SetKeyDelay 10, -1
}
SB_SetText("Input set to " . InStyle . " mode.", 1)
}
Return
DoSend:
HitEnter = 1
GotInput:
Gui 1:Submit, NoHide
if (InStyle = "Char") {
SetBatchLines -1
if (HitEnter = 1) {
SendMe := "{Enter}"
} else {
SendMe := TheInput
}
} else {
if (HitEnter = 1)
SendMe := TheInput . "{Enter}"
}
if (HitEnter = 1 || InStyle = "Char") {
GoSub OutputLoop
GuiControl Text, TheInput,
SetBatchLines 10ms
}
SendMe := ""
HitEnter = 0
Return
OutputLoop:
Loop %TermMax% {
if (Terms%A_Index%) {
id := Terms%A_Index%
IfWinExist ahk_id %id%
ControlSend , , %SendMe%, ahk_id %id%
else {
Terms%A_Index% = 0
TermCount--
}
if ErrorLevel
MsgBox Error %id%
}
}
Return
DoAdd:
SetTimer WipeStatus1, -10000
if (TermCount = TermMax) {
SB_SetText("Error: Maximum number of windows attached: " . TermCount . ".", 1)
Return
}
SB_SetText("Click on a window to add it to the " . WinTitle . " list.", 1)
WinWaitNotActive %WinTitle%,, %PickDelay%
if (ErrorLevel = 1) {
SB_SetText("Error: Action timed out, please try again.", 1)
SetTimer WipeStatus1, -10000
Return
}
WinGet FoundID, ID, A
WinGetClass FoundClass, A
if (FoundClass = "Progman" || Foundclass = "Shell_TrayWnd") {
SB_SetText("Error: You didn't click on a window.", 1)
Return
}
WinGetTitle FoundTitle, A
SB_SetText("Window added: " . FoundTitle, 1)
TermCount++
Loop %TermMax% {
if (Terms%A_Index% = FoundID ) {
Return
}
}
Loop %TermMax% {
if (Terms%A_Index% = 0 ) {
Terms%A_Index% = %FoundID%
break
}
}
if (TermCount = 1) {
GuiControl Enable, Rem
}
Return
DoRem:
SetTimer WipeStatus1, -10000
if (TermCount = 0) {
SB_SetText("Error: There are no more windows attached.", 1)
GuiControl Disable, Rem
Return
}
SB_SetText("Click on a window to remove it from the " . WinTitle . " list.", 1)
WinWaitNotActive %WinTitle%,, %PickDelay%
if (ErrorLevel = 1) {
SB_SetText("Error: Action timed out, please try again.", 1)
SetTimer WipeStatus1, -10000
Return
}
WinGet FoundID, ID, A
WinGetClass FoundClass, A
if (FoundClass = "Progman" || Foundclass = "Shell_TrayWnd") {
SB_SetText("Error: You didn't click on a window.", 1)
Return
}
WinGetTitle FoundTitle, A
SB_SetText("Window removed: " . FoundTitle, 1)
Loop %TermMax% {
if (Terms%A_Index% = FoundID ) {
Terms%A_Index% = 0
TermCount--
if (TermCount = 0) {
GuiControl Disable, Rem
}
Return
}
}
Return
WipeStatus1:
SB_SetText("", 1)
Return
#IfWinActive ahk_group MyApp
Esc::
Del::
Ins::
Home::
End::
PgUp::
PgDn::
Tab::
BS::
Left::
Right::
Up::
Down::
SendMe := "{" . A_ThisHotKey . "}"
^a::
^b::
^c::
^d::
^e::
^f::
^g::
^h::
^i::
^j::
^k::
^l::
^m::
^n::
^o::
^p::
^q::
^r::
^s::
^t::
^u::
^v::
^w::
^x::
^y::
^z::
a::
b::
c::
d::
e::
f::
g::
h::
i::
j::
k::
l::
m::
n::
o::
p::
q::
r::
s::
t::
u::
v::
w::
x::
y::
z::
+a::
+b::
+c::
+d::
+e::
+f::
+g::
+h::
+i::
+j::
+k::
+l::
+m::
+n::
+o::
+p::
+q::
+r::
+s::
+t::
+u::
+v::
+w::
+x::
+y::
+z::
1::
2::
3::
4::
5::
6::
7::
8::
9::
0::
if (SendMe = "")
SendMe = %A_ThisHotKey%
if (InStyle = "Char")
GoSub OutputLoop
else
Send %SendMe%
SendMe := ""
Return
#IfWinActive
DoHotkey:
WhichOne = %A_ThisHotKey%
DoMacro:
if (WhichOne = "") {
WhichOne = %A_GuiControl%
} else {
Loop 8
if (WhichOne = MacroHK%A_Index%)
WhichOne = %A_Index%
}
CurMacIdx = %WhichOne%
CurMacHK := MacroHK%WhichOne%
CurMacButt := MacroButt%WhichOne%
CurMacMac := MacroMacro%WhichOne%
CurMacKD := MacroKDelay%WhichOne%
WhichOne := ""
if (MacroMode = "Edit") {
Gui 1:+OwnDialogs
Gui 1:+Disabled
if (NoMacEdit)
GoSub CreateEditGUI
Gui 2:Show, AutoSize, %MyEditTitle%
GuiControl , 2:Text , TheHotKey, %CurMacHK%
GuiControl , 2:Text , ButtLabel, %CurMacButt%
GuiControl , 2:Text , Macro, %CurMacMac%
GuiControl , 2:Text , ShowKDelay, %CurMacKD%
Return
}
SendMe = %CurMacMac%
GoSub OutputLoop
Return
CreateEditGui:
Gui 2:Margin, 10, 10
Gui 2:Add, Text, xm ym+3 w60 r1 +Right, Hotkey
Gui 2:Add, Hotkey, ym w120 r1 vTheHotKey,
Gui 2:Add, Text, ym+3 w60 r1 +Right, Button label
Gui 2:Add, Edit, ym w120 r1 vButtLabel, Button Label
Gui 2:Add, Text, xm y+30 section w60 r3 +Right, Macro
Gui 2:Add, Edit, ys-20 r4 w320 vMacro, Macro
Gui 2:Add, Text, xm y+10 section w60 h20 +Right, Key delay
Gui 2:Add, Edit, ys-2 w40 h20 Number Limit3 gSetKDelay
Gui 2:Add, UpDown, Range0-500 vShowKDelay gSetKDelay, 10
Gui, 2:Add, Slider,
( Join
ys-4 w120 h20 vKDelay gKSlide
Range0-500 TickInterval50 Page50 Line10 AltSubmit
), 10
Gui 2:Add, Button, xm+210 ys+40 section w70 h20 gSaveButt, Save
Gui 2:Add, Button, xs+100 ys w70 h20 gCancelButt, Cancel
GroupAdd MyEdit, %MyEditTitle%
NoMacEdit = 0
Return
SetKDelay:
Gui 2:Submit, NoHide
Gui 2:+Disabled
if (ShowKDelay >= 500)
GuiControl ,, ShowKDelay, %ShowKDelay%
GuiControl ,, KDelay, %ShowKDelay%
Gui 2:-Disabled
Return
KSlide:
GuiControl ,,ShowKDelay, %KDelay%
Return
SaveButt:
Gui 2:Submit
GuiControlGet MacroHK%CurMacIdx%, , TheHotKey
GuiControlGet MacroButt%CurMacIdx%, , ButtLabel
GuiControlGet MacroMacro%CurMacIdx%, , Macro
GuiControlGet MacroKDelay%CurMacIdx%, , ShowKDelay
HotKey IfWinActive ahk_group MyApp
HotKey %CurMacHK%, Off
HotKey % MacroHK%CurMacIdx%, DoHotKey, T1
HotKey IfWinActive
GuiControl 1:Text, %CurMacIdx%, % MacroButt%CurMacIdx%
2GuiClose:
2GuiEscape:
CancelButt:
Gui 2:Hide
Gui 1:-Disabled
WinActivate %WinTitle%
Return
#IfWinActive ahk_group MyEdit
Esc::
Del::
Ins::
Home::
End::
PgUp::
PgDn::
Tab::
Enter::
#::
!::
^::
+::
&::
*::
~::
$::
EditMe := "{" . A_ThisHotKey . "}"
^a::
^b::
^c::
^d::
^e::
^f::
^g::
^h::
^i::
^j::
^k::
^l::
^m::
^n::
^o::
^p::
^q::
^r::
^s::
^t::
^u::
^v::
^w::
^x::
^y::
^z::
GuiControlGet Focii, 2:FocusV
if (Focii != "Macro") {
Send %EditMe%
return
}
if (EditMe = "")
EditMe = %A_ThisHotKey%
SendRaw %EditMe%
EditMe := ""
Return
#IfWinActive
ReadIni:
IniRead InStyle, %IniFile%, Defaults, InputStyle, Char
IniRead LocX, %IniFile%, Current, LocationX, Center
IniRead LocY, %IniFile%, Current, LocationY, Center
HotKey IfWinActive ahk_group MyApp
Loop 8 {
IniRead MacroHK%A_Index%, %IniFile%, Macro%A_Index%, HotKey, F%A_Index%
IniRead MacroButt%A_Index%, %IniFile%, Macro%A_Index%, ButtonLabel, Macro %A_Index%
IniRead MacroMacro%A_Index%, %IniFile%, Macro%A_Index%, Macro, %A_Space%
IniRead MacroKDelay%A_Index%, %IniFile%, Macro%A_Index%, KeyDelay, 10
if (MacroHK%A_Index%)
HotKey % MacroHK%A_Index%, DoHotKey, T1
}
HotKey IfWinActive
Return
SaveIni:
WinGetPos LocX, LocY, ,,%WinTitle%
IniWrite %LocX%, %IniFile%, Current, LocationX
IniWrite %LocY%, %IniFile%, Current, LocationY
Loop 8 {
IniWrite % MacroHK%A_Index%, %IniFile%, Macro%A_Index%, HotKey
IniWrite % MacroButt%A_Index%, %IniFile%, Macro%A_Index%, ButtonLabel
IniWrite % MacroMacro%A_Index%, %IniFile%, Macro%A_Index%, Macro
IniWrite % MacroKDelay%A_Index%, %IniFile%, Macro%A_Index%, KeyDelay
}
Return