"Fossies" - the Fresh Open Source Software Archive

Member "AutoHotkey_L-1.1.33.09/source/hotkey.cpp" (8 May 2021, 139772 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 "hotkey.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 "hotkey.h"
   19 #include "globaldata.h"  // For g_os and other global vars.
   20 #include "window.h" // For MsgBox()
   21 //#include "application.h" // For ExitApp()
   22 #include "script_func_impl.h"
   23 
   24 // Initialize static members:
   25 HookType Hotkey::sWhichHookNeeded = 0;
   26 HookType Hotkey::sWhichHookAlways = 0;
   27 DWORD Hotkey::sTimePrev = {0};
   28 DWORD Hotkey::sTimeNow = {0};
   29 Hotkey **Hotkey::shk = NULL;
   30 int Hotkey::shkMax = 0;
   31 HotkeyIDType Hotkey::sNextID = 0;
   32 const HotkeyIDType &Hotkey::sHotkeyCount = Hotkey::sNextID;
   33 bool Hotkey::sJoystickHasHotkeys[MAX_JOYSTICKS] = {false};
   34 DWORD Hotkey::sJoyHotkeyCount = 0;
   35 
   36 
   37 
   38 HWND HotCriterionAllowsFiring(HotkeyCriterion *aCriterion, LPTSTR aHotkeyName)
   39 // This is a global function because it's used by both hotkeys and hotstrings.
   40 // In addition to being called by the hook thread, this can now be called by the main thread.
   41 // That happens when a WM_HOTKEY message arrives (for non-hook hotkeys, i.e. RegisterHotkey).
   42 // Returns a non-NULL HWND if firing is allowed.  However, if it's a global criterion or
   43 // a "not-criterion" such as #IfWinNotActive, (HWND)1 is returned rather than a genuine HWND.
   44 {
   45     HWND found_hwnd;
   46     if (!aCriterion)
   47         return (HWND)1; // Always allow hotkey to fire.
   48     switch(aCriterion->Type)
   49     {
   50     case HOT_IF_ACTIVE:
   51     case HOT_IF_NOT_ACTIVE:
   52         found_hwnd = WinActive(g_default, aCriterion->WinTitle, aCriterion->WinText, _T(""), _T(""), false); // Thread-safe.
   53         break;
   54     case HOT_IF_EXIST:
   55     case HOT_IF_NOT_EXIST:
   56         found_hwnd = WinExist(g_default, aCriterion->WinTitle, aCriterion->WinText, _T(""), _T(""), false, false); // Thread-safe.
   57         break;
   58     // L4: Handling of #if (expression) hotkey variants.
   59     case HOT_IF_EXPR:
   60     case HOT_IF_CALLBACK:
   61         // Expression evaluation must be done in the main thread. If the message times out, the hotkey/hotstring is not allowed to fire.
   62         DWORD_PTR res;
   63         return (SendMessageTimeout(g_hWnd, AHK_HOT_IF_EVAL, (WPARAM)aCriterion, (LPARAM)aHotkeyName, SMTO_BLOCK | SMTO_ABORTIFHUNG, g_HotExprTimeout, &res) && res == CONDITION_TRUE) ? (HWND)1 : NULL;
   64     }
   65     return (aCriterion->Type == HOT_IF_ACTIVE || aCriterion->Type == HOT_IF_EXIST) ? found_hwnd : (HWND)!found_hwnd;
   66 }
   67 
   68 
   69 
   70 ResultType SetHotkeyCriterion(HotCriterionType aType, LPTSTR aWinTitle, LPTSTR aWinText)
   71 // Allocate memory for aWinTitle/Text (if necessary) and update g->HotWinTitle/Text to point to it.
   72 // Returns FAIL if memory couldn't be allocated, or OK otherwise.
   73 // This is a global function because it's used by both hotkeys and hotstrings.
   74 {
   75     // Caller relies on this check:
   76     if (!(*aWinTitle || *aWinText)) // In case of something weird but legit like: #IfWinActive, ,
   77     {
   78         g_HotCriterion = NULL;
   79         return OK;
   80     }
   81 
   82     // Storing combinations of WinTitle+WinText doesn't have as good a best-case memory savings as
   83     // have a separate linked list for Title vs. Text.  But it does save code size, and in the vast
   84     // majority of scripts, the memory savings would be insignificant.
   85     HotkeyCriterion *cp;
   86     for (cp = g_FirstHotCriterion; cp; cp = cp->NextCriterion)
   87         if (cp->Type == aType && !_tcscmp(cp->WinTitle, aWinTitle) && !_tcscmp(cp->WinText, aWinText)) // Case insensitive.
   88         {
   89             // Match found, so point to the existing memory.
   90             g_HotCriterion = cp;
   91             return OK;
   92         }
   93 
   94     // Since above didn't return, there is no existing entry in the linked list that matches this exact
   95     // combination of Title and Text.  So create a new item and allocate memory for it.
   96     if (   !(cp = (HotkeyCriterion *)SimpleHeap::Malloc(sizeof(HotkeyCriterion)))   )
   97         return FAIL;
   98     cp->Type = aType;
   99     cp->ExprLine = NULL;
  100     cp->NextCriterion = NULL;
  101     if (*aWinTitle)
  102     {
  103         if (   !(cp->WinTitle = SimpleHeap::Malloc(aWinTitle))   )
  104             return FAIL;
  105     }
  106     else
  107         cp->WinTitle = _T("");
  108     if (*aWinText)
  109     {
  110         if (   !(cp->WinText = SimpleHeap::Malloc(aWinText))   )
  111             return FAIL;
  112     }
  113     else
  114         cp->WinText = _T("");
  115 
  116     g_HotCriterion = cp;
  117 
  118     // Update the linked list:
  119     if (!g_FirstHotCriterion)
  120         g_FirstHotCriterion = g_LastHotCriterion = cp;
  121     else
  122     {
  123         g_LastHotCriterion->NextCriterion = cp;
  124         // This must be done after the above:
  125         g_LastHotCriterion = cp;
  126     }
  127 
  128     return OK;
  129 }
  130 
  131 
  132 HotkeyCriterion *AddHotkeyIfExpr()
  133 {
  134     HotkeyCriterion *cp;
  135     if (   !(cp = (HotkeyCriterion *)SimpleHeap::Malloc(sizeof(HotkeyCriterion)))   )
  136         return NULL;
  137     cp->NextCriterion = NULL;
  138     if (g_LastHotExpr)
  139         g_LastHotExpr->NextCriterion = cp;
  140     else
  141         g_FirstHotExpr = cp;
  142     g_LastHotExpr = cp;
  143     return cp;
  144 }
  145 
  146 
  147 HotkeyCriterion *FindHotkeyIfExpr(LPTSTR aExpr)
  148 {
  149     for (HotkeyCriterion *cp = g_FirstHotExpr; cp; cp = cp->NextCriterion)
  150         if (!_tcscmp(aExpr, cp->WinTitle)) // Case-sensitive since the expression might be.
  151             return cp;
  152     return NULL;
  153 }
  154 
  155 
  156 
  157 void Hotkey::ManifestAllHotkeysHotstringsHooks()
  158 // This function examines all hotkeys and hotstrings to determine:
  159 // - Which hotkeys to register/unregister, or activate/deactivate in the hook.
  160 // - Which hotkeys to be changed from HK_NORMAL to HK_KEYBD_HOOK (or vice versa).
  161 // - In pursuit of the above, also assess the interdependencies between hotkeys: the presence or
  162 //   absence of a given hotkey can sometimes impact whether other hotkeys need to be converted from
  163 //   HK_NORMAL to HK_KEYBD_HOOK.  For example, a newly added/enabled global hotkey variant can
  164 //   cause a HK_KEYBD_HOOK hotkey to become HK_NORMAL, and the converse is also true.
  165 // - Based on the above, decide whether the keyboard and/or mouse hooks need to be (de)activated.
  166 {
  167     // v1.0.37.05: A prefix key such as "a" in "a & b" should cause any use of "a" as a suffix
  168     // (such as ^!a) also to be a hook hotkey.  Otherwise, the ^!a hotkey won't fire because the
  169     // hook prevents the OS's hotkey monitor from seeing that the hotkey was pressed.  NOTE:
  170     // This is done only for virtual keys because prefix keys that are done by scan code (mModifierSC)
  171     // should already be hook hotkeys when used as suffix keys (there may be a few unusual exceptions,
  172     // but they seem too rare to justify the extra code size).
  173     // Update for v1.0.40: This first pass through the hotkeys now also checks things for hotkeys
  174     // that can affect other hotkeys. If this weren't done in the first pass, it might be possible
  175     // for a hotkey to make some other hotkey into a hook hotkey, but then the hook might not be
  176     // installed if that hotkey had already been processed earlier in the second pass.  Similarly,
  177     // a hotkey processed earlier in the second pass might have been registered when in fact it
  178     // should have become a hook hotkey due to something learned only later in the second pass.
  179     // Doing these types of things in the first pass resolves such situations.
  180     // Update for v1.1.27: Doing the above in the first pass doesn't work correctly, as mType is
  181     // reset to default during the first pass (even if a previous iteration might has set it to
  182     // HK_KEYBD_HOOK, such as when it is eclipsed by a wildcard hotkey).  One workaround would
  183     // be to set mKeybdHookMandatory = true, but that would prevent the hotkey from reverting to
  184     // HK_NORMAL when it no longer needs the hook.  Instead, there are now three passes.
  185     bool vk_is_prefix[VK_ARRAY_COUNT] = {false};
  186     bool *hk_is_inactive = (bool *)_alloca(sHotkeyCount * sizeof(bool)); // No init needed.  Currently limited to around 16k (HOTKEY_ID_MAX).
  187     HotkeyVariant *vp;
  188     int i, j;
  189 
  190     // FIRST PASS THROUGH THE HOTKEYS:
  191     for (i = 0; i < sHotkeyCount; ++i)
  192     {
  193         Hotkey &hot = *shk[i]; // For performance and convenience.
  194         if (   hk_is_inactive[i] = ((g_IsSuspended && !hot.IsExemptFromSuspend())
  195             || hot.IsCompletelyDisabled())   ) // Listed last for short-circuit performance.
  196         {
  197             // In the cases above, nothing later below can change the fact that this hotkey should
  198             // now be in an unregistered state.
  199             if (hot.mIsRegistered)
  200             {
  201                 hot.Unregister();
  202                 // In case the hotkey's thread is already running, it seems best to cancel any repeat-run
  203                 // that has already been scheduled.  Older comment: CT_SUSPEND, at least, relies on us to do this.
  204                 for (vp = hot.mFirstVariant; vp; vp = vp->mNextVariant)
  205                     vp->mRunAgainAfterFinished = false; // Applies to all hotkey types, not just registered ones.
  206             }
  207             continue;
  208         }
  209         // Otherwise, this hotkey will be in effect, so check its attributes.
  210 
  211         if (hot.mKeybdHookMandatory)
  212         {
  213             // v1.0.44: The following is relied upon by some things like the Hotkey constructor and the tilde prefix
  214             // (the latter can set mKeybdHookMandatory for a hotkey sometime after the first variant is added [such
  215             // as for a subsequent variant]).  This practice also improves maintainability.
  216             if (HK_TYPE_CAN_BECOME_KEYBD_HOOK(hot.mType)) // To ensure it hasn't since become a joystick/mouse/mouse-and-keyboard hotkey.
  217                 hot.mType = HK_KEYBD_HOOK;
  218         }
  219         else // Hook isn't mandatory, so set any non-mouse/joystick/both hotkey to normal for possibly overriding later below.
  220         {
  221             // v1.0.42: The following is done to support situations in which a hotkey can be a hook hotkey sometimes,
  222             // but after a (de)suspend or after a change to other hotkeys via the Hotkey command, might no longer
  223             // require the hook.  Examples include:
  224             // 1) A hotkey can't be registered because some other app is using it, but later
  225             //    that condition changes.
  226             // 2) Suspend or the Hotkey command changes wildcard hotkeys so that non-wildcard
  227             //    hotkeys that have the same suffix are no longer eclipsed, and thus don't need
  228             //    the hook.  The same type of thing can happen if a key-up hotkey is disabled,
  229             //    which would allow it's key-down hotkey to become non-hook.  Similarly, if a
  230             //    all of a prefix key's hotkeys become disabled, and that prefix is also a suffix,
  231             //    those suffixes no longer need to be hook hotkeys.
  232             // 3) There may be other ways, especially in the future involving #IfWin keys whose
  233             //    criteria change.
  234             if (hot.mType == HK_KEYBD_HOOK)
  235                 hot.mType = HK_NORMAL; // To possibly be overridden back to HK_KEYBD_HOOK later below; but if not, it will be registered later below.
  236         }
  237 
  238         if (hot.mModifierVK)
  239             vk_is_prefix[hot.mModifierVK] = true;
  240     } // End of first pass loop.
  241     
  242     // SECOND PASS THROUGH THE HOTKEYS:
  243     // Check for hotkeys that can affect other hotkeys, such as wildcard or key-up hotkeys.
  244     // This is separate to the other passes for reasons described at the top of the function.
  245     for (i = 0; i < sHotkeyCount; ++i)
  246     {
  247         if (hk_is_inactive[i])
  248             continue;
  249         Hotkey &hot = *shk[i]; // For performance and convenience.
  250 
  251         if (hot.mKeyUp && hot.mVK) // No need to do the below for mSC hotkeys since their down hotkeys would already be handled by the hook.
  252         {
  253             // For each key-up hotkey, search for any its counterpart that's a down-hotkey (if any).
  254             // Such a hotkey should also be handled by the hook because if registered, such as
  255             // "#5" (reg) and "#5 up" (hook), the hook would suppress the down event because it
  256             // is unaware that down-hotkey exists (it's suppressed to prevent the key from being
  257             // stuck in a logically down state).
  258             for (j = 0; j < sHotkeyCount; ++j)
  259             {
  260                 // No need to check the following because they are already hook hotkeys:
  261                 // mModifierVK/SC
  262                 // mAllowExtraModifiers
  263                 // mNoSuppress
  264                 // In addition, there is no need to check shk[j]->mKeyUp because that can't be
  265                 // true if it's mType is HK_NORMAL:
  266                 // Also, g_IsSuspended and IsCompletelyDisabled() aren't checked
  267                 // because it's harmless to operate on disabled hotkeys in this way.
  268                 if (shk[j]->mVK == hot.mVK && HK_TYPE_CAN_BECOME_KEYBD_HOOK(shk[j]->mType) // Ordered for short-circuit performance.
  269                     && shk[j]->mModifiersConsolidatedLR == hot.mModifiersConsolidatedLR)
  270                 {
  271                     shk[j]->mType = HK_KEYBD_HOOK;
  272                     // And if it's currently registered, it will be unregistered later below.
  273                 }
  274             }
  275         }
  276 
  277         // v1.0.40: If this is a wildcard hotkey, any hotkeys it eclipses (i.e. includes as subsets)
  278         // should be made into hook hotkeys also, because otherwise they would be overridden by hook.
  279         // The following criteria are checked:
  280         // 1) Exclude those that have a ModifierSC/VK because in those cases, mAllowExtraModifiers is
  281         //    ignored.
  282         // 2) Exclude those that lack an mVK because those with mSC can't eclipse registered hotkeys
  283         //   (since any would-be eclipsed mSC hotkey is already a hook hotkey due to is SC nature).
  284         // 3) It must not have any mModifiersLR because such hotkeys can't completely eclipse
  285         //    registered hotkeys since they always have neutral vs. left/right-specific modifiers.
  286         //    For example, if *<^a is a hotkey, ^a can still be a registered hotkey because it could
  287         //    still be activated by pressing RControl+a.
  288         // 4) For maintainability, it doesn't check mNoSuppress because the hook is needed anyway,
  289         //    so might as well handle eclipsed hotkeys with it too.
  290         if (hot.mAllowExtraModifiers && hot.mVK && !hot.mModifiersLR && !(hot.mModifierSC || hot.mModifierVK))
  291         {
  292             for (j = 0; j < sHotkeyCount; ++j)
  293             {
  294                 // If it's not of type HK_NORMAL, there's no need to change its type regardless
  295                 // of the values of its other members.  Also, if the wildcard hotkey (hot) has
  296                 // any neutral modifiers, this hotkey must have at least those neutral modifiers
  297                 // too or else it's not eclipsed (and thus registering it is okay).  In other words,
  298                 // the wildcard hotkey's neutral modifiers must be a perfect subset of this hotkey's
  299                 // modifiers for this one to be eclipsed by it. Note: Neither mModifiersLR nor
  300                 // mModifiersConsolidated is checked for simplicity and also because it seems to add
  301                 // flexibility.  For example, *<^>^a would require both left AND right ctrl to be down,
  302                 // not EITHER. In other words, mModifiersLR can never in effect contain a neutral modifier.
  303                 if (shk[j]->mVK == hot.mVK && HK_TYPE_CAN_BECOME_KEYBD_HOOK(shk[j]->mType) // Ordered for short-circuit performance.
  304                     && (hot.mModifiers & shk[j]->mModifiers) == hot.mModifiers)
  305                 {
  306                     // Note: No need to check mModifiersLR because it would already be a hook hotkey in that case;
  307                     // that is, the check of shk[j]->mType precludes it.  It also precludes the possibility
  308                     // of shk[j] being a key-up hotkey, wildcard hotkey, etc.
  309                     shk[j]->mType = HK_KEYBD_HOOK;
  310                     // And if it's currently registered, it will be unregistered later below.
  311                 }
  312             }
  313         }
  314     } // End of second pass loop.
  315 
  316     // THIRD PASS THROUGH THE HOTKEYS:
  317     // v1.0.42: Reset sWhichHookNeeded because it's now possible that the hook was on before but no longer
  318     // needed due to changing of a hotkey from hook to registered (for various reasons described above):
  319     // v1.0.91: Make sure to leave the keyboard hook active if the script needs it for collecting input.
  320     if (g_input) // There's an Input in progress (or just ending).
  321         sWhichHookNeeded = HOOK_KEYBD;
  322     else
  323         sWhichHookNeeded = 0;
  324     for (i = 0; i < sHotkeyCount; ++i)
  325     {
  326         if (hk_is_inactive[i])
  327             continue; // v1.0.40: Treat disabled hotkeys as though they're not even present.
  328         Hotkey &hot = *shk[i]; // For performance and convenience.
  329 
  330         // HK_MOUSE_HOOK hotkeys, and most HK_KEYBD_HOOK hotkeys, are handled by the hotkey constructor.
  331         // What we do here upgrade any NORMAL/registered hotkey to HK_KEYBD_HOOK if there are other
  332         // hotkeys that interact or overlap with it in such a way that the hook is preferred.
  333         // This evaluation is done here because only now that hotkeys are about to be activated do
  334         // we know which ones are disabled or suspended, and thus don't need to be taken into account.
  335         if (HK_TYPE_CAN_BECOME_KEYBD_HOOK(hot.mType))
  336         {
  337             if (vk_is_prefix[hot.mVK])
  338                 // If it's a suffix that is also used as a prefix, use hook (this allows ^!a to work without $ when "a & b" is a hotkey).
  339                 // v1.0.42: This was fixed so that mVK_WasSpecifiedByNumber dosn't affect it.  That is, a suffix that's
  340                 // also used as a prefix should become a hook hotkey even if the suffix is specified as "vkNNN::".
  341                 hot.mType = HK_KEYBD_HOOK;
  342                 // And if it's currently registered, it will be unregistered later below.
  343             else
  344             {
  345                 // v1.0.42: Any #IfWin keyboard hotkey must use the hook if it lacks an enabled,
  346                 // non-suspended, global variant.  Under those conditions, the hotkey is either:
  347                 // 1) Single-variant hotkey that has criteria (non-global).
  348                 // 2) Multi-variant hotkey but all variants have criteria (non-global).
  349                 // 3) A hotkey with a non-suppressed (~) variant (always, for code simplicity): already handled by AddVariant().
  350                 // In both cases above, the hook must handle the hotkey because there can be
  351                 // situations in which the hook should let the hotkey's keystroke pass through
  352                 // to the active window (i.e. the hook is needed to dynamically disable the hotkey).
  353                 // mHookAction isn't checked here since those hotkeys shouldn't reach this stage (since they're always hook hotkeys).
  354                 for (hot.mType = HK_KEYBD_HOOK, vp = hot.mFirstVariant; vp; vp = vp->mNextVariant)
  355                 {
  356                     if (   !vp->mHotCriterion && vp->mEnabled // It's a global variant (no criteria) and it's enabled...
  357                         && (!g_IsSuspended || vp->mJumpToLabel->IsExemptFromSuspend())   )
  358                         // ... and this variant isn't suspended (we already know IsCompletelyDisabled()==false from an earlier check).
  359                     {
  360                         hot.mType = HK_NORMAL; // Reset back to how it was before this loop started.  Hook not needed.
  361                         break;
  362                     }
  363                 }
  364                 // If the above promoted it from NORMAL to HOOK but the hotkey is currently registered,
  365                 // it will be unregistered later below.
  366             }
  367         }
  368 
  369         // Check if this mouse hotkey also requires the keyboard hook (e.g. #LButton).
  370         // Some mouse hotkeys, such as those with normal modifiers, don't require it
  371         // since the mouse hook has logic to handle that situation.  But those that
  372         // are composite hotkeys such as "RButton & Space" or "Space & RButton" need
  373         // the keyboard hook:
  374         if (hot.mType == HK_MOUSE_HOOK && (
  375             hot.mModifierSC || hot.mSC // i.e. since it's an SC, the modifying key isn't a mouse button.
  376             || hot.mHookAction // v1.0.25.05: At least some alt-tab actions require the keyboard hook. For example, a script consisting only of "MButton::AltTabAndMenu" would not work properly otherwise.
  377             // v1.0.25.05: The line below was added to prevent the Start Menu from appearing, which
  378             // requires the keyboard hook. ALT hotkeys don't need it because the mouse hook sends
  379             // a CTRL keystroke to disguise them, a trick that is unfortunately not reliable for
  380             // when it happens while the while key is down (though it does disguise a Win-up).
  381             || ((hot.mModifiersConsolidatedLR & (MOD_LWIN|MOD_RWIN)) && !(hot.mModifiersConsolidatedLR & (MOD_LALT|MOD_RALT)))
  382             // For v1.0.30, above has been expanded to include Win+Shift and Win+Control modifiers.
  383             || (hot.mVK && !IsMouseVK(hot.mVK)) // e.g. "RButton & Space"
  384             || (hot.mModifierVK && !IsMouseVK(hot.mModifierVK)))   ) // e.g. "Space & RButton"
  385             hot.mType = HK_BOTH_HOOKS;  // Needed by ChangeHookState().
  386             // For the above, the following types of mouse hotkeys do not need the keyboard hook:
  387             // 1) mAllowExtraModifiers: Already handled since the mouse hook fetches the modifier state
  388             //    manually when the keyboard hook isn't installed.
  389             // 2) mModifiersConsolidatedLR (i.e. the mouse button is modified by a normal modifier
  390             //    such as CTRL): Same reason as #1.
  391             // 3) As a subset of #2, mouse hotkeys that use WIN as a modifier will not have the
  392             //    Start Menu suppressed unless the keyboard hook is installed.  It's debatable,
  393             //    but that seems a small price to pay (esp. given how rare it is just to have
  394             //    the mouse hook with no keyboard hook) to avoid the overhead of the keyboard hook.
  395         
  396         // If the hotkey is normal, try to register it.  If the register fails, use the hook to try
  397         // to override any other script or program that might have it registered (as documented):
  398         if (hot.mType == HK_NORMAL)
  399         {
  400             if (!hot.Register()) // Can't register it, usually due to some other application or the OS using it.
  401                 hot.mType = HK_KEYBD_HOOK;
  402         }
  403         else // mType isn't NORMAL (possibly due to something above changing it), so ensure it isn't registered.
  404             if (hot.mIsRegistered) // Improves typical performance since this hotkey could be mouse, joystick, etc.
  405                 // Although the hook effectively overrides registered hotkeys, they should be unregistered anyway
  406                 // to prevent the Send command from triggering the hotkey, and perhaps other side-effects.
  407                 hot.Unregister();
  408 
  409         switch (hot.mType)
  410         {
  411         case HK_KEYBD_HOOK: sWhichHookNeeded |= HOOK_KEYBD; break;
  412         case HK_MOUSE_HOOK: sWhichHookNeeded |= HOOK_MOUSE; break;
  413         case HK_BOTH_HOOKS: sWhichHookNeeded |= HOOK_KEYBD|HOOK_MOUSE; break;
  414         }
  415     } // for()
  416 
  417     // Check if anything else requires the hook.
  418     // But do this part outside of the above block because these values may have changed since
  419     // this function was first called.  By design, the Num/Scroll/CapsLock AlwaysOn/Off setting
  420     // stays in effect even when Suspend in ON.
  421     if (   Hotstring::sEnabledCount
  422         || !(g_ForceNumLock == NEUTRAL && g_ForceCapsLock == NEUTRAL && g_ForceScrollLock == NEUTRAL)   )
  423         sWhichHookNeeded |= HOOK_KEYBD;
  424     if (g_BlockMouseMove || (g_HSResetUponMouseClick && Hotstring::sEnabledCount))
  425         sWhichHookNeeded |= HOOK_MOUSE;
  426 
  427     // Install or deinstall either or both hooks, if necessary, based on these param values.
  428     ChangeHookState(shk, sHotkeyCount, sWhichHookNeeded, sWhichHookAlways);
  429 
  430     // Fix for v1.0.34: If the auto-execute section uses the Hotkey command but returns before doing
  431     // something that calls MsgSleep, the main timer won't have been turned on.  For example:
  432     // Hotkey, Joy1, MySubroutine
  433     // ;Sleep 1  ; This was a workaround before this fix.
  434     // return
  435     // By putting the following check here rather than in AutoHotkey.cpp, that problem is resolved.
  436     // In addition...
  437     if (sJoyHotkeyCount)  // Joystick hotkeys require the timer to be always on.
  438         SET_MAIN_TIMER
  439 }
  440 
  441 
  442 
  443 void Hotkey::MaybeUninstallHook()
  444 // Caller knows that one of the users of the keyboard hook no longer requires it,
  445 // and wants it uninstalled if it is no longer needed by anything else.
  446 {
  447     // Do some quick checks to avoid scanning all hotkeys unnecessarily:
  448     if (g_input || Hotstring::sEnabledCount || (sWhichHookAlways & HOOK_KEYBD))
  449         return;
  450     // Do more thorough checking to determine whether the hook is still needed:
  451     ManifestAllHotkeysHotstringsHooks();
  452 }
  453 
  454 
  455 
  456 void Hotkey::AllDestructAndExit(int aExitCode)
  457 {
  458     // PostQuitMessage() might be needed to prevent hang-on-exit.  Once this is done, no message boxes or
  459     // other dialogs can be displayed.  MSDN: "The exit value returned to the system must be the wParam
  460     // parameter of the WM_QUIT message."  In our case, PostQuitMessage() should announce the same exit code
  461     // that we will eventually call exit() with:
  462     PostQuitMessage(aExitCode);
  463 
  464     AddRemoveHooks(0); // Remove all hooks. By contrast, registered hotkeys are unregistered below.
  465     if (g_PlaybackHook) // Would be unusual for this to be installed during exit, but should be checked for completeness.
  466         UnhookWindowsHookEx(g_PlaybackHook);
  467     for (int i = 0; i < sHotkeyCount; ++i)
  468         delete shk[i]; // Unregisters before destroying.
  469 
  470     // Do this only at the last possible moment prior to exit() because otherwise
  471     // it may free memory that is still in use by objects that depend on it.
  472     // This is actually kinda wrong because when exit() is called, the destructors
  473     // of static, global, and main-scope objects will be called.  If any of these
  474     // destructors try to reference memory freed() by DeleteAll(), there could
  475     // be trouble.
  476     // It's here mostly for traditional reasons.  I'm 99.99999 percent sure that there would be no
  477     // penalty whatsoever to omitting this, since any modern OS will reclaim all
  478     // memory dynamically allocated upon program termination.  Indeed, omitting
  479     // deletes and free()'s for simple objects will often improve the reliability
  480     // and performance since the OS is far more efficient at reclaiming the memory
  481     // than us doing it manually (which involves a potentially large number of deletes
  482     // due to all the objects and sub-objects to be destructed in a typical C++ program).
  483     // UPDATE: In light of the first paragraph above, it seems best not to do this at all,
  484     // instead letting all implicitly-called destructors run prior to program termination,
  485     // at which time the OS will reclaim all remaining memory:
  486     //SimpleHeap::DeleteAll();
  487 
  488     // In light of the comments below, and due to the fact that anyone using this app
  489     // is likely to want the anti-focus-stealing measure to always be disabled, I
  490     // think it's best not to bother with this ever, since its results are
  491     // unpredictable:
  492 /*  if (g_os.IsWin98orLater() || g_os.IsWin2000orLater())
  493         // Restore the original timeout value that was set by WinMain().
  494         // Also disables the compiler warning for the PVOID cast.
  495         // Note: In many cases, this call will fail to set the value (perhaps even if
  496         // SystemParametersInfo() reports success), probably because apps aren't
  497         // supposed to change this value unless they currently have the input
  498         // focus or something similar (and this app probably doesn't meet the criteria
  499         // at this stage).  So I think what will happen is: the value set
  500         // in WinMain() will stay in effect until the user reboots, at which time
  501         // the default value store in the registry will once again be in effect.
  502         // This limitation seems harmless.  Indeed, it's probably a good thing not to
  503         // set it back afterward so that windows behave more consistently for the user
  504         // regardless of whether this program is currently running.
  505 #ifdef _MSC_VER
  506     #pragma warning( disable : 4312 )
  507 #endif
  508         SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (PVOID)g_OriginalTimeout, SPIF_SENDCHANGE);
  509 #ifdef _MSC_VER
  510     #pragma warning( default : 4312 ) 
  511 #endif
  512 */
  513     // I know this isn't the preferred way to exit the program.  However, due to unusual
  514     // conditions such as the script having MsgBoxes or other dialogs displayed on the screen
  515     // at the time the user exits (in which case our main event loop would be "buried" underneath
  516     // the event loops of the dialogs themselves), this is the only reliable way I've found to exit
  517     // so far.  The caller has already called PostQuitMessage(), which might not help but it doesn't hurt:
  518     exit(aExitCode); // exit() is insignificant in code size.  It does more than ExitProcess(), but perhaps nothing more that this application actually requires.
  519     // By contrast to _exit(), exit() flushes all file buffers before terminating the process. It also
  520     // calls any functions registered via atexit or _onexit.
  521 }
  522 
  523 
  524 
  525 bool Hotkey::PrefixHasNoEnabledSuffixes(int aVKorSC, bool aIsSC)
  526 // aVKorSC contains the virtual key or scan code of the specified prefix key (it's a scan code if aIsSC is true).
  527 // Returns true if this prefix key has no suffixes that can possibly.  Each such suffix is prevented from
  528 // firing by one or more of the following:
  529 // 1) Hotkey is completely disabled via IsCompletelyDisabled().
  530 // 2) Hotkey has criterion and those criterion do not allow the hotkey to fire.
  531 {
  532     // v1.0.44: Added aAsModifier so that a pair of hotkeys such as:
  533     //   LControl::tooltip LControl
  534     //   <^c::tooltip ^c
  535     // ...works as it did in versions prior to 1.0.41, namely that LControl fires on key-up rather than
  536     // down because it is considered a prefix key for the <^c hotkey .
  537     modLR_type aAsModifier = KeyToModifiersLR(aIsSC ? 0 : aVKorSC, aIsSC ? aVKorSC : 0, NULL);
  538 
  539     for (int i = 0; i < sHotkeyCount; ++i)
  540     {
  541         Hotkey &hk = *shk[i];
  542         if (aVKorSC != (aIsSC ? hk.mModifierSC : hk.mModifierVK) && !(aAsModifier & hk.mModifiersLR)
  543             || hk.IsCompletelyDisabled())
  544             continue; // This hotkey isn't enabled or it doesn't use the specified key as a prefix.  No further checking for it.
  545         if (hk.mHookAction)
  546         {
  547             if (g_IsSuspended)
  548                 // An alt-tab hotkey (non-NULL mHookAction) is always suspended when g_IsSuspended==true because
  549                 // alt-tab hotkeys have no subroutine capable of making them exempt.  So g_IsSuspended is checked
  550                 // for alt-tab hotkeys here; and for other types of hotkeys, it's checked further below.
  551                 continue;
  552             else // This alt-tab hotkey is currently active.
  553                 return false; // Since any stored mHotCriterion are ignored for alt-tab hotkeys, no further checking is needed.
  554         }
  555         // Otherwise, find out if any of its variants is eligible to fire.  If so, immediately return
  556         // false because even one eligible hotkey means this prefix is enabled.
  557         for (HotkeyVariant *vp = hk.mFirstVariant; vp; vp = vp->mNextVariant)
  558             // v1.0.42: Fixed to take into account whether the hotkey is suspended (previously it only checked
  559             // whether the hotkey was enabled (above), which isn't enough):
  560             if (   vp->mEnabled // This particular variant within its parent hotkey is enabled.
  561                 && (!g_IsSuspended || vp->mJumpToLabel->IsExemptFromSuspend()) // This variant isn't suspended...
  562                 && (!vp->mHotCriterion || HotCriterionAllowsFiring(vp->mHotCriterion, hk.mName))   ) // ... and its criteria allow it to fire.
  563                 return false; // At least one of this prefix's suffixes is eligible for firing.
  564     }
  565     // Since above didn't return, no hotkeys were found for this prefix that are capable of firing.
  566     return true;
  567 }
  568 
  569 
  570 
  571 HotkeyVariant *Hotkey::CriterionAllowsFiring(HWND *aFoundHWND, ULONG_PTR aExtraInfo, LPTSTR aSingleChar)
  572 // Caller must not call this for AltTab hotkeys IDs because this will always return NULL in such cases.
  573 // Returns the address of the first matching non-global hotkey variant that is allowed to fire.
  574 // If there is no non-global one eligible, the global one is returned (or NULL if none).
  575 // If non-NULL, aFoundHWND is an output variable for the caller, but it is only set if a
  576 // non-global/criterion variant is found; that is, it isn't changed when no match is found or
  577 // when the match is a global variant.  Even when set, aFoundHWND will be (HWND)1 for
  578 // "not-criteria" such as #IfWinNotActive.
  579 {
  580     // Check mParentEnabled in case the hotkey became disabled between the time the message was posted
  581     // and the time it arrived.  A similar check is done for "suspend" later below (since "suspend"
  582     // is a per-variant attribute).
  583     if (!mParentEnabled) // IsCompletelyDisabled() isn't called because the loop below checks all the mEnabled flags, no need to do it twice.
  584         return NULL;
  585 
  586     HWND unused;
  587     HWND &found_hwnd = aFoundHWND ? *aFoundHWND : unused;  // To simplify other things.
  588     found_hwnd = NULL;  // Set default output parameter for caller (in case loop never sets it).
  589     HotkeyVariant *vp, *vp_to_fire;
  590 
  591     // aHookAction isn't checked because this should never be called for alt-tab hotkeys (see other comments above).
  592     for (vp_to_fire = NULL, vp = mFirstVariant; vp; vp = vp->mNextVariant)
  593     {
  594         // Technically, g_IsSuspended needs to be checked only if our caller is TriggerJoyHotkeys()
  595         // because other callers would never have received the hotkey message in the first place.
  596         // However, since it's possible for a hotkey to become suspended between the time its hotkey
  597         // message is posted and the time it is fetched and processed, aborting the firing seems
  598         // like the best choice for the widest variety of circumstances (even though it's a departure
  599         // from the behavior in previous versions).  Another reason to check g_IsSuspended unconditionally
  600         // is for maintainability and code size reduction.  Finally, it's unlikely to significantly
  601         // impact performance since the vast majority of hotkeys have either one or just a few variants.
  602         if (   vp->mEnabled // This particular variant within its parent hotkey is enabled.
  603             && (!g_IsSuspended || vp->mJumpToLabel->IsExemptFromSuspend()) // This variant isn't suspended...
  604             && HotInputLevelAllowsFiring(vp->mInputLevel, aExtraInfo, aSingleChar) // ... its #InputLevel allows it to fire...
  605             && (!vp->mHotCriterion || (found_hwnd = HotCriterionAllowsFiring(vp->mHotCriterion, mName)))   ) // ... and its criteria allow it to fire.
  606         {
  607             if (vp->mHotCriterion) // Since this is the first criteria hotkey, it takes precedence.
  608                 return vp;
  609             //else since this is variant has no criteria, let the first criteria variant in the list
  610             // take precedence over it (if there is one).  If none is found, the vp_to_fire will stay
  611             // set as the non-criterion variant.
  612             vp_to_fire = vp;
  613         }
  614     }
  615     return vp_to_fire; // Either NULL or the variant found by the loop.
  616 }
  617 
  618 bool HotInputLevelAllowsFiring(SendLevelType inputLevel, ULONG_PTR aEventExtraInfo, LPTSTR aKeyHistoryChar)
  619 {
  620     if (InputLevelFromInfo(aEventExtraInfo) <= inputLevel)
  621     {
  622         if (aKeyHistoryChar)
  623             *aKeyHistoryChar = 'i'; // Mark as ignored in KeyHistory
  624         return false;
  625     }
  626     return true;
  627 }
  628 
  629 
  630 HotkeyVariant *Hotkey::CriterionFiringIsCertain(HotkeyIDType &aHotkeyIDwithFlags, bool aKeyUp, ULONG_PTR aExtraInfo
  631     , UCHAR &aNoSuppress, bool &aFireWithNoSuppress, LPTSTR aSingleChar)
  632 // v1.0.44: Caller has ensured that aFireWithNoSuppress is true if has already been decided and false if undecided.
  633 // Upon return, caller can assume that the value in it is now decided rather than undecided.
  634 // v1.0.42: Caller must not call this for AltTab hotkeys IDs, but this will always return NULL in such cases.
  635 // aHotkeyToFireUponRelease is sometimes modified for the caller here, as is *aSingleChar (if aSingleChar isn't NULL).
  636 // Caller has ensured that aHotkeyIDwithFlags contains a valid/existing hotkey ID.
  637 // Technically, aHotkeyIDwithMask can be with or without the flags in the high bits.
  638 // If present, they're removed.
  639 {
  640     // aHookAction isn't checked because this should never be called for alt-tab hotkeys (see other comments above).
  641     HotkeyIDType hotkey_id = aHotkeyIDwithFlags & HOTKEY_ID_MASK;
  642     // The following check is for maintainability, since caller should have already checked and
  643     // handled HOTKEY_ID_ALT_TAB and similar.  Less-than-zero check not necessary because it's unsigned.
  644     if (hotkey_id >= sHotkeyCount)
  645         return NULL; // Special alt-tab hotkey quasi-ID used by the hook.
  646     Hotkey &hk = *shk[hotkey_id]; // For convenience and performance.
  647 
  648     if (aFireWithNoSuppress // Caller has already determined its value with certainty...
  649         || (hk.mNoSuppress & NO_SUPPRESS_SUFFIX_VARIES) != NO_SUPPRESS_SUFFIX_VARIES) // ...or its value is easy to determine, so do it now (compare to itself since it's a bitwise union).
  650     {
  651         // Since aFireWithNoSuppress can now be easily determined for the caller (or was already determined by the caller
  652         // itself), it's possible to take advantage of the following optimization, which is especially important in cases
  653         // where TitleMatchMode is "slow":
  654         // For performance, the following returns without having called WinExist/Active if it sees that one of this
  655         // hotkey's variant's will certainly fire due to the fact that it has a non-suspended global variant.
  656         // This reduces the number of situations in which double the number of WinExist/Active() calls are made
  657         // (once in the hook to determine whether the hotkey keystroke should be passed through to the active window,
  658         // and again upon receipt of the message for reasons explained there).
  659         for (HotkeyVariant *vp = hk.mFirstVariant; vp; vp = vp->mNextVariant)
  660             if (!vp->mHotCriterion && vp->mEnabled && (!g_IsSuspended || vp->mJumpToLabel->IsExemptFromSuspend())
  661                 && HotInputLevelAllowsFiring(vp->mInputLevel, aExtraInfo, aSingleChar))
  662             {
  663                 // Fix for v1.0.47.02: The following section (above "return") was moved into this block
  664                 // from above the for() because only when this for() returns is it certain that this
  665                 // hk/hotkey_id is actually the right one, and thus its attributes can be used to determine
  666                 // aFireWithNoSuppress for the caller.
  667                 // Since this hotkey has variants only of one type (tilde or non-tilde), this variant must be of that type.
  668                 if (!aFireWithNoSuppress) // Caller hasn't yet determined its value with certainty (currently, this statement might always be true).
  669                     aFireWithNoSuppress = (hk.mNoSuppress & AT_LEAST_ONE_VARIANT_HAS_TILDE); // Due to other checks, this means all variants are tilde.
  670                 return vp; // Caller knows this isn't necessarily the variant that will fire since !vp->mHotCriterion.
  671             }
  672     }
  673 
  674     // Since above didn't return, a slower method is needed to find out which variant of this hotkey (if any)
  675     // should fire.
  676     HotkeyVariant *vp;
  677     if (vp = hk.CriterionAllowsFiring(NULL, aExtraInfo, aSingleChar))
  678     {
  679         if (!aFireWithNoSuppress) // Caller hasn't yet determined its value with certainty (currently, this statement might always be true).
  680             aFireWithNoSuppress = vp->mNoSuppress;
  681         return vp; // It found an eligible variant to fire.
  682     }
  683 
  684     // Since above didn't find any variant of the hotkey than can fire, check for other eligible hotkeys.
  685     if (!hk.mHookAction) // Rule out those that aren't susceptible to the bug.
  686     {
  687         // Custom combos are no longer ruled out by the above since they allow extra modifiers and
  688         // are capable of obscuring non-custom combos; e.g. LCtrl & a:: obscures <^a::, ^+a:: and so on.
  689         // Fix for v1.0.46.13: Although the section higher above found no variant to fire for the
  690         // caller-specified hotkey ID, it's possible that some other hotkey (one with a wildcard) is
  691         // eligible to fire due to the eclipsing behavior of wildcard hotkeys.  For example:
  692         //    #IfWinNotActive Untitled
  693         //    q::tooltip %A_ThisHotkey% Non-notepad
  694         //    #IfWinActive Untitled
  695         //    *q::tooltip %A_ThisHotkey% Notepad
  696         // However, the logic here might not be a perfect solution because it fires the first available
  697         // hotkey that has a variant whose criteria are met (which might not be exactly the desired rules
  698         // of precedence).  However, I think it's extremely rare that there would be more than one hotkey
  699         // that matches the original hotkey (VK, SC, has-wildcard) etc.  Even in the rare cases that there
  700         // is more than one, the rarity is compounded by the rarity of the bug even occurring, which probably
  701         // makes the odds vanishingly small.  That's why the following simple, high-performance loop is used
  702         // rather than more a more complex one that "locates the smallest (most specific) eclipsed wildcard
  703         // hotkey", or "the uppermost variant among all eclipsed wildcards that is eligible to fire".
  704         // UPDATE: This now uses a linked list of hotkeys which share the same suffix key, in the order of
  705         // sort_most_general_before_least, which might solve the concern about precedence.
  706         mod_type modifiers = ConvertModifiersLR(g_modifiersLR_logical_non_ignored); // Neutral modifiers.
  707         for (HotkeyIDType candidate_id = hk.mNextHotkey; candidate_id != HOTKEY_ID_INVALID; )
  708         {
  709             Hotkey &hk2 = *shk[candidate_id]; // For performance and convenience.
  710             candidate_id = hk2.mNextHotkey;
  711             // Non-wildcard hotkeys are eligible for the workaround in cases like ^+a vs <^+a vs ^<+a, where
  712             // the neutral modifier acts as a sort of wildcard (it permits left, right or both).  This also
  713             // increases support for varying names, such as Esc vs. Escape vs. vk1B (which already partially
  714             // worked if wildcards were used).
  715             // However, must ensure only the allowed modifiers are down when !mAllowExtraModifiers.
  716             // mVK and mSC aren't checked since the linked list only includes hotkeys for this same suffix key.
  717             // This also allows the workaround to be partially applied to LCtrl vs. Ctrl and similar (as suffixes).
  718             if (  (hk2.mAllowExtraModifiers || !(~hk2.mModifiersConsolidatedLR & g_modifiersLR_logical_non_ignored))
  719                 && hk2.mKeyUp == hk.mKeyUp // Seems necessary that up/down nature is the same in both.
  720                 && !hk2.mModifierVK // Avoid accidental matching of normal hotkeys with custom-combo "&"
  721                 && !hk2.mModifierSC // hotkeys that happen to have the same mVK/SC.
  722                 && !hk2.mHookAction // Might be unnecessary to check this; but just in case.
  723                 && hk2.mID != hotkey_id // Don't consider the original hotkey because it was already found ineligible.
  724                 && !(hk2.mModifiers & ~modifiers) // All neutral modifiers required by the candidate are pressed.
  725                 && !(hk2.mModifiersLR & ~g_modifiersLR_logical_non_ignored) // All left-right specific modifiers required by the candidate are pressed.
  726                 //&& hk2.mType != HK_JOYSTICK // Seems unnecessary since joystick hotkeys don't call us and even if they did, probably shouldn't be included.
  727                 //&& hk2.mParentEnabled   ) // CriterionAllowsFiring() will check this for us.
  728                 )
  729             {
  730                 // The following section is similar to one higher above, so maintain them together:
  731                 if (vp = hk2.CriterionAllowsFiring(NULL, aExtraInfo, aSingleChar))
  732                 {
  733                     if (!aFireWithNoSuppress) // Caller hasn't yet determined its value with certainty (currently, this statement might always be true).
  734                         aFireWithNoSuppress = vp->mNoSuppress;
  735                     aHotkeyIDwithFlags = hk2.mID; // Caller currently doesn't need the flags put onto it, so they're omitted.
  736                     return vp; // It found an eligible variant to fire.
  737                 }
  738             }
  739         }
  740     }
  741 
  742     // Otherwise, this hotkey has no variants that can fire.  Caller wants a few things updated in that case.
  743     if (!aFireWithNoSuppress) // Caller hasn't yet determined its value with certainty.
  744         aFireWithNoSuppress = true; // Fix for v1.0.47.04: Added this line and the one above to fix the fact that a context-sensitive hotkey like "a UP::" would block the down-event of that key even when the right window/criteria aren't met.
  745     // If this is a key-down hotkey:
  746     // Leave aHotkeyToFireUponRelease set to whatever it was so that the criteria are
  747     // evaluated later, at the time of release.  It seems more correct that way, though the actual
  748     // change (hopefully improvement) in usability is unknown.
  749     // Since the down-event of this key won't be suppressed, it seems best never to suppress the
  750     // key-up hotkey (if it has one), if nothing else than to be sure the logical key state of that
  751     // key as shown by GetAsyncKeyState() returns the correct value (for modifiers, this is even more
  752     // important since them getting stuck down causes undesirable behavior).  If it doesn't have a
  753     // key-up hotkey, the up-keystroke should wind up being non-suppressed anyway due to default
  754     // processing).
  755     if (!aKeyUp)
  756         aNoSuppress |= NO_SUPPRESS_NEXT_UP_EVENT;  // Update output parameter for the caller.
  757     if (aSingleChar && *aSingleChar != 'i') // 'i' takes precedence because it's used to detect when #InputLevel prevented the hotkey from firing, to prevent it from being suppressed.
  758         *aSingleChar = '#'; // '#' in KeyHistory to indicate this hotkey is disabled due to #IfWin criterion.
  759     return NULL;
  760 }
  761 
  762 
  763 
  764 HotkeyIDType Hotkey::FindPairedHotkey(HotkeyIDType aFirstID, modLR_type aModsLR, bool aKeyUp)
  765 {
  766     mod_type modifiers = ConvertModifiersLR(aModsLR); // Neutral modifiers.
  767     for (HotkeyIDType candidate_id = aFirstID; candidate_id != HOTKEY_ID_INVALID; )
  768     {
  769         Hotkey &hk2 = *shk[candidate_id]; // For performance and convenience.
  770         candidate_id = hk2.mNextHotkey;
  771         if (  (hk2.mAllowExtraModifiers || !(~hk2.mModifiersConsolidatedLR & aModsLR))
  772             && hk2.mKeyUp == aKeyUp
  773             && !hk2.mModifierVK // Avoid accidental matching of normal hotkeys with custom-combo "&"
  774             && !hk2.mModifierSC // hotkeys that happen to have the same mVK/SC.
  775             && !hk2.mHookAction // Might be unnecessary to check this; but just in case.
  776             && !(hk2.mModifiers & ~modifiers) // All neutral modifiers required by the candidate are pressed.
  777             && !(hk2.mModifiersLR & ~aModsLR) // All left-right specific modifiers required by the candidate are pressed.
  778             //&& hk2.mParentEnabled // CriterionAllowsFiring() will check this for us.
  779             )
  780             return aKeyUp ? (hk2.mID | HOTKEY_KEY_UP) : hk2.mID;
  781     }
  782     return HOTKEY_ID_INVALID;
  783 }
  784 
  785 
  786 
  787 modLR_type Hotkey::HotkeyRequiresModLR(HotkeyIDType aHotkeyID, modLR_type aModLR)
  788 {
  789     if (aHotkeyID >= sHotkeyCount)
  790         return 0;
  791     return shk[aHotkeyID]->mModifiersConsolidatedLR & aModLR;
  792 }
  793 
  794 
  795 
  796 void Hotkey::TriggerJoyHotkeys(int aJoystickID, DWORD aButtonsNewlyDown)
  797 {
  798     for (int i = 0; i < sHotkeyCount; ++i)
  799     {
  800         Hotkey &hk = *shk[i]; // For performance and convenience.
  801         // Fix for v1.0.34: If hotkey isn't enabled, or hotkeys are suspended and this one isn't
  802         // exempt, don't fire it.  These checks are necessary only for joystick hotkeys because 
  803         // normal hotkeys are completely deactivated when turned off or suspended, but the joystick
  804         // is still polled even when some joystick hotkeys are disabled.  UPDATE: In v1.0.42, Suspend
  805         // is checked upon receipt of the message, not here upon sending.
  806         if (hk.mType == HK_JOYSTICK && hk.mVK == aJoystickID
  807             && (aButtonsNewlyDown & ((DWORD)0x01 << (hk.mSC - JOYCTRL_1)))) // This hotkey's button is among those newly pressed.
  808         {
  809             // Criteria are checked, and variant determined, upon arrival of message rather than when sending
  810             // ("suspend" is also checked then).  This is because joystick button presses are never hidden
  811             // from the active window (the concept really doesn't apply), so not checking here avoids the
  812             // performance loss of a second check (the loss can be significant in the case of
  813             // "SetTitleMatchMode Slow").
  814             //
  815             // Post it to the thread because the message pump itself (not the WindowProc) will handle it.
  816             // UPDATE: Posting to NULL would have a risk of discarding the message if a MsgBox pump or
  817             // pump other than MsgSleep() were running.  The only reason it doesn't is that this function
  818             // is only ever called from MsgSleep(), which is careful to process all messages (at least
  819             // those that aren't kept queued due to the message filter) prior to returning to its caller.
  820             // But for maintainability, it seems best to change this to g_hWnd vs. NULL to make joystick
  821             // hotkeys behave more like standard hotkeys.
  822             PostMessage(g_hWnd, WM_HOTKEY, (WPARAM)i, 0);
  823         }
  824         //else continue the loop in case the user has newly pressed more than one joystick button.
  825     }
  826 }
  827 
  828 
  829 
  830 void Hotkey::PerformInNewThreadMadeByCaller(HotkeyVariant &aVariant)
  831 // Caller is responsible for having called PerformIsAllowed() before calling us.
  832 // Caller must have already created a new thread for us, and must close the thread when we return.
  833 {
  834     static bool sDialogIsDisplayed = false;  // Prevents double-display caused by key buffering.
  835     if (sDialogIsDisplayed) // Another recursion layer is already displaying the warning dialog below.
  836         return; // Don't allow new hotkeys to fire during that time.
  837 
  838     // Help prevent runaway hotkeys (infinite loops due to recursion in bad script files):
  839     static UINT throttled_key_count = 0;  // This var doesn't belong in struct since it's used only here.
  840     UINT time_until_now;
  841     int display_warning;
  842     if (!sTimePrev)
  843         sTimePrev = GetTickCount();
  844 
  845     ++throttled_key_count;
  846     sTimeNow = GetTickCount();
  847     // Calculate the amount of time since the last reset of the sliding interval.
  848     // Note: A tickcount in the past can be subtracted from one in the future to find
  849     // the true difference between them, even if the system's uptime is greater than
  850     // 49 days and the future one has wrapped but the past one hasn't.  This is
  851     // due to the nature of DWORD subtraction.  The only time this calculation will be
  852     // unreliable is when the true difference between the past and future
  853     // tickcounts itself is greater than about 49 days:
  854     time_until_now = (sTimeNow - sTimePrev);
  855     if (display_warning = (throttled_key_count > (DWORD)g_MaxHotkeysPerInterval
  856         && time_until_now < (DWORD)g_HotkeyThrottleInterval))
  857     {
  858         // The moment any dialog is displayed, hotkey processing is halted since this
  859         // app currently has only one thread.
  860         TCHAR error_text[2048];
  861         // Using %f with wsprintf() yields a floating point runtime error dialog.
  862         // UPDATE: That happens if you don't cast to float, or don't have a float var
  863         // involved somewhere.  Avoiding floats altogether may reduce EXE size
  864         // and maybe other benefits (due to it not being "loaded")?
  865         sntprintf(error_text, _countof(error_text), _T("%u hotkeys have been received in the last %ums.\n\n")
  866             _T("Do you want to continue?\n(see #MaxHotkeysPerInterval in the help file)")  // In case its stuck in a loop.
  867             , throttled_key_count, time_until_now);
  868 
  869         // Turn off any RunAgain flags that may be on, which in essence is the same as de-buffering
  870         // any pending hotkey keystrokes that haven't yet been fired:
  871         ResetRunAgainAfterFinished();
  872 
  873         // This is now needed since hotkeys can still fire while a messagebox is displayed.
  874         // Seems safest to do this even if it isn't always necessary:
  875         sDialogIsDisplayed = true;
  876         g_AllowInterruption = FALSE;
  877         if (MsgBox(error_text, MB_YESNO) == IDNO)
  878             g_script.ExitApp(EXIT_CLOSE); // Might not actually Exit if there's an OnExit subroutine.
  879         g_AllowInterruption = TRUE;
  880         sDialogIsDisplayed = false;
  881     }
  882     // The display_warning var is needed due to the fact that there's an OR in this condition:
  883     if (display_warning || time_until_now > (DWORD)g_HotkeyThrottleInterval)
  884     {
  885         // Reset the sliding interval whenever it expires.  Doing it this way makes the
  886         // sliding interval more sensitive than alternate methods might be.
  887         // Also reset it if a warning was displayed, since in that case it didn't expire.
  888         throttled_key_count = 0;
  889         sTimePrev = sTimeNow;
  890     }
  891     if (display_warning)
  892         // At this point, even though the user chose to continue, it seems safest
  893         // to ignore this particular hotkey event since it might be WinClose or some
  894         // other command that would have unpredictable results due to the displaying
  895         // of the dialog itself.
  896         return;
  897 
  898 
  899     // This is stored as an attribute of the script (semi-globally) rather than passed
  900     // as a parameter to ExecUntil (and from their on to any calls to SendKeys() that it
  901     // makes) because it's possible for SendKeys to be called asynchronously, namely
  902     // by a timed subroutine, while #HotkeyModifierTimeout is still in effect,
  903     // in which case we would want SendKeys() to take note of these modifiers even
  904     // if it was called from an ExecUntil() other than ours here:
  905     g_script.mThisHotkeyModifiersLR = mModifiersConsolidatedLR;
  906 
  907     // LAUNCH HOTKEY SUBROUTINE:
  908     ++aVariant.mExistingThreads;  // This is the thread count for this particular hotkey only.
  909     ResultType result = aVariant.mJumpToLabel->ExecuteInNewThread(g_script.mThisHotkeyName);
  910     --aVariant.mExistingThreads;
  911 
  912     if (result == FAIL)
  913         aVariant.mRunAgainAfterFinished = false;  // Ensure this is reset due to the error.
  914     else if (aVariant.mRunAgainAfterFinished)
  915     {
  916         // But MsgSleep() can change it back to true again, when called by the above call
  917         // to ExecUntil(), to keep it auto-repeating:
  918         aVariant.mRunAgainAfterFinished = false;  // i.e. this "run again" ticket has now been used up.
  919         if (GetTickCount() - aVariant.mRunAgainTime <= 1000)
  920         {
  921             // v1.0.44.14: Post a message rather than directly running the above ExecUntil again.
  922             // This fixes unreported bugs in previous versions where the thread isn't reinitialized before
  923             // the launch of one of these buffered hotkeys, which caused settings such as SetKeyDelay
  924             // not to start off at their defaults.  Also, there are quite a few other things that the main
  925             // event loop does to prep for the launch of a hotkey.  Rather than copying them here or
  926             // trying to put them into a shared function (which would be difficult due to their nature),
  927             // it's much more maintainable to post a message, and in most cases, it shouldn't measurably
  928             // affect response time (this feature is rarely used anyway).
  929             PostMessage(g_hWnd, WM_HOTKEY, (WPARAM)mID, 0);
  930         }
  931         //else it was posted too long ago, so don't do it.  This is because most users wouldn't
  932         // want a buffered hotkey to stay pending for a long time after it was pressed, because
  933         // that might lead to unexpected behavior.
  934     }
  935 }
  936 
  937 
  938 
  939 ResultType Hotkey::Dynamic(LPTSTR aHotkeyName, LPTSTR aLabelName, LPTSTR aOptions, IObject *aJumpToLabel, Var *aJumpToLabelVar)
  940 // Creates, updates, enables, or disables a hotkey dynamically (while the script is running).
  941 // Returns OK or FAIL.
  942 {
  943     if (!_tcsnicmp(aHotkeyName, _T("IfWin"), 5)) // Seems reasonable to assume that anything starting with "IfWin" can't be the name of a hotkey.
  944     {
  945         HotCriterionType hot_criterion;
  946         bool invert = !_tcsnicmp(aHotkeyName + 5, _T("Not"), 3);
  947         if (!_tcsicmp(aHotkeyName + (invert ? 8 : 5), _T("Active"))) // It matches #IfWin[Not]Active.
  948             hot_criterion = invert ? HOT_IF_NOT_ACTIVE : HOT_IF_ACTIVE;
  949         else if (!_tcsicmp(aHotkeyName + (invert ? 8 : 5), _T("Exist")))
  950             hot_criterion = invert ? HOT_IF_NOT_EXIST : HOT_IF_EXIST;
  951         else // It starts with IfWin but isn't Active or Exist: Don't alter the current criterion.
  952             return g_script.SetErrorLevelOrThrow();
  953         if (!SetHotkeyCriterion(hot_criterion, aLabelName, aOptions)) // Currently, it only fails upon out-of-memory.
  954             return g_script.SetErrorLevelOrThrow();
  955         return g_ErrorLevel->Assign(ERRORLEVEL_NONE); // Indicate success.
  956     }
  957 
  958     // Hotkey, If  ; Set null criterion.
  959     // Hotkey, If, Exact-expression-text
  960     // Hotkey, If, % FunctionObject
  961     if (!_tcsicmp(aHotkeyName, _T("If")))
  962     {
  963         if (*aOptions)
  964         {   // Let the script know of this error since it may indicate an unescaped comma in the expression text.
  965             return g_script.ScriptError(ERR_PARAM3_MUST_BE_BLANK);
  966         }
  967         if (aJumpToLabelVar && aJumpToLabelVar->HasObject())
  968         {
  969             IObject *callback = aJumpToLabelVar->Object();
  970             HotkeyCriterion *cp;
  971             for (cp = g_FirstHotExpr; ; cp = cp->NextCriterion)
  972             {
  973                 if (!cp) // End of the list and it wasn't found.
  974                 {
  975                     if (  !(cp = AddHotkeyIfExpr())  )
  976                         return FAIL;
  977                     callback->AddRef();
  978                     cp->Type = HOT_IF_CALLBACK;
  979                     cp->Callback = callback;
  980                     cp->WinTitle = _T("");
  981                     cp->WinText = _T("");
  982                     break;
  983                 }
  984                 if (cp->Type == HOT_IF_CALLBACK && cp->Callback == callback)
  985                     break;
  986             }
  987             g_HotCriterion = cp;
  988         }
  989         else if (!*aLabelName)
  990         {
  991             g_HotCriterion = NULL;
  992         }
  993         else
  994         {
  995             HotkeyCriterion *cp = FindHotkeyIfExpr(aLabelName);
  996             if (!cp) // Expression not found.
  997                 // This should only occur if aLabelName contains a variable reference, since this parameter is
  998                 // validated at load time where possible.  Setting ErrorLevel might go unnoticed and would be
  999                 // inconsistent with other modes of this command (without UseErrorLevel), so throw an error.
 1000                 return g_script.ScriptError(ERR_HOTKEY_IF_EXPR);
 1001             g_HotCriterion = cp;
 1002         }
 1003         return g_ErrorLevel->Assign(ERRORLEVEL_NONE);
 1004     }
 1005 
 1006     // For maintainability (and script readability), don't support "U" as a substitute for "UseErrorLevel",
 1007     // since future options might contain the letter U as a "parameter" that immediately follows an option-letter.
 1008     bool use_errorlevel = tcscasestr(aOptions, _T("UseErrorLevel"));
 1009     #define RETURN_HOTKEY_ERROR(level, msg, info) return use_errorlevel ? g_ErrorLevel->Assign(level) \
 1010         : g_script.ScriptError(msg, info)
 1011 
 1012     HookActionType hook_action = 0; // Set default.
 1013     if (!aJumpToLabel) // It wasn't provided by caller (resolved at load-time).
 1014         if (   !(hook_action = ConvertAltTab(aLabelName, true))   )
 1015             if (   !(aJumpToLabel = g_script.FindCallable(aLabelName, aJumpToLabelVar)) // Returns NULL if given a function which requires parameters.
 1016                 && (*aLabelName || aJumpToLabelVar && aJumpToLabelVar->HasObject())   ) // HasObject: if true, its a function we can't call (see above).
 1017                 RETURN_HOTKEY_ERROR(HOTKEY_EL_BADLABEL, *aLabelName ? ERR_NO_LABEL : ERR_HOTKEY_FUNC_PARAMS, aLabelName);
 1018     // Above has ensured that aJumpToLabel and hook_action can't both be non-zero.  Furthermore,
 1019     // both can be zero/NULL only when the caller is updating an existing hotkey to have new options
 1020     // (i.e. it's retaining its current label).
 1021 
 1022     bool suffix_has_tilde, hook_is_mandatory;
 1023     Hotkey *hk = FindHotkeyByTrueNature(aHotkeyName, suffix_has_tilde, hook_is_mandatory); // NULL if not found.
 1024     HotkeyVariant *variant = hk ? hk->FindVariant() : NULL;
 1025     bool update_all_hotkeys = false;  // This method avoids multiple calls to ManifestAllHotkeysHotstringsHooks() (which is high-overhead).
 1026     bool variant_was_just_created = false;
 1027 
 1028     switch (hook_action)
 1029     {
 1030     case HOTKEY_ID_ON:
 1031     case HOTKEY_ID_OFF:
 1032     case HOTKEY_ID_TOGGLE:
 1033         if (!hk)
 1034             RETURN_HOTKEY_ERROR(HOTKEY_EL_NOTEXIST, ERR_NONEXISTENT_HOTKEY, aHotkeyName);
 1035         if (!(variant || hk->mHookAction)) // mHookAction (alt-tab) hotkeys don't need a variant that matches the current criteria.
 1036             // To avoid ambiguity and also allow the script to use ErrorLevel to detect whether a variant
 1037             // already exists, it seems best to strictly require a matching variant rather than falling back
 1038             // onto some "default variant" such as the global variant (if any).
 1039             RETURN_HOTKEY_ERROR(HOTKEY_EL_NOTEXISTVARIANT, ERR_NONEXISTENT_VARIANT, aHotkeyName);
 1040         if (hook_action == HOTKEY_ID_TOGGLE)
 1041             hook_action = hk->mHookAction
 1042                 ? (hk->mParentEnabled ? HOTKEY_ID_OFF : HOTKEY_ID_ON) // Enable/disable parent hotkey (due to alt-tab being a global hotkey).
 1043                 : (variant->mEnabled ? HOTKEY_ID_OFF : HOTKEY_ID_ON); // Enable/disable individual variant.
 1044         if (hook_action == HOTKEY_ID_ON)
 1045         {
 1046             if (hk->mHookAction ? hk->EnableParent() : hk->Enable(*variant))
 1047                 update_all_hotkeys = true; // Do it this way so that any previous "true" value isn't lost.
 1048         }
 1049         else
 1050             if (hk->mHookAction ? hk->DisableParent() : hk->Disable(*variant))
 1051                 update_all_hotkeys = true; // Do it this way so that any previous "true" value isn't lost.
 1052         break;
 1053 
 1054     default: // hook_action is 0 or an AltTab action.  COMMAND: Hotkey, Name, Label|AltTabAction
 1055         if (!hk) // No existing hotkey of this name, so create a new hotkey.
 1056         {
 1057             if (hook_action) // COMMAND (create hotkey): Hotkey, Name, AltTabAction
 1058                 hk = AddHotkey(NULL, hook_action, aHotkeyName, suffix_has_tilde, use_errorlevel);
 1059             else // COMMAND (create hotkey): Hotkey, Name, LabelName [, Options]
 1060             {
 1061                 if (!aJumpToLabel) // Caller is trying to set new aOptions for a nonexistent hotkey.
 1062                     RETURN_HOTKEY_ERROR(HOTKEY_EL_NOTEXIST, ERR_NONEXISTENT_HOTKEY, aHotkeyName);
 1063                 hk = AddHotkey(aJumpToLabel, 0, aHotkeyName, suffix_has_tilde, use_errorlevel);
 1064             }
 1065             if (!hk)
 1066                 return use_errorlevel ? OK : FAIL; // AddHotkey() already displayed the error (or set ErrorLevel).
 1067             variant = hk->mLastVariant; // Update for use with the options-parsing section further below.
 1068             update_all_hotkeys = true;
 1069             variant_was_just_created = true;
 1070         }
 1071         else // Hotkey already exists (though possibly not the required variant).  Update the hotkey if appropriate.
 1072         {
 1073             if (hk->mHookAction != hook_action) // COMMAND: Change to/from alt-tab hotkey.
 1074             {
 1075                 // LoadIncludedFile() contains logic and comments similar to this, so maintain them together.
 1076                 // If hook_action isn't zero, the caller is converting this hotkey into a global alt-tab
 1077                 // hotkey (alt-tab hotkeys are never subject to #IfWin, as documented).  Thus, variant can
 1078                 // be NULL because making a hotkey become alt-tab doesn't require the creation or existence
 1079                 // of a variant matching the current #IfWin criteria.  However, continue on to process the
 1080                 // Options parameter in case it contains "On" or some other keyword applicable to alt-tab.
 1081                 hk->mHookAction = hook_action;
 1082                 if (!hook_action)
 1083                     // Since this hotkey is going from alt-tab to non-alt-tab, make sure it's not disabled
 1084                     // because currently, mParentEnabled is only actually used by alt-tab hotkeys (though it
 1085                     // may have other uses in the future, which is why it's implemented and named the way it is).
 1086                     hk->mParentEnabled = true;
 1087                 else // This hotkey is becoming alt-tab.
 1088                 {
 1089                     // Make the hook mandatory for this hotkey. Known limitation: For maintainability and code size,
 1090                     // this is never undone (even if the hotkey is changed back to non-alt-tab) because there are
 1091                     // many other reasons a hotkey's mKeybdHookMandatory could be true, so can't change it back to
 1092                     // false without checking all those other things.
 1093                     if (HK_TYPE_CAN_BECOME_KEYBD_HOOK(hk->mType))
 1094                         hk->mKeybdHookMandatory = true; // Causes mType to be set to HK_KEYBD_HOOK by ManifestAllHotkeysHotstringsHooks().
 1095                 }
 1096                 // Even if it's still an alt-tab action (just a different one), hook's data structures still
 1097                 // need to be updated.  Otherwise, this is a change from an alt-tab type to a non-alt-tab type,
 1098                 // or vice versa: Due to the complexity of registered vs. hook hotkeys, for now just start from
 1099                 // scratch so that there is high confidence that the hook and all registered hotkeys, including
 1100                 // their interdependencies, will be re-initialized correctly.
 1101                 update_all_hotkeys = true;
 1102             }
 1103             
 1104             // If the above changed the action from an Alt-tab type to non-alt-tab, there may be a label present
 1105             // to be applied to the existing variant (or created as a new variant).
 1106             if (aJumpToLabel) // COMMAND (update hotkey): Hotkey, Name, LabelName [, Options]
 1107             {
 1108                 // If there's a matching variant, update it's label. Otherwise, create a new variant.
 1109                 if (variant) // There's an existing variant...
 1110                 {
 1111                     if (aJumpToLabel != variant->mJumpToLabel) // ...and it's label is being changed.
 1112                     {
 1113                         // If the new label's exempt status is different than the old's, re-manifest all hotkeys
 1114                         // in case the new presence/absence of this variant impacts other hotkeys.
 1115                         // v1.0.42: However, this only needs to be done if Suspend is currently turned on,
 1116                         // since otherwise the change in exempt status can't change whether this variant is
 1117                         // currently in effect.
 1118                         if (variant->mEnabled && g_IsSuspended && LabelPtr(aJumpToLabel)->IsExemptFromSuspend() != variant->mJumpToLabel->IsExemptFromSuspend())
 1119                             update_all_hotkeys = true;
 1120                         variant->mJumpToLabel = aJumpToLabel; // Must be done only after the above has finished using the old mJumpToLabel.
 1121                         // Older comment:
 1122                         // If this hotkey is currently a static hotkey (one not created by the Hotkey command):
 1123                         // Even though it's about to be transformed into a dynamic hotkey via the Hotkey command,
 1124                         // mName can be left pointing to the original Label::mName memory because that should
 1125                         // never change; it will always contain the true name of this hotkey, namely its
 1126                         // keystroke+modifiers (e.g. ^!c).
 1127                     }
 1128                 }
 1129                 else // No existing variant matching current #IfWin criteria, so create a new variant.
 1130                 {
 1131                     if (   !(variant = hk->AddVariant(aJumpToLabel, suffix_has_tilde))   ) // Out of memory.
 1132                         RETURN_HOTKEY_ERROR(HOTKEY_EL_MEM, ERR_OUTOFMEM, aHotkeyName);
 1133                     variant_was_just_created = true;
 1134                     update_all_hotkeys = true;
 1135                     // It seems undesirable for #UseHook to be applied to a hotkey just because it's options
 1136                     // were updated with the Hotkey command; therefore, #UseHook is only applied for newly
 1137                     // created variants such as this one.  For others, the $ prefix can be applied.
 1138                     if (g_ForceKeybdHook)
 1139                         hook_is_mandatory = true;
 1140                 }
 1141             }
 1142             else
 1143                 // NULL label, so either it just became an alt-tab hotkey above, or it's "Hotkey, Name,, Options".
 1144                 if (!variant) // Below relies on this check.
 1145                     break; // Let the error-catch below report it as an error.
 1146 
 1147             // v1.1.15: Allow the ~tilde prefix to be added/removed from an existing hotkey variant.
 1148             // v1.1.19: Apply this change even if aJumpToLabel is omitted.  This is redundant if
 1149             // variant_was_just_created, but checking that condition seems counter-productive.
 1150             if (variant->mNoSuppress = suffix_has_tilde)
 1151                 hk->mNoSuppress |= AT_LEAST_ONE_VARIANT_HAS_TILDE;
 1152             else
 1153                 hk->mNoSuppress |= AT_LEAST_ONE_VARIANT_LACKS_TILDE;
 1154                 
 1155             // v1.1.19: Allow the $UseHook prefix to be added to an existing hotkey.
 1156             if (!hk->mKeybdHookMandatory && (hook_is_mandatory || suffix_has_tilde))
 1157             {
 1158                 // Require the hook for all variants of this hotkey if any variant requires it.
 1159                 // This seems more intuitive than the old behaviour, which required $ or #UseHook
 1160                 // to be used on the *first* variant, even though it affected all variants.
 1161                 update_all_hotkeys = true; // Since it may be switching from reg to k-hook.
 1162                 hk->mKeybdHookMandatory = true;
 1163             }
 1164         } // Hotkey already existed.
 1165         break;
 1166     } // switch(hook_action)
 1167 
 1168     // Above has ensured that hk is not NULL.
 1169 
 1170     // The following check catches:
 1171     // Hotkey, Name,, Options  ; Where name exists as a hotkey, but the right variant doesn't yet exist.
 1172     // If it catches anything else, that could be a bug, so this error message will help spot it.
 1173     if (!(variant || hk->mHookAction)) // mHookAction (alt-tab) hotkeys don't need a variant that matches the current criteria.
 1174         RETURN_HOTKEY_ERROR(HOTKEY_EL_NOTEXISTVARIANT, ERR_NONEXISTENT_VARIANT, aHotkeyName);
 1175     // Below relies on the fact that either variant or hk->mHookAction (or both) is now non-zero.
 1176     // Specifically, when an existing hotkey was changed to become an alt-tab hotkey, above, there will sometimes
 1177     // be a NULL variant (depending on whether there happens to be a variant in the hotkey that matches the current criteria).
 1178 
 1179     // If aOptions is blank, any new hotkey or variant created above will have used the current values of
 1180     // g_MaxThreadsBuffer, etc.
 1181     if (*aOptions)
 1182     {
 1183         for (LPTSTR cp = aOptions; *cp; ++cp)
 1184         {
 1185             switch(ctoupper(*cp))
 1186             {
 1187             case 'O': // v1.0.38.02.
 1188                 if (ctoupper(cp[1]) == 'N') // Full validation for maintainability.
 1189                 {
 1190                     ++cp; // Omit the 'N' from further consideration in case it ever becomes a valid option letter.
 1191                     if (hk->mHookAction ? hk->EnableParent() : hk->Enable(*variant)) // Under these conditions, earlier logic has ensured variant is non-NULL.
 1192                         update_all_hotkeys = true; // Do it this way so that any previous "true" value isn't lost.
 1193                 }
 1194                 else if (!_tcsnicmp(cp, _T("Off"), 3))
 1195                 {
 1196                     cp += 2; // Omit the letters of the word from further consideration in case "f" ever becomes a valid option letter.
 1197                     if (hk->mHookAction ? hk->DisableParent() : hk->Disable(*variant)) // Under these conditions, earlier logic has ensured variant is non-NULL.
 1198                         update_all_hotkeys = true; // Do it this way so that any previous "true" value isn't lost.
 1199                     if (variant_was_just_created) // This variant (and possibly its parent hotkey) was just created above.
 1200                         update_all_hotkeys = false; // Override the "true" that was set (either right above *or* anywhere earlier) because this new hotkey/variant won't affect other hotkeys.
 1201                 }
 1202                 break;
 1203             case 'B':
 1204                 if (variant)
 1205                     variant->mMaxThreadsBuffer = (cp[1] != '0');  // i.e. if the char is NULL or something other than '0'.
 1206                 break;
 1207             // For options such as P & T: Use atoi() vs. ATOI() to avoid interpreting something like 0x01B
 1208             // as hex when in fact the B was meant to be an option letter:
 1209             case 'P':
 1210                 if (variant)
 1211                     variant->mPriority = _ttoi(cp + 1);
 1212                 break;
 1213             case 'T':
 1214                 if (variant)
 1215                 {
 1216                     variant->mMaxThreads = _ttoi(cp + 1);
 1217                     if (variant->mMaxThreads > g_MaxThreadsTotal) // To avoid array overflow, this limit must by obeyed except where otherwise documented.
 1218                         // Older comment: Keep this limited to prevent stack overflow due to too many pseudo-threads.
 1219                         variant->mMaxThreads = g_MaxThreadsTotal;
 1220                     else if (variant->mMaxThreads < 1)
 1221                         variant->mMaxThreads = 1;
 1222                 }
 1223                 break;
 1224             case 'U':
 1225                 // The actual presence of "UseErrorLevel" was already acted upon earlier, so nothing
 1226                 // is done here other than skip over the string so that the letters inside it aren't
 1227                 // misinterpreted as other option letters.
 1228                 if (!_tcsicmp(cp, _T("UseErrorLevel")))
 1229                     cp += 12; // Omit the rest of the letters in the string from further consideration.
 1230                 break;
 1231             case 'I':
 1232                 if (variant)
 1233                 {
 1234                     int new_input_level = _ttoi(cp + 1);
 1235                     if (SendLevelIsValid(new_input_level))
 1236                     {
 1237                         if (new_input_level && !hk->mKeybdHookMandatory)
 1238                         {
 1239                             // For simplicity, a hotkey requires the hook if any of its variants have a non-zero
 1240                             // input level, even if those variants are disabled.  The same is done for the tilde
 1241                             // prefix above and in AddVariant(); see there for more comments.
 1242                             hk->mKeybdHookMandatory = true;
 1243                             update_all_hotkeys = true;
 1244                         }
 1245                         variant->mInputLevel = (SendLevelType)new_input_level;
 1246                     }
 1247                 }
 1248                 break;
 1249             // Otherwise: Ignore other characters, such as the digits that comprise the number after the T option.
 1250             }
 1251         } // for()
 1252     } // if (*aOptions)
 1253         
 1254     if (update_all_hotkeys)
 1255         ManifestAllHotkeysHotstringsHooks(); // See its comments for why it's done in so many of the above situations.
 1256 
 1257     // Somewhat debatable, but the following special ErrorLevels are set even if the above didn't
 1258     // need to re-manifest the hotkeys.
 1259     if (use_errorlevel)
 1260     {
 1261         g_ErrorLevel->Assign(ERRORLEVEL_NONE); // Set default, possibly to be overridden below.
 1262         if (hk->mType == HK_NORMAL && !hk->mIsRegistered && (!g_IsSuspended || hk->IsExemptFromSuspend()) && !hk->IsCompletelyDisabled())
 1263             g_ErrorLevel->Assign(HOTKEY_EL_NOREG); // Generally doesn't happen because it should have reverted to hook when register failed.
 1264     }
 1265     return OK;
 1266 }
 1267 
 1268 
 1269 
 1270 Hotkey *Hotkey::AddHotkey(IObject *aJumpToLabel, HookActionType aHookAction, LPTSTR aName, bool aSuffixHasTilde, bool aUseErrorLevel)
 1271 // Caller provides aJumpToLabel rather than a Line* because at the time a hotkey or hotstring
 1272 // is created, the label's destination line is not yet known.  So the label is used a placeholder.
 1273 // Caller must ensure that either aJumpToLabel or aName is not NULL.
 1274 // aName is NULL whenever the caller is creating a static hotkey, at loadtime (i.e. one that
 1275 // points to a hotkey label rather than a normal label).  The only time aJumpToLabel should
 1276 // be NULL is when the caller is creating a dynamic hotkey that has an aHookAction.
 1277 // Returns the address of the new hotkey on success, or NULL otherwise.
 1278 // The caller is responsible for calling ManifestAllHotkeysHotstringsHooks(), if appropriate.
 1279 {
 1280     if (   (shkMax <= sNextID && !HookAdjustMaxHotkeys(shk, shkMax, shkMax ? shkMax * 2 : INITIAL_MAX_HOTKEYS)) // Allocate or expand shk if needed.
 1281         || !(shk[sNextID] = new Hotkey(sNextID, aJumpToLabel, aHookAction, aName, aSuffixHasTilde, aUseErrorLevel))   )
 1282     {
 1283         if (aUseErrorLevel)
 1284             g_ErrorLevel->Assign(HOTKEY_EL_MEM);
 1285         g_script.ScriptError(ERR_OUTOFMEM);
 1286         return NULL;
 1287     }
 1288     if (!shk[sNextID]->mConstructedOK)
 1289     {
 1290         delete shk[sNextID];  // SimpleHeap allows deletion of most recently added item.
 1291         return NULL;  // The constructor already displayed the error (or updated ErrorLevel).
 1292     }
 1293     ++sNextID;
 1294     return shk[sNextID - 1]; // Indicate success by returning the new hotkey.
 1295 }
 1296 
 1297 
 1298 
 1299 Hotkey::Hotkey(HotkeyIDType aID, IObject *aJumpToLabel, HookActionType aHookAction, LPTSTR aName
 1300     , bool aSuffixHasTilde, bool aUseErrorLevel)
 1301 // Constructor.
 1302 // Caller provides aJumpToLabel rather than a Line* because at the time a hotkey or hotstring
 1303 // is created, the label's destination line is not yet known.  So the label is used a placeholder.
 1304 // Even if the caller-provided aJumpToLabel is NULL, a non-NULL mJumpToLabel will be stored in
 1305 // each hotkey/variant so that NULL doesn't have to be constantly checked during script runtime.
 1306     : mID(HOTKEY_ID_INVALID)  // Default until overridden.
 1307     // Caller must ensure that either aName or aJumpToLabel isn't NULL.
 1308     , mVK(0)
 1309     , mSC(0)
 1310     , mModifiers(0)
 1311     , mModifiersLR(0)
 1312     , mKeybdHookMandatory(false)
 1313     , mAllowExtraModifiers(false)
 1314     , mKeyUp(false)
 1315     , mNoSuppress(0)  // Default is to suppress both prefixes and suffixes.
 1316     , mModifierVK(0)
 1317     , mModifierSC(0)
 1318     , mModifiersConsolidatedLR(0)
 1319     , mType(HK_NORMAL) // Default unless overridden to become mouse, joystick, hook, etc.
 1320     , mVK_WasSpecifiedByNumber(false)
 1321     , mIsRegistered(false)
 1322     , mParentEnabled(true)
 1323     , mHookAction(aHookAction)   // Alt-tab and possibly other uses.
 1324     , mFirstVariant(NULL), mLastVariant(NULL)  // Init linked list early for maintainability.
 1325     , mConstructedOK(false)
 1326 
 1327 // It's better to receive the hotkey_id as a param, since only the caller has better knowledge and
 1328 // verification of the fact that this hotkey's id is always set equal to it's index in the array
 1329 // (for performance reasons).
 1330 {
 1331     if (sNextID > HOTKEY_ID_MAX)
 1332     {
 1333         // This will actually cause the script to terminate if this hotkey is a static (load-time)
 1334         // hotkey.  In the future, some other behavior is probably better:
 1335         if (aUseErrorLevel)
 1336             g_ErrorLevel->Assign(HOTKEY_EL_MAXCOUNT);
 1337         else
 1338             MsgBox(_T("Max hotkeys."));  // Brief msg since so rare.
 1339         return;
 1340     }
 1341 
 1342     LPTSTR hotkey_name = aName;
 1343     if (!TextInterpret(hotkey_name, this, aUseErrorLevel)) // The called function already displayed the error.
 1344         return;
 1345 
 1346     if (mType != HK_JOYSTICK) // Perform modifier adjustment and other activities that don't apply to joysticks.
 1347     {
 1348         // Remove any modifiers that are obviously redundant from keys (even NORMAL/registered ones
 1349         // due to cases where RegisterHotkey() fails and the key is then auto-enabled via the hook).
 1350         // No attempt is currently made to correct a silly hotkey such as "lwin & lwin".  In addition,
 1351         // weird hotkeys such as <^Control and ^LControl are not currently validated and might yield
 1352         // unpredictable results.
 1353         bool is_neutral;
 1354         modLR_type modifiers_lr;
 1355         if (modifiers_lr = KeyToModifiersLR(mVK, mSC, &is_neutral))
 1356         {
 1357             // This hotkey's action-key is itself a modifier, so ensure that it's not defined
 1358             // to modify itself.  Other sections might rely on us doing this:
 1359             if (is_neutral)
 1360                 // Since the action-key is a neutral modifier (not left or right specific),
 1361                 // turn off any neutral modifiers that may be on:
 1362                 mModifiers &= ~ConvertModifiersLR(modifiers_lr);
 1363             else
 1364                 mModifiersLR &= ~modifiers_lr;
 1365         }
 1366 
 1367         if (   (mHookAction == HOTKEY_ID_ALT_TAB || mHookAction == HOTKEY_ID_ALT_TAB_SHIFT)
 1368             && !mModifierVK && !mModifierSC   )
 1369         {
 1370             TCHAR error_text[512];
 1371             if (mModifiers)
 1372             {
 1373                 if (aUseErrorLevel)
 1374                     g_ErrorLevel->Assign(HOTKEY_EL_ALTTAB);
 1375                 else
 1376                 {
 1377                     // Neutral modifier has been specified.  Future enhancement: improve this
 1378                     // to try to guess which key, left or right, should be used based on the
 1379                     // location of the suffix key on the keyboard.
 1380                     sntprintf(error_text, _countof(error_text), _T("The AltTab hotkey \"%s\" must specify which key (L or R)."), hotkey_name);
 1381                     if (g_script.mIsReadyToExecute) // Dynamically registered via the Hotkey command.
 1382                         g_script.ScriptError(error_text);
 1383                     else
 1384                         MsgBox(error_text);
 1385                 }
 1386                 return;  // Key is invalid so don't give it an ID.
 1387             }
 1388             if (mModifiersLR)
 1389             {
 1390                 // If mModifiersLR contains only a single modifier key, that is valid
 1391                 // so we convert it here to its corresponding mModifierVK for use by
 1392                 // the hook.
 1393                 switch (mModifiersLR)
 1394                 {
 1395                 case MOD_LCONTROL: mModifierVK = VK_LCONTROL; break;
 1396                 case MOD_RCONTROL: mModifierVK = VK_RCONTROL; break;
 1397                 case MOD_LSHIFT: mModifierVK = VK_LSHIFT; break;
 1398                 case MOD_RSHIFT: mModifierVK = VK_RSHIFT; break;
 1399                 case MOD_LALT: mModifierVK = VK_LMENU; break;
 1400                 case MOD_RALT: mModifierVK = VK_RMENU; break;
 1401                 case MOD_LWIN: mModifierVK = VK_LWIN; break;
 1402                 case MOD_RWIN: mModifierVK = VK_RWIN; break;
 1403                 default:
 1404                     if (aUseErrorLevel)
 1405                         g_ErrorLevel->Assign(HOTKEY_EL_ALTTAB);
 1406                     else
 1407                     {
 1408                         sntprintf(error_text, _countof(error_text), _T("The AltTab hotkey \"%s\" must have exactly ")
 1409                             _T("one modifier/prefix."), hotkey_name);
 1410                         if (g_script.mIsReadyToExecute) // Dynamically registered via the Hotkey command.
 1411                             g_script.ScriptError(error_text);
 1412                         else
 1413                             MsgBox(error_text);
 1414                     }
 1415                     return;  // Key is invalid so don't give it an ID.
 1416                 }
 1417                 // Since above didn't return:
 1418                 mModifiersLR = 0;  // Since ModifierVK/SC is now its substitute.
 1419             }
 1420             // Update: This is no longer needed because the hook attempts to compensate.
 1421             // However, leaving it enabled may improve performance and reliability.
 1422             // Update#2: No, it needs to be disabled, otherwise alt-tab won't work right
 1423             // in the rare case where an ALT key itself is defined as "AltTabMenu":
 1424             //else
 1425                 // It has no ModifierVK/SC and no modifiers, so it's a hotkey that is defined
 1426                 // to fire only when the Alt-Tab menu is visible.  Since the ALT key must be
 1427                 // down for that menu to be visible (on all OSes?), add the ALT key to this
 1428                 // keys modifiers so that it will be detected as a hotkey whenever the
 1429                 // Alt-Tab menu is visible:
 1430             //  modifiers |= MOD_ALT;
 1431         }
 1432 
 1433         if (HK_TYPE_CAN_BECOME_KEYBD_HOOK(mType)) // Added in v1.0.39 to make a hotkey such as "LButton & LCtrl" install the mouse hook.
 1434         {
 1435             switch (mVK)
 1436             {
 1437             case 0: // Scan codes having no available virtual key must always be handled by the hook.
 1438             // In addition, to support preventing the toggleable keys from toggling, handle those
 1439             // with the hook also.
 1440             case VK_NUMLOCK:
 1441             case VK_CAPITAL:
 1442             case VK_SCROLL:
 1443             // When the AppsKey used as a suffix, always use the hook to handle it because registering
 1444             // such keys with RegisterHotkey() will fail to suppress(hide) the key-up events from the system,
 1445             // and the key-up for Apps key, at least in apps like Explorer, is a special event that results in
 1446             // the context menu appearing (though most other apps seem to use the key-down event rather than
 1447             // the key-up, so they would probably work okay).  Note: Of possible future use is the fact that
 1448             // if the Alt key is held down before pressing Appskey, it's native function does
 1449             // not occur.  This may be similar to the fact that LWIN and RWIN don't cause the
 1450             // start menu to appear if a shift key is held down.
 1451             case VK_APPS:
 1452             // Finally, the non-neutral (left-right) modifier keys (except LWin and RWin) must also
 1453             // be done with the hook because even if RegisterHotkey() claims to succeed on them,
 1454             // I'm 99% sure I tried it and the hotkeys don't actually work with that method:
 1455             case VK_LCONTROL:
 1456             case VK_RCONTROL:
 1457             case VK_LSHIFT:
 1458             case VK_RSHIFT:
 1459             case VK_LMENU:
 1460             case VK_RMENU:
 1461                 mKeybdHookMandatory = true;
 1462                 break;
 1463 
 1464             // To prevent the Start Menu from appearing for a naked LWIN or RWIN, must
 1465             // handle this key with the hook (the presence of a normal modifier makes
 1466             // this unnecessary, at least under WinXP, because the Start Menu is
 1467             // never invoked when a modifier key is held down with lwin/rwin).
 1468             case VK_LWIN:
 1469             case VK_RWIN:
 1470             // If this hotkey is an unmodified modifier (e.g. Control::) and there
 1471             // are any other hotkeys that rely specifically on this modifier,
 1472             // have the hook handle this hotkey so that it will only fire on key-up
 1473             // rather than key-down.  Note: cases where this key's modifiersLR or
 1474             // ModifierVK/SC are non-zero -- as well as hotkeys that use sc vs. vk
 1475             // -- have already been set to use the keybd hook, so don't need to be
 1476             // handled here.  UPDATE: All the following cases have been already set
 1477             // to be HK_KEYBD_HOOK:
 1478             // - left/right ctrl/alt/shift (since RegisterHotkey() doesn't support them).
 1479             // - Any key with a ModifierVK/SC
 1480             // - The naked lwin or rwin key (due to the check above)
 1481             // Therefore, the only case left to be detected by this next line is the
 1482             // one in which the user configures the naked neutral key VK_SHIFT,
 1483             // VK_MENU, or VK_CONTROL.  As a safety precaution, always handle those
 1484             // neutral keys with the hook so that their action will only fire
 1485             // when the key is released (thus allowing each key to be used for its
 1486             // normal modifying function):
 1487             case VK_CONTROL:
 1488             case VK_MENU:
 1489             case VK_SHIFT:
 1490                 if (!mModifiers && !mModifiersLR) // Modifier key as suffix and has no modifiers (or only a ModifierVK/SC).
 1491                     mKeybdHookMandatory = true;
 1492                 //else keys modified by CTRL/SHIFT/ALT/WIN can always be registered normally because these
 1493                 // modifiers are never used (are overridden) when that key is used as a ModifierVK
 1494                 // for another key.  Example: if key1 is a ModifierVK for another key, ^key1
 1495                 // (or any other modified versions of key1) can be registered as a hotkey because
 1496                 // that doesn't affect the hook's ability to use key1 as a prefix:
 1497                 break;
 1498             }
 1499         } // if HK_TYPE_CAN_BECOME_KEYBD_HOOK(mType)
 1500 
 1501         if (HK_TYPE_CAN_BECOME_KEYBD_HOOK(mType))
 1502             if (   (mModifiersLR || aHookAction || mKeyUp || mModifierVK || mModifierSC) // mSC is handled higher above.
 1503                 || (g_ForceKeybdHook || mAllowExtraModifiers // mNoSuppress&NO_SUPPRESS_PREFIX has already been handled elsewhere. Other bits in mNoSuppress must be checked later because they can change by any variants added after *this* one.
 1504                     || (mVK && !mVK_WasSpecifiedByNumber && vk_to_sc(mVK, true)))   ) // Its mVK corresponds to two scan codes (such as "ENTER").
 1505                 mKeybdHookMandatory = true;
 1506             // v1.0.38.02: The check of mVK_WasSpecifiedByNumber above was added so that an explicit VK hotkey such
 1507             // as "VK24::" (which is VK_HOME) can be handled via RegisterHotkey() vs. the hook.  Someone asked for
 1508             // this ability, but even if it weren't for that it seems more correct to recognize an explicitly-specified
 1509             // VK as a "neutral VK" (i.e. one that fires for both scan codes if the VK has two scan codes). The user
 1510             // can always specify "SCnnn::" as a hotkey to avoid this fire-on-both-scan-codes behavior.
 1511 
 1512         // Currently, these take precedence over each other in the following order, so don't
 1513         // just bitwise-or them together in case there's any ineffectual stuff stored in
 1514         // the fields that have no effect (e.g. modifiers have no effect if there's a mModifierVK):
 1515         if (mModifierVK)
 1516             mModifiersConsolidatedLR = KeyToModifiersLR(mModifierVK);
 1517         else if (mModifierSC)
 1518             mModifiersConsolidatedLR = KeyToModifiersLR(0, mModifierSC);
 1519         else
 1520         {
 1521             mModifiersConsolidatedLR = mModifiersLR;
 1522             if (mModifiers)
 1523                 mModifiersConsolidatedLR |= ConvertModifiers(mModifiers);
 1524         }
 1525     } // if (mType != HK_JOYSTICK)
 1526 
 1527     // If mKeybdHookMandatory==true, ManifestAllHotkeysHotstringsHooks() will set mType to HK_KEYBD_HOOK for us.
 1528 
 1529     // To avoid memory leak, this is done only when it is certain the hotkey will be created:
 1530     if (   !(mName = aName ? SimpleHeap::Malloc(aName) : hotkey_name)
 1531         || !(AddVariant(aJumpToLabel, aSuffixHasTilde))   ) // Too rare to worry about freeing the other if only one fails.
 1532     {
 1533         if (aUseErrorLevel)
 1534             g_ErrorLevel->Assign(HOTKEY_EL_MEM);
 1535         else
 1536             g_script.ScriptError(ERR_OUTOFMEM);
 1537         return;
 1538     }
 1539     // Above has ensured that both mFirstVariant and mLastVariant are non-NULL, so callers can rely on that.
 1540 
 1541     // Always assign the ID last, right before a successful return, so that the caller is notified
 1542     // that the constructor succeeded:
 1543     mConstructedOK = true;
 1544     mID = aID;
 1545     // Don't do this because the caller still needs the old/unincremented value:
 1546     //++sHotkeyCount;  // Hmm, seems best to do this here, but revisit this sometime.
 1547 }
 1548 
 1549 
 1550 
 1551 HotkeyVariant *Hotkey::FindVariant()
 1552 // Returns the address of the variant in this hotkey whose criterion matches the current #IfWin criterion.
 1553 // If no match, it returns NULL.
 1554 {
 1555     for (HotkeyVariant *vp = mFirstVariant; vp; vp = vp->mNextVariant)
 1556         if (vp->mHotCriterion == g_HotCriterion)
 1557             return vp;
 1558     return NULL;
 1559 }
 1560 
 1561 
 1562 
 1563 HotkeyVariant *Hotkey::AddVariant(IObject *aJumpToLabel, bool aSuffixHasTilde)
 1564 // Returns NULL upon out-of-memory; otherwise, the address of the new variant.
 1565 // Even if aJumpToLabel is NULL, a non-NULL mJumpToLabel will be stored in each variant so that
 1566 // NULL doesn't have to be constantly checked during script runtime.
 1567 // The caller is responsible for calling ManifestAllHotkeysHotstringsHooks(), if appropriate.
 1568 {
 1569     HotkeyVariant *vp;
 1570     if (   !(vp = (HotkeyVariant *)SimpleHeap::Malloc(sizeof(HotkeyVariant)))   )
 1571         return NULL;
 1572     ZeroMemory(vp, sizeof(HotkeyVariant));
 1573     // The following members are left at 0/NULL by the above:
 1574     // mNextVariant
 1575     // mExistingThreads
 1576     // mRunAgainAfterFinished
 1577     // mRunAgainTime
 1578     // mPriority (default priority is always 0)
 1579     HotkeyVariant &v = *vp;
 1580     // aJumpToLabel can be NULL for dynamic hotkeys that are hook actions such as Alt-Tab.
 1581     // So for maintainability and to help avg-case performance in loops, provide a non-NULL placeholder:
 1582     v.mJumpToLabel = aJumpToLabel ? aJumpToLabel : g_script.mPlaceholderLabel;
 1583     v.mMaxThreads = g_MaxThreadsPerHotkey;    // The values of these can vary during load-time.
 1584     v.mMaxThreadsBuffer = g_MaxThreadsBuffer; //
 1585     v.mInputLevel = g_InputLevel;
 1586     v.mHotCriterion = g_HotCriterion; // If this hotkey is an alt-tab one (mHookAction), this is stored but ignored until/unless the Hotkey command converts it into a non-alt-tab hotkey.
 1587     v.mEnabled = true;
 1588     if (v.mInputLevel > 0)
 1589     {
 1590         // A non-zero InputLevel only works when using the hook
 1591         mKeybdHookMandatory = true;
 1592     }
 1593     if (aSuffixHasTilde)
 1594     {
 1595         v.mNoSuppress = true; // Override the false value set by ZeroMemory above.
 1596         mNoSuppress |= AT_LEAST_ONE_VARIANT_HAS_TILDE;
 1597         // For simplicity, make the hook mandatory for any hotkey that has at least one non-suppressed variant.
 1598         // Otherwise, ManifestAllHotkeysHotstringsHooks() would have to do a loop to check if any
 1599         // non-suppressed variants are actually enabled & non-suspended to decide if the hook is actually needed
 1600         // for a hotkey that has a global variant.  Due to rarity and code size, it doesn't seem worth it.
 1601         mKeybdHookMandatory = true;
 1602     }
 1603     else
 1604         mNoSuppress |= AT_LEAST_ONE_VARIANT_LACKS_TILDE;
 1605 
 1606     // Update the linked list:
 1607     if (!mFirstVariant)
 1608     {
 1609         vp->mIndex = 1; // Start at 1 since 0 means "undetermined variant".
 1610         mFirstVariant = mLastVariant = vp;
 1611     }
 1612     else
 1613     {
 1614         vp->mIndex = mLastVariant->mIndex + 1;
 1615         mLastVariant->mNextVariant = vp;
 1616         // This must be done after the above:
 1617         mLastVariant = vp;
 1618     }
 1619 
 1620     return vp;  // Indicate success by returning the new object.
 1621 }
 1622 
 1623 
 1624 
 1625 ResultType Hotkey::TextInterpret(LPTSTR aName, Hotkey *aThisHotkey, bool aUseErrorLevel)
 1626 // Returns OK or FAIL.  This function is static and aThisHotkey is passed in as a parameter
 1627 // so that aThisHotkey can be NULL. NULL signals that aName should be checked as a valid
 1628 // hotkey only rather than populating the members of the new hotkey aThisHotkey. This function
 1629 // and those it calls should avoid showing any error dialogs in validation mode.  Instead,
 1630 // it should simply return OK if aName is a valid hotkey and FAIL otherwise.
 1631 {
 1632     // Make a copy that can be modified:
 1633     TCHAR hotkey_name[256];
 1634     tcslcpy(hotkey_name, aName, _countof(hotkey_name));
 1635     LPTSTR term1 = hotkey_name;
 1636     LPTSTR term2 = _tcsstr(term1, COMPOSITE_DELIMITER);
 1637     if (!term2)
 1638         return TextToKey(TextToModifiers(term1, aThisHotkey), aName, false, aThisHotkey, aUseErrorLevel);
 1639     if (*term1 == '~')
 1640     {
 1641         if (aThisHotkey)
 1642         {
 1643             aThisHotkey->mNoSuppress |= NO_SUPPRESS_PREFIX;
 1644             aThisHotkey->mKeybdHookMandatory = true;
 1645         }
 1646         term1 = omit_leading_whitespace(term1 + 1);
 1647     }
 1648     LPTSTR end_of_term1 = omit_trailing_whitespace(term1, term2) + 1;
 1649     // Temporarily terminate the string so that the 2nd term is hidden:
 1650     TCHAR ctemp = *end_of_term1;
 1651     *end_of_term1 = '\0';
 1652     ResultType result = TextToKey(term1, aName, true, aThisHotkey, aUseErrorLevel);
 1653     *end_of_term1 = ctemp;  // Undo the termination.
 1654     if (result != OK)
 1655         return result;
 1656     term2 += COMPOSITE_DELIMITER_LENGTH;
 1657     term2 = omit_leading_whitespace(term2);
 1658     // Even though modifiers on keys already modified by a mModifierVK are not supported, call
 1659     // TextToModifiers() anyway to use its output (for consistency).  The modifiers it sets
 1660     // are currently ignored because the mModifierVK takes precedence.
 1661     // UPDATE: Treat any modifier other than '~' as an error, since otherwise users expect
 1662     // hotkeys like "' & +e::Send È" to work.
 1663     //term2 = TextToModifiers(term2, aThisHotkey);
 1664     if (*term2 == '~')
 1665         ++term2; // Some other stage handles this modifier, so just ignore it here.
 1666     return TextToKey(term2, aName, false, aThisHotkey, aUseErrorLevel);
 1667 }
 1668 
 1669 
 1670 
 1671 LPTSTR Hotkey::TextToModifiers(LPTSTR aText, Hotkey *aThisHotkey, HotkeyProperties *aProperties)
 1672 // This function and those it calls should avoid showing any error dialogs when caller passes NULL for aThisHotkey.
 1673 // Takes input param <text> to support receiving only a subset of object.text.
 1674 // Returns the location in <text> of the first non-modifier key.
 1675 // Checks only the first char(s) for modifiers in case these characters appear elsewhere (e.g. +{+}).
 1676 // But come to think of it, +{+} isn't valid because + itself is already shift-equals.  So += would be
 1677 // used instead, e.g. +==action.  Similarly, all the others, except =, would be invalid as hotkeys also.
 1678 // UPDATE: On some keyboard layouts, the + key and various others don't require the shift key to be
 1679 // manifest.  Thus, on these systems a hotkey such as ^+:: is now supported as meaning Ctrl-Plus.
 1680 {
 1681     // Init output parameter for caller if it gave one:
 1682     if (aProperties)
 1683         ZeroMemory(aProperties, sizeof(HotkeyProperties));
 1684 
 1685     if (!*aText)
 1686         return aText; // Below relies on this having ensured that aText isn't blank.
 1687 
 1688     // Explicitly avoids initializing modifiers to 0 because the caller may have already included
 1689     // some set some modifiers in there.
 1690     LPTSTR marker;
 1691     bool key_left, key_right;
 1692 
 1693     // Simplifies and reduces code size below:
 1694     mod_type temp_modifiers;
 1695     mod_type &modifiers = aProperties ? aProperties->modifiers : (aThisHotkey ? aThisHotkey->mModifiers : temp_modifiers);
 1696     modLR_type temp_modifiersLR;
 1697     modLR_type &modifiersLR = aProperties ? aProperties->modifiersLR: (aThisHotkey ? aThisHotkey->mModifiersLR : temp_modifiersLR);
 1698 
 1699     // Improved for v1.0.37.03: The loop's condition is now marker[1] vs. marker[0] so that
 1700     // the last character is never considered a modifier.  This allows a modifier symbol
 1701     // to double as the name of a suffix key.  It also fixes issues on layouts where the
 1702     // symbols +^#! do not require the shift key to be held down, such as the German layout.
 1703     //
 1704     // Improved for v1.0.40.01: The loop's condition now stops when it reaches a single space followed
 1705     // by the word "Up" so that hotkeys like "< up" and "+ up" are supported by seeing their '<' or '+' as
 1706     // a key name rather than a modifier symbol.
 1707     // Fix for v1.1.27.05: Stop at any space, not just " up", so that " & " is also covered.
 1708     // This fixes "> & v" to not interpret ">" as a modifier.  This also causes "+ ::" to be
 1709     // seen as invalid, where previously TextToModifiers() saw it as Shift+Space but a later
 1710     // stage trimmed the space and registered "+::".  This is best since trailing spaces are
 1711     // not allowed in any other hotkeys, and even "+  ::" (two spaces) was not allowed.
 1712     for (marker = aText, key_left = false, key_right = false; marker[1] && marker[1] != ' '; ++marker)
 1713     {
 1714         switch (*marker)
 1715         {
 1716         case '>':
 1717             key_right = true;
 1718             break;
 1719         case '<':
 1720             key_left = true;
 1721             break;
 1722         case '*':
 1723             if (aThisHotkey)
 1724                 aThisHotkey->mAllowExtraModifiers = true;
 1725             if (aProperties)
 1726                 aProperties->has_asterisk = true;
 1727             break;
 1728         case '~':
 1729             if (aProperties)
 1730                 aProperties->suffix_has_tilde = true; // If this is the prefix's tilde rather than the suffix, it will be overridden later below.
 1731             break;
 1732         case '$':
 1733             if (aThisHotkey)
 1734                 aThisHotkey->mKeybdHookMandatory = true; // This flag will be ignored if TextToKey() decides this is a JOYSTICK or MOUSE hotkey.
 1735             if (aProperties)
 1736                 aProperties->hook_is_mandatory = true;
 1737             break;
 1738         case '!':
 1739             if ((!key_right && !key_left))
 1740             {
 1741                 modifiers |= MOD_ALT;
 1742                 break;
 1743             }
 1744             // Both left and right may be specified, e.g. ><+a means both shift keys must be held down:
 1745             if (key_left)
 1746             {
 1747                 modifiersLR |= MOD_LALT;
 1748                 key_left = false;
 1749             }
 1750             if (key_right)
 1751             {
 1752                 modifiersLR |= MOD_RALT;
 1753                 key_right = false;
 1754             }
 1755             break;
 1756         case '^':
 1757             if ((!key_right && !key_left))
 1758             {
 1759                 modifiers |= MOD_CONTROL;
 1760                 break;
 1761             }
 1762             if (key_left)
 1763             {
 1764                 modifiersLR |= MOD_LCONTROL;
 1765                 key_left = false;
 1766             }
 1767             if (key_right)
 1768             {
 1769                 modifiersLR |= MOD_RCONTROL;
 1770                 key_right = false;
 1771             }
 1772             break;
 1773         case '+':
 1774             if ((!key_right && !key_left))
 1775             {
 1776                 modifiers |= MOD_SHIFT;
 1777                 break;
 1778             }
 1779             if (key_left)
 1780             {
 1781                 modifiersLR |= MOD_LSHIFT;
 1782                 key_left = false;
 1783             }
 1784             if (key_right)
 1785             {
 1786                 modifiersLR |= MOD_RSHIFT;
 1787                 key_right = false;
 1788             }
 1789             break;
 1790         case '#':
 1791             if ((!key_right && !key_left))
 1792             {
 1793                 modifiers |= MOD_WIN;
 1794                 break;
 1795             }
 1796             if (key_left)
 1797             {
 1798                 modifiersLR |= MOD_LWIN;
 1799                 key_left = false;
 1800             }
 1801             if (key_right)
 1802             {
 1803                 modifiersLR |= MOD_RWIN;
 1804                 key_right = false;
 1805             }
 1806             break;
 1807         default:
 1808             goto break_loop; // Stop immediately whenever a non-modifying char is found.
 1809         } // switch (*marker)
 1810     } // for()
 1811 break_loop:
 1812 
 1813     // Now *marker is the start of the key's name.  In addition, one of the following is now true:
 1814     // 1) marker[0] is a non-modifier symbol; that is, the loop stopped because it found the first non-modifier symbol.
 1815     // 2) marker[1] is '\0'; that is, the loop stopped because it reached the next-to-last char (the last char itself is never a modifier; e.g. ^+ is Ctrl+Plus on some keyboard layouts).
 1816     // 3) marker[1] is the start of the string " Up", in which case marker[0] is considered the suffix key even if it happens to be a modifier symbol (see comments at for-loop's control stmt).
 1817     if (aProperties)
 1818     {
 1819         // When caller passes non-NULL aProperties, it didn't omit the prefix portion of a composite hotkey
 1820         // (e.g. the "a & " part of "a & b" is present).  So parse these and all other types of hotkeys when in this mode.
 1821         LPTSTR composite, temp;
 1822         if (composite = _tcsstr(marker, COMPOSITE_DELIMITER))
 1823         {
 1824             tcslcpy(aProperties->prefix_text, marker, _countof(aProperties->prefix_text)); // Protect against overflow case script ultra-long (and thus invalid) key name.
 1825             if (temp = _tcsstr(aProperties->prefix_text, COMPOSITE_DELIMITER)) // Check again in case it tried to overflow.
 1826                 omit_trailing_whitespace(aProperties->prefix_text, temp)[1] = '\0'; // Truncate prefix_text so that the suffix text is omitted.
 1827             composite = omit_leading_whitespace(composite + COMPOSITE_DELIMITER_LENGTH);
 1828             if (aProperties->suffix_has_tilde = (*composite == '~')) // Override any value of suffix_has_tilde set higher above.
 1829                 ++composite; // For simplicity, no skipping of leading whitespace between tilde and the suffix key name.
 1830             tcslcpy(aProperties->suffix_text, composite, _countof(aProperties->suffix_text)); // Protect against overflow case script ultra-long (and thus invalid) key name.
 1831         }
 1832         else // A normal (non-composite) hotkey, so suffix_has_tilde was already set properly (higher above).
 1833             tcslcpy(aProperties->suffix_text, omit_leading_whitespace(marker), _countof(aProperties->suffix_text)); // Protect against overflow case script ultra-long (and thus invalid) key name.
 1834         if (temp = tcscasestr(aProperties->suffix_text, _T(" Up"))) // Should be reliable detection method because leading spaces have been omitted and it's unlikely a legitimate key name will ever contain a space followed by "Up".
 1835         {
 1836             omit_trailing_whitespace(aProperties->suffix_text, temp)[1] = '\0'; // Omit " Up" from suffix_text since caller wants that.
 1837             aProperties->is_key_up = true; // Override the default set earlier.
 1838         }
 1839     }
 1840     return marker;
 1841 }
 1842 
 1843 
 1844 
 1845 ResultType Hotkey::TextToKey(LPTSTR aText, LPTSTR aHotkeyName, bool aIsModifier, Hotkey *aThisHotkey, bool aUseErrorLevel)
 1846 // This function and those it calls should avoid showing any error dialogs when caller passes aUseErrorLevel==true or
 1847 // NULL for aThisHotkey (however, there is at least one exception explained in comments below where it occurs).
 1848 // Caller must ensure that aText is a modifiable string.
 1849 // Takes input param aText to support receiving only a subset of mName.
 1850 // In private members, sets the values of vk/sc or ModifierVK/ModifierSC depending on aIsModifier.
 1851 // It may also merge new modifiers into the existing value of modifiers, so the caller
 1852 // should never reset modifiers after calling this.
 1853 // Returns OK or FAIL.
 1854 {
 1855     TCHAR error_text[512];
 1856     vk_type temp_vk; // No need to initialize this one.
 1857     sc_type temp_sc = 0;
 1858     modLR_type modifiersLR = 0;
 1859     bool is_mouse = false;
 1860     int joystick_id;
 1861 
 1862     HotkeyTypeType hotkey_type_temp;
 1863     HotkeyTypeType &hotkey_type = aThisHotkey ? aThisHotkey->mType : hotkey_type_temp; // Simplifies and reduces code size below.
 1864 
 1865     if (!aIsModifier)
 1866     {
 1867         // Previous steps should make it unnecessary to call omit_leading_whitespace(aText).
 1868         LPTSTR cp = StrChrAny(aText, _T(" \t")); // Find first space or tab.
 1869         if (cp && !_tcsicmp(omit_leading_whitespace(cp), _T("Up")))
 1870         {
 1871             // This is a key-up hotkey, such as "Ctrl Up::".
 1872             if (aThisHotkey)
 1873                 aThisHotkey->mKeyUp = true;
 1874             *cp = '\0'; // Terminate at the first space so that the word "up" is removed from further consideration by us and callers.
 1875         }
 1876     }
 1877 
 1878     if (temp_vk = TextToVK(aText, &modifiersLR, true)) // Assign.
 1879     {
 1880         if (aIsModifier)
 1881         {
 1882             if (IS_WHEEL_VK(temp_vk))
 1883             {
 1884                 if (aUseErrorLevel)
 1885                     g_ErrorLevel->Assign(HOTKEY_EL_UNSUPPORTED_PREFIX);
 1886                 else
 1887                 {
 1888                     sntprintf(error_text, _countof(error_text), _T("\"%s\" is not allowed as a prefix key."), aText);
 1889                     g_script.ScriptError(error_text, aHotkeyName);
 1890                     // When aThisHotkey==NULL, return CONDITION_FALSE to indicate to our caller that it's
 1891                     // an invalid hotkey and we've already shown the error message.  Unlike the old method,
 1892                     // this method respects /ErrorStdOut and avoids the second, generic error message.
 1893                     if (!aThisHotkey)
 1894                         return CONDITION_FALSE;
 1895                 }
 1896                 return FAIL;
 1897             }
 1898         }
 1899         else
 1900             // This is done here rather than at some later stage because we have access to the raw
 1901             // name of the suffix key (with any leading modifiers such as ^ omitted from the beginning):
 1902             if (aThisHotkey)
 1903                 aThisHotkey->mVK_WasSpecifiedByNumber = !_tcsnicmp(aText, _T("VK"), 2);
 1904         is_mouse = IsMouseVK(temp_vk);
 1905         if (modifiersLR & (MOD_LSHIFT | MOD_RSHIFT))
 1906             if (temp_vk >= 'A' && temp_vk <= 'Z')  // VK of an alpha char is the same as the ASCII code of its uppercase version.
 1907                 modifiersLR &= ~(MOD_LSHIFT | MOD_RSHIFT);
 1908                 // Above: Making alpha chars case insensitive seems much more friendly.  In other words,
 1909                 // if the user defines ^Z as a hotkey, it will really be ^z, not ^+z.  By removing SHIFT
 1910                 // from the modifiers here, we're only removing it from our modifiers, not the global
 1911                 // modifiers that have already been set elsewhere for this key (e.g. +Z will still be +z).
 1912     }
 1913     else // No virtual key was found.  Is there a scan code?
 1914         if (   !(temp_sc = TextToSC(aText))   )
 1915             if (   !(temp_sc = (sc_type)ConvertJoy(aText, &joystick_id, true))   )  // Is there a joystick control/button?
 1916             {
 1917                 if (aUseErrorLevel)
 1918                 {
 1919                     // Tempting to store the name of the invalid key in ErrorLevel, but because it might
 1920                     // be really long, it seems best not to.  Another reason is that the keyname could
 1921                     // conceivably be the same as one of the other/reserved ErrorLevel numbers.
 1922                     g_ErrorLevel->Assign(HOTKEY_EL_INVALID_KEYNAME);
 1923                     return FAIL;
 1924                 }
 1925                 if (!aText[1] && !g_script.mIsReadyToExecute)
 1926                 {
 1927                     // At load time, single-character key names are always considered valid but show a
 1928                     // warning if they can't be registered as hotkeys on the current keyboard layout.
 1929                     if (!aThisHotkey) // First stage: caller wants to differentiate this case from others.
 1930                         return CONDITION_TRUE;
 1931                     return FAIL; // Second stage: return FAIL to avoid creating an invalid hotkey.
 1932                 }
 1933                 if (aThisHotkey)
 1934                 {
 1935                     // If it fails while aThisHotkey!=NULL, that should mean that this was called as
 1936                     // a result of the Hotkey command rather than at loadtime.  This is because at 
 1937                     // loadtime, the first call here (for validation, i.e. aThisHotkey==NULL) should have
 1938                     // caught the error and converted the line into a non-hotkey (command), which in turn
 1939                     // would make loadtime's second call to create the hotkey always succeed. Also, it's
 1940                     // more appropriate to say "key name" than "hotkey" in this message because it's only
 1941                     // showing the one bad key name when it's a composite hotkey such as "Capslock & y".
 1942                     sntprintf(error_text, _countof(error_text), _T("\"%s\" is not a valid key name."), aText);
 1943                     g_script.ScriptError(error_text);
 1944                 }
 1945                 //else do not show an error in this case because the loader will attempt to interpret
 1946                 // this line as a command.  If that too fails, it will show an "unrecognized action"
 1947                 // dialog.
 1948                 return FAIL;
 1949             }
 1950             else
 1951             {
 1952                 ++sJoyHotkeyCount;
 1953                 hotkey_type = HK_JOYSTICK;
 1954                 temp_vk = (vk_type)joystick_id;  // 0 is the 1st joystick, 1 the 2nd, etc.
 1955                 sJoystickHasHotkeys[joystick_id] = true;
 1956             }
 1957 
 1958 
 1959 /*
 1960 If ever do this, be sure to avoid doing it for keys that must be tracked by scan code (e.g. those in the
 1961 scan code array).
 1962     if (!temp_vk && !is_mouse)  // sc must be non-zero or else it would have already returned above.
 1963         if (temp_vk = sc_to_vk(temp_sc))
 1964         {
 1965             snprintf(error_text, sizeof(error_text), "DEBUG: \"%s\" (scan code %X) was successfully mapped to virtual key %X", text, temp_sc, temp_vk);
 1966             MsgBox(error_text);
 1967             temp_sc = 0; // Maybe set this just for safety, even though a non-zero vk should always take precedence over it.
 1968         }
 1969 */
 1970     if (is_mouse)
 1971         hotkey_type = HK_MOUSE_HOOK;
 1972 
 1973     if (aIsModifier)
 1974     {
 1975         if (aThisHotkey)
 1976         {
 1977             aThisHotkey->mModifierVK = temp_vk;
 1978             aThisHotkey->mModifierSC = temp_sc;
 1979         }
 1980     }
 1981     else
 1982     {
 1983         if (aThisHotkey)
 1984         {
 1985             aThisHotkey->mVK = temp_vk;
 1986             aThisHotkey->mSC = temp_sc;
 1987             // Turn on any additional modifiers.  e.g. SHIFT to realize '#'.
 1988             // Fix for v1.0.37.03: To avoid using the keyboard hook for something like "+::", which in
 1989             // turn would allow the hotkey fire only for LShift+Equals rather than RShift+Equals, convert
 1990             // modifiers from left-right to neutral.  But exclude right-side modifiers (except RWin) so that
 1991             // things like AltGr are more precisely handled (the implications of this policy could use
 1992             // further review).  Currently, right-Alt (via AltGr) is the only possible right-side key.
 1993             aThisHotkey->mModifiers |= ConvertModifiersLR(modifiersLR & (MOD_RWIN|MOD_LWIN|MOD_LCONTROL|MOD_LALT|MOD_LSHIFT));
 1994             aThisHotkey->mModifiersLR |= (modifiersLR & (MOD_RSHIFT|MOD_RALT|MOD_RCONTROL)); // Not MOD_RWIN since it belongs above.
 1995         }
 1996     }
 1997     return OK;
 1998 }
 1999 
 2000 
 2001 
 2002 ResultType Hotkey::Register()
 2003 // Returns OK or FAIL.  Caller is responsible for having checked whether the hotkey is suspended or disabled.
 2004 {
 2005     if (mIsRegistered)
 2006         return OK;  // It's normal for a disabled hotkey to return OK.
 2007 
 2008     if (mType != HK_NORMAL) // Caller normally checks this for performance, but it's checked again for maintainability.
 2009         return FAIL; // Don't attempt to register joystick or hook hotkeys, since their VK/modifiers aren't intended for that.
 2010 
 2011     // Indicate that the key modifies itself because RegisterHotkey() requires that +SHIFT,
 2012     // for example, be used to register the naked SHIFT key.  So what we do here saves the
 2013     // user from having to specify +SHIFT in the script:
 2014     mod_type modifiers_to_register = mModifiers;
 2015     switch (mVK)
 2016     {
 2017     case VK_LWIN:
 2018     case VK_RWIN: modifiers_to_register |= MOD_WIN; break;
 2019     case VK_CONTROL: modifiers_to_register |= MOD_CONTROL; break;
 2020     case VK_SHIFT: modifiers_to_register |= MOD_SHIFT; break;
 2021     case VK_MENU: modifiers_to_register |= MOD_ALT; break;
 2022     }
 2023 
 2024     // Must register them to our main window (i.e. don't use NULL to indicate our thread),
 2025     // otherwise any modal dialogs, such as MessageBox(), that call DispatchMessage()
 2026     // internally wouldn't be able to find anyone to send hotkey messages to, so they
 2027     // would probably be lost:
 2028     if (mIsRegistered = RegisterHotKey(g_hWnd, mID, modifiers_to_register, mVK))
 2029         return OK;
 2030     return FAIL;
 2031     // Above: On failure, reset the modifiers in case this function changed them.  This is
 2032     // done in case this hotkey will now be handled by the hook, which doesn't want any
 2033     // extra modifiers that were added above.
 2034     // UPDATE: In v1.0.42, the mModifiers value is never changed here because a hotkey that
 2035     // gets registered here one time might fail to be registered some other time (perhaps due
 2036     // to Suspend, followed by some other app taking ownership that hotkey, followed by
 2037     // de-suspend, which would then have a hotkey with the wrong modifiers in it for the hook.
 2038 }
 2039 
 2040 
 2041 
 2042 ResultType Hotkey::Unregister()
 2043 // Returns OK or FAIL.
 2044 {
 2045     if (!mIsRegistered)
 2046         return OK;
 2047     // Don't report any errors in here, at least not when we were called in conjunction
 2048     // with cleanup and exit.  Such reporting might cause an infinite loop, leading to
 2049     // a stack overflow if the reporting itself encounters an error and tries to exit,
 2050     // which in turn would call us again:
 2051     if (mIsRegistered = !UnregisterHotKey(g_hWnd, mID))  // I've see it fail in one rare case.
 2052         return FAIL;
 2053     return OK;
 2054 }
 2055 
 2056 
 2057 
 2058 void Hotkey::InstallKeybdHook()
 2059 // Caller must ensure that sWhichHookNeeded and sWhichHookAlways contain HOOK_MOUSE, if appropriate.
 2060 // Generally, this is achieved by having ensured that ManifestAllHotkeysHotstringsHooks() was called at least
 2061 // once since the last time any hotstrings or hotkeys were disabled/enabled/changed, but in any case at least
 2062 // once since the program started.
 2063 {
 2064     sWhichHookNeeded |= HOOK_KEYBD;
 2065     if (!g_KeybdHook)
 2066         ChangeHookState(shk, sHotkeyCount, sWhichHookNeeded, sWhichHookAlways);
 2067 }
 2068 
 2069 
 2070 
 2071 void Hotkey::InstallMouseHook()
 2072 // Same comment as for InstallKeybdHook() above.
 2073 {
 2074     sWhichHookNeeded |= HOOK_MOUSE;
 2075     if (!g_MouseHook)
 2076         ChangeHookState(shk, sHotkeyCount, sWhichHookNeeded, sWhichHookAlways);
 2077 }
 2078 
 2079 
 2080 
 2081 Hotkey *Hotkey::FindHotkeyByTrueNature(LPTSTR aName, bool &aSuffixHasTilde, bool &aHookIsMandatory)
 2082 // Returns the address of the hotkey if found, NULL otherwise.
 2083 // In v1.0.42, it tries harder to find a match so that the order of modifier symbols doesn't affect the true nature of a hotkey.
 2084 // For example, ^!c should be the same as !^c, primarily because RegisterHotkey() and the hook would consider them the same.
 2085 // Although this may break a few existing scripts that rely on the old behavior for obscure uses such as dynamically enabling
 2086 // a duplicate hotkey via the Hotkey command, the #IfWin directives should make up for that in most cases.
 2087 // Primary benefits to the above:
 2088 // 1) Catches script bugs, such as unintended duplicates.
 2089 // 2) Allows a script to use the Hotkey command more precisely and with greater functionality.
 2090 // 3) Allows hotkey variants to work correctly even when the order of modifiers varies.  For example, if ^!c is a hotkey that fires
 2091 //    only when window type 1 is active and !^c (reversed modifiers) is a hotkey that fires only when window type 2 is active,
 2092 //    one of them would never fire because the hook isn't capable or storing two hotkey IDs for the same combination of
 2093 //    modifiers+VK/SC.
 2094 {
 2095     HotkeyProperties prop_candidate, prop_existing;
 2096     TextToModifiers(aName, NULL, &prop_candidate);
 2097     aSuffixHasTilde = prop_candidate.suffix_has_tilde; // Set for caller.
 2098     aHookIsMandatory = prop_candidate.hook_is_mandatory; // Set for caller.
 2099     // Both suffix_has_tilde and a hypothetical prefix_has_tilde are ignored during dupe-checking below.
 2100     // See comments inside the loop for details.
 2101 
 2102     for (int i = 0; i < sHotkeyCount; ++i)
 2103     {
 2104         TextToModifiers(shk[i]->mName, NULL, &prop_existing);
 2105         if (   prop_existing.modifiers == prop_candidate.modifiers
 2106             && prop_existing.modifiersLR == prop_candidate.modifiersLR
 2107             && prop_existing.is_key_up == prop_candidate.is_key_up
 2108             // Treat wildcard (*) as an entirely separate hotkey from one without a wildcard.  This is because
 2109             // the hook has special handling for wildcards that allow non-wildcard hotkeys that overlap them to
 2110             // take precedence, sort of like "clip children".  The logic that builds the eclipsing array would
 2111             // need to be redesigned, which might not even be possible given the complexity of interactions
 2112             // between variant-precedence and hotkey/wildcard-precedence.
 2113             // By contrast, in v1.0.44 pass-through (~) is considered an attribute of each variant of a
 2114             // particular hotkey, not something that makes an entirely new hotkey.
 2115             // This was done because the old method of having them distinct appears to have only one advantage:
 2116             // the ability to dynamically enable/disable ~x separately from x (since if both were in effect
 2117             // simultaneously, one would override the other due to two different hotkey IDs competing for the same
 2118             // ID slot within the VK/SC hook arrays).  The advantages of allowing tilde to be a per-variant attribute
 2119             // seem substantial, namely to have some variant/siblings pass-through while others do not.
 2120             && prop_existing.has_asterisk == prop_candidate.has_asterisk
 2121             // v1.0.43.05: Use stricmp not lstrcmpi so that the higher ANSI letters because an uppercase
 2122             // high ANSI letter isn't necessarily produced by holding down the shift key and pressing the
 2123             // lowercase letter.  In addition, it preserves backward compatibility and may improve flexibility.
 2124             && !_tcsicmp(prop_existing.prefix_text, prop_candidate.prefix_text)
 2125             && !_tcsicmp(prop_existing.suffix_text, prop_candidate.suffix_text)   )
 2126             return shk[i]; // Match found.
 2127     }
 2128 
 2129     return NULL;  // No match found.
 2130 }
 2131 
 2132 
 2133 
 2134 Hotkey *Hotkey::FindHotkeyContainingModLR(modLR_type aModifiersLR) // , HotkeyIDType hotkey_id_to_omit)
 2135 // Returns the address of the hotkey if found, NULL otherwise.
 2136 // Find the first hotkey whose modifiersLR contains *any* of the modifiers shows in the parameter value.
 2137 // Obsolete: The caller tells us the ID of the hotkey to omit from the search because that one
 2138 // would always be found (since something like "lcontrol=calc.exe" in the script
 2139 // would really be defines as  "<^control=calc.exe".
 2140 // Note: By intent, this function does not find hotkeys whose normal/neutral modifiers
 2141 // contain <modifiersLR>.
 2142 {
 2143     if (!aModifiersLR)
 2144         return NULL;
 2145     for (int i = 0; i < sHotkeyCount; ++i)
 2146         // Bitwise set-intersection: indicates if anything in common:
 2147         if (shk[i]->mModifiersLR & aModifiersLR)
 2148         //if (i != hotkey_id_to_omit && shk[i]->mModifiersLR & modifiersLR)
 2149             return shk[i];
 2150     return NULL;  // No match found.
 2151 }
 2152 
 2153 
 2154 //Hotkey *Hotkey::FindHotkeyWithThisModifier(vk_type aVK, sc_type aSC)
 2155 //// Returns the address of the hotkey if found, NULL otherwise.
 2156 //// Answers the question: What is the first hotkey with mModifierVK or mModifierSC equal to those given?
 2157 //// A non-zero vk param will take precedence over any non-zero value for sc.
 2158 //{
 2159 //  if (!aVK & !aSC)
 2160 //      return NULL;
 2161 //  for (int i = 0; i < sHotkeyCount; ++i)
 2162 //      if (   (aVK && aVK == shk[i]->mModifierVK) || (aSC && aSC == shk[i]->mModifierSC)   )
 2163 //          return shk[i];
 2164 //  return NULL;  // No match found.
 2165 //}
 2166 //
 2167 //
 2168 //
 2169 //Hotkey *Hotkey::FindHotkeyBySC(sc2_type aSC2, mod_type aModifiers, modLR_type aModifiersLR)
 2170 //// Returns the address of the hotkey if found, NULL otherwise.
 2171 //// Answers the question: What is the first hotkey with the given sc & modifiers *regardless* of
 2172 //// any non-zero mModifierVK or mModifierSC it may have?  The mModifierSC/vk is ignored because
 2173 //// the caller wants to know whether this key would be blocked if its counterpart were registered.
 2174 //// For example, the hook wouldn't see "MEDIA_STOP & NumpadENTER" at all if NumPadENTER was
 2175 //// already registered via RegisterHotkey(), since RegisterHotkey() doesn't honor any modifiers
 2176 //// other than the standard ones.
 2177 //{
 2178 //  for (int i = 0; i < sHotkeyCount; ++i)
 2179 //      if (!shk[i]->mVK && (shk[i]->mSC == aSC2.a || shk[i]->mSC == aSC2.b))
 2180 //          if (shk[i]->mModifiers == aModifiers && shk[i]->mModifiersLR == aModifiersLR)  // Ensures an exact match.
 2181 //              return shk[i];
 2182 //  return NULL;  // No match found.
 2183 //}
 2184 
 2185 
 2186 
 2187 LPTSTR Hotkey::ListHotkeys(LPTSTR aBuf, int aBufSize)
 2188 // Translates this script's list of variables into text equivalent, putting the result
 2189 // into aBuf and returning the position in aBuf of its new string terminator.
 2190 {
 2191     LPTSTR aBuf_orig = aBuf;
 2192     // Save vertical space by limiting newlines here:
 2193     aBuf += sntprintf(aBuf, BUF_SPACE_REMAINING, _T("Type\tOff?\tLevel\tRunning\tName\r\n")
 2194                              _T("-------------------------------------------------------------------\r\n"));
 2195     // Start at the oldest and continue up through the newest:
 2196     for (int i = 0; i < sHotkeyCount; ++i)
 2197         aBuf = shk[i]->ToText(aBuf, BUF_SPACE_REMAINING, true);
 2198     return aBuf;
 2199 }
 2200 
 2201 
 2202 
 2203 LPTSTR Hotkey::ToText(LPTSTR aBuf, int aBufSize, bool aAppendNewline)
 2204 // aBufSize is an int so that any negative values passed in from caller are not lost.
 2205 // Caller has ensured that aBuf isn't NULL.
 2206 // Translates this var into its text equivalent, putting the result into aBuf and
 2207 // returning the position in aBuf of its new string terminator.
 2208 {
 2209     LPTSTR aBuf_orig = aBuf;
 2210 
 2211     HotkeyVariant *vp;
 2212     int existing_threads;
 2213     for (existing_threads = 0, vp = mFirstVariant; vp; vp = vp->mNextVariant)
 2214         existing_threads += vp->mExistingThreads;
 2215 
 2216     TCHAR existing_threads_str[128];
 2217     if (existing_threads)
 2218         _itot(existing_threads, existing_threads_str, 10);
 2219     else
 2220         *existing_threads_str = '\0'; // Make it blank to avoid clutter in the hotkey display.
 2221 
 2222     TCHAR htype[32];
 2223     switch (mType)
 2224     {
 2225     case HK_NORMAL: _tcscpy(htype, _T("reg")); break;
 2226     case HK_KEYBD_HOOK: _tcscpy(htype, _T("k-hook")); break;
 2227     case HK_MOUSE_HOOK: _tcscpy(htype, _T("m-hook")); break;
 2228     case HK_BOTH_HOOKS: _tcscpy(htype, _T("2-hooks")); break;
 2229     case HK_JOYSTICK: _tcscpy(htype, _T("joypoll")); break;
 2230     default: *htype = '\0'; // For maintainability; should never happen.
 2231     }
 2232 
 2233     LPTSTR enabled_str;
 2234     if (IsCompletelyDisabled()) // Takes into account alt-tab vs. non-alt-tab, etc.
 2235         enabled_str = _T("OFF");
 2236     else if (mHookAction && mParentEnabled) // It's completely "on" in this case.
 2237         enabled_str = _T("");
 2238     else // It's on or if all individual variants are on, otherwise it's partial.
 2239     {
 2240         // Set default: Empty string means "ON" because it reduces clutter in the displayed list.
 2241         for (enabled_str = _T(""), vp = mFirstVariant; vp; vp = vp->mNextVariant)
 2242             if (!vp->mEnabled)
 2243             {
 2244                 enabled_str = _T("PART");
 2245                 break;
 2246             }
 2247     }
 2248 
 2249     TCHAR level_str[7]; // Room for "99-100".
 2250     int min_level = 100, max_level = -1;
 2251     for (vp = mFirstVariant; vp; vp = vp->mNextVariant)
 2252     {
 2253         if (min_level > vp->mInputLevel)
 2254             min_level = vp->mInputLevel;
 2255         if (max_level < vp->mInputLevel)
 2256             max_level = vp->mInputLevel;
 2257     }
 2258     if (min_level != max_level)
 2259         _stprintf(level_str, _T("%i-%i"), min_level, max_level);
 2260     else if (min_level)
 2261         ITOA(min_level, level_str);
 2262     else // Show nothing for level 0.
 2263         *level_str = '\0';
 2264 
 2265     aBuf += sntprintf(aBuf, BUF_SPACE_REMAINING, _T("%s%s\t%s\t%s\t%s\t%s")
 2266         , htype, (mType == HK_NORMAL && !mIsRegistered) ? _T("(no)") : _T("")
 2267         , enabled_str
 2268         , level_str
 2269         , existing_threads_str
 2270         , mName);
 2271     if (aAppendNewline && BUF_SPACE_REMAINING >= 2)
 2272     {
 2273         *aBuf++ = '\r';
 2274         *aBuf++ = '\n';
 2275         *aBuf = '\0';
 2276     }
 2277     return aBuf;
 2278 }
 2279 
 2280 
 2281 ///////////////
 2282 // Hot Strings
 2283 ///////////////
 2284 
 2285 // Init static variables:
 2286 Hotstring **Hotstring::shs = NULL;
 2287 HotstringIDType Hotstring::sHotstringCount = 0;
 2288 HotstringIDType Hotstring::sHotstringCountMax = 0;
 2289 UINT Hotstring::sEnabledCount = 0;
 2290 
 2291 
 2292 void Hotstring::SuspendAll(bool aSuspend)
 2293 {
 2294     if (sHotstringCount < 1) // At least one part below relies on this check.
 2295         return;
 2296 
 2297     UINT u;
 2298     if (aSuspend) // Suspend all those that aren't exempt.
 2299     {
 2300         // Recalculating sEnabledCount might perform better in the average case since most aren't exempt.
 2301         for (sEnabledCount = 0, u = 0; u < sHotstringCount; ++u)
 2302             if (shs[u]->mJumpToLabel->IsExemptFromSuspend())
 2303             {
 2304                 shs[u]->mSuspended &= ~HS_SUSPENDED;
 2305                 if (!shs[u]->mSuspended) // Not turned off.
 2306                     ++sEnabledCount;
 2307             }
 2308             else
 2309                 shs[u]->mSuspended |= HS_SUSPENDED;
 2310     }
 2311     else // Unsuspend all.
 2312     {
 2313         UINT previous_count = sEnabledCount;
 2314         // Recalculating sEnabledCount is probably best since we otherwise need to both remove HS_SUSPENDED
 2315         // and determine if the final suspension status has changed (i.e. no other bits were set).
 2316         for (sEnabledCount = 0, u = 0; u < sHotstringCount; ++u)
 2317         {
 2318             shs[u]->mSuspended &= ~HS_SUSPENDED;
 2319             if (!shs[u]->mSuspended) // Not turned off.
 2320                 ++sEnabledCount;
 2321         }
 2322         // v1.0.44.08: Added the following section.  Also, the HS buffer is reset, but only when hotstrings
 2323         // are newly enabled after having been entirely disabled.  This is because CollectInput() would not
 2324         // have been called in a long time, making the contents of g_HSBuf obsolete, which in turn might
 2325         // otherwise cause accidental firings based on old keystrokes coupled with new ones.
 2326         if (previous_count == 0 && sEnabledCount > 0)
 2327         {
 2328             *g_HSBuf = '\0';
 2329             g_HSBufLength = 0;
 2330         }
 2331     }
 2332 }
 2333 
 2334 
 2335 
 2336 ResultType Hotstring::PerformInNewThreadMadeByCaller()
 2337 // Returns OK or FAIL.  Caller has already ensured that the backspacing (if specified by mDoBackspace)
 2338 // has been done.  Caller must have already created a new thread for us, and must close the thread when
 2339 // we return.
 2340 {
 2341     // Although our caller may have already called ACT_IS_ALWAYS_ALLOWED(), it was for a different reason:
 2342     ActionTypeType act = mJumpToLabel->TypeOfFirstLine();
 2343     if (mExistingThreads >= mMaxThreads && !ACT_IS_ALWAYS_ALLOWED(act)) // See above.
 2344         return FAIL;
 2345     // See Hotkey::Perform() for details about this.  For hot strings -- which also use the
 2346     // g_script.mThisHotkeyStartTime value to determine whether g_script.mThisHotkeyModifiersLR
 2347     // is still timely/accurate -- it seems best to set to "no modifiers":
 2348     g_script.mThisHotkeyModifiersLR = 0;
 2349     ++mExistingThreads;  // This is the thread count for this particular hotstring only.
 2350     ResultType result;
 2351     result = mJumpToLabel->ExecuteInNewThread(g_script.mThisHotkeyName);
 2352     --mExistingThreads;
 2353     return result ? OK : FAIL;  // Return OK on all non-failure results.
 2354 }
 2355 
 2356 
 2357 
 2358 void Hotstring::DoReplace(LPARAM alParam)
 2359 // alParam contains details about how the hotstring was triggered.
 2360 {
 2361     global_struct &g = *::g; // Reduces code size and may improve performance.
 2362     // The below buffer allows room for the longest replacement text plus MAX_HOTSTRING_LENGTH for the
 2363     // optional backspaces, +10 for the possible presence of {Raw} and a safety margin.
 2364     TCHAR SendBuf[LINE_SIZE + MAX_HOTSTRING_LENGTH + 10];
 2365     *SendBuf = '\0';
 2366     LPTSTR start_of_replacement = SendBuf;  // Set default.
 2367 
 2368     if (mDoBackspace)
 2369     {
 2370         // Subtract 1 from backspaces because the final key pressed by the user to make a
 2371         // match was already suppressed by the hook (it wasn't sent through to the active
 2372         // window).  So what we do is backspace over all the other keys prior to that one,
 2373         // put in the replacement text (if applicable), then send the EndChar through
 2374         // (if applicable) to complete the sequence.
 2375         int backspace_count = mStringLength - 1;
 2376         if (mEndCharRequired)
 2377             ++backspace_count;
 2378         for (int i = 0; i < backspace_count; ++i)
 2379             *start_of_replacement++ = '\b';  // Use raw backspaces, not {BS n}, in case the send will be raw.
 2380         *start_of_replacement = '\0'; // Terminate the string created above.
 2381     }
 2382 
 2383     if (mReplacement)
 2384     {
 2385         _tcscpy(start_of_replacement, mReplacement);
 2386         CaseConformModes case_conform_mode = (CaseConformModes)HIWORD(alParam);
 2387         if (case_conform_mode == CASE_CONFORM_ALL_CAPS)
 2388             CharUpper(start_of_replacement);
 2389         else if (case_conform_mode == CASE_CONFORM_FIRST_CAP)
 2390             *start_of_replacement = ltoupper(*start_of_replacement);
 2391         if (!mOmitEndChar) // The ending character (if present) needs to be sent too.
 2392         {
 2393             // Send the final character in raw mode so that chars such as !{} are sent properly.
 2394             // v1.0.43: Avoid two separate calls to SendKeys because:
 2395             // 1) It defeats the uninterruptibility of the hotstring's replacement by allowing the user's
 2396             //    buffered keystrokes to take effect in between the two calls to SendKeys.
 2397             // 2) Performance: Avoids having to install the playback hook twice, etc.
 2398             TCHAR end_char;
 2399             if (mEndCharRequired && (end_char = (TCHAR)LOWORD(alParam))) // Must now check mEndCharRequired because LOWORD has been overloaded with context-sensitive meanings.
 2400             {
 2401                 LPTSTR end = start_of_replacement + _tcslen(start_of_replacement);
 2402                 // v1.0.43.02: Don't send "{Raw}" if already in raw mode!
 2403                 // v1.1.27: Avoid adding {Raw} if it gets switched on within the replacement text.
 2404                 if (mSendRaw || tcscasestr(start_of_replacement, _T("{Raw}")) || tcscasestr(start_of_replacement, _T("{Text}")))
 2405                     *end++ = end_char, *end = '\0';
 2406                 else
 2407                     _stprintf(end, _T("%s%c"), _T("{Raw}"), end_char);
 2408             }
 2409         }
 2410     }
 2411 
 2412     if (!*SendBuf) // No keys to send.
 2413         return;
 2414 
 2415     // For the following, mSendMode isn't checked because the backup/restore is needed to varying extents
 2416     // by every mode.
 2417     int old_delay = g.KeyDelay;
 2418     int old_press_duration = g.PressDuration;
 2419     int old_delay_play = g.KeyDelayPlay;
 2420     int old_press_duration_play = g.PressDurationPlay;
 2421     SendLevelType old_send_level = g.SendLevel;
 2422 
 2423     g.KeyDelay = mKeyDelay; // This is relatively safe since SendKeys() normally can't be interrupted by a new thread.
 2424     g.PressDuration = -1;   // Always -1, since Send command can be used in body of hotstring to have a custom press duration.
 2425     g.KeyDelayPlay = -1;
 2426     g.PressDurationPlay = mKeyDelay; // Seems likely to be more useful (such as in games) to apply mKeyDelay to press duration rather than above.
 2427     // Setting the SendLevel to 0 rather than this->mInputLevel since auto-replace hotstrings are used for text replacement rather than
 2428     // key remapping, which means the user almost always won't want the generated input to trigger other hotkeys or hotstrings.
 2429     // Action hotstrings (not using auto-replace) do get their thread's SendLevel initialized to the hotstring's InputLevel.
 2430     g.SendLevel = 0;
 2431 
 2432     // v1.0.43: The following section gives time for the hook to pass the final keystroke of the hotstring to the
 2433     // system.  This is necessary only for modes other than the original/SendEvent mode because that one takes
 2434     // advantage of the serialized nature of the keyboard hook to ensure the user's final character always appears
 2435     // on screen before the replacement text can appear.
 2436     // By contrast, when the mode is SendPlay (and less frequently, SendInput), the system and/or hook needs
 2437     // another timeslice to ensure that AllowKeyToGoToSystem() actually takes effect on screen (SuppressThisKey()
 2438     // doesn't seem to have this problem).
 2439     if (!(mDoBackspace || mOmitEndChar) && mSendMode != SM_EVENT) // The final character of the abbreviation (or its EndChar) was not suppressed by the hook.
 2440         Sleep(0);
 2441 
 2442     SendKeys(SendBuf, (SendRawModes)mSendRaw, mSendMode); // Send the backspaces and/or replacement.
 2443 
 2444     // Restore original values.
 2445     g.KeyDelay = old_delay;
 2446     g.PressDuration = old_press_duration;
 2447     g.KeyDelayPlay = old_delay_play;
 2448     g.PressDurationPlay = old_press_duration_play;
 2449     g.SendLevel = old_send_level;
 2450 }
 2451 
 2452 
 2453 
 2454 ResultType Hotstring::AddHotstring(LPTSTR aName, LabelPtr aJumpToLabel, LPTSTR aOptions, LPTSTR aHotstring
 2455         , LPTSTR aReplacement, bool aHasContinuationSection, UCHAR aSuspend)
 2456 // Caller provides aJumpToLabel rather than a Line* because at the time a hotkey or hotstring
 2457 // is created, the label's destination line is not yet known.  So the label is used a placeholder.
 2458 // Returns OK or FAIL.
 2459 // Caller has ensured that aHotstringOptions is blank if there are no options.  Otherwise, aHotstringOptions
 2460 // should end in a colon, which marks the end of the options list.  aHotstring is the hotstring itself
 2461 // (e.g. "ahk"), which does not have to be unique, unlike the label name, which was made unique by also
 2462 // including any options in with the label name (e.g. ::ahk:: is a different label than :c:ahk::).
 2463 // Caller has also ensured that aHotstring is not blank.
 2464 {
 2465     // The length is limited for performance reasons, notably so that the hook does not have to move
 2466     // memory around in the buffer it uses to watch for hotstrings:
 2467     if (_tcslen(aHotstring) > MAX_HOTSTRING_LENGTH)
 2468         return g_script.ScriptError(_T("Hotstring max abbreviation length is ") MAX_HOTSTRING_LENGTH_STR _T("."), aHotstring);
 2469 
 2470     if (!shs)
 2471     {
 2472         if (   !(shs = (Hotstring **)malloc(HOTSTRING_BLOCK_SIZE * sizeof(Hotstring *)))   )
 2473             return g_script.ScriptError(ERR_OUTOFMEM); // Short msg. since so rare.
 2474         sHotstringCountMax = HOTSTRING_BLOCK_SIZE;
 2475     }
 2476     else if (sHotstringCount >= sHotstringCountMax) // Realloc to preserve contents and keep contiguous array.
 2477     {
 2478         // Expand the array by one block.  Use a temp var. because realloc() returns NULL on failure
 2479         // but leaves original block allocated.
 2480         void *realloc_temp = realloc(shs, (sHotstringCountMax + HOTSTRING_BLOCK_SIZE) * sizeof(Hotstring *));
 2481         if (!realloc_temp)
 2482             return g_script.ScriptError(ERR_OUTOFMEM);  // Short msg. since so rare.
 2483         shs = (Hotstring **)realloc_temp;
 2484         sHotstringCountMax += HOTSTRING_BLOCK_SIZE;
 2485     }
 2486 
 2487     if (   !(shs[sHotstringCount] = new Hotstring(aName, aJumpToLabel, aOptions, aHotstring, aReplacement, aHasContinuationSection, aSuspend))   )
 2488         return g_script.ScriptError(ERR_OUTOFMEM); // Short msg. since so rare.
 2489     if (!shs[sHotstringCount]->mConstructedOK)
 2490     {
 2491         delete shs[sHotstringCount];  // SimpleHeap allows deletion of most recently added item.
 2492         return FAIL;  // The constructor already displayed the error.
 2493     }
 2494 
 2495     ++sHotstringCount;
 2496     if (!g_script.mIsReadyToExecute) // Caller is LoadIncludedFile(); allow BIF_Hotstring to manage this at runtime.
 2497         ++sEnabledCount; // This works because the script can't be suspended during startup (aSuspend is always FALSE).
 2498     return OK;
 2499 }
 2500 
 2501 
 2502 
 2503 Hotstring::Hotstring(LPTSTR aName, LabelPtr aJumpToLabel, LPTSTR aOptions, LPTSTR aHotstring, LPTSTR aReplacement
 2504     , bool aHasContinuationSection, UCHAR aSuspend)
 2505     : mJumpToLabel(aJumpToLabel)  // Any NULL value will cause failure further below.
 2506     , mName(aName)
 2507     , mString(NULL), mReplacement(NULL), mStringLength(0)
 2508     , mSuspended(aSuspend)
 2509     , mExistingThreads(0)
 2510     , mMaxThreads(g_MaxThreadsPerHotkey)  // The value of g_MaxThreadsPerHotkey can vary during load-time.
 2511     , mPriority(g_HSPriority), mKeyDelay(g_HSKeyDelay), mSendMode(g_HSSendMode)  // And all these can vary too.
 2512     , mCaseSensitive(g_HSCaseSensitive), mConformToCase(g_HSConformToCase), mDoBackspace(g_HSDoBackspace)
 2513     , mOmitEndChar(g_HSOmitEndChar), mSendRaw(aHasContinuationSection ? true : g_HSSendRaw)
 2514     , mEndCharRequired(g_HSEndCharRequired), mDetectWhenInsideWord(g_HSDetectWhenInsideWord), mDoReset(g_HSDoReset)
 2515     , mHotCriterion(g_HotCriterion)
 2516     , mInputLevel(g_InputLevel)
 2517     , mConstructedOK(false)
 2518 {
 2519     // Insist on certain qualities so that they never need to be checked other than here:
 2520     if (!mJumpToLabel) // Caller has already ensured that aHotstring is not blank.
 2521         mJumpToLabel = g_script.mPlaceholderLabel;
 2522     bool execute_action = false; // do not assign  mReplacement if execute_action is true.
 2523     ParseOptions(aOptions, mPriority, mKeyDelay, mSendMode, mCaseSensitive, mConformToCase, mDoBackspace
 2524         , mOmitEndChar, mSendRaw, mEndCharRequired, mDetectWhenInsideWord, mDoReset, execute_action);
 2525     
 2526     // To avoid memory leak, this is done only when it is certain the hotstring will be created:
 2527     if (   !(mString = SimpleHeap::Malloc(aHotstring))   )
 2528         return; // ScriptError() was already called by Malloc().
 2529     if (   g_script.mIsReadyToExecute && !(mName = SimpleHeap::Malloc(aName))   ) // mName already contains persistent memory when we're called at load time.
 2530     {
 2531         SimpleHeap::Delete(mString); // SimpleHeap allows deletion of most recently added item.
 2532         return;
 2533     }
 2534     mStringLength = (UCHAR)_tcslen(mString);
 2535     if (!execute_action && *aReplacement)
 2536     {
 2537         // SimpleHeap is not used for the replacement as it can be changed at runtime by Hotstring().
 2538         if (   !(mReplacement = _tcsdup(aReplacement))   )
 2539         {
 2540             g_script.ScriptError(ERR_OUTOFMEM); // Short msg since very rare.
 2541             return;
 2542         }
 2543     }
 2544     else // Leave mReplacement NULL, but make this false so that the hook doesn't do extra work.
 2545         mConformToCase = false;
 2546 
 2547     mConstructedOK = true; // Done at the very end.
 2548 }
 2549 
 2550 
 2551 
 2552 void Hotstring::ParseOptions(LPTSTR aOptions)
 2553 {
 2554     bool unused_X_option;
 2555     ParseOptions(aOptions, mPriority, mKeyDelay, mSendMode, mCaseSensitive, mConformToCase, mDoBackspace
 2556         , mOmitEndChar, mSendRaw, mEndCharRequired, mDetectWhenInsideWord, mDoReset, unused_X_option);
 2557 }
 2558 
 2559 
 2560 
 2561 void Hotstring::ParseOptions(LPTSTR aOptions, int &aPriority, int &aKeyDelay, SendModes &aSendMode
 2562     , bool &aCaseSensitive, bool &aConformToCase, bool &aDoBackspace, bool &aOmitEndChar, SendRawType &aSendRaw
 2563     , bool &aEndCharRequired, bool &aDetectWhenInsideWord, bool &aDoReset, bool &aExecuteAction)
 2564 {
 2565     // In this case, colon rather than zero marks the end of the string.  However, the string
 2566     // might be empty so check for that too.  In addition, this is now called from
 2567     // IsDirective(), so that's another reason to check for normal string termination.
 2568     LPTSTR cp1;
 2569     for (LPTSTR cp = aOptions; *cp && *cp != ':'; ++cp)
 2570     {
 2571         cp1 = cp + 1;
 2572         switch(ctoupper(*cp))
 2573         {
 2574         case '*':
 2575             aEndCharRequired = (*cp1 == '0');
 2576             break;
 2577         case '?':
 2578             aDetectWhenInsideWord = (*cp1 != '0');
 2579             break;
 2580         case 'B': // Do backspacing.
 2581             aDoBackspace = (*cp1 != '0');
 2582             break;
 2583         case 'C':
 2584             if (*cp1 == '0') // restore both settings to default.
 2585             {
 2586                 aConformToCase = true;
 2587                 aCaseSensitive = false;
 2588             }
 2589             else if (*cp1 == '1')
 2590             {
 2591                 aConformToCase = false;
 2592                 aCaseSensitive = false;
 2593             }
 2594             else // treat as plain "C"
 2595             {
 2596                 aConformToCase = false;  // No point in conforming if its case sensitive.
 2597                 aCaseSensitive = true;
 2598             }
 2599             break;
 2600         case 'O':
 2601             aOmitEndChar = (*cp1 != '0');
 2602             break;
 2603         // For options such as K & P: Use atoi() vs. ATOI() to avoid interpreting something like 0x01C
 2604         // as hex when in fact the C was meant to be an option letter:
 2605         case 'K':
 2606             aKeyDelay = _ttoi(cp1);
 2607             break;
 2608         case 'P':
 2609             aPriority = _ttoi(cp1);
 2610             break;
 2611         case 'R':
 2612             aSendRaw = (*cp1 != '0') ? SCM_RAW : SCM_NOT_RAW;
 2613             break;
 2614         case 'T':
 2615             aSendRaw = (*cp1 != '0') ? SCM_RAW_TEXT : SCM_NOT_RAW;
 2616             break;
 2617         case 'S':
 2618             if (*cp1)
 2619                 ++cp; // Skip over S's sub-letter (if any) to exclude it from  further consideration.
 2620             switch (ctoupper(*cp1))
 2621             {
 2622             // There is no means to choose SM_INPUT because it seems too rarely desired (since auto-replace
 2623             // hotstrings would then become interruptible, allowing the keystrokes of fast typists to get
 2624             // interspersed with the replacement text).
 2625             case 'I': aSendMode = SM_INPUT_FALLBACK_TO_PLAY; break;
 2626             case 'E': aSendMode = SM_EVENT; break;
 2627             case 'P': aSendMode = SM_PLAY; break;
 2628             //default: leave it unchanged.
 2629             }
 2630             break;
 2631         case 'Z':
 2632             aDoReset = (*cp1 != '0');
 2633             break;
 2634         case 'X':
 2635             aExecuteAction = (*cp1 != '0');
 2636             break;
 2637         // Otherwise: Ignore other characters, such as the digits that comprise the number after the P option.
 2638         }
 2639     }
 2640 }
 2641 
 2642 
 2643 
 2644 Hotstring *Hotstring::FindHotstring(LPTSTR aHotstring, bool aCaseSensitive, bool aDetectWhenInsideWord, HotkeyCriterion *aHotCriterion)
 2645 {
 2646     for (UINT u = 0; u < sHotstringCount; ++u)
 2647     {
 2648         Hotstring &hs = *shs[u];
 2649         // hs.mEndCharRequired is not checked because although it affects the conditions for activating
 2650         // the hotstring, ::abbrev:: and :*:abbrev:: cannot co-exist (the latter would always take over).
 2651         if (   hs.mHotCriterion == aHotCriterion // Same #If criterion.
 2652             && hs.mCaseSensitive == aCaseSensitive // ::BTW:: and :C:BTW:: can co-exist.
 2653             && hs.mDetectWhenInsideWord == aDetectWhenInsideWord // :?:ion:: and ::ion:: can co-exist.
 2654             && (aCaseSensitive ? !_tcscmp(hs.mString, aHotstring) : !lstrcmpi(hs.mString, aHotstring))   ) // :C:BTW:: and :C:btw:: can co-exist, but not ::BTW:: and ::btw::.
 2655             return &hs;
 2656     }
 2657     return NULL;
 2658 }
 2659 
 2660 
 2661 
 2662 BIF_DECL(BIF_Hotstring)
 2663 {
 2664     aResultToken.symbol = SYM_STRING;
 2665     aResultToken.marker = _T("");
 2666 
 2667     _f_param_string(name, 0);
 2668     _f_param_string_opt(action, 1);
 2669     _f_param_string_opt(onoff, 2);
 2670 
 2671     if (!_tcsicmp(name, _T("EndChars"))) // Equivalent to #Hotstring EndChars <action>
 2672     {
 2673         TokenSetResult(aResultToken, g_EndChars); // Return the old value.
 2674         if (!ParamIndexIsOmitted(1))
 2675             // There is some concern of a race condition with the hook thread, but since g_EndChars
 2676             // has static storage duration and is therefore zero-initialized at startup (in particular,
 2677             // the last char is always zero), the only consequence would be that some old end chars may
 2678             // be used if a hotstring is evaluated during the tcslcpy() call.
 2679             tcslcpy(g_EndChars, action, _countof(g_EndChars));
 2680         return;
 2681     }
 2682     else if (!_tcsicmp(name, _T("MouseReset"))) // "MouseReset, true" seems more intuitive than "NoMouse, false"
 2683     {
 2684         bool previous_value = g_HSResetUponMouseClick;
 2685         if (!ParamIndexIsOmitted(1))
 2686         {
 2687             g_HSResetUponMouseClick = ParamIndexToBOOL(1);
 2688             if (g_HSResetUponMouseClick != previous_value && Hotstring::sEnabledCount) // No need if there aren't any hotstrings.
 2689                 Hotkey::ManifestAllHotkeysHotstringsHooks(); // Install the hook if needed, or uninstall if no longer needed.
 2690         }
 2691         aResultToken.symbol = SYM_INTEGER;
 2692         aResultToken.value_int64 = previous_value;
 2693         return;
 2694     }
 2695     else if (!_tcsicmp(name, _T("Reset")))
 2696     {
 2697         *g_HSBuf = '\0';
 2698         g_HSBufLength = 0;
 2699         return;
 2700     }
 2701     else if (aParamCount == 1 && *name != ':') // Equivalent to #Hotstring <name>
 2702     {
 2703         // TODO: Build string of current options and return it?
 2704         bool unused_X_option; // 'X' option is required to be passed for each Hotstring() call, for clarity.
 2705         Hotstring::ParseOptions(name, g_HSPriority, g_HSKeyDelay, g_HSSendMode, g_HSCaseSensitive
 2706             , g_HSConformToCase, g_HSDoBackspace, g_HSOmitEndChar, g_HSSendRaw, g_HSEndCharRequired
 2707             , g_HSDetectWhenInsideWord, g_HSDoReset, unused_X_option);
 2708         return;
 2709     }
 2710 
 2711     // Parse the hotstring name (this is similar to a section in LoadIncludedFile()):
 2712     LPTSTR hotstring_start = NULL;
 2713     LPTSTR hotstring_options = _T(""); // Set default as "no options were specified for this hotstring".
 2714     if (name[0] == ':' && name[1])
 2715     {
 2716         if (name[1] != ':')
 2717         {
 2718             hotstring_options = name + 1; // Point it to the hotstring's option letters.
 2719             // The following relies on the fact that options should never contain a literal colon.
 2720             if (   !(hotstring_start = _tcschr(hotstring_options, ':'))   )
 2721                 hotstring_start = NULL; // Indicate that this isn't a hotstring after all.
 2722             else
 2723                 ++hotstring_start; // Points to the hotstring itself.
 2724         }
 2725         else // Double-colon, so it's a hotstring if there's more after this (but this means no options are present).
 2726             if (name[2])
 2727                 hotstring_start = name + 2;
 2728             //else it's just a naked "::", which is invalid.
 2729     }
 2730     if (!hotstring_start)
 2731         _f_throw(ERR_PARAM1_INVALID, action);
 2732     
 2733     // Determine options which affect hotstring identity/uniqueness.
 2734     bool case_sensitive = g_HSCaseSensitive;
 2735     bool detect_inside_word = g_HSDetectWhenInsideWord;
 2736     bool execute_action = false; // Unlike the others, 'X' must be specified each time.
 2737     bool un; int iun; SendModes sm; SendRawType sr; // Unused.
 2738     if (*hotstring_options)
 2739         Hotstring::ParseOptions(hotstring_options, iun, iun, sm, case_sensitive, un, un, un, sr, un, detect_inside_word, un, execute_action);
 2740     
 2741     IObject *action_obj = NULL;
 2742     if (!ParamIndexIsOmitted(1))
 2743     {
 2744         action_obj = ParamIndexToObject(1);
 2745         if (   execute_action // Caller specified 'X' option (which is ignored when passing an object).
 2746             && !action_obj // Caller did not specify an object, so must specify a function or label name.
 2747             && !(action_obj = g_script.FindCallable(action))   ) // No valid label or function found.
 2748             _f_throw(ERR_PARAM2_INVALID, action);
 2749     }
 2750     ToggleValueType toggle = NEUTRAL;
 2751     if (  *onoff && !(toggle = Line::ConvertOnOffToggle(onoff))   )
 2752         _f_throw(ERR_PARAM3_INVALID, onoff);
 2753 
 2754     bool was_already_enabled;
 2755     Hotstring *existing = Hotstring::FindHotstring(hotstring_start, case_sensitive, detect_inside_word, g_HotCriterion);
 2756     if (existing)
 2757     {
 2758         was_already_enabled = !existing->mSuspended;
 2759 
 2760         // Update the replacement string or function/label, if specified.
 2761         if (action_obj || *action)
 2762         {
 2763             LabelPtr new_label = action_obj ? action_obj : g_script.mPlaceholderLabel; // Other parts may rely on mJumpToLabel always being non-NULL.
 2764             LPTSTR new_replacement = NULL; // Set default: not auto-replace.
 2765             if (!action_obj) // Caller specified a replacement string ('E' option was handled above).
 2766             {
 2767                 if (existing->mReplacement && !_tcscmp(action, existing->mReplacement))
 2768                 {
 2769                     // Caller explicitly passed the same string it already had, which might be common,
 2770                     // such as if a single Hotstring() call site is used to both create and update.
 2771                     new_replacement = existing->mReplacement; // Avoid reallocating it.
 2772                 }
 2773                 else if (   !(new_replacement = _tcsdup(action))   )
 2774                     _f_throw(ERR_OUTOFMEM);
 2775             }
 2776             existing->mSuspended |= HS_TEMPORARILY_DISABLED;
 2777             WaitHookIdle();
 2778             // At this point it is certain the hook thread is not in the middle of reading this
 2779             // hotstring's other properties, such as mReplacement (which we may be about to free).
 2780             if (new_replacement != existing->mReplacement)
 2781             {
 2782                 if (existing->mReplacement)
 2783                     free(existing->mReplacement);
 2784                 existing->mReplacement = new_replacement;
 2785             }
 2786             if (new_label != existing->mJumpToLabel)
 2787             {
 2788                 existing->mJumpToLabel = new_label;
 2789                 // Update suspension status in case new or old label was exempt:
 2790                 if (g_IsSuspended && !new_label->IsExemptFromSuspend())
 2791                     existing->mSuspended |= HS_SUSPENDED;
 2792                 else
 2793                     existing->mSuspended &= ~HS_SUSPENDED;
 2794             }
 2795         }
 2796         // Update the hotstring's options.  Note that mCaseSensitive and mDetectWhenInsideWord
 2797         // can't be changed this way since FindHotstring() would not have found it if they differed.
 2798         // This is done after the above to avoid *partial* updates in the event of a failure.
 2799         existing->ParseOptions(hotstring_options);
 2800         switch (toggle)
 2801         {
 2802         case TOGGLE:      existing->mSuspended ^=  HS_TURNED_OFF; break;
 2803         case TOGGLED_ON:  existing->mSuspended &= ~HS_TURNED_OFF; break;
 2804         case TOGGLED_OFF: existing->mSuspended |=  HS_TURNED_OFF; break;
 2805         }
 2806         existing->mSuspended &= ~HS_TEMPORARILY_DISABLED; // Re-enable if it was disabled above.
 2807     }
 2808     else // No matching hotstring yet.
 2809     {
 2810         if (!action_obj && !*action)
 2811             _f_throw(aParamCount > 1 ? ERR_PARAM2_MUST_NOT_BE_BLANK : _T("Hotstring not found."));
 2812 
 2813         UCHAR initial_suspend_state = (toggle == TOGGLED_OFF) ? HS_TURNED_OFF : FALSE;
 2814         if (g_IsSuspended && !(action_obj && LabelPtr(action_obj)->IsExemptFromSuspend()))
 2815             initial_suspend_state |= HS_SUSPENDED;
 2816 
 2817         if (!Hotstring::AddHotstring(name, action_obj, hotstring_options, hotstring_start, action, false, initial_suspend_state))
 2818             _f_return_FAIL;
 2819 
 2820         existing = Hotstring::shs[Hotstring::sHotstringCount-1];
 2821         was_already_enabled = false; // Because it didn't exist.
 2822     }
 2823 
 2824     // Note that mSuspended must be 0 to count as enabled, meaning the hotstring was neither
 2825     // turned off by us nor suspended by SuspendAll().  If it was suspended, there's no change
 2826     // in status unless the label was changed to/from one which is exempt from suspension.
 2827     bool is_enabled = !existing->mSuspended; // Important to avoid direct comparison with mSuspended becauses it isn't pure bool.
 2828     if (is_enabled != was_already_enabled)
 2829     {
 2830         // One of the following just happened:
 2831         //  - a hotstring was created and enabled
 2832         //  - an existing disabled hotstring was just enabled
 2833         //  - an existing enabled hotstring was just disabled
 2834         UINT previously_enabled = Hotstring::sEnabledCount;
 2835         Hotstring::sEnabledCount += is_enabled ? +1 : -1;
 2836         if ((Hotstring::sEnabledCount > 0) != (previously_enabled > 0)) // Change in status of whether the hotstring recognizer is needed.
 2837         {
 2838             if (is_enabled)
 2839             {
 2840                 *g_HSBuf = '\0'; // See SuspendAll() for comments.
 2841                 g_HSBufLength = 0;
 2842             }
 2843             if (!is_enabled || !g_KeybdHook) // Hook may not be needed anymore || hook is needed but not present.
 2844                 Hotkey::ManifestAllHotkeysHotstringsHooks();
 2845         }
 2846     }
 2847 }