0

I have a script that uses Ctrl+j to run

  1. mongod (the mongo server)
  2. mongo (the mongo database)
  3. npm start (starts node's web server)
  4. Opens localhost:3000 in Chrome.

Each task must be ready before the next one can start. For instance, mongod is the mongo server, so if mongo starts before the server is ready, an error will occur.

Here's my script:

// Start or stop mongod, mongo, node
^j::
    IfWinNotExist, npm // start everything up. This must be done in order, but the timing varies.
    {
        // Start the mongo server
        Run, mongod.exe
        WinGet, active_id, ID, A            // Get the id of the window
        GroupAdd, One, ahk_id %active_id%   // Add the window to a new Group so we can minimize them all later
        Sleep 1000   // This works, but the time varies. I'd like to replace it


        // Start the mongo database
        Run, mongo.exe
        WinGet, active_id, ID, A
        GroupAdd, One, ahk_id %active_id%
        Sleep 1000 // I'd like to replace this

        // Start the node server
        Run, cmd.exe
        Sleep 100
        send, cd webroot{\}{enter}
        Sleep 300
        send, npm start{enter}
        WinGet, active_id, ID, A 
        GroupAdd, One, ahk_id %active_id%
        Sleep 1000 // I'd like to replace this

        // Minimize all the cmd windows
        WinMinimize, ahk_group One

        // Always opens a new tab - but that's for another question...
        Run, chrome.exe http://localhost:3000

    } else {        // shut everything down if they're already running
        SetKeyDelay, 400
        ControlSend, ,^cy{enter}, npm
        SetKeyDelay, -1
        Sleep 1000
        WinClose, ahk_class ConsoleWindowClass

        SetTitleMatchMode 2
        ControlSend, ,^c, mongo
        Sleep 1000
        WinClose, ahk_class ConsoleWindowClass

        ControlSend, ,^c, mongod
        SetKeyDelay, 200,
        Sleep 1000
        WinClose, ahk_class ConsoleWindowClass
    }
Return

// Bonus for anyone that's interested in using this script.
// Recycle the node server in the background
!`::
    SetKeyDelay, 200
    ControlSend, ,^c y{enter} npm start{enter}, npm
Return

Is there a way to wait until the services are completely started before moving to the next task?


Edit: Changed the structure of the code to put the important section closer to the top.
Travis Heeter
  • 13,002
  • 13
  • 87
  • 129
  • 1
    Did you look into `WinWaitClose` described here: https://autohotkey.com/docs/commands/WinWaitClose.htm You may also like `WinWaitActive` (which also finds when a win is inactive) described here: https://autohotkey.com/docs/commands/WinWaitActive.htm – PGilm Jan 12 '17 at 19:39

2 Answers2

1

Per my comment, try:

    ...
    SetKeyDelay, 400
    ControlSend, ,^cy{enter}, npm
    SetKeyDelay, -1
    Sleep 1000
    WinClose, ahk_class ConsoleWindowClass

    WinWaitClose, ahk_class ConsoleWindowClass, , 3

    SetTitleMatchMode 2
    ControlSend, ,^c, mongo
    Sleep 1000
    WinClose, ahk_class ConsoleWindowClass

    WinWaitClose, ahk_class ConsoleWindowClass, , 3
    ...

Hth

PGilm
  • 2,262
  • 1
  • 14
  • 26
  • This is insightful, but I'm trying to get rid of the `Sleep` commands. In your example `Sleep` is still necessary since we need to wait for the command to end before closing the window. But, in researching your suggestions I stumbled across [`Process`](https://autohotkey.com/docs/commands/Process.htm). Which has a `wait` option, but I'm not sure if I can use it the way I want. Looking into it.. – Travis Heeter Jan 13 '17 at 15:45
  • 1
    Another approach might be to use one or more batch files to do the processing (or program starting). There is a useful cl command: `START` command runs programs: `START "title" [/D path] [options] "command" [parameters]` Every START invocation runs the command given in its parameter and returns immediately, unless executed with a `/WAIT` switch. You can also use the batch file `Exit` command to self-dismiss (so you wouldn't need AHK to close the window). Hth – PGilm Jan 13 '17 at 16:22
  • 1
    Oh, so it occurs to me you can do it all at once: `cmd.exe /C start /wait mongo` I think would work. – PGilm Jan 13 '17 at 16:29
  • Brilliant! I'll try that. – Travis Heeter Jan 13 '17 at 20:32
0

In AutoHotkey scripts, some methods to replace Sleep are:
- WinWaitActive or WinWait ('win wait exist').
- Retrieving a process's PID on creation via the Run command.
e.g.

DetectHiddenWindows, On

Run, mongod.exe, , , vPID1
WinWaitActive, ahk_pid %vPID1%
WinGet, hWnd1, ID, ahk_pid %vPID1%

Run, mongod.exe, , , vPID2
WinWaitActive, ahk_pid %vPID2%
WinGet, hWnd2, ID, ahk_pid %vPID2%

;then later

WinMinimize, ahk_id %hWnd1%
WinMinimize, ahk_id %hWnd2%

AutoHotkey is good at doing everything that bat files do, for example if can retrieve StdOut. Generally speaking you should not need to open cmd.exe and type things in.

You can use cmd.exe (ComSpec) and specify a path/target.
This example selects a file in a folder.
(Tested on Windows 7.)

vPathNotepad = C:\Windows\System32\notepad.exe
Run, %ComSpec% /c explorer.exe /select`, "%vPathNotepad%",, Hide

Note: literal commas need to be escaped in a Run command with a backtick, but not when a variable is assigned, notice the backtick after the word 'select' above, but not below.

Or an easier to follow rewrite:

vPathNotepad = C:\Windows\System32\notepad.exe
vTarget = %ComSpec% /c explorer.exe /select, "%vPathNotepad%"
Run, %vTarget%,, Hide

If you want a process to run, and wait for it to terminate, before doing anything else you can use RunWait instead of Run.
e.g.

vPath = C:\webroot\npm.exe ;or whatever the path is
RunWait, %vPath%

It is also possible to start a process with the windows hidden/minimised. e.g.

Run, %vPath%, , Hide
Run, %vPath%, , Min
RunWait, %vPath%, , Hide
RunWait, %vPath%, , Min

Are mongo and mongod, command line, or GUI? If they are GUI there may be other things that one can detect, to determine what to do, such as retrieve text from controls.

[EDIT:]
Useful links:

Run a command line tool on every files and (sub)folders even those containing spaces - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=26819

Regarding Chrome, 'Always opens a new tab - but that's for another question...', some functions that I wrote:
Firefox/Chrome, get tab names/focus tab - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=26947&p=126248#p126248

vafylec
  • 965
  • 1
  • 6
  • 23
  • I tested your code, but both `WinWaitActive` and `RunWait` are triggered as soon as the *window* is finished opening, not when the process finishes - if using `cmd.exe`. If running `mongod.exe`, `RunWait` will wait until the process has finished shutting down, meaning not until I send the kill command. But, I'm reading through the [Drugoy AHK scripts](https://github.com/Drugoy/Autohotkey-scripts-.ahk). One of which is needed for your Chrome tab finder ([ACC](https://github.com/Drugoy/Autohotkey-scripts-.ahk/blob/master/Libraries/Acc.ahk)). Seems like there's some great stuff in there. Thanks! – Travis Heeter Jan 18 '17 at 17:01
  • Possibly, retrieving StdOut can be used to retrieve the status of the program. Thanks re. the Firefox/Chrome scripts. – vafylec Jan 18 '17 at 17:17