Many of the JW freeware plug-ins use the window concept of a tree view to the left (with tasks arranged into containers) and a panel to the right that is specific to the task. This page contains code for [[http://www.autohotkey.com|AutoHotkey]] for Windows on how to fully automate a task in such a plug-in. AutoHotkey is a script-based Windows freeware macro application that's robust and extremely powerful, although it has some learning curve to work fluently (there are also GUI frontends and other tools available to simplify tasks). However, once the basic script is set up, adding new tasks is extremely trivial. This page contains functions and scripts to get you started. The full example can be downloaded here, so you can tweak it with more hotkeys: {{:wiki:autohotkey:finale-autohotkey-jwplugins.zip|Finale-autohotkey-jwplugins.zip}} ==== All you need to know ==== When you're basic script is set up, the following example should cover all you need to know to interact with the plug-in: #IfWinActive, ahk_class Finale ^!T:: if (openJWpluginwindow("JW Plug-ins", "JW Meter and Rhythm", 5, 1) = 1) { setJWpluginpanelvalue("JW Meter and Rhythm", 1, 1) applyandcloseJWpluginwindow("JW Meter and Rhythm") } return Since it's important to understand these lines of code, here's a closer look. #IfWinActive, ahk_class Finale means that the keyboard macro will only be available **when Finale is active**. (More specifically, it requires that a window with a window class called Finale is active.) ^!T:: is the **start of a keyboard macro**. ^ is the //Ctrl// key. ! is the //Alt// key. So the keyboard combination in the example is //Ctrl+Alt+T//. if (openJWpluginwindow("JW Plug-ins", "JW Meter and Rhythm", 5, 1) = 1) calls the openJWpluginwindow function in the script (the code for the function is listed below). The function will start the plug-in from the menu, assure that the window opens and select container and task in the window. If everything went well, the function returns 1. //Since the plug-in is modeless, you can execute this function even if the window is already on the screen.// The first parameter to the function is the name of the submenu in Finale's //Plug-in// menu. ==== How the code works ==== This section lists the specific functions and other code that are required for the script. At the start of the script, add the following standard lines: #NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. #Warn ; Enable warnings to assist with detecting common errors. SendMode Input ; Recommended for new scripts due to its superior speed and reliability. SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. Here's a general function, called //openJWpluginwindow()// that will open a plug-in and selects a task from the tree list. ; This function will open a plug-in and selects a task from the tree list. ; ; submenuname: The name of the Plug-ins submenu (where the plug-in is located) within quotes. ; Use "" for the root Plug-in menu. ; pluginname: The name of the plug-in name and window title (supply it within quotes) ; containerindex: The 1-based container from the top. Top container is 1, second container is 2, etc. ; taskindex: The 1-based task from the top of the container. First task is 1, second task is 2, etc. openJWpluginwindow(submenuname, pluginname, containerindex, taskindex) { ; open plugin window (from submenu or root Plug-in menu) if (submenuname = "") { WinMenuSelectItem, Finale 201, , Plug-ins, %pluginname% ; Root Plug-ins menu } else { WinMenuSelectItem, Finale 201, , Plug-ins, %submenuname%, %pluginname% ; Submenu in Plug-ins menu } ; Wait for max 1 second for the plug-in window to open WinWaitActive %pluginname%, ,1 if ErrorLevel { return 0 ; fail } ; Set focus to the tree view WinActivate %pluginname% ControlFocus SysTreeView321, %pluginname% if (ErrorLevel) { return 0 } ; Collapse all containers Send {Home} Loop 20 { Send {NumpadSub}{Down} } ; Move up to first container Send {Home} ; Move down to the correct container containerloop := containerindex - 1 Loop %containerloop% { Send {Down} } Send {NumpadAdd} ; Expand the container Send {NumpadAdd} ; Select the task in the container Loop %taskindex% { Send {Down} } return 1 ; Success } The //setJWpluginpanelvalue()// function sets a value in the panel to the right. setJWpluginpanelvalue(pluginname, panelitemnumber, value) { ControlFocus SysTreeView321, %pluginname% if (ErrorLevel) { return 0 } ; Tab to the panel item Loop %panelitemnumber% { Send {Tab} } ; Allow the new control to get focus, which take some time... Sleep 20 ControlGetFocus controlvar, %pluginname% IfInString controlvar, Button { ; *** Checkbox *** if (value = 0) Control Uncheck, ,%controlvar% else Control Check, ,%controlvar% } IfInString controlvar, ComboBox { ; *** Pull-down list - 1-based list index *** Control Choose, %value%, %controlvar% } IfInString controlvar, Edit { ; *** Edit - set the text ** ControlSetText %controlvar%, %value% sleep 20 ; a little sleep here as well, since multiple edit boxes seem to need it } ; MsgBox %controlvar% return 1 } The //applyandcloseJWpluginwindow()// function will simulate a press of the Enter key and close the plug-in window: applyandcloseJWpluginwindow(pluginname) { WinActivate %pluginname% if (ErrorLevel) { return 0 } ControlFocus SysTreeView321, %pluginname% if (ErrorLevel) { return 0 } Send {Enter} sleep 50 WinClose %pluginname% }