home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Open Source / AutoHotKey / Source / AutoHotkey104705_source.exe / source / application.cpp next >
Encoding:
C/C++ Source or Header  |  2007-07-19  |  131.9 KB  |  2,122 lines

  1. /*
  2. AutoHotkey
  3.  
  4. Copyright 2003-2007 Chris Mallett (support@autohotkey.com)
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15. */
  16.  
  17. #include "stdafx.h" // pre-compiled headers
  18. #include "application.h"
  19. #include "globaldata.h" // for access to g_clip, the "g" global struct, etc.
  20. #include "window.h" // for serveral MsgBox and window functions
  21. #include "util.h" // for strlcpy()
  22. #include "resources\resource.h"  // For ID_TRAY_OPEN.
  23.  
  24.  
  25. bool MsgSleep(int aSleepDuration, MessageMode aMode)
  26. // Returns true if it launched at least one thread, and false otherwise.
  27. // aSleepDuration can be be zero to do a true Sleep(0), or less than 0 to avoid sleeping or
  28. // waiting at all (i.e. messages are checked and if there are none, the function will return
  29. // immediately).  aMode is either RETURN_AFTER_MESSAGES (default) or WAIT_FOR_MESSAGES.
  30. // If the caller doesn't specify aSleepDuration, this function will return after a
  31. // time less than or equal to SLEEP_INTERVAL (i.e. the exact amount of the sleep
  32. // isn't important to the caller).  This mode is provided for performance reasons
  33. // (it avoids calls to GetTickCount and the TickCount math).  However, if the
  34. // caller's script subroutine is suspended due to action by us, an unknowable
  35. // amount of time may pass prior to finally returning to the caller.
  36. {
  37.     bool we_turned_on_defer = false; // Set default.
  38.     if (aMode == RETURN_AFTER_MESSAGES_SPECIAL_FILTER)
  39.     {
  40.         aMode = RETURN_AFTER_MESSAGES; // To simplify things further below, eliminate the mode RETURN_AFTER_MESSAGES_SPECIAL_FILTER from further consideration.
  41.         // g_DeferMessagesForUnderlyingPump is a global because the instance of MsgSleep on the calls stack
  42.         // that set it to true could launch new thread(s) that call MsgSleep again (i.e. a new layer), and a global
  43.         // is the easiest way to inform all such MsgSleeps that there's a non-standard msg pump beneath them on the
  44.         // call stack.
  45.         if (!g_DeferMessagesForUnderlyingPump)
  46.         {
  47.             g_DeferMessagesForUnderlyingPump = true;
  48.             we_turned_on_defer = true;
  49.         }
  50.         // So now either we turned it on or some layer beneath us did.  Therefore, we know there's at least one
  51.         // non-standard msg pump beneath us on the call stack.
  52.     }
  53.  
  54.     // The following is done here for performance reasons.  UPDATE: This probably never needs
  55.     // to close the clipboard now that Line::ExecUntil() also calls CLOSE_CLIPBOARD_IF_OPEN:
  56.     CLOSE_CLIPBOARD_IF_OPEN;
  57.  
  58.     // While in mode RETURN_AFTER_MESSAGES, there are different things that can happen:
  59.     // 1) We launch a new hotkey subroutine, interrupting/suspending the old one.  But
  60.     //    subroutine calls this function again, so now it's recursed.  And thus the
  61.     //    new subroutine can be interrupted yet again.
  62.     // 2) We launch a new hotkey subroutine, but it returns before any recursed call
  63.     //    to this function discovers yet another hotkey waiting in the queue.  In this
  64.     //    case, this instance/recursion layer of the function should process the
  65.     //    hotkey messages linearly rather than recursively?  No, this doesn't seem
  66.     //    necessary, because we can just return from our instance/layer and let the
  67.     //    caller handle any messages waiting in the queue.  Eventually, the queue
  68.     //    should be emptied, especially since most hotkey subroutines will run
  69.     //    much faster than the user could press another hotkey, with the possible
  70.     //    exception of the key-repeat feature triggered by holding a key down.
  71.     //    Even in that case, the worst that would happen is that messages would
  72.     //    get dropped off the queue because they're too old (I think that's what
  73.     //    happens).
  74.     // Based on the above, when mode is RETURN_AFTER_MESSAGES, we process
  75.     // all messages until a hotkey message is encountered, at which time we
  76.     // launch that subroutine only and then return when it returns to us, letting
  77.     // the caller handle any additional messages waiting on the queue.  This avoids
  78.     // the need to have a "run the hotkeys linearly" mode in a single iteration/layer
  79.     // of this function.  Note: The WM_QUIT message does not receive any higher
  80.     // precedence in the queue than other messages.  Thus, if there's ever concern
  81.     // that that message would be lost, as a future change perhaps can use PeekMessage()
  82.     // with a filter to explicitly check to see if our queue has a WM_QUIT in it
  83.     // somewhere, prior to processing any messages that might take result in
  84.     // a long delay before the remainder of the queue items are processed (there probably
  85.     // aren't any such conditions now, so nothing to worry about?)
  86.  
  87.     // Above is somewhat out-of-date.  The objective now is to spend as much time
  88.     // inside GetMessage() as possible, since it's the keystroke/mouse engine
  89.     // whenever the hooks are installed.  Any time we're not in GetMessage() for
  90.     // any length of time (say, more than 20ms), keystrokes and mouse events
  91.     // will be lagged.  PeekMessage() is probably almost as good, but it probably
  92.     // only clears out any waiting keys prior to returning.  CONFIRMED: PeekMessage()
  93.     // definitely routes to the hook, perhaps only if called regularly (i.e. a single
  94.     // isolated call might not help much).
  95.  
  96.     // This var allows us to suspend the currently-running subroutine and run any
  97.     // hotkey events waiting in the message queue (if there are more than one, they
  98.     // will be executed in sequence prior to resuming the suspended subroutine).
  99.     // Never static because we could be recursed (e.g. when one hotkey iterruptes
  100.     // a hotkey that has already been interrupted) and each recursion layer should
  101.     // have it's own value for this:
  102.     global_struct global_saved;
  103.     char ErrorLevel_saved[ERRORLEVEL_SAVED_SIZE];
  104.  
  105.     // Decided to support a true Sleep(0) for aSleepDuration == 0, as well
  106.     // as no delay at all if aSleepDuration < 0.  This is needed to implement
  107.     // "SetKeyDelay, 0" and possibly other things.  I believe a Sleep(0)
  108.     // is always <= Sleep(1) because both of these will wind up waiting
  109.     // a full timeslice if the CPU is busy.
  110.  
  111.     // Reminder for anyone maintaining or revising this code:
  112.     // Giving each subroutine its own thread rather than suspending old ones is
  113.     // probably not a good idea due to the exclusive nature of the GUI
  114.     // (i.e. it's probably better to suspend existing subroutines rather than
  115.     // letting them continue to run because they might activate windows and do
  116.     // other stuff that would interfere with the window automation activities of
  117.     // other threads)
  118.  
  119.     // If caller didn't specify, the exact amount of the Sleep() isn't
  120.     // critical to it, only that we handles messages and do Sleep()
  121.     // a little.
  122.     // Most of this initialization section isn't needed if aMode == WAIT_FOR_MESSAGES,
  123.     // but it's done anyway for consistency:
  124.     bool allow_early_return;
  125.     if (aSleepDuration == INTERVAL_UNSPECIFIED)
  126.     {
  127.         aSleepDuration = SLEEP_INTERVAL;  // Set interval to be the default length.
  128.         allow_early_return = true;
  129.     }
  130.     else
  131.         // The timer resolution makes waiting for half or less of an
  132.         // interval too chancy.  The correct thing to do on average
  133.         // is some kind of rounding, which this helps with:
  134.         allow_early_return = (aSleepDuration <= SLEEP_INTERVAL_HALF);
  135.  
  136.     // Record the start time when the caller first called us so we can keep
  137.     // track of how much time remains to sleep (in case the caller's subroutine
  138.     // is suspended until a new subroutine is finished).  But for small sleep
  139.     // intervals, don't worry about it.
  140.     // Note: QueryPerformanceCounter() has very high overhead compared to GetTickCount():
  141.     DWORD start_time = allow_early_return ? 0 : GetTickCount();
  142.  
  143.     // This check is also done even if the main timer will be set (below) so that
  144.     // an initial check is done rather than waiting 10ms more for the first timer
  145.     // message to come in.  Some of our many callers would want this, and although some
  146.     // would not need it, there are so many callers that it seems best to just do it
  147.     // unconditionally, especially since it's not a high overhead call (e.g. it returns
  148.     // immediately if the tickcount is still the same as when it was last run).
  149.     // Another reason for doing this check immediately is that our msg queue might
  150.     // contains a time-consuming msg prior to our WM_TIMER msg, e.g. a hotkey msg.
  151.     // In that case, the hotkey would be processed and launched without us first having
  152.     // emptied the queue to discover the WM_TIMER msg.  In other words, WM_TIMER msgs
  153.     // might get buried in the queue behind others, so doing this check here should help
  154.     // ensure that timed subroutines are checked often enough to keep them running at
  155.     // their specified frequencies.
  156.     // Note that ExecUntil() no longer needs to call us solely for prevention of lag
  157.     // caused by the keyboard & mouse hooks, so checking the timers early, rather than
  158.     // immediately going into the GetMessage() state, should not be a problem:
  159.     POLL_JOYSTICK_IF_NEEDED  // Do this first since it's much faster.
  160.     bool return_value = false; //  Set default.  Also, this is used by the macro below.
  161.     CHECK_SCRIPT_TIMERS_IF_NEEDED
  162.  
  163.     // Because this function is called recursively: for now, no attempt is
  164.     // made to improve performance by setting the timer interval to be
  165.     // aSleepDuration rather than a standard short interval.  That would cause
  166.     // a problem if this instance of the function invoked a new subroutine,
  167.     // suspending the one that called this instance.  The new subroutine
  168.     // might need a timer of a longer interval, which would mess up
  169.     // this layer.  One solution worth investigating is to give every
  170.     // layer/instance its own timer (the ID of the timer can be determined
  171.     // from info in the WM_TIMER message).  But that can be a real mess
  172.     // because what if a deeper recursion level receives our first
  173.     // WM_TIMER message because we were suspended too long?  Perhaps in
  174.     // that case we wouldn't our WM_TIMER pulse because upon returning
  175.     // from those deeper layers, we would check to see if the current
  176.     // time is beyond our finish time.  In addition, having more timers
  177.     // might be worse for overall system performance than having a single
  178.     // timer that pulses very frequently (because the system must keep
  179.     // them all up-to-date).  UPDATE: Timer is now also needed whenever an
  180.     // aSleepDuration greater than 0 is about to be done and there are some
  181.     // script timers that need to be watched (this happens when aMode == WAIT_FOR_MESSAGES).
  182.     // UPDATE: Make this a macro so that it is dynamically resolved every time, in case
  183.     // the value of g_script.mTimerEnabledCount changes on-the-fly.
  184.     // UPDATE #2: The below has been changed in light of the fact that the main timer is
  185.     // now kept always-on whenever there is at least one enabled timed subroutine.
  186.     // This policy simplifies ExecUntil() and long-running commands such as FileSetAttrib.
  187.     // UPDATE #3: Use aMode == RETURN_AFTER_MESSAGES, not g_nThreads > 0, because the
  188.     // "Edit This Script" menu item (and possibly other places) might result in an indirect
  189.     // call to us and we will need the timer to avoid getting stuck in the GetMessageState()
  190.     // with hotkeys being disallowed due to filtering:
  191.     bool this_layer_needs_timer = (aSleepDuration > 0 && aMode == RETURN_AFTER_MESSAGES);
  192.     if (this_layer_needs_timer)
  193.     {
  194.         ++g_nLayersNeedingTimer;  // IsCycleComplete() is responsible for decrementing this for us.
  195.         SET_MAIN_TIMER
  196.         // Reasons why the timer might already have been on:
  197.         // 1) g_script.mTimerEnabledCount is greater than zero.
  198.         // 2) another instance of MsgSleep() (beneath us in the stack) needs it (see the comments
  199.         //    in IsCycleComplete() near KILL_MAIN_TIMER for details).
  200.     }
  201.  
  202.     // Only used when aMode == RETURN_AFTER_MESSAGES:
  203.     // True if the current subroutine was interrupted by another:
  204.     //bool was_interrupted = false;
  205.     bool sleep0_was_done = false;
  206.     bool empty_the_queue_via_peek = false;
  207.  
  208.     int i, gui_count;
  209.     bool msg_was_handled;
  210.     HWND fore_window, focused_control, focused_parent, criterion_found_hwnd;
  211.     char wnd_class_name[32], gui_action_errorlevel[16], *walk;
  212.     UserMenuItem *menu_item;
  213.     Hotkey *hk;
  214.     HotkeyVariant *variant;
  215.     ActionTypeType type_of_first_line;
  216.     int priority;
  217.     Hotstring *hs;
  218.     GuiType *pgui; // This is just a temp variable and should not be referred to once the below has been determined.
  219.     GuiControlType *pcontrol, *ptab_control;
  220.     GuiIndexType gui_control_index, gui_index; // gui_index is needed to avoid using pgui in cases where that pointer becomes invalid (e.g. if ExecUntil() executes "Gui Destroy").
  221.     GuiEventType gui_action;
  222.     DWORD gui_event_info, gui_size;
  223.     bool *pgui_label_is_running, event_is_control_generated, peek_was_done, do_special_msg_filter;
  224.     Label *gui_label;
  225.     HDROP hdrop_to_free;
  226.     DWORD tick_before, tick_after, peek1_time;
  227.     LRESULT msg_reply;
  228.     BOOL peek_result;
  229.     MSG msg;
  230.  
  231.     for (;;) // Main event loop.
  232.     {
  233.         tick_before = GetTickCount();
  234.         if (aSleepDuration > 0 && !empty_the_queue_via_peek && !g_DeferMessagesForUnderlyingPump) // g_Defer: Requires a series of Peeks to handle non-contingous ranges, which is why GetMessage() can't be used.
  235.         {
  236.             // The following comment is mostly obsolete as of v1.0.39 (which introduces a thread
  237.             // dedicated to the hooks).  However, using GetMessage() is still superior to
  238.             // PeekMessage() for performance reason.  Add to that the risk of breaking things
  239.             // and it seems clear that it's best to retain GetMessage().
  240.             // Older comment:
  241.             // Use GetMessage() whenever possible -- rather than PeekMessage() or a technique such
  242.             // MsgWaitForMultipleObjects() -- because it's the "engine" that passes all keyboard
  243.             // and mouse events immediately to the low-level keyboard and mouse hooks
  244.             // (if they're installed).  Otherwise, there's greater risk of keyboard/mouse lag.
  245.             // PeekMessage(), depending on how, and how often it's called, will also do this, but
  246.             // I'm not as confident in it.
  247.             if (GetMessage(&msg, NULL, 0, MSG_FILTER_MAX) == -1) // -1 is an error, 0 means WM_QUIT
  248.                 continue; // Error probably happens only when bad parameters were passed to GetMessage().
  249.             //else let any WM_QUIT be handled below.
  250.             // The below was added for v1.0.20 to solve the following issue: If BatchLines is 10ms
  251.             // (its default) and there are one or more 10ms script-timers active, those timers would
  252.             // actually only run about every 20ms.  In addition to solving that problem, the below
  253.             // might also improve reponsiveness of hotkeys, menus, buttons, etc. when the CPU is
  254.             // under heavy load:
  255.             tick_after = GetTickCount();
  256.             if (tick_after - tick_before > 3)  // 3 is somewhat arbitrary, just want to make sure it rested for a meaningful amount of time.
  257.                 g_script.mLastScriptRest = tick_after;
  258.         }
  259.         else // aSleepDuration < 1 || empty_the_queue_via_peek || g_DeferMessagesForUnderlyingPump
  260.         {
  261.             peek_was_done = false; // Set default.
  262.             // Check the active window in each iteration in case a signficant amount of time has passed since
  263.             // the previous iteration (due to launching threads, etc.)
  264.             if (g_DeferMessagesForUnderlyingPump && (fore_window = GetForegroundWindow()) != NULL  // There is a foreground window.
  265.                 && GetWindowThreadProcessId(fore_window, NULL) == g_MainThreadID) // And it belongs to our main thread (the main thread is the only one that owns any windows).
  266.             {
  267.                 do_special_msg_filter = false; // Set default.
  268.                 if (g_nFileDialogs) // v1.0.44.12: Also do the special Peek/msg filter below for FileSelectFile because testing shows that frequently-running timers disrupt the ability to double-click.
  269.                 {
  270.                     GetClassName(fore_window, wnd_class_name, sizeof(wnd_class_name));
  271.                     do_special_msg_filter = !strcmp(wnd_class_name, "#32770");  // Due to checking g_nFileDialogs above, this means that this dialog is probably FileSelectFile rather than MsgBox/InputBox/FileSelectFolder (even if this guess is wrong, it seems fairly inconsequential to filter the messages since other pump beneath us on the call-stack will handle them ok).
  272.                 }
  273.                 if (!do_special_msg_filter && (focused_control = GetFocus()))
  274.                 {
  275.                     GetClassName(focused_control, wnd_class_name, sizeof(wnd_class_name));
  276.                     do_special_msg_filter = !stricmp(wnd_class_name, "SysTreeView32"); // A TreeView owned by our thread has focus (includes FileSelectFolder's TreeView).
  277.                 }
  278.                 if (do_special_msg_filter)
  279.                 {
  280.                     // v1.0.44.12: Below now applies to FileSelectFile dialogs too (see reason above).
  281.                     // v1.0.44.11: Since one of our thread's TreeViews has focus (even in FileSelectFolder), this
  282.                     // section is a work-around for the fact that the TreeView's message pump (somewhere beneath
  283.                     // us on the call stack) is apparently designed to process some mouse messages directly rather
  284.                     // than receiving them indirectly (in its WindowProc) via our call to DispatchMessage() here
  285.                     // in this pump.  The symptoms of this issue are an inability of a user to reliably select
  286.                     // items in a TreeView (the selection sometimes snaps back to the previously selected item),
  287.                     // which can be reproduced by showing a TreeView while a 10ms script timer is running doing
  288.                     // a trivial single line such as x=1.
  289.                     // NOTE: This happens more often in FileSelectFolder dialogs, I believe because it's msg
  290.                     // pump is ALWAYS running but that of a GUI TreeView is running only during mouse capture
  291.                     // (i.e. when left/right button is down).
  292.                     // This special handling for TreeView can someday be broadened so that focused control's
  293.                     // class isn't checked: instead, could check whether left and/or right mouse button is
  294.                     // logically down (which hasn't yet been tested).  Or it could be broadened to include
  295.                     // other system dialogs and/or common controls that have unusual processing in their
  296.                     // message pumps -- processing that requires them to directly receive certain messages
  297.                     // rather than having them dispatched directly to their WindowProc.
  298.                     peek_was_done = true;
  299.                     // Peek() must be used instead of Get(), and Peek() must be called more than once to handle
  300.                     // the two ranges on either side of the mouse messages.  But since it would be improper
  301.                     // to process messages out of order (and might lead to side-effects), force the retrieval
  302.                     // to be in chronological order by checking the timestamps of each Peek first message, and
  303.                     // then fetching the one that's oldest (since it should be the one that's been waiting the
  304.                     // longest and thus generally should be ahead of the other Peek's message in the queue):
  305. #define PEEK1(mode) PeekMessage(&msg, NULL, 0, WM_MOUSEFIRST-1, mode) // Relies on the fact that WM_MOUSEFIRST < MSG_FILTER_MAX
  306. #define PEEK2(mode) PeekMessage(&msg, NULL, WM_MOUSELAST+1, MSG_FILTER_MAX, mode)
  307.                     if (!PEEK1(PM_NOREMOVE))  // Since no message in Peek1, safe to always use Peek2's (even if it has no message either).
  308.                         peek_result = PEEK2(PM_REMOVE);
  309.                     else // Peek1 has a message.  So if Peek2 does too, compare their timestamps.
  310.                     {
  311.                         peek1_time = msg.time; // Save it due to overwrite in next line.
  312.                         if (!PEEK2(PM_NOREMOVE)) // Since no message in Peek2, use Peek1's.
  313.                             peek_result = PEEK1(PM_REMOVE);
  314.                         else // Both Peek2 and Peek1 have a message waiting, so to break the tie, retrieve the oldest one.
  315.                         {
  316.                             // In case tickcount has wrapped, compare it the better way (must cast to int to avoid
  317.                             // loss of negative values):
  318.                             peek_result = ((int)(msg.time - peek1_time) > 0) // Peek2 is newer than Peek1, so treat peak1 as oldest and thus first in queue.
  319.                                 ? PEEK1(PM_REMOVE) : PEEK2(PM_REMOVE);
  320.                         }
  321.                     }
  322.                 }
  323.             }
  324.             if (!peek_was_done) // Since above didn't Peek(), fall back to doing the Peek with the standard filter.
  325.                 peek_result = PeekMessage(&msg, NULL, 0, MSG_FILTER_MAX, PM_REMOVE);
  326.             if (!peek_result) // No more messages
  327.             {
  328.                 // Since the Peek() didn't find any messages, our timeslice may have just been
  329.                 // yielded if the CPU is under heavy load (update: this yielding effect is now diffcult
  330.                 // to reproduce, so might be a thing of past service packs).  If so, it seems best to count
  331.                 // that as a "rest" so that 10ms script-timers will run closer to the desired frequency
  332.                 // (see above comment for more details).
  333.                 // These next few lines exact match the ones above, so keep them in sync:
  334.                 tick_after = GetTickCount();
  335.                 if (tick_after - tick_before > 3)
  336.                     g_script.mLastScriptRest = tick_after;
  337.                 // UPDATE: The section marked "OLD" below is apparently not quite true: although Peek() has been
  338.                 // caught yielding our timeslice, it's now difficult to reproduce.  Perhaps it doesn't consistently
  339.                 // yield (maybe it depends on the relative priority of competing processes) and even when/if it
  340.                 // does yield, it might somehow not as long or as good as Sleep(0).  This is evidenced by the fact
  341.                 // that some of my script's WinWaitClose's finish too quickly when the Sleep(0) is omitted after a
  342.                 // Peek() that returned FALSE.
  343.                 // OLD (mostly obsolete in light of above): It is not necessary to actually do the Sleep(0) when
  344.                 // aSleepDuration == 0 because the most recent PeekMessage() has just yielded our prior timeslice.
  345.                 // This is because when Peek() doesn't find any messages, it automatically behaves as though it
  346.                 // did a Sleep(0).
  347.                 if (aSleepDuration == 0 && !sleep0_was_done)
  348.                 {
  349.                     Sleep(0);
  350.                     sleep0_was_done = true;
  351.                     // Now start a new iteration of the loop that will see if we
  352.                     // received any messages during the up-to-20ms delay (perhaps even more)
  353.                     // that just occurred.  It's done this way to minimize keyboard/mouse
  354.                     // lag (if the hooks are installed) that will occur if any key or
  355.                     // mouse events are generated during that 20ms.  Note: It seems that
  356.                     // the OS knows not to yield our timeslice twice in a row: once for
  357.                     // the Sleep(0) above and once for the upcoming PeekMessage() (if that
  358.                     // PeekMessage() finds no messages), so it does not seem necessary
  359.                     // to check HIWORD(GetQueueStatus(QS_ALLEVENTS)).  This has been confirmed
  360.                     // via the following test, which shows that while BurnK6 (CPU maxing program)
  361.                     // is foreground, a Sleep(0) really does a Sleep(60).  But when it's not
  362.                     // foreground, it only does a Sleep(20).  This behavior is UNAFFECTED by
  363.                     // the added presence of of a HIWORD(GetQueueStatus(QS_ALLEVENTS)) check here:
  364.                     //SplashTextOn,,, xxx
  365.                     //WinWait, xxx  ; set last found window
  366.                     //Loop
  367.                     //{
  368.                     //    start = %a_tickcount%
  369.                     //    Sleep, 0
  370.                     //    elapsed = %a_tickcount%
  371.                     //    elapsed -= %start%
  372.                     //    WinSetTitle, %elapsed%
  373.                     //}
  374.                     continue;
  375.                 }
  376.                 // Otherwise: aSleepDuration is non-zero or we already did the Sleep(0)
  377.                 // Macro notes:
  378.                 // Must decrement prior to every RETURN to balance it.
  379.                 // Do this prior to checking whether timer should be killed, below.
  380.                 // Kill the timer only if we're about to return OK to the caller since the caller
  381.                 // would still need the timer if FAIL was returned above.  But don't kill it if
  382.                 // there are any enabled timed subroutines, because the current policy it to keep
  383.                 // the main timer always-on in those cases.  UPDATE: Also avoid killing the timer
  384.                 // if there are any script threads running.  To do so might cause a problem such
  385.                 // as in this example scenario: MsgSleep() is called for any reason with a delay
  386.                 // large enough to require the timer.  The timer is set.  But a msg arrives that
  387.                 // MsgSleep() dispatches to MainWindowProc().  If it's a hotkey or custom menu,
  388.                 // MsgSleep() is called recursively with a delay of -1.  But when it finishes via
  389.                 // IsCycleComplete(), the timer would be wrongly killed because the underlying
  390.                 // instance of MsgSleep still needs it.  Above is even more wide-spread because if
  391.                 // MsgSleep() is called recursively for any reason, even with a duration >10, it will
  392.                 // wrongly kill the timer upon returning, in some cases.  For example, if the first call to
  393.                 // MsgSleep(-1) finds a hotkey or menu item msg, and executes the corresponding subroutine,
  394.                 // that subroutine could easily call MsgSleep(10+) for any number of reasons, which
  395.                 // would then kill the timer.
  396.                 // Also require that aSleepDuration > 0 so that MainWindowProc()'s receipt of a
  397.                 // WM_HOTKEY msg, to which it responds by turning on the main timer if the script
  398.                 // is uninterruptible, is not defeated here.  In other words, leave the timer on so
  399.                 // that when the script becomes interruptible once again, the hotkey will take effect
  400.                 // almost immediately rather than having to wait for the displayed dialog to be
  401.                 // dismissed (if there is one).
  402.                 // If timer doesn't exist, the new-thread-launch routine of MsgSleep() relies on this
  403.                 // to turn it back on whenever a layer beneath us needs it.  Since the timer
  404.                 // is never killed while g_script.mTimerEnabledCount is >0, it shouldn't be necessary
  405.                 // to check g_script.mTimerEnabledCount here.
  406.                 //
  407.                 // "we_turned_on_defer" is necessary to prevent us from turning it off if some other
  408.                 // instance of MsgSleep beneath us on the calls stack turned it on.  Only it should
  409.                 // turn it off because it might still need the "true" value for further processing.
  410.                 #define RETURN_FROM_MSGSLEEP \
  411.                 {\
  412.                     if (we_turned_on_defer)\
  413.                         g_DeferMessagesForUnderlyingPump = false;\
  414.                     if (this_layer_needs_timer)\
  415.                         --g_nLayersNeedingTimer;\
  416.                     if (g_MainTimerExists)\
  417.                     {\
  418.                         if (aSleepDuration > 0 && !g_nLayersNeedingTimer && !g_script.mTimerEnabledCount && !Hotkey::sJoyHotkeyCount)\
  419.                             KILL_MAIN_TIMER \
  420.                     }\
  421.                     else if (g_nLayersNeedingTimer)\
  422.                         SET_MAIN_TIMER \
  423.                     return return_value;\
  424.                 }
  425.                 // IsCycleComplete should always return OK in this case.  Also, was_interrupted
  426.                 // will always be false because if this "aSleepDuration < 1" call really
  427.                 // was interrupted, it would already have returned in the hotkey cases
  428.                 // of the switch().  UPDATE: was_interrupted can now the hotkey case in
  429.                 // the switch() doesn't return, relying on us to do it after making sure
  430.                 // the queue is empty.
  431.                 // The below is checked here rather than in IsCycleComplete() because
  432.                 // that function is sometimes called more than once prior to returning
  433.                 // (e.g. empty_the_queue_via_peek) and we only want this to be decremented once:
  434.                 if (IsCycleComplete(aSleepDuration, start_time, allow_early_return)) // v1.0.44.11: IsCycleComplete() must be called for all modes, but now its return value is checked due to the new g_DeferMessagesForUnderlyingPump mode.
  435.                     RETURN_FROM_MSGSLEEP
  436.                 // Otherwise (since above didn't return) combined logic has ensured that all of the following are true:
  437.                 // 1) aSleepDuration > 0
  438.                 // 2) !empty_the_queue_via_peek
  439.                 // 3) The above two combined with logic above means that g_DeferMessagesForUnderlyingPump==true.
  440.                 Sleep(5); // Since Peek() didn't find a message, avoid maxing the CPU.  This is a somewhat arbitrary value: the intent of a value below 10 is to avoid yielding more than one timeslice on all systems even if they have unusual timeslice sizes / system timers.
  441.                 continue;
  442.             }
  443.             // else Peek() found a message, so process it below.
  444.         } // PeekMessage() vs. GetMessage()
  445.  
  446.         // Since above didn't return or "continue", a message has been received that is eligible
  447.         // for further processing.
  448.  
  449.         // For max. flexibility, it seems best to allow the message filter to have the first
  450.         // crack at looking at the message, before even TRANSLATE_AHK_MSG:
  451.         if (g_MsgMonitorCount && MsgMonitor(msg.hwnd, msg.message, msg.wParam, msg.lParam, &msg, msg_reply))  // Count is checked here to avoid function-call overhead.
  452.         {
  453.             continue; // MsgMonitor has returned "true", indicating that this message should be omitted from further processing.
  454.             // NOTE: Above does "continue" and ignores msg_reply.  This is because testing shows that
  455.             // messages received via Get/PeekMessage() were always sent via PostMessage.  If an
  456.             // another thread sends ours a message, MSDN implies that Get/PeekMessage() internally
  457.             // calls the message's WindowProc directly and sends the reply back to the other thread.
  458.             // That makes sense because it seems unlikely that DispatchMessage contains any means
  459.             // of replying to a message because it has no way of knowing whether the MSG struct
  460.             // arrived via Post vs. SendMessage.
  461.         }
  462.  
  463.         // If this message might be for one of our GUI windows, check that before doing anything
  464.         // else with the message.  This must be done first because some of the standard controls
  465.         // also use WM_USER messages, so we must not assume they're generic thread messages just
  466.         // because they're >= WM_USER.  The exception is AHK_GUI_ACTION should always be handled
  467.         // here rather than by IsDialogMessage().  Note: sGuiCount is checked first to help
  468.         // performance, since all messages must come through this bottleneck.
  469.         if (GuiType::sGuiCount && msg.hwnd && msg.hwnd != g_hWnd && !(msg.message == AHK_GUI_ACTION || msg.message == AHK_USER_MENU))
  470.         {
  471.             if (msg.message == WM_KEYDOWN)
  472.             {
  473.                 // Relies heavily on short-circuit boolean order:
  474.                 if (  (msg.wParam == VK_NEXT || msg.wParam == VK_PRIOR || msg.wParam == VK_TAB
  475.                     || msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT)
  476.                     && (focused_control = GetFocus()) && (focused_parent = GetNonChildParent(focused_control))
  477.                     && (pgui = GuiType::FindGui(focused_parent)) && pgui->mTabControlCount
  478.                     && (pcontrol = pgui->FindControl(focused_control)) && pcontrol->type != GUI_CONTROL_HOTKEY   )
  479.                 {
  480.                     ptab_control = NULL; // Set default.
  481.                     if (pcontrol->type == GUI_CONTROL_TAB) // The focused control is a tab control itself.
  482.                     {
  483.                         ptab_control = pcontrol;
  484.                         // For the below, note that Alt-left and Alt-right are automatically excluded,
  485.                         // as desired, since any key modified only by alt would be WM_SYSKEYDOWN vs. WM_KEYDOWN.
  486.                         if (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT)
  487.                         {
  488.                             pgui->SelectAdjacentTab(*ptab_control, msg.wParam == VK_RIGHT, false, false);
  489.                             // Pass false for both the above since that's the whole point of having arrow
  490.                             // keys handled separately from the below: Focus should stay on the tabs
  491.                             // rather than jumping to the first control of the tab, it focus should not
  492.                             // wrap around to the beginning or end (to conform to standard behavior for
  493.                             // arrow keys).
  494.                             continue; // Suppress this key even if the above failed (probably impossible in this case).
  495.                         }
  496.                         //else fall through to the next part.
  497.                     }
  498.                     // If focus is in a multiline edit control, don't act upon Control-Tab (and
  499.                     // shift-control-tab -> for simplicity & consistency) since Control-Tab is a special
  500.                     // keystroke that inserts a literal tab in the edit control:
  501.                     if (   msg.wParam != VK_LEFT && msg.wParam != VK_RIGHT
  502.                         && (GetKeyState(VK_CONTROL) & 0x8000) // Even if other modifiers are down, it still qualifies. Use GetKeyState() vs. GetAsyncKeyState() because the former's definition is more suitable.
  503.                         && (msg.wParam != VK_TAB || pcontrol->type != GUI_CONTROL_EDIT
  504.                             || !(GetWindowLong(pcontrol->hwnd, GWL_STYLE) & ES_MULTILINE))   )
  505.                     {
  506.                         // If ptab_control wasn't determined above, check if focused control is owned by a tab control:
  507.                         if (!ptab_control && !(ptab_control = pgui->FindTabControl(pcontrol->tab_control_index))   )
  508.                             // Fall back to the first tab control (for consistency & simplicty, seems best
  509.                             // to always use the first rather than something fancier such as "nearest in z-order".
  510.                             ptab_control = pgui->FindTabControl(0);
  511.                         if (ptab_control)
  512.                         {
  513.                             pgui->SelectAdjacentTab(*ptab_control
  514.                                 , msg.wParam == VK_NEXT || (msg.wParam == VK_TAB && !(GetKeyState(VK_SHIFT) & 0x8000)) // Use GetKeyState() vs. GetAsyncKeyState() because the former's definition is more suitable.
  515.                                 , true, true);
  516.                             // Update to the below: Must suppress the tab key at least, to prevent it
  517.                             // from navigating *and* changing the tab.  And since this one is suppressed,
  518.                             // might as well suppress the others for consistency.
  519.                             // Older: Since WM_KEYUP is not handled/suppressed here, it seems best not to
  520.                             // suppress this WM_KEYDOWN either (it should do nothing in this case
  521.                             // anyway, but for balance this seems best): Fall through to the next section.
  522.                             continue;
  523.                         }
  524.                         //else fall through to the below.
  525.                     }
  526.                     //else fall through to the below.
  527.                 } // Interception of keystrokes for navigation in tab control.
  528.  
  529.                 // v1.0.34: Fix for the fact that a multiline edit control will send WM_CLOSE to its parent
  530.                 // when user presses ESC while it has focus.  The following check is similar to the block's above.
  531.                 // The alternative to this approach would have been to override the edit control's WindowProc,
  532.                 // but the following seemed to be less code. Although this fix is only necessary for multiline
  533.                 // edits, its done for all edits since it doesn't do any harm.  In addition, there is no need to
  534.                 // check what modifiers are down because we never receive the keystroke for Ctrl-Esc and Alt-Esc
  535.                 // (the OS handles those beforehand) and both Win-Esc and Shift-Esc are identical to a naked Esc
  536.                 // inside an edit.  The following check relies heavily on short-circuit eval. order.
  537.                 if (   (msg.wParam == VK_ESCAPE || msg.wParam == VK_TAB // v1.0.38.03: Added VK_TAB handling for "WantTab".
  538.                         || (msg.wParam == 'A' && (GetKeyState(VK_CONTROL) & 0x8000))) // v1.0.44: Added support for "WantCtrlA".
  539.                     && (focused_control = GetFocus()) && (focused_parent = GetNonChildParent(focused_control))
  540.                     && (pgui = GuiType::FindGui(focused_parent)) && (pcontrol = pgui->FindControl(focused_control))
  541.                     && pcontrol->type == GUI_CONTROL_EDIT)
  542.                 {
  543.                     switch(msg.wParam)
  544.                     {
  545.                     case 'A': // v1.0.44: Support for Ctrl-A to select all text.
  546.                         if (!(pcontrol->attrib & GUI_CONTROL_ATTRIB_ALTSUBMIT)) // i.e. presence of AltSubmit bit DISABLES Ctrl-A handling.
  547.                         {
  548.                             SendMessage(pcontrol->hwnd, EM_SETSEL, 0, -1); // Select all text.
  549.                             continue; // Omit this keystroke from any further processing.
  550.                         }
  551.                         break;
  552.                     case VK_ESCAPE:
  553.                         pgui->Escape();
  554.                         continue; // Omit this keystroke from any further processing.
  555.                     default: // VK_TAB
  556.                         if (pcontrol->attrib & GUI_CONTROL_ATTRIB_ALTBEHAVIOR) // It has the "WantTab" property.
  557.                         {
  558.                             // For flexibility, do this even for single-line edit controls, though in that
  559.                             // case the tab keystroke will produce an "empty box" character.
  560.                             // Strangely, if a message pump other than this one (MsgSleep) is running,
  561.                             // such as that of a MsgBox, "WantTab" is already in effect unconditionally,
  562.                             // perhaps because MsgBox and others respond to WM_GETDLGCODE with DLGC_WANTTAB.
  563.                             SendMessage(pcontrol->hwnd, EM_REPLACESEL, TRUE, (LPARAM)"\t");
  564.                             continue; // Omit this keystroke from any further processing.
  565.                         }
  566.                     } // switch()
  567.                 }
  568.  
  569.                 if (GuiType::sTreeWithEditInProgress)
  570.                 {
  571.                     if (msg.wParam == VK_RETURN)
  572.                     {
  573.                         TreeView_EndEditLabelNow(GuiType::sTreeWithEditInProgress, FALSE); // Save changes to label/text.
  574.                         continue;
  575.                     }
  576.                     else if (msg.wParam == VK_ESCAPE)
  577.                     {
  578.                         TreeView_EndEditLabelNow(GuiType::sTreeWithEditInProgress, TRUE); // Cancel without saving.
  579.                         continue;
  580.                     }
  581.                 }
  582.             } // if (msg.message == WM_KEYDOWN)
  583.  
  584.             for (i = 0, gui_count = 0, msg_was_handled = false; i < MAX_GUI_WINDOWS; ++i)
  585.             {
  586.                 // Note: indications are that IsDialogMessage() should not be called with NULL as
  587.                 // its first parameter (perhaps as an attempt to get allow dialogs owned by our
  588.                 // thread to be handled at once). Although it might work on some versions of Windows,
  589.                 // it's undocumented and shouldn't be relied on.
  590.                 // Also, can't call IsDialogMessage against msg.hwnd because that is not a complete
  591.                 // solution: at the very least, tab key navigation will not work in GUI windows.
  592.                 // There are probably other side-effects as well.
  593.                 if (g_gui[i])
  594.                 {
  595.                     if (g_gui[i]->mHwnd)
  596.                     {
  597.                         g.CalledByIsDialogMessageOrDispatch = true;
  598.                         g.CalledByIsDialogMessageOrDispatchMsg = msg.message; // Added in v1.0.44.11 because it's known that IsDialogMessage can change the message number (e.g. WM_KEYDOWN->WM_NOTIFY for UpDowns)
  599.                         if (IsDialogMessage(g_gui[i]->mHwnd, &msg))
  600.                         {
  601.                             msg_was_handled = true;
  602.                             g.CalledByIsDialogMessageOrDispatch = false;
  603.                             break;
  604.                         }
  605.                         g.CalledByIsDialogMessageOrDispatch = false;
  606.                     }
  607.                     if (GuiType::sGuiCount == ++gui_count) // No need to keep searching.
  608.                         break;
  609.                 }
  610.             }
  611.             if (msg_was_handled) // This message was handled by IsDialogMessage() above.
  612.                 continue; // Continue with the main message loop.
  613.         }
  614.  
  615.         // v1.0.44: There's no reason to call TRANSLATE_AHK_MSG here because all WM_COMMNOTIFY messages
  616.         // are sent to g_hWnd. Thus, our call to DispatchMessage() later below will route such messages to
  617.         // MainWindowProc(), which will then call TRANSLATE_AHK_MSG().
  618.         //TRANSLATE_AHK_MSG(msg.message, msg.wParam)
  619.  
  620.         switch(msg.message)
  621.         {
  622.         // MSG_FILTER_MAX should prevent us from receiving this first group of messages whenever g_AllowInterruption or
  623.         // g.AllowThreadToBeInterrupted is false.
  624.         case AHK_HOOK_HOTKEY:  // Sent from this app's keyboard or mouse hook.
  625.         case AHK_HOTSTRING:    // Sent from keybd hook to activate a non-auto-replace hotstring.
  626.         case AHK_CLIPBOARD_CHANGE:
  627.             // This extra handling is present because common controls and perhaps other OS features tend
  628.             // to use WM_USER+NN messages, a practice that will probably be even more common in the future.
  629.             // To cut down on message conflicts, dispatch such messages whenever their HWND isn't a what
  630.             // it should be for a message our own code generated. That way, the target control (if any)
  631.             // will still get the msg.
  632.             if (msg.hwnd && msg.hwnd != g_hWnd) // v1.0.44: It's wasn't sent by our code; perhaps by a common control's code.
  633.                 break; // Dispatch it vs. discarding it, in case it's for a control.
  634.             //ELSE FALL THROUGH:
  635.         case AHK_GUI_ACTION:   // The user pressed a button on a GUI window, or some other actionable event. Listed before the below for performance.
  636.         case WM_HOTKEY:        // As a result of this app having previously called RegisterHotkey(), or from TriggerJoyHotkeys().
  637.         case AHK_USER_MENU:    // The user selected a custom menu item.
  638.             hdrop_to_free = NULL;  // Set default for this message's processing (simplifies code).
  639.             switch(msg.message)
  640.             {
  641.             case AHK_GUI_ACTION: // Listed first for performance.
  642.                 // Assume that it is possible that this message's GUI window has been destroyed
  643.                 // (and maybe even recreated) since the time the msg was posted.  If this can happen,
  644.                 // that's another reason for finding which GUI this control is associate with (it also
  645.                 // needs to be found so that we can call the correct GUI window object to perform
  646.                 // the action):
  647.                 if (   !(pgui = GuiType::FindGui(msg.hwnd))   ) // No associated GUI object, so ignore this event.
  648.                     // v1.0.44: Dispatch vs. continue/discard since it's probably for a common control
  649.                     // whose msg number happens to be AHK_GUI_ACTION.  Do this *only* when HWND isn't recognized,
  650.                     // not when msg content is inavalid, because dispatching a msg whose HWND is one of our own
  651.                     // GUI windows might cause GuiWindowProc to fwd it back to us, creating an infinite loop.
  652.                     goto break_out_of_main_switch; // Goto seems preferably in this case for code size & performance.
  653.                 gui_index = pgui->mWindowIndex; // Stored in case ExecUntil() performs "Gui Destroy" further below.
  654.  
  655.                 gui_event_info =    (DWORD)msg.lParam;
  656.                 gui_action =        LOWORD(msg.wParam);
  657.                 gui_control_index = HIWORD(msg.wParam); // Caller has set it to NO_CONTROL_INDEX if it isn't applicable.
  658.  
  659.                 if (gui_action == GUI_EVENT_RESIZE) // This section be done after above but before pcontrol below.
  660.                 {
  661.                     gui_size = gui_event_info; // Temp storage until the "g" struct becomes available for the new thread.
  662.                     gui_event_info = gui_control_index; // SizeType is stored in index in this case.
  663.                     gui_control_index = NO_CONTROL_INDEX;
  664.                 }
  665.                 // Below relies on the GUI_EVENT_RESIZE section above having been done:
  666.                 pcontrol = gui_control_index < pgui->mControlCount ? pgui->mControl + gui_control_index : NULL; // Set for use in other places below.
  667.  
  668.                 pgui_label_is_running = NULL; // Set default (in cases other than AHK_GUI_ACTION it is not used, so not initialized).
  669.                 event_is_control_generated = false; // Set default.
  670.  
  671.                 switch(gui_action)
  672.                 {
  673.                 case GUI_EVENT_RESIZE: // This is the signal to run the window's OnEscape label. Listed first for performance.
  674.                     if (   !(gui_label = pgui->mLabelForSize)   ) // In case it became NULL since the msg was posted.
  675.                         continue;
  676.                     pgui_label_is_running = &pgui->mLabelForSizeIsRunning;
  677.                     break;
  678.                 case GUI_EVENT_CLOSE:  // This is the signal to run the window's OnClose label.
  679.                     if (   !(gui_label = pgui->mLabelForClose)   ) // In case it became NULL since the msg was posted.
  680.                         continue;
  681.                     pgui_label_is_running = &pgui->mLabelForCloseIsRunning;
  682.                     break;
  683.                 case GUI_EVENT_ESCAPE: // This is the signal to run the window's OnEscape label.
  684.                     if (   !(gui_label = pgui->mLabelForEscape)   ) // In case it became NULL since the msg was posted.
  685.                         continue;
  686.                     pgui_label_is_running = &pgui->mLabelForEscapeIsRunning;
  687.                     break;
  688.                 case GUI_EVENT_CONTEXTMENU:
  689.                     if (   !(gui_label = pgui->mLabelForContextMenu)   ) // In case it became NULL since the msg was posted.
  690.                         continue;
  691.                     // UPDATE: Must allow multiple threads because otherwise the user cannot right-click twice
  692.                     // consecutively (the second click is blocked because the menu is still displayed at the
  693.                     // instant of the click.  The following older reason is probably not entirely correct because
  694.                     // the display of a popup menu via "Menu, MyMenu, Show" will spin off a new thread if the
  695.                     // user selects an item in the menu:
  696.                     // Unlike most other Gui labels, it seems best by default to allow GuiContextMenu to be
  697.                     // launched multiple times so that multiple items in the menu can be running simultaneously
  698.                     // as separate threads.  Therefore, leave pgui_label_is_running at its default of NULL.
  699.                     break;
  700.                 case GUI_EVENT_DROPFILES: // This is the signal to run the window's DropFiles label.
  701.                     hdrop_to_free = pgui->mHdrop; // This variable simplifies the code further below.
  702.                     if (   !(gui_label = pgui->mLabelForDropFiles) // In case it became NULL since the msg was posted.
  703.                         || !hdrop_to_free // Checked just in case, so that the below can query it.
  704.                         || !(gui_event_info = DragQueryFile(hdrop_to_free, 0xFFFFFFFF, NULL, 0))   ) // Probably impossible, but if it ever can happen, seems best to ignore it.
  705.                     {
  706.                         if (hdrop_to_free) // Checked again in case short-circuit boolean above never checked it.
  707.                         {
  708.                             DragFinish(hdrop_to_free); // Since the drop-thread will not be launched, free the memory.
  709.                             pgui->mHdrop = NULL; // Indicate that this GUI window is ready for another drop.
  710.                         }
  711.                         continue;
  712.                     }
  713.                     // It is not necessary to check if the label is running in this case because
  714.                     // the caller who posted this message to us has ensured that it's the only message in the queue
  715.                     // or in progress (by virtue of pgui->mHdrop being NULL at the time the message was posted).
  716.                     // Therefore, leave pgui_label_is_running at its default of NULL.
  717.                     break;
  718.                 default: // This is an action from a particular control in the GUI window.
  719.                     if (!pcontrol) // gui_control_index was beyond the quantity of controls, possibly due to parent window having been destroyed since the msg was sent (or bogus msg).
  720.                         continue;  // Discarding an invalid message here is relied upon both other sections below.
  721.                     if (   !(gui_label = pcontrol->jump_to_label)   )
  722.                     {
  723.                         // On if there's no label is the implicit action considered.
  724.                         if (pcontrol->attrib & GUI_CONTROL_ATTRIB_IMPLICIT_CANCEL)
  725.                             pgui->Cancel();
  726.                         continue; // Fully handled by the above; or there was no label.
  727.                         // This event might lack both a label and an action if its control was changed to be
  728.                         // non-actionable since the time the msg was posted.
  729.                     }
  730.                     // Above has confirmed it has a label, so now it's valid to check if that label is already running.
  731.                     // It seems best by default not to allow multiple threads for the same control.
  732.                     // Such events are discarded because it seems likely that most script designers
  733.                     // would want to see the effects of faulty design (e.g. long running timers or
  734.                     // hotkeys that interrupt gui threads) rather than having events for later,
  735.                     // when they might suddenly take effect unexpectedly:
  736.                     if (pcontrol->attrib & GUI_CONTROL_ATTRIB_LABEL_IS_RUNNING)
  737.                         continue;
  738.                     event_is_control_generated = true; // As opposed to a drag-and-drop or context-menu event that targets a specific control.
  739.                     // And leave pgui_label_is_running at its default of NULL because it doesn't apply to these.
  740.                 } // switch(gui_action)
  741.                 type_of_first_line = gui_label->mJumpToLine->mActionType; // Above would already have discarded this message if it there was no label.
  742.                 break; // case AHK_GUI_ACTION
  743.  
  744.             case AHK_USER_MENU: // user-defined menu item
  745.                 if (   !(menu_item = g_script.FindMenuItemByID((UINT)msg.lParam))   ) // Item not found.
  746.                     continue; // ignore the msg
  747.                 // And just in case a menu item that lacks a label (such as a separator) is ever
  748.                 // somehow selected (perhaps via someone sending direct messages to us, bypassing
  749.                 // the menu):
  750.                 if (!menu_item->mLabel)
  751.                     continue;
  752.                 type_of_first_line = menu_item->mLabel->mJumpToLine->mActionType;
  753.                 break;
  754.  
  755.             case AHK_HOTSTRING:
  756.                 if (msg.wParam >= Hotstring::sHotstringCount) // Invalid hotstring ID (perhaps spoofed by external app)
  757.                     continue; // Do nothing.
  758.                 hs = Hotstring::shs[msg.wParam];  // For performance and convenience.
  759.                 if (hs->mHotCriterion)
  760.                 {
  761.                     // For details, see comments in the hotkey section of this switch().
  762.                     if (   !(criterion_found_hwnd = HotCriterionAllowsFiring(hs->mHotCriterion, hs->mHotWinTitle, hs->mHotWinText))   )
  763.                         // Hotstring is no longer eligible to fire even though it was when the hook sent us
  764.                         // the message.  Abort the firing even though the hook may have already started
  765.                         // executing the hotstring by suppressing the final end-character or other actions.
  766.                         // It seems preferable to abort midway through the execution than to continue sending
  767.                         // keystrokes to the wrong window, or when the hotstring has become suspended.
  768.                         continue;
  769.                     // For details, see comments in the hotkey section of this switch().
  770.                     if (!(hs->mHotCriterion == HOT_IF_ACTIVE || hs->mHotCriterion == HOT_IF_EXIST))
  771.                         criterion_found_hwnd = NULL; // For "NONE" and "NOT", there is no last found window.
  772.                 }
  773.                 else // No criterion, so it's a global hotstring.  It can always fire, but it has no "last found window".
  774.                     criterion_found_hwnd = NULL;
  775.                 // Do a simple replacement for the hotstring if that's all that's called for.
  776.                 // Don't create a new quasi-thread or any of that other complexity done further
  777.                 // below.  But also do the backspacing (if specified) for a non-autoreplace hotstring,
  778.                 // even if it can't launch due to MaxThreads, MaxThreadsPerHotkey, or some other reason:
  779.                 hs->DoReplace(msg.lParam);  // Does only the backspacing if it's not an auto-replace hotstring.
  780.                 if (*hs->mReplacement) // Fully handled by the above; i.e. it's an auto-replace hotstring.
  781.                     continue;
  782.                 // Otherwise, continue on and let a new thread be created to handle this hotstring.
  783.                 // Since this isn't an auto-replace hotstring, set this value to support
  784.                 // the built-in variable A_EndChar:
  785.                 g_script.mEndChar = (char)LOWORD(msg.lParam);
  786.                 type_of_first_line = hs->mJumpToLabel->mJumpToLine->mActionType;
  787.                 break;
  788.  
  789.             case AHK_CLIPBOARD_CHANGE: // Due to the presence of an OnClipboardChange label in the script.
  790.                 // Caller has ensured that mOnClipboardChangeLabel is a non-NULL, valid pointer.
  791.                 type_of_first_line = g_script.mOnClipboardChangeLabel->mJumpToLine->mActionType;
  792.                 break;
  793.  
  794.             default: // hotkey
  795.                 if (msg.wParam >= Hotkey::sHotkeyCount) // Invalid hotkey ID.
  796.                     continue;
  797.                 hk = Hotkey::shk[msg.wParam];
  798.                 // Check if criterion allows firing.
  799.                 // For maintainability, this is done here rather than a little further down
  800.                 // past the MAX_THREADS_LIMIT and thread-priority checks.  Those checks hardly
  801.                 // ever abort a hotkey launch anyway.
  802.                 //
  803.                 // If message is WM_HOTKEY, it's either:
  804.                 // 1) A joystick hotkey from TriggerJoyHotkeys(), in which case the lParam is ignored.
  805.                 // 2) A hotkey message sent by the OS, in which case lParam contains currently-unused info set by the OS.
  806.                 //
  807.                 // An incoming WM_HOTKEY can be subject to #IfWin at this stage under the following conditions:
  808.                 // 1) Joystick hotkey, because it relies on us to do the check so that the check is done only
  809.                 //    once rather than twice.
  810.                 // 2) Win9x's support for #IfWin, which never uses the hook but instead simply does nothing if
  811.                 //    none of the hotkey's criteria is satisfied.
  812.                 // 3) #IfWin keybd hotkeys that were made non-hook because they have a non-suspended, global variant.
  813.                 //
  814.                 // If message is AHK_HOOK_HOTKEY:
  815.                 // Rather than having the hook pass the qualified variant to us, it seems preferable
  816.                 // to search through all the criteria again and rediscover it.  This is because conditions
  817.                 // may have changed since the message was posted, and although the hotkey might still be
  818.                 // eligible for firing, a different variant might now be called for (e.g. due to a change
  819.                 // in the active window).  Since most criteria hotkeys have at most only a few criteria,
  820.                 // and since most such criteria are #IfWinActive rather than Exist, the performance will
  821.                 // typically not be reduced much at all.  Futhermore, trading performance for greater
  822.                 // reliability seems worth it in this case.
  823.                 // 
  824.                 // The inefficiency of calling HotCriterionAllowsFiring() twice for each hotkey --
  825.                 // once in the hook and again here -- seems justifed for the following reasons:
  826.                 // - It only happens twice if the hotkey a hook hotkey (multi-variant keyboard hotkeys
  827.                 //   that have a global variant are usually non-hook, even on NT/2k/XP).
  828.                 // - The hook avoids doing its first check of WinActive/Exist if it sees that the hotkey
  829.                 //   has a non-suspended, global variant.  That way, hotkeys that are hook-hotkeys for
  830.                 //   reasons other than #IfWin (such as mouse, overriding OS hotkeys, or hotkeys
  831.                 //   that are too fancy for RegisterHotkey) will not have to do the check twice.
  832.                 // - It provides the ability to set the last-found-window for #IfWinActive/Exist
  833.                 //   (though it's not needed for the "Not" counterparts).  This HWND could be passed
  834.                 //   via the message, but that would require malloc-there and free-here, and might
  835.                 //   result in memory leaks if its ever possible for messages to get discarded by the OS.
  836.                 // - It allows hotkeys that were eligible for firing at the time the message was
  837.                 //   posted but that have since become ineligible to be aborted.  This seems like a
  838.                 //   good precaution for most users/situations because such hotkey subroutines will
  839.                 //   often assume (for scripting simplicity) that the specified window is active or
  840.                 //   exists when the subroutine executes its first line.
  841.                 // - Most criterion hotkeys use #IfWinActive, which is a very fast call.  Also, although
  842.                 //   WinText and/or "SetTitleMatchMode Slow" slow down window searches, those are rarely
  843.                 //   used too.
  844.                 if (   !(variant = hk->CriterionAllowsFiring(&criterion_found_hwnd))   )
  845.                     continue; // No criterion is eligible, so ignore this hotkey event (see other comments).
  846.                     // If this is AHK_HOOK_HOTKEY, criterion was eligible at time message was posted,
  847.                     // but not now.  Seems best to abort (see other comments).
  848.                 // Now that above has ensured variant is non-NULL:
  849.                 if (!(variant->mHotCriterion == HOT_IF_ACTIVE || variant->mHotCriterion == HOT_IF_EXIST))
  850.                     criterion_found_hwnd = NULL; // For "NONE" and "NOT", there is no last found window.
  851.                 type_of_first_line = variant->mJumpToLabel->mJumpToLine->mActionType;
  852.             } // switch(msg.message)
  853.  
  854.             if (g_nThreads >= g_MaxThreadsTotal)
  855.             {
  856.                 // The below allows 1 thread beyond the limit in case the script's configured
  857.                 // #MaxThreads is exactly equal to the absolute limit.  This is because we want
  858.                 // subroutines whose first line is something like ExitApp to take effect even
  859.                 // when we're at the absolute limit:
  860.                 if (g_nThreads > MAX_THREADS_LIMIT || !ACT_IS_ALWAYS_ALLOWED(type_of_first_line))
  861.                 {
  862.                     // Allow only a limited number of recursion levels to avoid any chance of
  863.                     // stack overflow.  So ignore this message.  Later, can devise some way
  864.                     // to support "queuing up" these launch-thread events for use later when
  865.                     // there is "room" to run them, but that might cause complications because
  866.                     // in some cases, the user didn't intend to hit the key twice (e.g. due to
  867.                     // "fat fingers") and would have preferred to have it ignored.  Doing such
  868.                     // might also make "infinite key loops" harder to catch because the rate
  869.                     // of incoming hotkeys would be slowed down to prevent the subroutines from
  870.                     // running concurrently.
  871.                     if (hdrop_to_free) // This is only non-NULL when pgui is non-NULL and gui_action==GUI_EVENT_DROPFILES
  872.                     {
  873.                         DragFinish(hdrop_to_free); // Since the drop-thread will not be launched, free the memory.
  874.                         pgui->mHdrop = NULL; // Indicate that this GUI window is ready for another drop.
  875.                     }
  876.                     continue;
  877.                 }
  878.                 // If the above "continued", it seems best not to re-queue/buffer the key since
  879.                 // it might be a while before the number of threads drops back below the limit.
  880.             }
  881.  
  882.             // Find out the new thread's priority will be so that it can be checked against the current thread's:
  883.             switch(msg.message)
  884.             {
  885.             case AHK_GUI_ACTION: // Listed first for performance.
  886.                 if (pgui_label_is_running && *pgui_label_is_running) // GuiSize/Close/Escape/etc. These subroutines are currently limited to one thread each.
  887.                     continue; // hdrop_to_free: Not necessary to check it because it's always NULL when pgui_label_is_running is non-NULL.
  888.                 //else the check wasn't needed because it was done elsewhere (GUI_EVENT_DROPFILES) or the
  889.                 // action is not thread-restricted (GUI_EVENT_CONTEXTMENU).
  890.                 // And since control-specific events were already checked for "already running" higher above, this
  891.                 // event is now eligible to start a new thread.
  892.                 priority = 0;  // Always use default for now.
  893.                 break;
  894.             case AHK_USER_MENU: // user-defined menu item
  895.                 // Ignore/discard a hotkey or custom menu item event if the current thread's priority
  896.                 // is higher than it's:
  897.                 priority = menu_item->mPriority;
  898.                 // Below: the menu type is passed with the message so that its value will be in sync
  899.                 // with the timestamp of the message (in case this message has been stuck in the
  900.                 // queue for a long time):
  901.                 if (msg.wParam < MAX_GUI_WINDOWS) // Poster specified that this menu item was from a gui's menu bar (since wParam is unsigned, any incoming -1 is seen as greater than max).
  902.                 {
  903.                     // msg.wParam is the index rather than a pointer to avoid any chance of problems with
  904.                     // a gui object or its window having been destroyed while the msg was waiting in the queue.
  905.                     if (!(pgui = g_gui[msg.wParam]) // Not a GUI's menu bar item...
  906.                         && msg.hwnd && msg.hwnd != g_hWnd) // ...and not a script menu item.
  907.                         goto break_out_of_main_switch; // See "goto break_out_of_main_switch" higher above for complete explanation.
  908.                 }
  909.                 else
  910.                     pgui = NULL; // Set for use in later sections.
  911.                 break;
  912.             case AHK_HOTSTRING:
  913.                 priority = hs->mPriority;
  914.                 break;
  915.             case AHK_CLIPBOARD_CHANGE: // Due to the presence of an OnClipboardChange label in the script.
  916.                 if (g_script.mOnClipboardChangeIsRunning)
  917.                     continue;
  918.                 priority = 0;  // Always use default for now.
  919.                 break;
  920.             default: // hotkey
  921.                 // Due to the key-repeat feature and the fact that most scripts use a value of 1
  922.                 // for their #MaxThreadsPerHotkey, this check will often help average performance
  923.                 // by avoiding a lot of unncessary overhead that would otherwise occur:
  924.                 if (!hk->PerformIsAllowed(*variant))
  925.                 {
  926.                     // The key is buffered in this case to boost the responsiveness of hotkeys
  927.                     // that are being held down by the user to activate the keyboard's key-repeat
  928.                     // feature.  This way, there will always be one extra event waiting in the queue,
  929.                     // which will be fired almost the instant the previous iteration of the subroutine
  930.                     // finishes (this above descript applies only when MaxThreadsPerHotkey is 1,
  931.                     // which it usually is).
  932.                     hk->RunAgainAfterFinished(*variant); // Wheel notch count (g.EventInfo below) should be okay because subsequent launches reuse the same thread attributes to do the repeats.
  933.                     continue;
  934.                 }
  935.                 priority = variant->mPriority;
  936.             }
  937.  
  938.             // Discard the event if it's priority is lower than that of the current thread:
  939.             if (priority < g.Priority)
  940.             {
  941.                 if (hdrop_to_free) // This is only non-NULL when pgui is non-NULL and gui_action==GUI_EVENT_DROPFILES
  942.                 {
  943.                     DragFinish(hdrop_to_free); // Since the drop-thread will not be launched, free the memory.
  944.                     pgui->mHdrop = NULL; // Indicate that this GUI window is ready for another drop.
  945.                 }
  946.                 continue;
  947.             }
  948.  
  949.             // Now it is certain that the new thread will be launched, so set everything up.
  950.             // Perform the new thread's subroutine:
  951.             return_value = true; // We will return this value to indicate that we launched at least one new thread.
  952.  
  953.             // Always kill the main timer, for performance reasons and for simplicity of design,
  954.             // prior to embarking on new subroutine whose duration may be long (e.g. if BatchLines
  955.             // is very high or infinite, the called subroutine may not return to us for seconds,
  956.             // minutes, or more; during which time we don't want the timer running because it will
  957.             // only fill up the queue with WM_TIMER messages and thus hurt performance).
  958.             // UPDATE: But don't kill it if it should be always-on to support the existence of
  959.             // at least one enabled timed subroutine or joystick hotkey:
  960.             if (!g_script.mTimerEnabledCount && !Hotkey::sJoyHotkeyCount)
  961.                 KILL_MAIN_TIMER;
  962.  
  963.             switch(msg.message)
  964.             {
  965.             case AHK_GUI_ACTION: // Listed first for performance.
  966.             case AHK_CLIPBOARD_CHANGE:
  967.                 break; // Do nothing at this stage.
  968.             case AHK_USER_MENU: // user-defined menu item
  969.                 // Safer to make a full copies than point to something potentially volatile.
  970.                 strlcpy(g_script.mThisMenuItemName, menu_item->mName, sizeof(g_script.mThisMenuItemName));
  971.                 strlcpy(g_script.mThisMenuName, menu_item->mMenu->mName, sizeof(g_script.mThisMenuName));
  972.                 break;
  973.             default: // hotkey or hotstring
  974.                 // Just prior to launching the hotkey, update these values to support built-in
  975.                 // variables such as A_TimeSincePriorHotkey:
  976.                 g_script.mPriorHotkeyName = g_script.mThisHotkeyName;
  977.                 g_script.mPriorHotkeyStartTime = g_script.mThisHotkeyStartTime;
  978.                 // Unlike hotkeys -- which can have a name independent of their label by being created or updated
  979.                 // with the HOTKEY command -- a hot string's unique name is always its label since that includes
  980.                 // the options that distinguish between (for example) :c:ahk:: and ::ahk::
  981.                 g_script.mThisHotkeyName = (msg.message == AHK_HOTSTRING) ? hs->mJumpToLabel->mName : hk->mName;
  982.                 g_script.mThisHotkeyStartTime = GetTickCount(); // Fixed for v1.0.35.10 to not happen for GUI threads.
  983.             }
  984.  
  985.             // Also save the ErrorLevel of the subroutine that's about to be suspended.
  986.             // Current limitation: If the user put something big in ErrorLevel (very unlikely
  987.             // given its nature, but allowed) it will be truncated by this, if too large.
  988.             // Also: Don't use var->Get() because need better control over the size:
  989.             strlcpy(ErrorLevel_saved, g_ErrorLevel->Contents(), sizeof(ErrorLevel_saved));
  990.             // v1.0.37.06: The following must be done regardless of aMode because the idle thread is now
  991.             // resumed via ResumeUnderlyingThread():
  992.             CopyMemory(&global_saved, &g, sizeof(global_struct));
  993.             // Make every newly launched subroutine start off with the global default values that
  994.             // the user set up in the auto-execute part of the script (e.g. KeyDelay, WinDelay, etc.).
  995.             // However, we do not set ErrorLevel to anything special here (except for GUI threads, later
  996.             // below) because it's more flexible that way (i.e. the user may want one hotkey subroutine
  997.             // to use the value of ErrorLevel set by another):
  998.             InitNewThread(priority, false, true, type_of_first_line);
  999.  
  1000.             // Fix for v1.0.37.06:  Must do the following only after InitNewThread() has updated
  1001.             // g.IsPaused for the new thread.
  1002.             // If the current quasi-thread is paused, the thread we're about to launch
  1003.             // will not be, so the icon needs to be checked:
  1004.             g_script.UpdateTrayIcon();
  1005.  
  1006.             // Do this nearly last, right before launching the thread:
  1007.             if (g_nFileDialogs)
  1008.                 // Since there is a quasi-thread with an open file dialog underneath the one
  1009.                 // we're about to launch, set the current directory to be the one the user
  1010.                 // would expect to be in effect.  This is not a 100% fix/workaround for the
  1011.                 // fact that the dialog changes the working directory as the user navigates
  1012.                 // from folder to folder because the dialog can still function even when its
  1013.                 // quasi-thread is suspended (i.e. while our new thread being launched here
  1014.                 // is in the middle of running).  In other words, the user can still use
  1015.                 // the dialog of a suspended quasi-thread, and thus change the working
  1016.                 // directory indirectly.  But that should be very rare and I don't see an
  1017.                 // easy way to fix it completely without using a "HOOK function to monitor
  1018.                 // the WM_NOTIFY message", calling SetCurrentDirectory() after every script
  1019.                 // line executes (which seems too high in overhead to be justified), or
  1020.                 // something similar.  Note changing to a new directory here does not seem
  1021.                 // to hurt the ongoing FileSelectFile() dialog.  In other words, the dialog
  1022.                 // does not seem to care that its changing of the directory as the user
  1023.                 // navigates is "undone" here:
  1024.                 SetCurrentDirectory(g_WorkingDir);
  1025.  
  1026.             // Do this nearly last, right before launching the thread:
  1027.             // It seems best to reset mLinesExecutedThisCycle unconditionally (now done by InitNewThread),
  1028.             // because the user has pressed a hotkey or selected a custom menu item, so would expect
  1029.             // maximum responsiveness (e.g. in a game where split second timing can matter) rather than
  1030.             // the risk that a "rest" will be done immediately by ExecUntil() just because
  1031.             // mLinesExecutedThisCycle happens to be large some prior subroutine.  The same applies to
  1032.             // mLastScriptRest, which is why that is reset also:
  1033.             g_script.mLastScriptRest = g_script.mLastPeekTime = GetTickCount();
  1034.             // v1.0.38.04: The above now resets mLastPeekTime too to reduce situations in which a thread
  1035.             // doesn't even run one line before being interrupted by another thread.  Here's how that would
  1036.             // happen: ExecUntil() would see that a Peek() is due and call PeekMessage().  The Peek() will
  1037.             // yield if we have no messages and the CPU is under heavy load, and thus the script might not
  1038.             // get another timeslice for 20ms (or even longer if there is more than one other needy process).
  1039.             // Even if the Peek() doesn't yield (i.e. we have messages), those messages might take a long time
  1040.             // to process (such as WM_PAINT) even though the script is uninterruptible.  Either way, when the
  1041.             // Peek-check completes, a long time might have passed, and the thread might now be interruptible
  1042.             // due to the interruptible-timer having expired (which is probably possible only in the no-yield
  1043.             // scenario above, since in the case of yield, ExecUntil wouldn't check messages again after the
  1044.             // yield).  Thus, the Peek-check's MsgSleep() might launch an interrupting thread before the prior
  1045.             // thread had a chance to execute even one line.  Resetting mLastPeekTime above should alleviate that,
  1046.             // perhaps even completely resolve it due to the way tickcounts tend not to change early on in
  1047.             // a timeslice (perhaps because timeslices fall exactly upon tick-count boundaries).  If it doesn't
  1048.             // completely resolve it, mLastPeekTime could instead be set to zero as a special value that
  1049.             // ExecUntil recognizes to do the following processing, but this processing reduces performance
  1050.             // by 2.5% in a simple addition-loop benchmark:
  1051.             //if (g_script.mLastPeekTime)
  1052.             //    LONG_OPERATION_UPDATE
  1053.             //else
  1054.             //    g_script.mLastPeekTime = GetTickCount();
  1055.  
  1056.             switch (msg.message)
  1057.             {
  1058.             case AHK_GUI_ACTION: // Listed first for performance.
  1059.                 *gui_action_errorlevel = '\0'; // Set default, which is possibly overridden below.
  1060.                 // When appropriate, the below sets g.GuiPoint (to support A_GuiX and A_GuiY).
  1061.                 switch(gui_action)
  1062.                 {
  1063.                 case GUI_EVENT_CONTEXTMENU:
  1064.                     // Caller stored 1 in gui_event_info if this context-menu was generated via the keyboard
  1065.                     // (such as AppsKey or Shift-F10):
  1066.                     g.GuiEvent = gui_event_info ? GUI_EVENT_NORMAL : GUI_EVENT_RCLK; // Must be done prior to below.
  1067.                     gui_event_info = NO_EVENT_INFO; // Now that it has been used above, reset it to a default, to be conditionally overridden below.
  1068.                     g.GuiPoint = msg.pt; // Set default. v1.0.38: More accurate/customary to use msg.pt than GetCursorPos().
  1069.                     if (pcontrol) // i.e. this context menu is for a control rather than a click somewhere in the parent window itself.
  1070.                     {
  1071.                         // By definition, pcontrol should be the focused control.  However, testing shows that
  1072.                         // it can also be the only control in a window that lacks any focus-capable controls.
  1073.                         // If the window has no controls at all, testing shows that pcontrol will be NULL,
  1074.                         // in which case GuiPoint default set earlier is retained (for AppsKey too).
  1075.                         if (g.GuiEvent == GUI_EVENT_NORMAL) // Context menu was invoked via keyboard.
  1076.                             pgui->ControlGetPosOfFocusedItem(*pcontrol, g.GuiPoint); // Since pcontrol!=NULL, find out which item is focused in this control.
  1077.                         //else this is a context-menu event that was invoked via normal mouse click.  Leave
  1078.                         // g.GuiPoint at its default set earlier.
  1079.                         switch(pcontrol->type)
  1080.                         {
  1081.                         case GUI_CONTROL_LISTBOX: // Use +1 to convert to one-based index:
  1082.                             gui_event_info = 1 + (int)SendMessage(pcontrol->hwnd, LB_GETCARETINDEX, 0, 0); // Cast to int to preserve any -1 value.
  1083.                             break;
  1084.                         case GUI_CONTROL_LISTVIEW:
  1085.                             // v1.0.44: I realized that it would perhaps be more correct/flexible to use ListView_HitTest()
  1086.                             // when g.GuiEvent != GUI_EVENT_NORMAL (like TreeVIew below).  However, for the following reasons,
  1087.                             // it hasn't yet been done:
  1088.                             // 1) Backward compatbility for scripts that rely on the old behavior.
  1089.                             // 2) It may be more complex to implement than TreeView's hittest due to dealing with subitems vs. items in a ListView.
  1090.                             // 3) Code size.
  1091.                             // Therefore, this difference in behavior will be documented in the help.
  1092.                             gui_event_info = 1 + ListView_GetNextItem(pcontrol->hwnd, -1, LVNI_FOCUSED);
  1093.                             // Testing shows that only one item at a time can have focus, even when mulitple items are selected.
  1094.                             break;
  1095.                         case GUI_CONTROL_TREEVIEW:
  1096.                             // Retrieves the HTREEITEM that is the true target of this event.
  1097.                             if (g.GuiEvent == GUI_EVENT_NORMAL) // AppsKey or Shift+F10.
  1098.                                 gui_event_info = (DWORD)SendMessage(pcontrol->hwnd, TVM_GETNEXTITEM, TVGN_CARET, NULL); // Get focused item.
  1099.                             else // Context menu invoked via right-click.  Find out which item (if any) was clicked on.
  1100.                             {
  1101.                                 // Use HitTest because the focused item isn't necessarily the one that was
  1102.                                 // clicked on.  This is because unlike a ListView, right-clicking a TreeView
  1103.                                 // item doesn't change the focus.  Instead, the target item is momentarily
  1104.                                 // selected for visual confirmation and then unselected.
  1105.                                 TVHITTESTINFO ht;
  1106.                                 ht.pt = msg.pt;
  1107.                                 ScreenToClient(pcontrol->hwnd, &ht.pt);
  1108.                                 gui_event_info = (DWORD)(size_t)TreeView_HitTest(pcontrol->hwnd, &ht);
  1109.                             }
  1110.                             break;
  1111.                         }
  1112.                     }
  1113.                     //else pcontrol==NULL: Since there is no focused control, it seems best to report the
  1114.                     // cursor's position rather than some arbitrary center-point, or top-left point in the
  1115.                     // parent window.  This is because it might be more convenient for the user to move the
  1116.                     // mouse to select a menu item (since menu will be close to mouse cursor).
  1117.                     ScreenToWindow(g.GuiPoint, pgui->mHwnd); // For compatibility with "Menu Show", convert to window coordinates. A CoordMode option can be added to change this if desired.
  1118.                     break; // case GUI_CONTEXT_MENU.
  1119.  
  1120.                 case GUI_EVENT_DROPFILES:
  1121.                     g.GuiEvent = gui_action; // i.e. set to GUI_EVENT_DROPFILES for special use by GetGuiEvent().
  1122.                     g.GuiPoint = msg.pt; // v1.0.38: More accurate/customary to use msg.pt than GetCursorPos().
  1123.                     ScreenToWindow(g.GuiPoint, pgui->mHwnd);
  1124.                     // Visually indicate that drops aren't allowed while and existing drop is still being
  1125.                     // processed. Fix for v1.0.31.02: The window's current ExStyle is fetched every time
  1126.                     // in case a non-GUI command altered it (such as making it transparent):
  1127.                     SetWindowLong(pgui->mHwnd, GWL_EXSTYLE, GetWindowLong(pgui->mHwnd, GWL_EXSTYLE) & ~WS_EX_ACCEPTFILES);
  1128.                     break;
  1129.  
  1130.                 case GUI_EVENT_CLOSE:
  1131.                 case GUI_EVENT_ESCAPE:
  1132.                 case GUI_EVENT_RESIZE:
  1133.                     g.GuiEvent = GUI_EVENT_NORMAL; // Set for use by GetGuiEvent(), which should consider Close/Escape "Normal" for lack of anything more specific.
  1134.                     if (gui_action == GUI_EVENT_RESIZE)
  1135.                         // Overload another member to avoid having to dedicate a member to size.  Script shouldn't
  1136.                         // look at A_GuiX inside the GuiSize label anyway (it's undefined there).
  1137.                         g.GuiPoint.x = gui_size;
  1138.                     break;
  1139.                 default: // Control-generated event (i.e. event_is_control_generated==true).
  1140.                     switch(pcontrol->type)
  1141.                     {
  1142.                     case GUI_CONTROL_STATUSBAR: // An earlier stage has ensured pcontrol isn't NULL in this case.
  1143.                         // For performance reasons, this isn't done for all GUI events, just ones that
  1144.                         // have a typical use for the coords.
  1145.                         g.GuiPoint = msg.pt;
  1146.                         ScreenToWindow(g.GuiPoint, pgui->mHwnd);
  1147.                         break;
  1148.                     case GUI_CONTROL_LISTVIEW: // v1.0.46.10: Added this section to support notifying the script of HOW the item changed.
  1149.                         if (LOBYTE(gui_action) == 'I')
  1150.                         {
  1151.                             walk = gui_action_errorlevel;
  1152.                             if (gui_action & AHK_LV_SELECT) // Keep this one first, and the others below in the same order, in case any scripts come to rely on the ordering of the letters within the string.
  1153.                                 *walk++ = 'S';
  1154.                             else if (gui_action & AHK_LV_DESELECT)
  1155.                                 *walk++ = 's';
  1156.                             if (gui_action & AHK_LV_FOCUS)
  1157.                                 *walk++ = 'F';
  1158.                             else if (gui_action & AHK_LV_DEFOCUS)
  1159.                                 *walk++ = 'f';
  1160.                             if (gui_action & AHK_LV_CHECK)
  1161.                                 *walk++ = 'C';
  1162.                             else if (gui_action & AHK_LV_UNCHECK)
  1163.                                 *walk++ = 'c';
  1164.                             // Search on "AHK_LV_DROPHILITE" for comments about why the below is commented out:
  1165.                             //if (gui_action & AHK_LV_DROPHILITE)
  1166.                             //    *walk++ = 'D';
  1167.                             //else if (gui_action & AHK_LV_UNDROPHILITE)
  1168.                             //    *walk++ = 'd';
  1169.                             *walk = '\0'; // Provide terminator inside gui_action_errorlevel.
  1170.                             gui_action = 'I'; // Done only after we're done using it above. This clears out the flags above to leave only a naked 'I'.
  1171.                         }
  1172.                         break;
  1173.                     //default: No action for any other control-generated events since caller already set things up properly.
  1174.                     }
  1175.                     g.GuiEvent = gui_action; // Set g.GuiEvent to indicate whether a double-click or other non-standard event launched it.
  1176.                 } // switch (msg.message)
  1177.  
  1178.                 // We're still in case AHK_GUI_ACTION; other cases have their own handling for g.EventInfo.
  1179.                 // gui_event_info is a separate variable because it is sometimes set before g.EventInfo is available
  1180.                 // for the new thread.
  1181.                 // v1.0.44: For the following reasons, make ErrorLevel mirror A_EventInfo only when it
  1182.                 // is documented to do so for backward compatibility:
  1183.                 // 1) Avoids slight performance drain of having to convert a number to text and store it in ErrorLevel.
  1184.                 // 2) Reserves ErrorLevel for potential future uses.
  1185.                 if (gui_action == GUI_EVENT_RESIZE || gui_action == GUI_EVENT_DROPFILES)
  1186.                     g_ErrorLevel->Assign(gui_event_info); // For backward compatibility.
  1187.                 else
  1188.                     g_ErrorLevel->Assign(gui_action_errorlevel); // Helps reserve it for future use. See explanation above.
  1189.  
  1190.                 // Set last found window (as documented).  It's not necessary to check IsWindow/IsWindowVisible/
  1191.                 // DetectHiddenWindows since GetValidLastUsedWindow() takes care of that whenever the script
  1192.                 // actually tries to use the last found window.  UPDATE: Definitely don't want to check
  1193.                 // IsWindowVisible/DetectHiddenWindows now that the last-found window is exempt from
  1194.                 // DetectHiddenWindows if the last-found window is one of the script's GUI windows [v1.0.25.13]:
  1195.                 g.hWndLastUsed = pgui->mHwnd;
  1196.                 g.GuiWindowIndex = pgui->mWindowIndex;
  1197.                 g.GuiDefaultWindowIndex = pgui->mWindowIndex; // GUI threads default to operating upon their own window.
  1198.                 g.GuiControlIndex = gui_control_index; // Must be set only after the "g" struct has been initialized. This will be NO_CONTROL_INDEX if the sender of the message said to do that.
  1199.                 g.EventInfo = gui_event_info; // Override the thread-default of NO_EVENT_INFO.
  1200.  
  1201.                 if (pgui_label_is_running) // i.e. GuiClose, GuiEscape, and related window-level events.
  1202.                     *pgui_label_is_running = true;
  1203.                 else if (event_is_control_generated) // An earlier stage has ensured pcontrol isn't NULL in this case.
  1204.                     pcontrol->attrib |= GUI_CONTROL_ATTRIB_LABEL_IS_RUNNING; // Must be careful to set this flag only when the event is control-generated, not for a drag-and-drop onto the control, or context menu on the control, etc.
  1205.  
  1206.                 // LAUNCH GUI THREAD:
  1207.                 gui_label->Execute();
  1208.  
  1209.                 // Bug-fix for v1.0.22: If the above ExecUntil() performed a "Gui Destroy", the
  1210.                 // pointers below are now invalid so should not be dereferenced.  In such a case,
  1211.                 // hdrop_to_free will already have been freed as part of the window destruction
  1212.                 // process, so don't do it here.  g_gui[gui_index] is checked to ensure the window
  1213.                 // still exists:
  1214.                 if (pgui = g_gui[gui_index]) // Assign.  This refresh is a bug-fix as explained below.
  1215.                 {
  1216.                     // Bug-fix for v1.0.30.04: If the thread that was just launched above destroyed
  1217.                     // its own GUI window, but then recreated it, that window's members obviously aren't
  1218.                     // guaranteed to have the same memory addresses that they did prior to destruction.
  1219.                     // Even g_gui[gui_index] would probably be a different address, so pgui would be
  1220.                     // invalid too.  Therefore, refresh the original pointers (pgui is refreshed above).
  1221.                     // See similar switch() higher above for comments about the below:
  1222.                     pcontrol = gui_control_index < pgui->mControlCount ? pgui->mControl + gui_control_index : NULL; // Refresh unconditionally for maintainability.
  1223.                     switch(gui_action)
  1224.                     {
  1225.                     case GUI_EVENT_RESIZE: pgui->mLabelForSizeIsRunning = false; break;   // Safe to reset even if there is
  1226.                     case GUI_EVENT_CLOSE:  pgui->mLabelForCloseIsRunning = false; break;  // no label due to the window having
  1227.                     case GUI_EVENT_ESCAPE: pgui->mLabelForEscapeIsRunning = false; break; // been destroyed and recreated.
  1228.                     case GUI_EVENT_CONTEXTMENU: break; // Do nothing, but avoid the default case below.
  1229.                     case GUI_EVENT_DROPFILES:
  1230.                         if (pgui->mHdrop) // It's no longer safe to refer to hdrop_to_free (see comments above).
  1231.                         {
  1232.                             DragFinish(pgui->mHdrop); // Since the DropFiles quasi-thread is finished, free the HDROP resources.
  1233.                             pgui->mHdrop = NULL; // Indicate that this GUI window is ready for another drop.
  1234.                         }
  1235.                         // Fix for v1.0.31.02: The window's current ExStyle is fetched every time in case a non-GUI
  1236.                         // command altered it (such as making it transparent):
  1237.                         SetWindowLong(pgui->mHwnd, GWL_EXSTYLE, GetWindowLong(pgui->mHwnd, GWL_EXSTYLE) | WS_EX_ACCEPTFILES);
  1238.                         break;
  1239.                     default: // It's a control's action, so set its attribute.
  1240.                         if (pcontrol) // Recheck to ensure that control still exists (in case window was recreated as explained above).
  1241.                             pcontrol->attrib &= ~GUI_CONTROL_ATTRIB_LABEL_IS_RUNNING;
  1242.                     }
  1243.                 } // if (this gui window wasn't destroyed-without-recreation by the thread we just launched).
  1244.                 break;
  1245.  
  1246.             case AHK_USER_MENU: // user-defined menu item
  1247.                 // Below: the menu type is passed with the message so that its value will be in sync
  1248.                 // with the timestamp of the message (in case this message has been stuck in the
  1249.                 // queue for a long time):
  1250.                 if (pgui) // Set by an earlier stage. It means poster specified that this menu item was from a gui's menu bar.
  1251.                 {
  1252.                     // As documented, set the last found window if possible/applicable.  It's not necessary to
  1253.                     // check IsWindow/IsWindowVisible/DetectHiddenWindows since GetValidLastUsedWindow()
  1254.                     // takes care of that whenever the script actually tries to use the last found window.
  1255.                     g.hWndLastUsed = pgui->mHwnd; // OK if NULL.
  1256.                     // This flags GUI menu items as being GUI so that the script has a way of detecting
  1257.                     // whether a given submenu's item was selected from inside a menu bar vs. a popup:
  1258.                     g.GuiEvent = GUI_EVENT_NORMAL;
  1259.                     g.GuiWindowIndex = g.GuiDefaultWindowIndex = pgui->mWindowIndex; // But leave GuiControl at its default, which flags this event as from a menu item.
  1260.                 }
  1261.                 menu_item->mLabel->Execute();
  1262.                 break;
  1263.  
  1264.             case AHK_HOTSTRING:
  1265.                 g.hWndLastUsed = criterion_found_hwnd; // v1.0.42. Even if the window is invalid for some reason, IsWindow() and such are called whenever the script accesses it (GetValidLastUsedWindow()).
  1266.                 hs->Perform();
  1267.                 break;
  1268.  
  1269.             case AHK_CLIPBOARD_CHANGE:
  1270.                 g.EventInfo = CountClipboardFormats() ? (IsClipboardFormatAvailable(CF_TEXT) || IsClipboardFormatAvailable(CF_HDROP) ? 1 : 2) : 0;
  1271.                 g_ErrorLevel->Assign(g.EventInfo); // For backward compatibility.
  1272.                 // ACT_IS_ALWAYS_ALLOWED() was already checked above.
  1273.                 // The message poster has ensured that g_script.mOnClipboardChangeLabel is non-NULL and valid.
  1274.                 g_script.mOnClipboardChangeIsRunning = true;
  1275.                 g_script.mOnClipboardChangeLabel->Execute();
  1276.                 g_script.mOnClipboardChangeIsRunning = false;
  1277.                 break;
  1278.  
  1279.             default: // hotkey
  1280.                 if (hk->mVK == VK_WHEEL_DOWN || hk->mVK == VK_WHEEL_UP) // If this is true then also: msg.message==AHK_HOOK_HOTKEY
  1281.                     g.EventInfo = (DWORD)msg.lParam; // v1.0.43.03: Override the thread default of 0 with the number of notches by which the wheel was turned.
  1282.                     // Above also works for RunAgainAfterFinished since that feature reuses the same thread attributes set above.
  1283.                 g.hWndLastUsed = criterion_found_hwnd; // v1.0.42. Even if the window is invalid for some reason, IsWindow() and such are called whenever the script accesses it (GetValidLastUsedWindow()).
  1284.                 hk->Perform(*variant);
  1285.             }
  1286.  
  1287.             // v1.0.37.06: Call ResumeUnderlyingThread() even if aMode==WAIT_FOR_MESSAGES; this is for
  1288.             // maintainability and also in case the pause command has been used to unpause the idle thread.
  1289.             ResumeUnderlyingThread(&global_saved, ErrorLevel_saved, true);
  1290.  
  1291.             if (aMode == WAIT_FOR_MESSAGES) // This is the "idle thread", meaning that the end of the thread above has returned the script to an idle state.
  1292.             {
  1293.                 // v1.0.38.04: The following line is for maintainability and reliability.  It avoids the need
  1294.                 // for other sections to figure out whether they should reset g.ThreadIsCritical to false
  1295.                 // when a thread is resumed (a resumed thread might still be critical if it was interrupted
  1296.                 // by an emergency thread such as OnExit or OnMessage).
  1297.                 g.AllowThreadToBeInterrupted = true; // This one is probably necessary due to the way it conforms to ThreadIsCritical in other sections.
  1298.                 g.ThreadIsCritical = false; // Not strictly necessary but improves maintainability.
  1299.                 g.AllowTimers = true; // Same as above.
  1300.                 g.Priority = PRIORITY_MINIMUM; // Ensure minimum priority so that idle state can always be "interrupted".
  1301.             }
  1302.             else // Some thread other than the idle thread.
  1303.             {
  1304.                 if (IsCycleComplete(aSleepDuration, start_time, allow_early_return))
  1305.                 {
  1306.                     // Check for messages once more in case the subroutine that just completed
  1307.                     // above didn't check them that recently.  This is done to minimize the time
  1308.                     // our thread spends *not* pumping messages, which in turn minimizes keyboard
  1309.                     // and mouse lag if the hooks are installed (even though this is no longer
  1310.                     // true due to v1.0.39's dedicated hook thread, it seems best to continue this
  1311.                     // practice to maximize responsiveness of hotkeys, the app itself [e.g. tray
  1312.                     // menu], and also to retain backward compatibility).  Set the state of this
  1313.                     // function/layer/instance so that it will use peek-mode.  UPDATE: Don't change
  1314.                     // the value of aSleepDuration to -1 because IsCycleComplete() needs to know the
  1315.                     // original sleep time specified by the caller to determine whether
  1316.                     // to decrement g_nLayersNeedingTimer:
  1317.                     empty_the_queue_via_peek = true;
  1318.                     allow_early_return = true;
  1319.                     // And now let it fall through to the "continue" statement below.
  1320.                 }
  1321.                 else if (this_layer_needs_timer) // Ensure the timer is back on since we still need it here.
  1322.                     SET_MAIN_TIMER // This won't do anything if it's already on.
  1323.                 // and now if the cycle isn't complete, stay in the blessed GetMessage() state until the time
  1324.                 // has expired.
  1325.             }
  1326.             continue;
  1327.         // End of cases that launch new threads, such as hotkeys and GUI events.
  1328.  
  1329.         case WM_TIMER:
  1330.             if (msg.lParam // This WM_TIMER is intended for a TimerProc...
  1331.                 || msg.hwnd != g_hWnd) // ...or its intended for a window other than the main window, which implies that it doesn't belong to program internals (i.e. the script is probably using it). This fix was added in v1.0.47.02 and it also fixes the ES_NUMBER balloon bug.
  1332.                 break; // Fall through to let a later section do DispatchMessage() on it.
  1333.             // It seems best to poll the joystick for every WM_TIMER message (i.e. every 10ms or so on
  1334.             // NT/2k/XP).  This is because if the system is under load, it might be 20ms, 40ms, or even
  1335.             // longer before we get a timeslice again and that is a long time to be away from the poll
  1336.             // (a fast button press-and-release might occur in less than 50ms, which could be missed if
  1337.             // the polling frequency is too low):
  1338.             POLL_JOYSTICK_IF_NEEDED // Do this first since it's much faster.
  1339.             // v1.0.38.04: The following line is done prior to the timer-check to reduce situations
  1340.             // in which a timer thread is interrupted before it can execute even a single line.
  1341.             // Search for mLastPeekTime in MsgSleep() for detailed explanation.
  1342.             g_script.mLastPeekTime = GetTickCount(); // It's valid to reset this because by definition, "msg" just came in via Get() or Peek(), both of which qualify as a Peek() for this purpose.
  1343.             CHECK_SCRIPT_TIMERS_IF_NEEDED
  1344.             if (aMode == WAIT_FOR_MESSAGES)
  1345.                 // Timer should have already been killed if we're in this state.
  1346.                 // But there might have been some WM_TIMER msgs already in the queue
  1347.                 // (they aren't removed when the timer is killed).  Or perhaps
  1348.                 // a caller is calling us with this aMode even though there
  1349.                 // are suspended subroutines (currently never happens).
  1350.                 // In any case, these are always ignored in this mode because
  1351.                 // the caller doesn't want us to ever return.  UPDATE: This can now
  1352.                 // happen if there are any enabled timed subroutines we need to keep an
  1353.                 // eye on, which is why the mTimerEnabledCount value is checked above
  1354.                 // prior to starting a new iteration.
  1355.                 continue;
  1356.             if (aSleepDuration < 1) // In this case, WM_TIMER messages have already fulfilled their function, above.
  1357.                 continue;
  1358.             // Otherwise aMode == RETURN_AFTER_MESSAGES:
  1359.             // Realistically, there shouldn't be any more messages in our queue
  1360.             // right now because the queue was stripped of WM_TIMER messages
  1361.             // prior to the start of the loop, which means this WM_TIMER
  1362.             // came in after the loop started.  So in the vast majority of
  1363.             // cases, the loop would have had enough time to empty the queue
  1364.             // prior to this message being received.  Therefore, just return rather
  1365.             // than trying to do one final iteration in peek-mode (which might
  1366.             // complicate things, i.e. the below function makes certain changes
  1367.             // in preparation for ending this instance/layer, only to be possibly,
  1368.             // but extremely rarely, interrupted/recursed yet again if that final
  1369.             // peek were to detect a recursable message):
  1370.             if (IsCycleComplete(aSleepDuration, start_time, allow_early_return))
  1371.                 RETURN_FROM_MSGSLEEP
  1372.             // Otherwise, stay in the blessed GetMessage() state until the time has expired:
  1373.             continue;
  1374.  
  1375.         case WM_CANCELJOURNAL:
  1376.             // IMPORTANT: It's tempting to believe that WM_CANCELJOURNAL might be lost/dropped if the script
  1377.             // is displaying a MsgBox or other dialog that has its own msg pump (since such a pump would
  1378.             // discard any msg with a NULL HWND).  However, that is not true in this case because such a dialog's
  1379.             // msg pump would be beneath this one on the call stack.  This is because our caller is calling us in
  1380.             // a loop that does not permit the script to display any *additional* dialogs.  Thus, our msg pump
  1381.             // here should always receive the OS-generated WM_CANCELJOURNAL msg reliably.
  1382.             // v1.0.44: This message is now received only when the user presses Ctrl-Alt-Del or Ctrl-Esc during
  1383.             // playback. For performance and simplicity, the playback hook itself no longer sends this message,
  1384.             // instead directly sets g_PlaybackHook = NULL to notify the installer of the hook that it's gone.
  1385.             g_PlaybackHook = NULL; // A signal for caller.
  1386.             empty_the_queue_via_peek = true;
  1387.             // Above is set to so that we return faster, since our caller should be SendKeys() whenever
  1388.             // WM_CANCELJOURNAL is received, and SendKeys() benefits from a faster return.
  1389.             continue;
  1390.  
  1391.         case WM_KEYDOWN:
  1392.             if (msg.hwnd == g_hWndEdit && msg.wParam == VK_ESCAPE)
  1393.             {
  1394.                 // This won't work if a MessageBox() window is displayed because its own internal
  1395.                 // message pump will dispatch the message to our edit control, which will just
  1396.                 // ignore it.  And avoiding setting the focus to the edit control won't work either
  1397.                 // because the user can simply click in the window to set the focus.  But for now,
  1398.                 // this is better than nothing:
  1399.                 ShowWindow(g_hWnd, SW_HIDE);  // And it's okay if this msg gets dispatched also.
  1400.                 continue;
  1401.             }
  1402.             // Otherwise, break so that the messages will get dispatched.  We need the other
  1403.             // WM_KEYDOWN msgs to be dispatched so that the cursor is keyboard-controllable in
  1404.             // the edit window:
  1405.             break;
  1406.  
  1407.         case WM_QUIT:
  1408.             // The app normally terminates before WM_QUIT is ever seen here because of the way
  1409.             // WM_CLOSE is handled by MainWindowProc().  However, this is kept here in case anything
  1410.             // external ever explicitly posts a WM_QUIT to our thread's queue:
  1411.             g_script.ExitApp(EXIT_WM_QUIT);
  1412.             continue; // Since ExitApp() won't necessarily exit.
  1413.         } // switch()
  1414. break_out_of_main_switch:
  1415.  
  1416.         // If a "continue" statement wasn't encountered somewhere in the switch(), we want to
  1417.         // process this message in a more generic way.
  1418.         // This little part is from the Miranda source code.  But it doesn't seem
  1419.         // to provide any additional functionality: You still can't use keyboard
  1420.         // keys to navigate in the dialog unless it's the topmost dialog.
  1421.         // UPDATE: The reason it doesn't work for non-topmost MessageBoxes is that
  1422.         // this message pump isn't even the one running.  It's the pump of the
  1423.         // top-most MessageBox itself, which apparently doesn't properly dispatch
  1424.         // all types of messages to other MessagesBoxes.  However, keeping this
  1425.         // here is probably a good idea because testing reveals that it does
  1426.         // sometimes receive messages intended for MessageBox windows (which makes
  1427.         // sense because our message pump here retrieves all thread messages).
  1428.         // It might cause problems to dispatch such messages directly, since
  1429.         // IsDialogMessage() is supposed to be used in lieu of DispatchMessage()
  1430.         // for these types of messages.
  1431.         // NOTE: THE BELOW IS CONFIRMED to be needed, at least for a FileSelectFile()
  1432.         // dialog whose quasi-thread has been suspended, and probably for some of the other
  1433.         // types of dialogs as well:
  1434.         if ((fore_window = GetForegroundWindow()) != NULL  // There is a foreground window.
  1435.             && GetWindowThreadProcessId(fore_window, NULL) == g_MainThreadID) // And it belongs to our main thread (the main thread is the only one that owns any windows).
  1436.         {
  1437.             GetClassName(fore_window, wnd_class_name, sizeof(wnd_class_name));
  1438.             if (!strcmp(wnd_class_name, "#32770"))  // MsgBox, InputBox, FileSelectFile/Folder dialog.
  1439.             {
  1440.                 g.CalledByIsDialogMessageOrDispatch = true; // In case there is any way IsDialogMessage() can call one of our own window proc's rather than that of a MsgBox, etc.
  1441.                 g.CalledByIsDialogMessageOrDispatchMsg = msg.message; // Added in v1.0.44.11 because it's known that IsDialogMessage can change the message number (e.g. WM_KEYDOWN->WM_NOTIFY for UpDowns)
  1442.                 if (IsDialogMessage(fore_window, &msg))  // This message is for it, so let it process it.
  1443.                 {
  1444.                     // If it is likely that a FileSelectFile dialog is active, this
  1445.                     // section attempt to retain the current directory as the user
  1446.                     // navigates from folder to folder.  This is done because it is
  1447.                     // possible that our caller is a quasi-thread other than the one
  1448.                     // that originally launched the FileSelectFile (i.e. that dialog
  1449.                     // is in a suspended thread), in which case the user's navigation
  1450.                     // would cause the active threads working dir to change unexpectedly
  1451.                     // unless the below is done.  This is not a complete fix since if
  1452.                     // a message pump other than this one is running (e.g. that of a
  1453.                     // MessageBox()), these messages will not be detected:
  1454.                     if (g_nFileDialogs) // See MsgSleep() for comments on this.
  1455.                         // The below two messages that are likely connected with a user
  1456.                         // navigating to a different folder within the FileSelectFile dialog.
  1457.                         // That avoids changing the directory for every message, since there
  1458.                         // can easily be thousands of such messages every second if the
  1459.                         // user is moving the mouse.  UPDATE: This doesn't work, so for now,
  1460.                         // just call SetCurrentDirectory() for every message, which does work.
  1461.                         // A brief test of CPU utilization indicates that SetCurrentDirectory()
  1462.                         // is not a very high overhead call when it is called many times here:
  1463.                         //if (msg.message == WM_ERASEBKGND || msg.message == WM_DELETEITEM)
  1464.                         SetCurrentDirectory(g_WorkingDir);
  1465.                     g.CalledByIsDialogMessageOrDispatch = false;
  1466.                     continue;  // This message is done, so start a new iteration to get another msg.
  1467.                 }
  1468.                 g.CalledByIsDialogMessageOrDispatch = false;
  1469.             }
  1470.         }
  1471.         // Translate keyboard input for any of our thread's windows that need it:
  1472.         if (!g_hAccelTable || !TranslateAccelerator(g_hWnd, g_hAccelTable, &msg))
  1473.         {
  1474.             g.CalledByIsDialogMessageOrDispatch = true; // Relies on the fact that the types of messages we dispatch can't result in a recursive call back to this function.
  1475.             g.CalledByIsDialogMessageOrDispatchMsg = msg.message; // Added in v1.0.44.11. Do it prior to Translate & Dispatch in case either one of them changes the message number (it is already known that IsDialogMessage can change message numbers).
  1476.             TranslateMessage(&msg);
  1477.             DispatchMessage(&msg); // This is needed to send keyboard input and other messages to various windows and for some WM_TIMERs.
  1478.             g.CalledByIsDialogMessageOrDispatch = false;
  1479.         }
  1480.     } // infinite-loop
  1481. }
  1482.  
  1483.  
  1484.  
  1485. ResultType IsCycleComplete(int aSleepDuration, DWORD aStartTime, bool aAllowEarlyReturn)
  1486. // This function is used just to make MsgSleep() more readable/understandable.
  1487. {
  1488.     // Note: Even if TickCount has wrapped due to system being up more than about 49 days,
  1489.     // DWORD math still gives the right answer as long as aStartTime itself isn't more
  1490.     // than about 49 days ago. Note: must cast to int or any negative result will be lost
  1491.     // due to DWORD type:
  1492.     DWORD tick_now = GetTickCount();
  1493.     if (!aAllowEarlyReturn && (int)(aSleepDuration - (tick_now - aStartTime)) > SLEEP_INTERVAL_HALF)
  1494.         // Early return isn't allowed and the time remaining is large enough that we need to
  1495.         // wait some more (small amounts of remaining time can't be effectively waited for
  1496.         // due to the 10ms granularity limit of SetTimer):
  1497.         return FAIL; // Tell the caller to wait some more.
  1498.  
  1499.     // Update for v1.0.20: In spite of the new resets of mLinesExecutedThisCycle that now appear
  1500.     // in MsgSleep(), it seems best to retain this reset here for peace of mind, maintainability,
  1501.     // and because it might be necessary in some cases (a full study was not done):
  1502.     // Reset counter for the caller of our caller, any time the thread
  1503.     // has had a chance to be idle (even if that idle time was done at a deeper
  1504.     // recursion level and not by this one), since the CPU will have been
  1505.     // given a rest, which is the main (perhaps only?) reason for using BatchLines
  1506.     // (e.g. to be more friendly toward time-critical apps such as games,
  1507.     // video capture, video playback).  UPDATE: mLastScriptRest is also reset
  1508.     // here because it has a very similar purpose.
  1509.     if (aSleepDuration > -1)
  1510.     {
  1511.         g_script.mLinesExecutedThisCycle = 0;
  1512.         g_script.mLastScriptRest = tick_now;
  1513.     }
  1514.     // v1.0.38.04: Reset mLastPeekTime because caller has just done a GetMessage() or PeekMessage(),
  1515.     // both of which should have routed events to the keyboard/mouse hooks like LONG_OPERATION_UPDATE's
  1516.     // PeekMessage() and thus satisified the reason that mLastPeekTime is tracked in the first place.
  1517.     // UPDATE: Although the hooks now have a dedicated thread, there's a good chance mLastPeekTime is
  1518.     // beneficial in terms of increasing GUI & script responsiveness, so it is kept.
  1519.     // The following might also improve performance slightly by avoiding extra Peek() calls, while also
  1520.     // reducing premature thread interruptions.
  1521.     g_script.mLastPeekTime = tick_now;
  1522.     return OK;
  1523. }
  1524.  
  1525.  
  1526.  
  1527. bool CheckScriptTimers()
  1528. // Returns true if it launched at least one thread, and false otherwise.
  1529. // It's best to call this function only directly from MsgSleep() or when there is an instance of
  1530. // MsgSleep() closer on the call stack than the nearest dialog's message pump (e.g. MsgBox).
  1531. // This is because threads some events might get queued up for our thread during the execution
  1532. // of the timer subroutines here.  When those subroutines finish, if we return directly to a dialog's
  1533. // message pump, and such pending messages might be discarded or mishandled.
  1534. // Caller should already have checked the value of g_script.mTimerEnabledCount to ensure it's
  1535. // greater than zero, since we don't check that here (for performance).
  1536. // This function will go through the list of timed subroutines only once and then return to its caller.
  1537. // It does it only once so that it won't keep a thread beneath it permanently suspended if the sum
  1538. // total of all timer durations is too large to be run at their specified frequencies.
  1539. // This function is allowed to be called recursively, which handles certain situations better:
  1540. // 1) A hotkey subroutine interrupted and "buried" one of the timer subroutines in the stack.
  1541. //    In this case, we don't want all the timers blocked just because that one is, so recursive
  1542. //    calls from ExecUntil() are allowed, and they might discover other timers to run.
  1543. // 2) If the script is idle but one of the timers winds up taking a long time to execute (perhaps
  1544. //    it gets stuck in a long WinWait), we want a recursive call (from MsgSleep() in this example)
  1545. //    to launch any other enabled timers concurrently with the first, so that they're not neglected
  1546. //    just because one of the timers happens to be long-running.
  1547. // Of course, it's up to the user to design timers so that they don't cause problems when they
  1548. // interrupted hotkey subroutines, or when they themselves are interrupted by hotkey subroutines
  1549. // or other timer subroutines.
  1550. {
  1551.     // When this is true, such as during a SendKeys() operation, it seems best not to launch any new
  1552.     // timed subroutines.  The reasons for this are similar to the reasons for not allowing hotkeys
  1553.     // to fire during such times.  Those reasons are discussed in other comments.  In addition,
  1554.     // it seems best as a policy not to allow timed subroutines to run while the script's current
  1555.     // quasi-thread is paused.  Doing so would make the tray icon flicker (were it even updated below,
  1556.     // which it currently isn't) and in any case is probably not what the user would want.  Most of the
  1557.     // time, the user would want all timed subroutines stopped while the current thread is paused.
  1558.     // And even if this weren't true, the confusion caused by the subroutines still running even when
  1559.     // the current thread is paused isn't worth defaulting to the opposite approach.  In the future,
  1560.     // and if there's demand, perhaps a config option can added that allows a different default behavior.
  1561.     // UPDATE: It seems slightly better (more consistent) to disallow all timed subroutines whenever
  1562.     // there is even one paused thread anywhere in the "stack".  UPDATE for v1.0.37.06: g_IdleIsPaused is
  1563.     // now checked in case the "idle thread" is paused (since that thread is not counted in
  1564.     // g_nPausedThreads).  However, g_nPausedThreads must still be checked in case the uppermost thread
  1565.     // isn't paused but some other thread isn't (as documented, timers don't run when any thread is paused).
  1566.     if (!INTERRUPTIBLE || g_nPausedThreads > 0 || g_IdleIsPaused || !g.AllowTimers || g_nThreads >= g_MaxThreadsTotal)
  1567.         return false; // Above: To be safe (prevent stack faults) don't allow max threads to be exceeded.
  1568.  
  1569.     ScriptTimer *ptimer;
  1570.     UINT launched_threads;
  1571.     DWORD tick_start;
  1572.     global_struct global_saved;
  1573.     char ErrorLevel_saved[ERRORLEVEL_SAVED_SIZE];
  1574.  
  1575.     // Note: It seems inconsequential if a subroutine that the below loop executes causes a
  1576.     // new timer to be added to the linked list while the loop is still enumerating the timers.
  1577.  
  1578.     for (launched_threads = 0, ptimer = g_script.mFirstTimer; ptimer != NULL; ptimer = ptimer->mNextTimer)
  1579.     {
  1580.         // Call GetTickCount() every time in case a previous iteration of the loop took a long
  1581.         // time to execute.  Also, as of v1.0.36.03, the following subtracts two DWORDs to support
  1582.         // intervals of 49.7 vs. 24.8 days.  This should work as long as the distance between the
  1583.         // values being compared isn't greater than 49.7 days. This is because 1 minus 2 in unsigned
  1584.         // math yields 0xFFFFFFFF milliseconds (49.7 days).
  1585.         ScriptTimer &timer = *ptimer; // For performance and convenience.
  1586.         if (timer.mEnabled && timer.mExistingThreads < 1 && timer.mPriority >= g.Priority // thread priorities
  1587.             && (tick_start = GetTickCount()) - timer.mTimeLastRun >= (DWORD)timer.mPeriod)
  1588.         {
  1589.             if (!launched_threads)
  1590.             {
  1591.                 // Since this is the first subroutine that will be launched during this call to
  1592.                 // this function, we know it will wind up running at least one subroutine, so
  1593.                 // certain changes are made:
  1594.                 // Increment the count of quasi-threads only once because this instance of this
  1595.                 // function will never create more than 1 thread (i.e. if there is more than one
  1596.                 // enabled timer subroutine, the will always be run sequentially by this instance).
  1597.                 // If g_nThreads is zero, incrementing it will also effectively mark the script as
  1598.                 // non-idle, the main consequence being that an otherwise-idle script can be paused
  1599.                 // if the user happens to do it at the moment a timed subroutine is running, which
  1600.                 // seems best since some timed subroutines might take a long time to run:
  1601.                 ++g_nThreads;
  1602.                 // Next, save the current state of the globals so that they can be restored just prior
  1603.                 // to returning to our caller:
  1604.                 strlcpy(ErrorLevel_saved, g_ErrorLevel->Contents(), sizeof(ErrorLevel_saved)); // Save caller's errorlevel.
  1605.                 CopyMemory(&global_saved, &g, sizeof(global_struct));
  1606.                 // But never kill the main timer, since the mere fact that we're here means that
  1607.                 // there's at least one enabled timed subroutine.  Though later, performance can
  1608.                 // be optimized by killing it if there's exactly one enabled subroutine, or if
  1609.                 // all the subroutines are already in a running state (due to being buried beneath
  1610.                 // the current quasi-thread).  However, that might introduce unwanted complexity
  1611.                 // in other places that would need to start up the timer again because we stopped it, etc.
  1612.             }
  1613.  
  1614.             // Fix for v1.0.31: mTimeLastRun is now given its new value *before* the thread is launched
  1615.             // rather than after.  This allows a timer to be reset by its own thread -- by means of
  1616.             // "SetTimer, TimerName", which is otherwise impossible because the reset was being
  1617.             // overridden by us here when the thread finished.
  1618.             // Seems better to store the start time rather than the finish time, though it's clearly
  1619.             // debatable.  The reason is that it's sometimes more important to ensure that a given
  1620.             // timed subroutine is *begun* at the specified interval, rather than assuming that
  1621.             // the specified interval is the time between when the prior run finished and the new
  1622.             // one began.  This should make timers behave more consistently (i.e. how long a timed
  1623.             // subroutine takes to run SHOULD NOT affect its *apparent* frequency, which is number
  1624.             // of times per second or per minute that we actually attempt to run it):
  1625.             timer.mTimeLastRun = tick_start;
  1626.             if (timer.mRunOnlyOnce)
  1627.                 timer.Disable();  // This is done prior to launching the thread for reasons similar to above.
  1628.             ++launched_threads;
  1629.  
  1630.             if (g_nFileDialogs) // See MsgSleep() for comments on this.
  1631.                 SetCurrentDirectory(g_WorkingDir);
  1632.  
  1633.             // Note that it is not necessary to call UpdateTrayIcon() here since timers won't run
  1634.             // if there is any paused thread, thus the icon can't currently be showing "paused".
  1635.  
  1636.             // This next line is necessary in case a prior iteration of our loop invoked a different
  1637.             // timed subroutine that changed any of the global struct's values.  In other words, make
  1638.             // every newly launched subroutine start off with the global default values that
  1639.             // the user set up in the auto-execute part of the script (e.g. KeyDelay, WinDelay, etc.).
  1640.             // However, we do not set ErrorLevel to NONE here because it's more flexible that way
  1641.             // (i.e. the user may want one hotkey subroutine to use the value of ErrorLevel set by another):
  1642.             InitNewThread(timer.mPriority, false, false, timer.mLabel->mJumpToLine->mActionType); // False as last param because ++g_nThreads should be done only once rather than each Init().
  1643.             // The above also resets g_script.mLinesExecutedThisCycle to zero, which should slightly
  1644.             // increase the expectation that any short timed subroutine will run all the way through
  1645.             // to completion rather than being interrupted by the press of a hotkey, and thus potentially
  1646.             // buried in the stack.  However, mLastScriptRest is not set to GetTickCount() here because
  1647.             // unlike other events -- which are typically in response to an explicit action by the user
  1648.             // such as pressing a button or hotkey -- timers are lower priority and more relaxed.
  1649.             // Also, mLastScriptRest really should only be set when a call to Get/PeekMsg has just
  1650.             // occurred, so it should be left as the responsibilty of the section in MsgSleep that
  1651.             // launches new threads.
  1652.  
  1653.             ++timer.mExistingThreads;
  1654.             timer.mLabel->Execute();
  1655.             --timer.mExistingThreads;
  1656.  
  1657.             KILL_UNINTERRUPTIBLE_TIMER
  1658.         } // if timer is due to launch.
  1659.     } // for() each timer.
  1660.  
  1661.     if (launched_threads) // Since at least one subroutine was run above, restore various values for our caller.
  1662.     {
  1663.         ResumeUnderlyingThread(&global_saved, ErrorLevel_saved, false); // Last param "false" because KILL_UNINTERRUPTIBLE_TIMER was already done above.
  1664.         return true;
  1665.     }
  1666.     return false;
  1667. }
  1668.  
  1669.  
  1670.  
  1671. void PollJoysticks()
  1672. // It's best to call this function only directly from MsgSleep() or when there is an instance of
  1673. // MsgSleep() closer on the call stack than the nearest dialog's message pump (e.g. MsgBox).
  1674. // This is because events posted to the thread indirectly by us here would be discarded or mishandled
  1675. // by a non-standard (dialog) message pump.
  1676. //
  1677. // Polling the joysticks this way rather than using joySetCapture() is preferable for several reasons:
  1678. // 1) I believe joySetCapture() internally polls the joystick anyway, via a system timer, so it probably
  1679. //    doesn't perform much better (if at all) than polling "manually".
  1680. // 2) joySetCapture() only supports 4 buttons;
  1681. // 3) joySetCapture() will fail if another app is already capturing the joystick;
  1682. // 4) Even if the joySetCapture() succeeds, other programs (e.g. older games), would be prevented from
  1683. //    capturing the joystick while the script in question is running.
  1684. {
  1685.     // Even if joystick hotkeys aren't currently allowed to fire, poll it anyway so that hotkey
  1686.     // messages can be buffered for later.
  1687.     static DWORD sButtonsPrev[MAX_JOYSTICKS] = {0}; // Set initial state to "all buttons up for all joysticks".
  1688.     JOYINFOEX jie;
  1689.     DWORD buttons_newly_down;
  1690.  
  1691.     for (int i = 0; i < MAX_JOYSTICKS; ++i)
  1692.     {
  1693.         if (!Hotkey::sJoystickHasHotkeys[i])
  1694.             continue;
  1695.         // Reset these every time in case joyGetPosEx() ever changes them. Also, most systems have only one joystick,
  1696.         // so this code will hardly ever be executed more than once (and sometimes zero times):
  1697.         jie.dwSize = sizeof(JOYINFOEX);
  1698.         jie.dwFlags = JOY_RETURNBUTTONS; // vs. JOY_RETURNALL
  1699.         if (joyGetPosEx(i, &jie) != JOYERR_NOERROR) // Skip this joystick and try the others.
  1700.             continue;
  1701.         // The exclusive-or operator determines which buttons have changed state.  After that,
  1702.         // the bitwise-and operator determines which of those have gone from up to down (the
  1703.         // down-to-up events are currently not significant).
  1704.         buttons_newly_down = (jie.dwButtons ^ sButtonsPrev[i]) & jie.dwButtons;
  1705.         sButtonsPrev[i] = jie.dwButtons;
  1706.         if (!buttons_newly_down)
  1707.             continue;
  1708.         // See if any of the joystick hotkeys match this joystick ID and one of the buttons that
  1709.         // has just been pressed on it.  If so, queue up (buffer) the hotkey events so that they will
  1710.         // be processed when messages are next checked:
  1711.         Hotkey::TriggerJoyHotkeys(i, buttons_newly_down);
  1712.     }
  1713. }
  1714.  
  1715.  
  1716.  
  1717. bool MsgMonitor(HWND aWnd, UINT aMsg, WPARAM awParam, LPARAM alParam, MSG *apMsg, LRESULT &aMsgReply)
  1718. // Returns false if the message is not being monitored, or it is but the called function indicated
  1719. // that the message should be given its normal processing.  Returns true when the caller should
  1720. // not process this message but should instead immediately reply with aMsgReply (if a reply is possible).
  1721. // When false is returned, caller should ignore the value of aMsgReply.
  1722. {
  1723.     // This function directly launches new threads rather than posting them as something like
  1724.     // AHK_GUI_ACTION (which would allow them to be queued by means of MSG_FILTER_MAX) because a message
  1725.     // monitor function in the script can return "true" to exempt the message from further processing.
  1726.     // Consequently, the MSG_FILTER_MAX queuing effect will only occur for monitored messages that are
  1727.     // numerically greater than WM_HOTKEY. Other messages will not be subject to the filter and thus
  1728.     // will arrive here even when the script is currently uninterruptible, in which case it seems best
  1729.     // to discard the message because the current design doesn't allow for interruptions. The design
  1730.     // could be reviewed to find out what the consequences of interruption would be.  Also, the message
  1731.     // could be suppressed (via return 1) and reposted, but if there are other messages already in
  1732.     // the queue that qualify to fire a msg-filter (or even messages such as WM_LBUTTONDOWN that have
  1733.     // a normal effect that relies on ordering), the messages would then be processed out of their
  1734.     // original order, which would be very undesirable in many cases.
  1735.     //
  1736.     // Parts of the following are obsolete:
  1737.     // In light of the above, INTERRUPTIBLE_IF_NECESSARY is used instead of INTERRUPTIBLE_IN_EMERGENCY
  1738.     // to reduce on the unreliability of message filters that are numerically less than WM_HOTKEY.
  1739.     // For example, if the user presses a hotkey and an instant later a qualified WM_LBUTTONDOWN arrives,
  1740.     // the filter will still be able to run by interrupting the uinterruptible thread.  In this case,
  1741.     // ResumeUnderlyingThread() sets g.AllowThreadToBeInterrupted to false for us in case the
  1742.     // timer "TIMER_ID_UNINTERRUPTIBLE" fired for the new thread rather than for the old one (this
  1743.     // prevents the interrupted thread from becoming permanently uninterruptible).
  1744.     if (!INTERRUPTIBLE_IN_EMERGENCY)
  1745.         return false;
  1746.  
  1747.     // Linear search vs. binary search should perform better on average because the vast majority
  1748.     // of message monitoring scripts are expected to monitor only a few message numbers.
  1749.     int msg_index, msg_count_orig;
  1750.     for (msg_count_orig = g_MsgMonitorCount, msg_index = 0; msg_index < g_MsgMonitorCount; ++msg_index)
  1751.         if (g_MsgMonitor[msg_index].msg == aMsg)
  1752.             break;
  1753.     if (msg_index == g_MsgMonitorCount) // No match found, so the script isn't monitoring this message.
  1754.         return false; // Tell the caller to give this message any additional/default processing.
  1755.     // Otherwise, the script is monitoring this message, so continue on.
  1756.  
  1757.     MsgMonitorStruct &monitor = g_MsgMonitor[msg_index]; // For performance and convenience.
  1758.     Func &func = *monitor.func;                          // Above, but also in case monitor item gets deleted while the function is running (e.g. by the function itself).
  1759.  
  1760.     // Many of the things done below are similar to the thread-launch procedure used in MsgSleep(),
  1761.     // so maintain them together and see MsgSleep() for more detailed commments.
  1762.     if (g_nThreads >= g_MaxThreadsTotal)
  1763.         // Below: Only a subset of ACT_IS_ALWAYS_ALLOWED is done here because:
  1764.         // 1) The omitted action types seem too obscure to grant always-run permission for msg-monitor events.
  1765.         // 2) Reduction in code size.
  1766.         if (g_nThreads > MAX_THREADS_LIMIT
  1767.             || func.mJumpToLine->mActionType != ACT_EXITAPP && func.mJumpToLine->mActionType != ACT_RELOAD)
  1768.             return false;
  1769.     if (monitor.instance_count >= monitor.max_instances || g.Priority > 0) // Monitor is already running more than the max number of instances, or existing thread's priority is too high to be interrupted.
  1770.         return false;
  1771.  
  1772.     // Need to check if backup is needed in case script explicitly called the function rather than using
  1773.     // it solely as a callback.  UPDATE: And now that max_instances is supported, also need it for that.
  1774.     // See ExpandExpression() for detailed comments about the following section.
  1775.     VarBkp *var_backup = NULL;   // If needed, it will hold an array of VarBkp objects.
  1776.     int var_backup_count; // The number of items in the above array.
  1777.     if (func.mInstances > 0) // Backup is needed.
  1778.         if (!Var::BackupFunctionVars(func, var_backup, var_backup_count)) // Out of memory.
  1779.             return false;
  1780.             // Since we're in the middle of processing messages, and since out-of-memory is so rare,
  1781.             // it seems justifiable not to have any error reporting and instead just avoid launching
  1782.             // the new thread.
  1783.  
  1784.     // Since above didn't return, the launch of the new thread is now considered unavoidable.
  1785.  
  1786.     // See MsgSleep() for comments about the following section.
  1787.     char ErrorLevel_saved[ERRORLEVEL_SAVED_SIZE];
  1788.     strlcpy(ErrorLevel_saved, g_ErrorLevel->Contents(), sizeof(ErrorLevel_saved));
  1789.     global_struct global_saved;
  1790.     CopyMemory(&global_saved, &g, sizeof(global_struct));
  1791.     if (g_nFileDialogs)
  1792.         SetCurrentDirectory(g_WorkingDir);
  1793.     InitNewThread(0, false, true, func.mJumpToLine->mActionType);
  1794.     g_script.UpdateTrayIcon();
  1795.  
  1796.     // Set last found window (as documented).  Can be NULL.
  1797.     // Nested controls like ComboBoxes require more than a simple call to GetParent().
  1798.     if (g.hWndLastUsed = GetNonChildParent(aWnd)) // Assign parent window as the last found window (it's ok if it's hidden).
  1799.     {
  1800.         GuiType *pgui = GuiType::FindGui(g.hWndLastUsed);
  1801.         if (pgui) // This parent window is a GUI window.
  1802.         {
  1803.             g.GuiWindowIndex = pgui->mWindowIndex;  // Update the built-in variable A_GUI.
  1804.             g.GuiDefaultWindowIndex = pgui->mWindowIndex; // Consider this a GUI thread; so it defaults to operating upon its own window.
  1805.             GuiIndexType control_index = (GuiIndexType)(size_t)pgui->FindControl(aWnd, true); // v1.0.44.03: Call FindControl() vs. GUI_HWND_TO_INDEX so that a combobox's edit control is properly resolved to the combobox itself.
  1806.             if (control_index < pgui->mControlCount) // Match found (relies on unsigned for out-of-bounds detection).
  1807.                 g.GuiControlIndex = control_index;
  1808.             //else leave it at its default, which was set when the new thread was initialized.
  1809.         }
  1810.         //else leave the above members at their default values set when the new thread was initialized.
  1811.     }
  1812.     if (apMsg)
  1813.     {
  1814.         g.GuiPoint = apMsg->pt;
  1815.         g.EventInfo = apMsg->time;
  1816.     }
  1817.     //else leave them at their init-thread defaults.
  1818.  
  1819.     // See ExpandExpression() for detailed comments about the following section.
  1820.     if (func.mParamCount > 0)
  1821.     {
  1822.         // Copy the appropriate values into each of the function's formal parameters.
  1823.         func.mParam[0].var->Assign((DWORD)awParam); // Assign parameter #1: wParam
  1824.         if (func.mParamCount > 1) // Assign parameter #2: lParam
  1825.         {
  1826.             // v1.0.38.01: LPARAM is now written out as a DWORD because the majority of system messages
  1827.             // use LPARAM as a pointer or other unsigned value.  This shouldn't affect most scripts because
  1828.             // of the way ATOI64() and ATOU() wrap a negative number back into the unsigned domain for
  1829.             // commands such as PostMessage/SendMessage.
  1830.             func.mParam[1].var->Assign((DWORD)alParam);
  1831.             if (func.mParamCount > 2) // Assign parameter #3: Message number (in case this function monitors more than one).
  1832.             {
  1833.                 func.mParam[2].var->AssignHWND((HWND)(size_t)aMsg); // Write msg number as hex because it's a lot more common. Casting issues make it easier to retain the name "AssignHWND".
  1834.                 if (func.mParamCount > 3) // Assign parameter #4: HWND (listed last since most scripts won't use it for anything).
  1835.                     func.mParam[3].var->AssignHWND(aWnd); // Can be a parent or child window.
  1836.             }
  1837.         }
  1838.     }
  1839.  
  1840.     // v1.0.38.04: Below was added to maximize responsiveness to incoming messages.  The reasoning
  1841.     // is similar to why the same thing is done in MsgSleep() prior to its launch of a thread, so see
  1842.     // MsgSleep for more comments:
  1843.     g_script.mLastScriptRest = g_script.mLastPeekTime = GetTickCount();
  1844.     ++monitor.instance_count;
  1845.  
  1846.     char *return_value;
  1847.     func.Call(return_value); // Call the UDF.
  1848.  
  1849.     // Fix for v1.0.47: Must handle return_value BEFORE calling FreeAndRestoreFunctionVars() because return_value
  1850.     // might be the contents of one of the function's local variables (which are about to be free'd).
  1851.     bool block_further_processing = *return_value; // No need to check the following because they're implied for *return_value!=0: result != EARLY_EXIT && result != FAIL;
  1852.     if (block_further_processing)
  1853.         aMsgReply = (LPARAM)ATOI64(return_value); // Use 64-bit in case it's an unsigned number greater than 0x7FFFFFFF, in which case this allows it to wrap around to a negative.
  1854.     //else leave aMsgReply uninitialized because we'll be returning false later below, which tells our caller
  1855.     // to ignore aMsgReply.
  1856.     Var::FreeAndRestoreFunctionVars(func, var_backup, var_backup_count);
  1857.     ResumeUnderlyingThread(&global_saved, ErrorLevel_saved, true);
  1858.     // Check that the msg_index item still exists (it may have been deleted during the thread that just finished,
  1859.     // either by the thread itself or some other thread that interrupted it).  BIF_OnMessage has been sure to
  1860.     // reset deleted array elements to have a NULL func.  Even so, the following scenario could happen:
  1861.     // 1) The message element is deleted.
  1862.     // 2) It is recreated to be the same as before, but now it has a different array index.
  1863.     // 3) It's instance_count member would have been set to 0 upon creation, and the thread for the same
  1864.     //    message might have launched the same function we did above, or some other.
  1865.     // 4) Everything seems okay in this case, especially given its rarity.
  1866.     //
  1867.     // But what if step 2 above created the same msg+func in the same position as before?  It's instance_count
  1868.     // member would have been wrongly decremented, which would have allowed this msg-monitor thread to launch
  1869.     // a thread beyond max-threads while it was techically still running above.  This scenario seems too rare
  1870.     // and the consequences too small to justify the extra code size, so it is documented here as a known limitation.
  1871.     //
  1872.     // Thus, if "monitor" is defunct due to deletion, decrementing its instance_count is harmless.
  1873.     // However, "monitor" might have been reused by BIF_OnMessage() to create a new msg-monitor, so the
  1874.     // thing that must be checked is the message number to avoid wrongly decrementing some other msg-monitor's
  1875.     // instance_count.  Update: Check g_MsgMonitorCount in case it has shrunk (which could leave
  1876.     // "monitor" pointing to an element in the array that is now unused/obsolete).
  1877.     if (g_MsgMonitorCount >= msg_count_orig && monitor.msg == aMsg)
  1878.     {
  1879.         if (monitor.instance_count) // Avoid going negative, which might otherwise be possible in weird circumstances described in other comments.
  1880.             --monitor.instance_count;
  1881.     }
  1882.     else // "monitor" is now some other msg-monitor (or an obsolete item in array), so do don't change it (see above comments).
  1883.     {
  1884.         // Fix for v1.0.44.10: If OnMessage is called from *inside* some other monitor function in a way that
  1885.         // deletes a message monitor, monitor.instance_count wouldn't get decremented (but only if the
  1886.         // message(s) that were deleted lay to the left of it in the array).  So check if the monitor is
  1887.         // somewhere else in the array and if found (i.e. it didn't delete itself), update it.
  1888.         for (msg_index = 0; msg_index < g_MsgMonitorCount; ++msg_index)
  1889.             if (g_MsgMonitor[msg_index].msg == aMsg)
  1890.             {
  1891.                 if (g_MsgMonitor[msg_index].instance_count) // Avoid going negative, which might otherwise be possible in weird circumstances described in other comments.
  1892.                     --g_MsgMonitor[msg_index].instance_count;
  1893.                 break;
  1894.             }
  1895.     }
  1896.  
  1897.     return block_further_processing; // If false, the caller will ignore aMsgReply and process this message normally. If true, aMsgReply contains the reply the caller should immediately send for this message.
  1898. }
  1899.  
  1900.  
  1901.  
  1902. void InitNewThread(int aPriority, bool aSkipUninterruptible, bool aIncrementThreadCount
  1903.     , ActionTypeType aTypeOfFirstLine)
  1904. // The value of aTypeOfFirstLine is ignored when aSkipUninterruptible==true.
  1905. // To reduce the expectation that a newly launched hotkey or timed subroutine will
  1906. // be immediately interrupted by a timed subroutine or hotkey, interruptions are
  1907. // forbidden for a short time (user-configurable).  If the subroutine is a quick one --
  1908. // finishing prior to when ExecUntil() or the Timer would have set g_AllowInterruption to be
  1909. // true -- we will set it to be true afterward so that it gets done as quickly as possible.
  1910. // The following rules of precedence apply:
  1911. // If either UninterruptibleTime or UninterruptedLineCountMax is zero, newly launched subroutines
  1912. // are always interruptible.  Otherwise: If both are negative, newly launched subroutines are
  1913. // never interruptible.  If only one is negative, newly launched subroutines cannot be interrupted
  1914. // due to that component, only the other one (which is now known to be positive otherwise the
  1915. // first rule of precedence would have applied).
  1916. {
  1917.     g_nThreads += aIncrementThreadCount; // It is the caller's responsibility to avoid calling us if the thread count is too high.
  1918.  
  1919.     // v1.0.38.04: mLinesExecutedThisCycle is now reset in this function for maintainability. For simplicity,
  1920.     // the reset is unconditional because it is desirable 99% of the time.
  1921.     // See comments in CheckScriptTimers() for why g_script.mLastScriptRest isn't altered here.
  1922.     g_script.mLinesExecutedThisCycle = 0; // Make it start fresh to avoid unnecessary delays due to SetBatchLines.
  1923.  
  1924.     bool underlying_thread_is_paused = g.IsPaused;  // Indicate in the upcoming thread whether the thread to be interrupted is paused.
  1925.     CopyMemory(&g, &g_default, sizeof(global_struct));
  1926.     g.UnderlyingThreadIsPaused = underlying_thread_is_paused;
  1927.     g.Priority = aPriority;
  1928.  
  1929.     if (aSkipUninterruptible)
  1930.         return;
  1931.  
  1932.     // v1.0.38.04: Mark the thread critical here, for maintainability and also to avoid doing
  1933.     // SET_UNINTERRUPTIBLE_TIMER when the script has taken explicit control of this thread's
  1934.     // interruptibility.
  1935.     // OLDER (somewhat obsolete but good background): There is no need to set g.ThreadIsCritical here
  1936.     // because when actually encountered, "Critical [On]" will do it (and we're sure that first line
  1937.     // will execute because: 1) g.AllowThreadToBeInterrupted was set to false above; and 2) the
  1938.     // the uinterruptible timer will not be activated. Thus, the thread cannot be interrupted by
  1939.     // anything short of OnExit/OnMessage, in which case g.ThreadIsCritical's value doesn't matter,
  1940.     // and it will be set later when "Critical [On]" is actually encountered by the resumed thread.
  1941.     // UPDATE: But there might be a tiny window of opportunity for a critical thread to get interrupted
  1942.     // by a non-emergency thread after it was previously interrupted by an emergency thread, therefore
  1943.     // the following line is here for maintainability and reliability:
  1944.     if (!g.ThreadIsCritical) // If the thread default isn't "critical", make this thread critical only if it's explicitly marked that way.
  1945.     {
  1946.         if (g.ThreadIsCritical = (aTypeOfFirstLine == ACT_CRITICAL))
  1947.         {
  1948.             g.LinesPerCycle = -1;      // v1.0.47: It seems best to ensure SetBatchLines -1 is in effect because
  1949.             g.IntervalBeforeRest = -1; // otherwise it may check messages during the interval that it isn't supposed to.
  1950.         }
  1951.     }
  1952.     //else it's already critical, so leave it that way until "Critical Off" (which may be the very first line) is encountered at runtime.
  1953.  
  1954.     if (g_script.mUninterruptibleTime && g_script.mUninterruptedLineCountMax // Both components must be non-zero to start off uninterruptible.
  1955.         || g.ThreadIsCritical) // v1.0.38.04.
  1956.     {
  1957.         // Use g.AllowThreadToBeInterrupted vs. g_AllowInterruption in case g_AllowInterruption
  1958.         // just happens to have been set to true for some other reason (e.g. SendKeys()):
  1959.         g.AllowThreadToBeInterrupted = false;
  1960.         // v1.0.38.04: If the first line is "Critical" (even "Critical Off"), don't activate the timer
  1961.         // because "Critical [On]" means uninterruptible until it's turned off.  And "Critical Off"
  1962.         // means immediately interruptible.
  1963.         if (g_script.mUninterruptibleTime > 0  // Known to be either negative or positive (but not zero) at this point.
  1964.             && !g.ThreadIsCritical)
  1965.             // It's much better to set a timer than have ExecUntil() watch for the time
  1966.             // to expire.  This is because it performs better, but more importantly
  1967.             // consider the case when ExecUntil() calls a WinWait, FileSetAttrib, or any
  1968.             // single command that might take a long time to execute.  While that command
  1969.             // is executing, ExecUntil() would be unable to keep an eye on things, thus
  1970.             // the script would stay uninterruptible for far longer than intended unless
  1971.             // many checks were added in various places, which would be cumbersome to
  1972.             // maintain.  By using a timer, the message loop (which is called frequently
  1973.             // by just about every long-running script command) will be able to make the
  1974.             // script interruptible again much closer to the desired moment in time.
  1975.             SET_UNINTERRUPTIBLE_TIMER
  1976.         // else if it's negative, it's considered to be infinite, so no timer need be set.
  1977.     }
  1978. }
  1979.  
  1980.  
  1981.  
  1982. void ResumeUnderlyingThread(global_struct *pSavedStruct, char *aSavedErrorLevel, bool aKillInterruptibleTimer)
  1983. {
  1984.     --g_nThreads; // Below relies on this having been done early.
  1985.  
  1986.     if (aKillInterruptibleTimer)
  1987.         KILL_UNINTERRUPTIBLE_TIMER // g.AllowThreadToBeInterrupted is set later below, after the g struct has been restored.
  1988.  
  1989.     bool underlying_thread_is_paused = g.UnderlyingThreadIsPaused; // Done this way for performance (to avoid multiple indirections).
  1990.     CopyMemory(&g, pSavedStruct, sizeof(global_struct));
  1991.     g_ErrorLevel->Assign(aSavedErrorLevel);
  1992.  
  1993.     // The below relies on the above having restored "g":
  1994.     if (g.IsPaused != underlying_thread_is_paused) // The thread to be resumed has been marked with a new state by the thread above.
  1995.     {
  1996.         if (g.IsPaused = underlying_thread_is_paused) // The thread to be resumed is being put into a paused state.
  1997.         {
  1998.             if (g_nThreads) // The script is not about to become idle (i.e. a non-idle thread is being paused now).
  1999.                 ++g_nPausedThreads;
  2000.             else
  2001.                 g_IdleIsPaused = true;
  2002.         }
  2003.         else // The thread to be resumed is being unpaused.
  2004.         {
  2005.             if (g_nThreads) // The script is not about to become idle.
  2006.                 --g_nPausedThreads;
  2007.             else // The script is about to become idle, so by definition the "idle thread" is being unpaused.
  2008.                 g_IdleIsPaused = false;
  2009.         }
  2010.         CheckMenuItem(GetMenu(g_hWnd), ID_FILE_PAUSE, g.IsPaused ? MF_CHECKED : MF_UNCHECKED);
  2011.     }
  2012.  
  2013.     // If the thread to be resumed was paused and has not been unpaused above, it will automatically be
  2014.     // resumed in a paused state because when we return from this function, we should be returning to
  2015.     // an instance of ExecUntil() (our caller), which should be in a pause loop still.  Conversely,
  2016.     // if the thread to be resumed wasn't paused but was just paused above, the icon will be changed now
  2017.     // but the thread won't actually pause until ExecUntil() goes into its pause loop (which should be
  2018.     // immediately after the current command finishes, if execution is right in the middle of a command
  2019.     // due to the command having done a MsgSleep to allow a thread to interrupt).
  2020.     // Older comment: Always update the tray icon in case the paused state of the subroutine
  2021.     // we're about to resume is different from our previous paused state.  Do this even
  2022.     // when the macro is used by CheckScriptTimers(), which although it might not techically
  2023.     // need it, lends maintainability and peace of mind.
  2024.     // UPDATE: Doing "g.AllowThreadToBeInterrupted = true" seems like a good idea to be safe,
  2025.     // at least in the case where CheckScriptTimers() calls this macro at a time when there
  2026.     // is no thread other than the "idle thread" to resume.  A resumed thread should always
  2027.     // be interruptible anyway, since otherwise it couldn't have been interrupted in the
  2028.     // first place to get us here. UPDATE #2: Making it "true" is now also relied upon by MsgMonitor(),
  2029.     // which sometimes launches a new thread even when the current thread is interruptible.
  2030.     // UPDATE #3: In v1.0.38.04, make it reflect the state of ThreadIsCritical for cases where
  2031.     // a critical thread was interrupted by an OnExit or OnMessage thread.  Upon being resumed after
  2032.     // such an emergency interruption, a critical thread should be uninterruptible again.
  2033.     g_script.UpdateTrayIcon();
  2034.     g.AllowThreadToBeInterrupted = !g.ThreadIsCritical;
  2035. }
  2036.  
  2037.  
  2038.  
  2039. VOID CALLBACK MsgBoxTimeout(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
  2040. {
  2041.     // Unfortunately, it appears that MessageBox() will return zero rather
  2042.     // than AHK_TIMEOUT, specified below -- at least under WinXP.  This
  2043.     // makes it impossible to distinguish between a MessageBox() that's been
  2044.     // timed out (destroyed) by this function and one that couldn't be
  2045.     // created in the first place due to some other error.  But since
  2046.     // MessageBox() errors are rare, we assume that they timed out if
  2047.     // the MessageBox() returns 0.  UPDATE: Due to the fact that TimerProc()'s
  2048.     // are called via WM_TIMER messages in our msg queue, make sure that the
  2049.     // window really exists before calling EndDialog(), because if it doesn't,
  2050.     // chances are that EndDialog() was already called with another value.
  2051.     // UPDATE #2: Actually that isn't strictly needed because MessageBox()
  2052.     // ignores the AHK_TIMEOUT value we send here.  But it feels safer:
  2053.     if (IsWindow(hWnd))
  2054.         EndDialog(hWnd, AHK_TIMEOUT);
  2055.     KillTimer(hWnd, idEvent);
  2056.     // v1.0.33: The following was added to fix the fact that a MsgBox with only an OK button
  2057.     // does not acutally send back the code sent by EndDialog() above.  The HWND is checked
  2058.     // in case "g" is no longer the original thread due to another thread having interrupted it.
  2059.     // Consequently, MsgBox's with an OK button won't be 100% reliable with the timeout feature
  2060.     // if an interrupting thread is running at the time the box times out.  This is in the help
  2061.     // file as a known limitation:
  2062.     if (g.DialogHWND == hWnd) // Regardless of whether IsWindow() is true.
  2063.         g.MsgBoxTimedOut = true;
  2064. }
  2065.  
  2066.  
  2067.  
  2068. VOID CALLBACK AutoExecSectionTimeout(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
  2069. // See the comments in AutoHotkey.cpp for an explanation of this function.
  2070. {
  2071.     // Since this was called, it means the AutoExec section hasn't yet finished (otherwise
  2072.     // this timer would have been killed before we got here).  UPDATE: I don't think this is
  2073.     // necessarily true.  I think it's possible for the WM_TIMER msg (since even TimerProc()
  2074.     // timers use WM_TIMER msgs) to be still buffered in the queue even though its timer
  2075.     // has been killed (killing the timer does not auto-purge any pending messages for
  2076.     // that timer, and it is risky/problematic to try to do so manually).  Therefore, although
  2077.     // we kill the timer here, we also do a double check further below to make sure
  2078.     // the desired action hasn't already occurred.  Finally, the macro is used here because
  2079.     // it's possible that the timer has already been killed, so we don't want to risk any
  2080.     // problems that might arise from killing a non-existent timer (which this prevents):
  2081.     // The below also sets "g.AllowThreadToBeInterrupted = true".  Notes about this:
  2082.     // And since the AutoExecute is taking a long time (or might never complete), we now allow
  2083.     // interruptions such as hotkeys and timed subroutines. Use g.AllowThreadToBeInterrupted
  2084.     // vs. g_AllowInterruption in case commands in the AutoExecute section need exclusive use of
  2085.     // g_AllowInterruption (i.e. they might change its value to false and then back to true,
  2086.     // which would interfere with our use of that var):
  2087.     KILL_AUTOEXEC_TIMER
  2088.  
  2089.     // This is a double-check because it's possible for the WM_TIMER message to have
  2090.     // been received (thus calling this TimerProc() function) even though the timer
  2091.     // was already killed by AutoExecSection().  In that case, we don't want to update
  2092.     // the global defaults again because the g struct might have incorrect/unintended
  2093.     // values by now:
  2094.     if (!g_script.AutoExecSectionIsRunning)
  2095.         return;
  2096.  
  2097.     // Otherwise, it's still running (or paused). So update global DEFAULTS, which are for all threads launched in the future:
  2098.     CopyMemory(&g_default, &g, sizeof(global_struct));
  2099.     global_clear_state(g_default);  // Only clear g_default, not g.  This also ensures that IsPaused gets set to false in case it's true in "g".
  2100. }
  2101.  
  2102.  
  2103.  
  2104. VOID CALLBACK UninterruptibleTimeout(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
  2105. {
  2106.     // v1.0.38.04: Make AllowThreadToBeInterrupted conform to ThreadIsCritical. This is necessary
  2107.     // in the case where the timer was killed by the "Critical" command but not before a WM_TIMER message
  2108.     // got posted to our queue.
  2109.     g.AllowThreadToBeInterrupted = !g.ThreadIsCritical;
  2110.     // But unconditionally kill the timer since it should be killed even when g.ThreadIsCritical==true.
  2111.     // This is because any thread that uses the command "Critical" has taken charge of its own interruptibility.
  2112.     KILL_UNINTERRUPTIBLE_TIMER // Best to use the macro so that g_UninterruptibleTimerExists is reset to false.
  2113. }
  2114.  
  2115.  
  2116.  
  2117. VOID CALLBACK InputTimeout(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
  2118. {
  2119.     KILL_INPUT_TIMER
  2120.     g_input.status = INPUT_TIMED_OUT;
  2121. }
  2122.