"Fossies" - the Fresh Open Source Software Archive

Member "AutoHotkey_L-1.1.33.09/source/application.cpp" (8 May 2021, 143993 Bytes) of package /windows/misc/AutoHotkey_L-1.1.33.09.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "application.cpp" see the Fossies "Dox" file reference documentation.

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