"Fossies" - the Fresh Open Source Software Archive

Member "AutoHotkey_L-1.1.33.09/source/hook.cpp" (8 May 2021, 261680 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 "hook.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 "hook.h"
   19 #include "globaldata.h"  // for access to several global vars
   20 #include "util.h" // for snprintfcat()
   21 #include "window.h" // for MsgBox()
   22 #include "application.h" // For MsgSleep().
   23 
   24 // Declare static variables (global to only this file/module, i.e. no external linkage):
   25 static HANDLE sKeybdMutex = NULL;
   26 static HANDLE sMouseMutex = NULL;
   27 #define KEYBD_MUTEX_NAME _T("AHK Keybd")
   28 #define MOUSE_MUTEX_NAME _T("AHK Mouse")
   29 
   30 // It's done the following way because:
   31 // It's unclear that zero is always an invalid thread ID (not even GetWindowThreadProcessId's
   32 // documentation gives any hint), so its safer to assume that a thread ID can be zero and yet still valid.
   33 static HANDLE sThreadHandle = NULL;
   34 
   35 // Whether to disguise the next up-event for lwin/rwin to suppress Start Menu.
   36 // There is only one variable because even if multiple modifiers are pressed
   37 // simultaneously and they do not cancel each other out, disguising one will
   38 // have the effect of disguising all (with the exception that key-repeat can
   39 // reset LWin/RWin after the other modifier is released, so this variable
   40 // should not be reset until all Win keys are released).
   41 // These are made global, rather than static inside the hook function, so that
   42 // we can ensure they are initialized by the keyboard init function every
   43 // time it's called (currently it can be only called once):
   44 static bool sDisguiseNextMenu;          // Initialized by ResetHook().
   45 static bool sUndisguisedMenuInEffect;   //
   46 
   47 // Whether the alt-tab menu was shown by an AltTab hotkey or alt-tab was detected
   48 // by the hook.  This might be inaccurate if the menu was displayed before the hook
   49 // was installed or the keys weren't detected because of UIPI.  If this turns out to
   50 // be a problem, the accuracy could be improved by additional checks with FindWindow(),
   51 // keeping in mind that there are at least 3 different window classes to check,
   52 // depending on OS and the "AltTabSettings" registry value.
   53 static bool sAltTabMenuIsVisible;       // Initialized by ResetHook().
   54 
   55 // The prefix key that's currently down (i.e. in effect).
   56 // It's tracked this way, rather than as a count of the number of prefixes currently down, out of
   57 // concern that such a count might accidentally wind up above zero (due to a key-up being missed somehow)
   58 // and never come back down, thus penalizing performance until the program is restarted:
   59 key_type *pPrefixKey;  // Initialized by ResetHook().
   60 
   61 // Less memory overhead (space and performance) to allocate a solid block for multidimensional arrays:
   62 // These store all the valid modifier+suffix combinations (those that result in hotkey actions) except
   63 // those with a ModifierVK/SC.  Doing it this way should cut the CPU overhead caused by having many
   64 // hotkeys handled by the hook, down to a fraction of what it would be otherwise.  Indeed, doing it
   65 // this way makes the performance impact of adding many additional hotkeys of this type exactly zero
   66 // once the program has started up and initialized.  The main alternative is a binary search on an
   67 // array of keyboard-hook hotkeys (similar to how the mouse is done):
   68 static HotkeyIDType *kvkm = NULL;
   69 static HotkeyIDType *kscm = NULL;
   70 static HotkeyIDType *hotkey_up = NULL;
   71 static key_type *kvk = NULL;
   72 static key_type *ksc = NULL;
   73 // Macros for convenience in accessing the above arrays as multidimensional objects.
   74 // When using them, be sure to consistently access the first index as ModLR (i.e. the rows)
   75 // and the second as VK or SC (i.e. the columns):
   76 #define Kvkm(i,j) kvkm[(i)*(VK_ARRAY_COUNT) + (j)]
   77 #define Kscm(i,j) kscm[(i)*(SC_ARRAY_COUNT) + (j)]
   78 #define KVKM_SIZE ((MODLR_MAX + 1)*(VK_ARRAY_COUNT))
   79 #define KSCM_SIZE ((MODLR_MAX + 1)*(SC_ARRAY_COUNT))
   80 
   81 
   82 // Notes about fake shift-key events (there used to be some related variables defined here,
   83 // but they were superseded by SC_FAKE_LSHIFT and SC_FAKE_RSHIFT):
   84 // Used to help make a workaround for the way the keyboard driver generates physical
   85 // shift-key events to release the shift key whenever it is physically down during
   86 // the press or release of a dual-state Numpad key. These keyboard driver generated
   87 // shift-key events only seem to happen when Numlock is ON, the shift key is logically
   88 // or physically down, and a dual-state numpad key is pressed or released (i.e. the shift
   89 // key might not have been down for the press, but if it's down for the release, the driver
   90 // will suddenly start generating shift events).  I think the purpose of these events is to
   91 // allow the shift key to temporarily alter the state of the Numlock key for the purpose of
   92 // sending that one key, without the shift key actually being "seen" as down while the key
   93 // itself is sent (since some apps may have special behavior when they detect the shift key
   94 // is down).
   95 
   96 // Note: numlock, numpaddiv/mult/sub/add/enter are not affected by this because they have only
   97 // a single state (i.e. they are unaffected by the state of the Numlock key).  Also, these
   98 // driver-generated events occur at a level lower than the hook, so it doesn't matter whether
   99 // the hook suppresses the keys involved (i.e. the shift events still happen anyway).
  100 
  101 // So which keys are not physical even though they're non-injected?:
  102 // 1) The shift-up that precedes a down of a dual-state numpad key (only happens when shift key is logically down).
  103 // 2) The shift-down that precedes a pressing down (or releasing in certain very rare cases caused by the
  104 //    exact sequence of keys received) of a key WHILE the numpad key in question is still down.
  105 //    Although this case may seem rare, it's happened to both Robert Yaklin and myself when doing various
  106 //    sorts of hotkeys.
  107 // 3) The shift-up that precedes an up of a dual-state numpad key.  This only happens if the shift key is
  108 //    logically down for any reason at this exact moment, which can be achieved via the send command.
  109 // 4) The shift-down that follows the up of a dual-state numpad key (i.e. the driver is restoring the shift state
  110 //    to what it was before).  This can be either immediate or "lazy".  It's lazy whenever the user had pressed
  111 //    another key while a numpad key was being held down (i.e. case #2 above), in which case the driver waits
  112 //    indefinitely for the user to press any other key and then immediately sneaks in the shift key-down event
  113 //    right before it in the input stream (insertion).
  114 // 5) Similar to #4, but if the driver needs to generate a shift-up for an unexpected Numpad-up event,
  115 //    the restoration of the shift key will be "lazy".  This case was added in response to the below
  116 //    example, wherein the shift key got stuck physically down (incorrectly) by the hook:
  117 // 68  048      d   0.00    Num 8           
  118 // 6B  04E      d   0.09    Num +           
  119 // 68  048  i   d   0.00    Num 8           
  120 // 68  048  i   u   0.00    Num 8           
  121 // A0  02A  i   d   0.02    Shift           part of the macro
  122 // 01  000  i   d   0.03    LButton         
  123 // A0  02A      u   0.00    Shift           driver, for the next key
  124 // 26  048      u   0.00    Num 8           
  125 // A0  02A      d   0.49    Shift           driver lazy down (but not detected as non-physical)
  126 // 6B  04E      d   0.00    Num +           
  127 
  128 
  129 static bool sHookSyncd; // Only valid while in WaitHookIdle().
  130 
  131 /////////////////////////////////////////////////////////////////////////////////////////////
  132 
  133 /*
  134 One of the main objectives of a the hooks is to minimize the amount of CPU overhead caused by every
  135 input event being handled by the procedure.  One way this is done is to return immediately on
  136 simple conditions that are relatively frequent (such as receiving a key that's not involved in any
  137 hotkey combination).
  138 
  139 Another way is to avoid API or system calls that might have a high overhead.  That's why the state of
  140 every prefix key is tracked independently, rather than calling the WinAPI to determine if the
  141 key is actually down at the moment of consideration.
  142 */
  143 
  144 inline bool IsIgnored(ULONG_PTR aExtraInfo)
  145 // KEY_PHYS_IGNORE events must be mostly ignored because currently there is no way for a given
  146 // hook instance to detect if it sent the event or some other instance.  Therefore, to treat
  147 // such events as true physical events might cause infinite loops or other side-effects in
  148 // the instance that generated the event.  More review of this is needed if KEY_PHYS_IGNORE
  149 // events ever need to be treated as true physical events by the instances of the hook that
  150 // didn't originate them. UPDATE: The foregoing can now be accomplished using SendLevel.
  151 {
  152     return aExtraInfo == KEY_IGNORE || aExtraInfo == KEY_PHYS_IGNORE || aExtraInfo == KEY_IGNORE_ALL_EXCEPT_MODIFIER;
  153 }
  154 
  155 
  156 
  157 LRESULT CALLBACK LowLevelKeybdProc(int aCode, WPARAM wParam, LPARAM lParam)
  158 {
  159     if (aCode != HC_ACTION)  // MSDN docs specify that both LL keybd & mouse hook should return in this case.
  160         return CallNextHookEx(g_KeybdHook, aCode, wParam, lParam);
  161 
  162     KBDLLHOOKSTRUCT &event = *(PKBDLLHOOKSTRUCT)lParam;  // For convenience, maintainability, and possibly performance.
  163 
  164     // Change the event to be physical if that is indicated in its dwExtraInfo attribute.
  165     // This is done for cases when the hook is installed multiple times and one instance of
  166     // it wants to inform the others that this event should be considered physical for the
  167     // purpose of updating modifier and key states:
  168     if (event.dwExtraInfo == KEY_PHYS_IGNORE)
  169         event.flags &= ~LLKHF_INJECTED;
  170     else if (event.dwExtraInfo == KEY_BLOCK_THIS)
  171         return TRUE;
  172 
  173     // Make all keybd events physical to try to fool the system into accepting CTRL-ALT-DELETE.
  174     // This didn't work, which implies that Ctrl-Alt-Delete is trapped at a lower level than
  175     // this hook (folks have said that it's trapped in the keyboard driver itself):
  176     //event.flags &= ~LLKHF_INJECTED;
  177 
  178     // Note: Some scan codes are shared by more than one key (e.g. Numpad7 and NumpadHome).  This is why
  179     // the keyboard hook must be able to handle hotkeys by either their virtual key or their scan code.
  180     // i.e. if sc were always used in preference to vk, we wouldn't be able to distinguish between such keys.
  181 
  182     bool key_up = (wParam == WM_KEYUP || wParam == WM_SYSKEYUP);
  183     vk_type vk = (vk_type)event.vkCode;
  184     sc_type sc = (sc_type)event.scanCode;
  185     if (vk && !sc) // Might happen if another app calls keybd_event with a zero scan code.
  186         sc = vk_to_sc(vk);
  187     // MapVirtualKey() does *not* include 0xE0 in HIBYTE if key is extended.  In case it ever
  188     // does in the future (or if event.scanCode ever does), force sc to be an 8-bit value
  189     // so that it's guaranteed consistent and to ensure it won't exceed SC_MAX (which might cause
  190     // array indexes to be out-of-bounds).  The 9th bit is later set to 1 if the key is extended:
  191     sc &= 0xFF;
  192     // Change sc to be extended if indicated.  But avoid doing so for VK_RSHIFT, which is
  193     // apparently considered extended by the API when it shouldn't be.  Update: Well, it looks like
  194     // VK_RSHIFT really is an extended key, at least on WinXP (and probably be extension on the other
  195     // NT based OSes as well).  What little info I could find on the 'net about this is contradictory,
  196     // but it's clear that some things just don't work right if the non-extended scan code is sent.  For
  197     // example, the shift key will appear to get stuck down in the foreground app if the non-extended
  198     // scan code is sent with VK_RSHIFT key-up event:
  199     if ((event.flags & LLKHF_EXTENDED)) // && vk != VK_RSHIFT)
  200         sc |= 0x100;
  201 
  202     // The below must be done prior to any returns that indirectly call UpdateKeybdState() to update
  203     // modifier state.
  204     // Update: It seems best to do the below unconditionally, even if the OS is Win2k or WinXP,
  205     // since it seems like this translation will add value even in those cases:
  206     // To help ensure consistency with Windows XP and 2k, for which this hook has been primarily
  207     // designed and tested, translate neutral modifier keys into their left/right specific VKs,
  208     // since beardboy's testing shows that NT4 receives the neutral keys like Win9x does:
  209     switch (vk)
  210     {
  211     case VK_SHIFT:   vk = (sc == SC_RSHIFT)   ? VK_RSHIFT   : VK_LSHIFT; break;
  212     case VK_CONTROL: vk = (sc == SC_RCONTROL) ? VK_RCONTROL : VK_LCONTROL; break;
  213     case VK_MENU:    vk = (sc == SC_RALT)     ? VK_RMENU    : VK_LMENU; break;
  214     }
  215 
  216     // Now that the above has translated VK_CONTROL to VK_LCONTROL (if necessary):
  217     if (vk == VK_LCONTROL)
  218     {
  219         // The following helps hasten AltGr detection after script startup.  It's kept to supplement
  220         // LayoutHasAltGr() because that function isn't 100% reliable for the reasons described there.
  221         // It shouldn't be necessary to check what type of LControl event (up or down) is received, since
  222         // it should be impossible for any unrelated keystrokes to be received while g_HookReceiptOfLControlMeansAltGr
  223         // is true.  This is because all unrelated keystrokes stay buffered until the main thread calls GetMessage().
  224         // UPDATE for v1.0.39: Now that the hook has a dedicated thread, the above is no longer 100% certain.
  225         // However, I think confidence is very high that this AltGr detection method is okay as it is because:
  226         // 1) Hook thread has high priority, which means it generally shouldn't get backlogged with buffered keystrokes.
  227         // 2) When the main thread calls keybd_event(), there is strong evidence that the OS immediately preempts
  228         //    the main thread (or executes a SendMessage(), which is the same as preemption) and gives the next
  229         //    timeslice to the hook thread, which then immediately processes the incoming keystroke as long
  230         //    as there are no keystrokes in the queue ahead of it (see #1).
  231         // 3) Even if #1 and #2 fail to hold, the probability of misclassifying an LControl event seems very low.
  232         //    If there is ever concern, adding a call to IsIgnored() below would help weed out physical keystrokes
  233         //    (or those of other programs) that arrive during a vulnerable time.
  234         if (g_HookReceiptOfLControlMeansAltGr)
  235         {
  236             // But don't reset g_HookReceiptOfLControlMeansAltGr here to avoid timing problems where the hook
  237             // is installed at a time when g_HookReceiptOfLControlMeansAltGr is wrongly true because the
  238             // inactive hook never made it false.  Let KeyEvent() do that.
  239             Get_active_window_keybd_layout // Defines the variable active_window_keybd_layout for use below.
  240             LayoutHasAltGr(active_window_keybd_layout, CONDITION_TRUE);
  241             // The following must be done; otherwise, if LayoutHasAltGr hasn't yet been autodetected by the
  242             // time the first AltGr keystroke comes through, that keystroke would cause LControl to get stuck down
  243             // as seen in g_modifiersLR_physical.
  244             event.flags |= LLKHF_INJECTED; // Flag it as artificial for any other instances of the hook that may be running.
  245             event.dwExtraInfo = g_HookReceiptOfLControlMeansAltGr; // The one who set this variable put the desired ExtraInfo in it.
  246         }
  247         else // Since AltGr wasn't detected above, see if any other means is ready to detect it.
  248         {
  249             // v1.0.42.04: This section was moved out of IsIgnored() to here because:
  250             // 1) Immediately correcting the incoming event simplifies other parts of the hook.
  251             // 2) It allows this instance of the hook to communicate with other instances of the hook by
  252             //    correcting the bogus values directly inside the event structure.  This is something those
  253             //    other hooks can't do easily if the keystrokes were generated/simulated inside our instance
  254             //    (due to our instance's KeyEvent() function communicating corrections via
  255             //    g_HookReceiptOfLControlMeansAltGr and g_IgnoreNextLControlDown/Up).
  256             //
  257             // This new approach solves an AltGr keystroke's disruption of A_TimeIdlePhysical and related
  258             // problems that were caused by AltGr's incoming keystroke being marked by the driver or OS as a
  259             // physical event (even when the AltGr keystroke that caused it was artificial).  It might not
  260             // be a perfect solution, but it's pretty complete. For example, with the exception of artificial
  261             // AltGr keystrokes from non-AHK sources, it completely solves the A_TimeIdlePhysical issue because
  262             // by definition, any script that *uses* A_TimeIdlePhysical in a way that the fix applies to also
  263             // has the keyboard hook installed (if it only has the mouse hook installed, the fix isn't in effect,
  264             // but it also doesn't matter because that script detects only mouse events as true physical events,
  265             // as described in the documentation for A_TimeIdlePhysical).
  266             if (key_up)
  267             {
  268                 if (g_IgnoreNextLControlUp)
  269                 {
  270                     event.flags |= LLKHF_INJECTED; // Flag it as artificial for any other instances of the hook that may be running.
  271                     event.dwExtraInfo = g_IgnoreNextLControlUp; // The one who set this variable put the desired ExtraInfo in here.
  272                 }
  273             }
  274             else // key-down event
  275             {
  276                 if (g_IgnoreNextLControlDown)
  277                 {
  278                     event.flags |= LLKHF_INJECTED; // Flag it as artificial for any other instances of the hook that may be running.
  279                     event.dwExtraInfo = g_IgnoreNextLControlDown; // The one who set this variable put the desired ExtraInfo in here.
  280                 }
  281             }
  282         }
  283     } // if (vk == VK_LCONTROL)
  284 
  285     return LowLevelCommon(g_KeybdHook, aCode, wParam, lParam, vk, sc, key_up, event.dwExtraInfo, event.flags);
  286 }
  287 
  288 
  289 
  290 LRESULT CALLBACK LowLevelMouseProc(int aCode, WPARAM wParam, LPARAM lParam)
  291 {
  292     // code != HC_ACTION should be evaluated PRIOR to considering the values
  293     // of wParam and lParam, because those values may be invalid or untrustworthy
  294     // whenever code < 0.
  295     if (aCode != HC_ACTION)
  296         return CallNextHookEx(g_MouseHook, aCode, wParam, lParam);
  297 
  298     MSLLHOOKSTRUCT &event = *(PMSLLHOOKSTRUCT)lParam;  // For convenience, maintainability, and possibly performance.
  299 
  300     // Make all mouse events physical to try to simulate mouse clicks in games that normally ignore
  301     // artificial input.
  302     //event.flags &= ~LLMHF_INJECTED;
  303 
  304     if (!(event.flags & LLMHF_INJECTED)) // Physical mouse movement or button action (uses LLMHF vs. LLKHF).
  305         g_TimeLastInputPhysical = g_TimeLastInputMouse = GetTickCount();
  306         // Above: Don't use event.time, mostly because SendInput can produce invalid timestamps on such events
  307         // (though in truth, that concern isn't valid because SendInput's input isn't marked as physical).
  308         // Another concern is the comments at the other update of "g_TimeLastInputPhysical" elsewhere in this file.
  309         // A final concern is that some drivers might be faulty and might not generate an accurate timestamp.
  310 
  311     if (wParam == WM_MOUSEMOVE) // Only after updating for physical input, above, is this checked.
  312         return (g_BlockMouseMove && !(event.flags & LLMHF_INJECTED)) ? 1 : CallNextHookEx(g_MouseHook, aCode, wParam, lParam);
  313         // Above: In v1.0.43.11, a new mode was added to block mouse movement only since it's more flexible than
  314         // BlockInput (which keybd too, and blocks all mouse buttons too).  However, this mode blocks only
  315         // physical mouse movement because it seems most flexible (and simplest) to allow all artificial
  316         // movement, even if that movement came from a source other than an AHK script (such as some other
  317         // macro program).
  318 
  319     // MSDN: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL [, WM_MOUSEHWHEEL], WM_RBUTTONDOWN, or WM_RBUTTONUP.
  320     // But what about the middle button?  It's undocumented, but it is received.
  321     // What about doubleclicks (e.g. WM_LBUTTONDBLCLK): I checked: They are NOT received.
  322     // This is expected because each click in a doubleclick could be separately suppressed by
  323     // the hook, which would make it become a non-doubleclick.
  324     vk_type vk = 0;
  325     sc_type sc = 0; // To be overridden if this even is a wheel turn.
  326     short wheel_delta;
  327     bool key_up = true;  // Set default to safest value.
  328 
  329     switch (wParam)
  330     {
  331         case WM_MOUSEWHEEL:
  332         case WM_MOUSEHWHEEL: // v1.0.48: Lexikos: Support horizontal scrolling in Windows Vista and later.
  333             // MSDN: "A positive value indicates that the wheel was rotated forward, away from the user;
  334             // a negative value indicates that the wheel was rotated backward, toward the user. One wheel
  335             // click is defined as WHEEL_DELTA, which is 120."  Testing shows that on XP at least, the
  336             // abs(delta) is greater than 120 when the user turns the wheel quickly (also depends on
  337             // granularity of wheel hardware); i.e. the system combines multiple turns into a single event.
  338             wheel_delta = GET_WHEEL_DELTA_WPARAM(event.mouseData); // Must typecast to short (not int) via macro, otherwise the conversion to negative/positive number won't be correct.
  339             if (wParam == WM_MOUSEWHEEL)
  340                 vk = wheel_delta < 0 ? VK_WHEEL_DOWN : VK_WHEEL_UP;
  341             else
  342                 vk = wheel_delta < 0 ? VK_WHEEL_LEFT : VK_WHEEL_RIGHT;
  343             // Dividing by WHEEL_DELTA was a mistake because some mice can yield deltas less than 120.
  344             // However, this behavior is kept for backward compatibility because some scripts may rely
  345             // on A_EventInfo==0 meaning "delta is between 1 and 119".  WheelLeft/Right were also done
  346             // that way because consistency may be more important than correctness.  In the future, perhaps
  347             // an A_EventInfo2 can be added, or some hotkey aliases like "FineWheelXXX".
  348             sc = (wheel_delta > 0 ? wheel_delta : -wheel_delta) / WHEEL_DELTA; // See above. Note that sc is unsigned.
  349             key_up = false; // Always consider wheel movements to be "key down" events.
  350             break;
  351         case WM_LBUTTONUP: vk = VK_LBUTTON; break;
  352         case WM_RBUTTONUP: vk = VK_RBUTTON; break;
  353         case WM_MBUTTONUP: vk = VK_MBUTTON; break;
  354         case WM_NCXBUTTONUP:  // NC means non-client.
  355         case WM_XBUTTONUP: vk = (HIWORD(event.mouseData) == XBUTTON1) ? VK_XBUTTON1 : VK_XBUTTON2; break;
  356         case WM_LBUTTONDOWN: vk = VK_LBUTTON; key_up = false; break;
  357         case WM_RBUTTONDOWN: vk = VK_RBUTTON; key_up = false; break;
  358         case WM_MBUTTONDOWN: vk = VK_MBUTTON; key_up = false; break;
  359         case WM_NCXBUTTONDOWN:
  360         case WM_XBUTTONDOWN: vk = (HIWORD(event.mouseData) == XBUTTON1) ? VK_XBUTTON1 : VK_XBUTTON2; key_up = false; break;
  361     }
  362 
  363     return LowLevelCommon(g_MouseHook, aCode, wParam, lParam, vk, sc, key_up, event.dwExtraInfo, event.flags);
  364 }
  365 
  366 
  367 
  368 LRESULT LowLevelCommon(const HHOOK aHook, int aCode, WPARAM wParam, LPARAM lParam, const vk_type aVK
  369     , sc_type aSC, bool aKeyUp, ULONG_PTR aExtraInfo, DWORD aEventFlags)
  370 // v1.0.38.06: The keyboard and mouse hooks now call this common function to reduce code size and improve
  371 // maintainability.  The code size savings as of v1.0.38.06 is 3.5 KB of uncompressed code, but that
  372 // savings will grow larger if more complexity is ever added to the hooks.
  373 {
  374     WPARAM hotkey_id_to_post = HOTKEY_ID_INVALID; // Set default.
  375     bool is_ignored = IsIgnored(aExtraInfo);
  376 
  377     // The following is done for more than just convenience.  It solves problems that would otherwise arise
  378     // due to the value of a global var such as KeyHistoryNext changing due to the reentrancy of
  379     // this procedure.  For example, a call to KeyEvent() in here would alter the value of
  380     // KeyHistoryNext, in most cases before we had a chance to finish using the old value.  In other
  381     // words, we use an automatic variable so that every instance of this function will get its
  382     // own copy of the variable whose value will stays constant until that instance returns:
  383     KeyHistoryItem *pKeyHistoryCurr, khi_temp; // Must not be static (see above).  Serves as a storage spot for a single keystroke in case key history is disabled.
  384     if (!g_KeyHistory)
  385         pKeyHistoryCurr = &khi_temp;  // Having a non-NULL pKeyHistoryCurr simplifies the code in other places.
  386     else
  387     {
  388         pKeyHistoryCurr = g_KeyHistory + g_KeyHistoryNext;
  389         if (++g_KeyHistoryNext >= g_MaxHistoryKeys)
  390             g_KeyHistoryNext = 0;
  391         pKeyHistoryCurr->vk = aVK; // aSC is done later below.
  392         pKeyHistoryCurr->key_up = aKeyUp;
  393         g_HistoryTickNow = GetTickCount();
  394         pKeyHistoryCurr->elapsed_time = (g_HistoryTickNow - g_HistoryTickPrev) / (float)1000;
  395         g_HistoryTickPrev = g_HistoryTickNow;
  396         HWND fore_win = GetForegroundWindow();
  397         if (fore_win)
  398         {
  399             if (fore_win != g_HistoryHwndPrev)
  400             {
  401                 // The following line is commented out in favor of the one beneath it (seem below comment):
  402                 //GetWindowText(fore_win, pKeyHistoryCurr->target_window, sizeof(pKeyHistoryCurr->target_window));
  403                 PostMessage(g_hWnd, AHK_GETWINDOWTEXT, (WPARAM)pKeyHistoryCurr->target_window, (LPARAM)fore_win);
  404                 // v1.0.44.12: The reason for the above is that clicking a window's close or minimize button
  405                 // (and possibly other types of title bar clicks) causes a delay for the following window, at least
  406                 // when XP Theme (but not classic theme) is in effect:
  407                 //#InstallMouseHook
  408                 //Gui, +AlwaysOnTop
  409                 //Gui, Show, w200 h100
  410                 //return
  411                 // The problem came about from the following sequence of events:
  412                 // 1) User clicks the one of the script's window's title bar's close, minimize, or maximize button.
  413                 // 2) WM_NCLBUTTONDOWN is sent to the window's window proc, which then passes it on to
  414                 //    DefWindowProc or DefDlgProc, which then apparently enters a loop in which no messages
  415                 //    (or a very limited subset) are pumped.
  416                 // 3) If anyone sends a message to that window (such as GetWindowText(), which sends a message
  417                 //    in cases where it doesn't have the title pre-cached), the message will not receive a reply
  418                 //    until after the mouse button is released.
  419                 // 4) But the hook is the very thing that's supposed to release the mouse button, and it can't
  420                 //    until a reply is received.
  421                 // 5) Thus, a deadlock occurs.  So after a short but noticeable delay, the OS sees the hook as
  422                 //    unresponsive and bypasses it, sending the click through normally, which breaks the deadlock.
  423                 // 6) A similar situation might arise when a right-click-down is sent to the title bar or
  424                 //    sys-menu-icon.
  425                 //
  426                 // SOLUTION:
  427                 // Post the message to our main thread to have it do the GetWindowText call.  That way, if
  428                 // the target window is one of the main thread's own window's, there's no chance it can be
  429                 // in an unresponsive state like the deadlock described above.  In addition, do this for ALL
  430                 // windows because its simpler, more maintainable, and especially might solve other hook
  431                 // performance problems if GetWindowText() has other situations where it is slow to return
  432                 // (which seems likely).
  433                 // Although the above solution could create rare situations where there's a lag before window text
  434                 // is updated, that seems unlikely to be common or have significant consequences.  Furthermore,
  435                 // it has the advantage of improving hook performance by avoiding the call to GetWindowText (which
  436                 // incidentally might solve hotkey lag problems that have been observed while the active window
  437                 // is momentarily busy/unresponsive -- but maybe not because the main thread would then be lagged
  438                 // instead of the hook thread, which is effectively the same result from user's POV).
  439                 // Note: It seems best not to post the message to the hook thread because if LButton is down,
  440                 // the hook's main event loop would be sending a message to an unresponsive thread (our main thread),
  441                 // which would create the same deadlock.
  442                 // ALTERNATE SOLUTIONS:
  443                 // - #1: Avoid calling GetWindowText at all when LButton or RButton is in a logically-down state.
  444                 // - Same as #1, but do so only if one of the main thread's target windows is known to be in a tight loop (might be too unreliable to detect all such cases).
  445                 // - Same as #1 but less rigorous and more catch-all, such as by checking if the active window belongs to our thread.
  446                 // - Avoid calling GetWindowText at all upon release of LButton.
  447                 // - Same, but only if the window to have text retrieved belongs to our process.
  448                 // - Same, but only if the mouse is inside the close/minimize/etc. buttons of the active window.
  449             }
  450             else // i.e. where possible, avoid the overhead of the call to GetWindowText().
  451                 *pKeyHistoryCurr->target_window = '\0';
  452         }
  453         else
  454             _tcscpy(pKeyHistoryCurr->target_window, _T("N/A")); // Due to AHK_GETWINDOWTEXT, this could collide with main thread's writing to same string; but in addition to being extremely rare, it would likely be inconsequential.
  455         g_HistoryHwndPrev = fore_win;  // Updated unconditionally in case fore_win is NULL.
  456     }
  457     // Keep the following flush with the above to indicate that they're related.
  458     // The following is done even if key history is disabled because firing a wheel hotkey via PostMessage gets
  459     // the notch count from pKeyHistoryCurr->sc.
  460     if (aVK == VK_PACKET) // Win2k/XP: VK_PACKET is used to send Unicode characters as if they were keystrokes.  sc is a 16-bit character code in that case.
  461     {
  462         aSC = 0; // This held a truncated character code, not to be mistaken for a real scan code.
  463         pKeyHistoryCurr->sc = (sc_type)((PKBDLLHOOKSTRUCT)lParam)->scanCode; // Get the full character code.
  464         pKeyHistoryCurr->event_type = 'U'; // Give it a unique identifier even though it can be distinguished by the 4-digit "SC".  'U' vs 'u' to avoid confusion with 'u'=up.
  465         // Artificial character input via VK_PACKET isn't supported by hotkeys, since they always work via
  466         // keycode, but hotstrings and Input are supported via the macro below when #InputLevel is non-zero.
  467         // Must return now to avoid misinterpreting aSC as an actual scancode in the code below.
  468         return AllowKeyToGoToSystem;
  469     }
  470     //else: Use usual modified value.
  471     pKeyHistoryCurr->sc = aSC; // Will be zero if our caller is the mouse hook (except for wheel notch count).
  472     // After logging the wheel notch count (above), purify aSC for readability and maintainability.
  473     if (IS_WHEEL_VK(aVK))
  474         aSC = 0; // Also relied upon by sc_takes_precedence below.
  475 
  476     bool is_artificial;
  477     if (aHook == g_MouseHook)
  478     {
  479         if (   !(is_artificial = (aEventFlags & LLMHF_INJECTED))   ) // It's a physical mouse event.
  480             g_PhysicalKeyState[aVK] = aKeyUp ? 0 : STATE_DOWN;
  481     }
  482     else // Keybd hook.
  483     {
  484         // Even if the below is set to false, the event might be reclassified as artificial later (though it
  485         // won't be logged as such).  See comments in KeybdEventIsPhysical() for details.
  486         is_artificial = aEventFlags & LLKHF_INJECTED; // LLKHF vs. LLMHF
  487 
  488         // Track physical state of keyboard & mouse buttons. Also, if it's a modifier, let another section
  489         // handle it because it's not as simple as just setting the value to true or false (e.g. if LShift
  490         // goes up, the state of VK_SHIFT should stay down if VK_RSHIFT is down, or up otherwise).
  491         // Also, even if this input event will wind up being suppressed (usually because of being
  492         // a hotkey), still update the physical state anyway, because we want the physical state to
  493         // be entirely independent of the logical state (i.e. we want the key to be reported as
  494         // physically down even if it isn't logically down):
  495         if (!kvk[aVK].as_modifiersLR && KeybdEventIsPhysical(aEventFlags, aVK, aKeyUp))
  496             g_PhysicalKeyState[aVK] = aKeyUp ? 0 : STATE_DOWN;
  497 
  498         // Pointer to the key record for the current key event.  Establishes this_key as an alias
  499         // for the array element in kvk or ksc that corresponds to the vk or sc, respectively.
  500         // I think the compiler can optimize the performance of reference variables better than
  501         // pointers because the pointer indirection step is avoided.  In any case, this must be
  502         // a true alias to the object, not a copy of it, because it's address (&this_key) is compared
  503         // to other addresses for equality further below.
  504     }
  505 
  506     // The following is done even if key history is disabled because sAltTabMenuIsVisible relies on it:
  507     pKeyHistoryCurr->event_type = is_ignored ? 'i' : (is_artificial ? 'a' : ' '); // v1.0.42.04: 'a' was added, but 'i' takes precedence over 'a'.
  508 
  509     // v1.0.43: Block the Win keys during journal playback to prevent keystrokes hitting the Start Menu
  510     // if the user accidentally presses one of those keys during playback.  Note: Keys other than Win
  511     // don't need to be blocked because the playback hook defers them until after playback.
  512     // Only block the down-events in case the user is physically holding down the key at the start
  513     // of playback but releases it during the Send (avoids Win key becoming logically stuck down).
  514     // This also serves to block Win shortcuts such as Win+R and Win+E during playback.
  515     // Also, it seems best to block artificial LWIN keystrokes too, in case some other script or
  516     // program tries to display the Start Menu during playback.
  517     if (g_BlockWinKeys && (aVK == VK_LWIN || aVK == VK_RWIN) && !aKeyUp)
  518         return SuppressThisKey;
  519 
  520     // v1.0.37.07: Cancel the alt-tab menu upon receipt of Escape so that it behaves like the OS's native Alt-Tab.
  521     // Even if is_ignored==true, it seems more flexible/useful to cancel the Alt-Tab menu upon receiving
  522     // an Escape keystroke of any kind.
  523     // Update: Must not handle Alt-Up here in a way similar to Esc-down in case the hook sent Alt-up to
  524     // dismiss its own menu. Otherwise, the shift key might get stuck down if Shift-Alt-Tab was in effect.
  525     // Instead, the release-of-prefix-key section should handle it via its checks of this_key.it_put_shift_down, etc.
  526     if (sAltTabMenuIsVisible && aVK == VK_ESCAPE && !aKeyUp)
  527     {
  528         // When the alt-tab window is owned by the script (it is owned by csrss.exe unless the script
  529         // is the process that invoked the alt-tab window), testing shows that the script must be the
  530         // originator of the Escape keystroke.  Therefore, substitute a simulated keystroke for the
  531         // user's physical keystroke. It might be necessary to do this even if is_ignored==true because
  532         // a keystroke from some other script/process might not qualify as a valid means to cancel it.
  533         // UPDATE for v1.0.39: The escape handler below works only if the hook's thread invoked the
  534         // alt-tab window, not if the script's thread did via something like "Send {Alt down}{tab down}".
  535         // This is true even if the process ID is checked instead of the thread ID below.  I think this
  536         // behavior is due to the window obeying escape only when its own thread sends it.  This
  537         // is probably done to allow a program to automate the alt-tab menu without interference
  538         // from Escape keystrokes typed by the user.  Although this could probably be fixed by
  539         // sending a message to the main thread and having it send the Escape keystroke, it seems
  540         // best not to do this because:
  541         // 1) The ability to dismiss a script-invoked alt-tab menu with escape would vary depending on
  542         //    whether the keyboard hook is installed (i.e. it's inconsistent).
  543         // 2) It's more flexible to preserve the ability to protect the alt-tab menu from physical
  544         //    escape keystrokes typed by the user.  The script can simulate an escape key to explicitly
  545         //    close an alt-tab window it invoked (a simulated escape keystroke can apparently also close
  546         //    any alt-tab menu, even one invoked by physical keystrokes; but the converse isn't true).
  547         // 3) Lesser reason: Reduces code size and complexity.
  548         // UPDATE in 2019: Testing on Windows 7 and 10 indicate this does not apply to the more modern
  549         // versions of Alt-Tab, but it still applies if the classic Alt-Tab is restored via the registry.
  550         // However, on these OSes, the user is able to press Esc to dismiss our Alt-Tab.  Other scripts
  551         // (and presumably other processes) are *NOT* able to dismiss it by simulating Esc.
  552         HWND alt_tab_window;
  553         if ((alt_tab_window = FindWindow(_T("#32771"), NULL)) // There is an alt-tab window...
  554             && GetWindowThreadProcessId(alt_tab_window, NULL) == GetCurrentThreadId()) // ...and it's owned by the hook thread (not the main thread).
  555         {
  556             KeyEvent(KEYDOWN, VK_ESCAPE);
  557             // By definition, an Alt key should be logically down if the alt-tab menu is visible (even if it
  558             // isn't, sending an extra up-event seems harmless).  Releasing that Alt key seems best because:
  559             // 1) If the prefix key that pushed down the alt key is still physically held down and the user
  560             //    presses a new (non-alt-tab) suffix key to form a hotkey, it avoids any alt-key disruption
  561             //    of things such as MouseClick that that subroutine might due.
  562             // 2) If the user holds down the prefix, presses Escape to dismiss the menu, then presses an
  563             //    alt-tab suffix, testing shows that the existing alt-tab logic here in the hook will put
  564             //    alt or shift-alt back down if it needs to.
  565             KeyEvent(KEYUP, (g_modifiersLR_logical & MOD_RALT) ? VK_RMENU : VK_LMENU);
  566             return SuppressThisKey; // Testing shows that by contrast, the upcoming key-up on Escape doesn't require this logic.
  567         }
  568         // Otherwise, the alt-tab window doesn't exist or (more likely) it's owned by some other process
  569         // such as crss.exe.  Do nothing extra to avoid interfering with the native function of Escape or
  570         // any remappings or hotkeys assigned to Escape.  Also, do not set sAltTabMenuIsVisible to false
  571         // in any of the cases here because there is logic elsewhere in the hook that does that more
  572         // reliably; it takes into account things such as whether the Escape keystroke will be suppressed
  573         // due to being a hotkey).
  574     }
  575 
  576     bool sc_takes_precedence = ksc[aSC].sc_takes_precedence;
  577     // Check hook type too in case a script every explicitly specifies scan code zero as a hotkey:
  578     key_type &this_key = *((aHook == g_KeybdHook && sc_takes_precedence) ? (ksc + aSC) : (kvk + aVK));
  579 
  580     // Do this after above since AllowKeyToGoToSystem requires that sc be properly determined.
  581     // Another reason to do it after the above is due to the fact that KEY_PHYS_IGNORE permits
  582     // an ignored key to be considered physical input, which is handled above:
  583     if (is_ignored)
  584     {
  585         // This is a key sent by our own app that we want to ignore.
  586         // It's important never to change this to call the SuppressKey function because
  587         // that function would cause an infinite loop when the Numlock key is pressed,
  588         // which would likely hang the entire system:
  589         // UPDATE: This next part is for cases where more than one script is using the hook
  590         // simultaneously.  In such cases, it desirable for the KEYEVENT_PHYS() of one
  591         // instance to affect the down-state of the current prefix-key in the other
  592         // instances.  This check is done here -- even though there may be a better way to
  593         // implement it -- to minimize the chance of side-effects that a more fundamental
  594         // change might cause (i.e. a more fundamental change would require a lot more
  595         // testing, though it might also fix more things):
  596         if (aExtraInfo == KEY_PHYS_IGNORE && aKeyUp && pPrefixKey == &this_key)
  597         {
  598             this_key.is_down = false;
  599             this_key.down_performed_action = false;  // Seems best, but only for PHYS_IGNORE.
  600             pPrefixKey = NULL;
  601         }
  602         return AllowKeyToGoToSystem;
  603     }
  604 
  605     if (!aKeyUp) // Set defaults for this down event.
  606     {
  607         this_key.hotkey_down_was_suppressed = false;
  608         this_key.hotkey_to_fire_upon_release = HOTKEY_ID_INVALID;
  609         // Don't do the following because of the keyboard key-repeat feature.  In other words,
  610         // the NO_SUPPRESS_NEXT_UP_EVENT should stay pending even in the face of consecutive
  611         // down-events.  Even if it's possible for the flag to never be cleared due to never
  612         // reaching any of the parts that clear it (which currently seems impossible), it seems
  613         // inconsequential since by its very nature, this_key never consults the flag.
  614         // this_key.no_suppress &= ~NO_SUPPRESS_NEXT_UP_EVENT;
  615     }
  616 
  617     if (aHook == g_MouseHook)
  618     {
  619         // If no vk, there's no mapping for this key, so currently there's no way to process it.
  620         if (!aVK)
  621             return AllowKeyToGoToSystem;
  622         // Also, if the script is displaying a menu (tray, main, or custom popup menu), always
  623         // pass left-button events through -- even if LButton is defined as a hotkey -- so
  624         // that menu items can be properly selected.  This is necessary because if LButton is
  625         // a hotkey, it can't launch now anyway due to the script being uninterruptible while
  626         // a menu is visible.  And since it can't launch, it can't do its typical "MouseClick
  627         // left" to send a true mouse-click through as a replacement for the suppressed
  628         // button-down and button-up events caused by the hotkey.  Also, for simplicity this
  629         // is done regardless of which modifier keys the user is holding down since the desire
  630         // to fire mouse hotkeys while a context or popup menu is displayed seems too rare.
  631         //
  632         // Update for 1.0.37.05: The below has been extended to look for menus beyond those
  633         // supported by g_MenuIsVisible, namely the context menus of a MonthCal or Edit control
  634         // (even the script's main window's edit control's context menu).  It has also been
  635         // extended to include RButton because:
  636         // 1) Right and left buttons may have been swapped via control panel to take on each others' functions.
  637         // 2) Right-click is a valid way to select a context menu items (but apparently not popup or menu bar items).
  638         // 3) Right-click should invoke another instance of the context menu (or dismiss existing menu, depending
  639         //    on where the click occurs) if user clicks outside of our thread's existing context menu.
  640         HWND menu_hwnd;
  641         if (   (aVK == VK_LBUTTON || aVK == VK_RBUTTON) && (g_MenuIsVisible // Ordered for short-circuit performance.
  642                 || ((menu_hwnd = FindWindow(_T("#32768"), NULL))
  643                     && GetWindowThreadProcessId(menu_hwnd, NULL) == g_MainThreadID))   ) // Don't call GetCurrentThreadId() because our thread is different than main's.
  644         {
  645             // Bug-fix for v1.0.22: If "LControl & LButton::" (and perhaps similar combinations)
  646             // is a hotkey, the foreground window would think that the mouse is stuck down, at least
  647             // if the user clicked outside the menu to dismiss it.  Specifically, this comes about
  648             // as follows:
  649             // The wrong up-event is suppressed:
  650             // ...because down_performed_action was true when it should have been false
  651             // ...because the while-menu-was-displayed up-event never set it to false
  652             // ...because it returned too early here before it could get to that part further below.
  653             this_key.down_performed_action = false; // Seems ok in this case to do this for both aKeyUp and !aKeyUp.
  654             this_key.is_down = !aKeyUp;
  655             return AllowKeyToGoToSystem;
  656         }
  657     } // Mouse hook.
  658 
  659     // Any key-down event (other than those already ignored and returned from,
  660     // above) should probably be considered an attempt by the user to use the
  661     // prefix key that's currently being held down as a "modifier".  That way,
  662     // if pPrefixKey happens to also be a suffix, its suffix action won't fire
  663     // when the key is released, which is probably the correct thing to do 90%
  664     // or more of the time.  But don't consider the modifiers themselves to have
  665     // been modified by a prefix key, since that is almost never desirable:
  666     if (pPrefixKey && pPrefixKey != &this_key && !aKeyUp) // There is a prefix key being held down and the user has now pressed some other key.
  667         if (   (aHook == g_KeybdHook) ? !this_key.as_modifiersLR : pPrefixKey->as_modifiersLR   )
  668             pPrefixKey->was_just_used = AS_PREFIX; // Indicate that currently-down prefix key has been "used".
  669     // Formerly, the above was done only for keyboard hook, not the mouse.  This was because
  670     // most people probably would not want a prefix key's suffix-action to be stopped
  671     // from firing just because a non-hotkey mouse button was pressed while the key
  672     // was held down (i.e. for games).  But now a small exception to this has been made:
  673     // Prefix keys that are also modifiers (ALT/SHIFT/CTRL/WIN) will now not fire their
  674     // suffix action on key-up if they modified a mouse button event (since Ctrl-LeftClick,
  675     // for example, is a valid native action and we don't want to give up that flexibility).
  676 
  677     // WinAPI docs state that for both virtual keys and scan codes:
  678     // "If there is no translation, the return value is zero."
  679     // Therefore, zero is never a key that can be validly configured (and likely it's never received here anyway).
  680     // UPDATE: For performance reasons, this check isn't even done.  Even if sc and vk are both zero, both kvk[0]
  681     // and ksc[0] should have all their attributes initialized to FALSE so nothing should happen for that key
  682     // anyway.
  683     //if (!vk && !sc)
  684     //  return AllowKeyToGoToSystem;
  685 
  686     
  687 
  688     if (!this_key.used_as_prefix && !this_key.used_as_suffix)
  689     {
  690         // Fix for v1.1.31.02: This is done regardless of used_as to ensure it doesn't get "stuck down"
  691         // when a custom combination hotkey Suspends itself, thereby causing used_as to be reset to false.
  692         // Fix for v1.1.31.03: Done conditionally because its previous value is used below.  This affects
  693         // modifier keys as hotkeys, such as Shift::MsgBox.
  694         this_key.is_down = !aKeyUp;
  695         return AllowKeyToGoToSystem;
  696     }
  697 
  698     HotkeyIDType hotkey_id_with_flags = HOTKEY_ID_INVALID; // Set default.
  699     HotkeyVariant *firing_is_certain = NULL;               //
  700     HotkeyIDType hotkey_id_temp; // For informal/temp storage of the ID-without-flags.
  701 
  702     bool down_performed_action, was_down_before_up;
  703     if (aKeyUp)
  704     {
  705         // Save prior to reset.  These var's should only be used further below in conjunction with aKeyUp
  706         // being TRUE.  Otherwise, their values will be unreliable (refer to some other key, probably).
  707         was_down_before_up = this_key.is_down;
  708         down_performed_action = this_key.down_performed_action;  // Save prior to reset below.
  709         // Reset these values in preparation for the next call to this procedure that involves this key:
  710         this_key.down_performed_action = false;
  711         if (this_key.hotkey_to_fire_upon_release != HOTKEY_ID_INVALID)
  712         {
  713             hotkey_id_with_flags = this_key.hotkey_to_fire_upon_release;
  714             // The line below is done even though the down-event also resets it in case it is ever
  715             // possible for keys to generate multiple consecutive key-up events (faulty or unusual keyboards?)
  716             this_key.hotkey_to_fire_upon_release = HOTKEY_ID_INVALID;
  717         }
  718     }
  719     this_key.is_down = !aKeyUp;
  720     bool modifiers_were_corrected = false;
  721 
  722     if (aHook == g_KeybdHook)
  723     {
  724         // The below was added to fix hotkeys that have a neutral suffix such as "Control & LShift".
  725         // It may also fix other things and help future enhancements:
  726         if (this_key.as_modifiersLR)
  727         {
  728             // The neutral modifier "Win" is not currently supported.
  729             kvk[VK_CONTROL].is_down = kvk[VK_LCONTROL].is_down || kvk[VK_RCONTROL].is_down;
  730             kvk[VK_MENU].is_down = kvk[VK_LMENU].is_down || kvk[VK_RMENU].is_down;
  731             kvk[VK_SHIFT].is_down = kvk[VK_LSHIFT].is_down || kvk[VK_RSHIFT].is_down;
  732             // No longer possible because vk is translated early on from neutral to left-right specific:
  733             // I don't think these ever happen with physical keyboard input, but it might with artificial input:
  734             //case VK_CONTROL: kvk[sc == SC_RCONTROL ? VK_RCONTROL : VK_LCONTROL].is_down = !aKeyUp; break;
  735             //case VK_MENU: kvk[sc == SC_RALT ? VK_RMENU : VK_LMENU].is_down = !aKeyUp; break;
  736             //case VK_SHIFT: kvk[sc == SC_RSHIFT ? VK_RSHIFT : VK_LSHIFT].is_down = !aKeyUp; break;
  737         }
  738     }
  739     else // Mouse hook
  740     {
  741         // If the mouse hook is installed without the keyboard hook, update g_modifiersLR_logical
  742         // manually so that it can be referred to by the mouse hook after this point:
  743         if (!g_KeybdHook)
  744         {
  745             g_modifiersLR_logical = g_modifiersLR_logical_non_ignored = GetModifierLRState(true);
  746             modifiers_were_corrected = true;
  747         }
  748     }
  749 
  750     modLR_type modifiersLRnew;
  751 
  752     bool this_toggle_key_can_be_toggled = this_key.pForceToggle && *this_key.pForceToggle == NEUTRAL; // Relies on short-circuit boolean order.
  753 
  754     // Prior to considering whether to fire a hotkey, correct the hook's modifier state.
  755     // Although this is rarely needed, there are times when the OS disables the hook, thus
  756     // it is possible for it to miss keystrokes.  This should be done before pPrefixKey is
  757     // consulted below as pPrefixKey itself might be corrected if it is a standard modifier.
  758     // See comments in GetModifierLRState() for more info:
  759     if (!modifiers_were_corrected)
  760     {
  761         modifiers_were_corrected = true;
  762         GetModifierLRState(true);
  763     }
  764 
  765     ///////////////////////////////////////////////////////////////////////////////////////
  766     // CASE #1 of 4: PREFIX key has been pressed down.  But use it in this capacity only if
  767     // no other prefix is already in effect or if this key isn't a suffix.  Update: Or if
  768     // this key-down is the same as the prefix already down, since we want to be able to
  769     // a prefix when it's being used in its role as a modified suffix (see below comments).
  770     ///////////////////////////////////////////////////////////////////////////////////////
  771     if (this_key.used_as_prefix && !aKeyUp && (!pPrefixKey || !this_key.used_as_suffix || &this_key == pPrefixKey))
  772     {
  773         // v1.0.41: Even if this prefix key is non-suppressed (passes through to active window),
  774         // still call PrefixHasNoEnabledSuffixes() because don't want to overwrite the old value of
  775         // pPrefixKey (see comments in "else" later below).
  776         // v1.0.44: Added check for PREFIX_ACTUAL so that a PREFIX_FORCED prefix will be considered
  777         // a prefix even if it has no suffixes.  This fixes an unintentional change in v1.0.41 where
  778         // naked, neutral modifier hotkeys Control::, Alt::, and Shift:: started firing on press-down
  779         // rather than release as intended.  The PREFIX_FORCED facility may also provide the means to
  780         // introduce a new hotkey modifier such as an "up2" keyword that makes any key into a prefix
  781         // key even if it never acts as a prefix for other keys, which in turn has the benefit of firing
  782         // on key-up, but only if the no other key was pressed while the user was holding it down.
  783         bool has_no_enabled_suffixes;
  784         if (   !(has_no_enabled_suffixes = (this_key.used_as_prefix == PREFIX_ACTUAL)
  785             && Hotkey::PrefixHasNoEnabledSuffixes(sc_takes_precedence ? aSC : aVK, sc_takes_precedence))   )
  786         {
  787             // This check is necessary in cases such as the following, in which the "A" key continues
  788             // to repeat because pressing a mouse button (unlike pressing a keyboard key) does not
  789             // stop the prefix key from repeating:
  790             // $a::send, a
  791             // a & lbutton::
  792             if (&this_key != pPrefixKey)
  793             {
  794                 // Override any other prefix key that might be in effect with this one, in case the
  795                 // prior one, due to be old for example, was invalid somehow.  UPDATE: It seems better
  796                 // to leave the old one in effect to support the case where one prefix key is modifying
  797                 // a second one in its role as a suffix.  In other words, if key1 is a prefix and
  798                 // key2 is both a prefix and a suffix, we want to leave key1 in effect as a prefix,
  799                 // rather than key2.  Hence, a null-check was added in the above if-stmt:
  800                 pPrefixKey = &this_key;
  801                 // It should be safe to init this because even if the current key is repeating,
  802                 // it should be impossible to receive here the key-downs that occurred after
  803                 // the first, because there's a return-on-repeat check farther above (update: that check
  804                 // is gone now).  Even if that check weren't done, it's safe to reinitialize this to zero
  805                 // because on most (all?) keyboards & OSs, the moment the user presses another key while
  806                 // this one is held down, the key-repeating ceases and does not resume for
  807                 // this key (though the second key will begin to repeat if it too is held down).
  808                 // In other words, the fear that this would be wrongly initialized and thus cause
  809                 // this prefix's suffix-action to fire upon key-release seems unfounded.
  810                 // It seems easier (and may perform better than alternative ways) to init this
  811                 // here rather than say, upon the release of the prefix key:
  812                 this_key.was_just_used = 0; // Init to indicate it hasn't yet been used in its role as a prefix.
  813             }
  814         }
  815         //else this prefix has no enabled suffixes, so its role as prefix is also disabled.
  816         // Therefore, don't set pPrefixKey to this_key because don't want the following line
  817         // (in another section) to execute when a suffix comes in (there may be other reasons too,
  818         // such as not wanting to lose track of the previous prefix key in cases where the user is
  819         // holding down more than one prefix):
  820         // pPrefixKey->was_just_used = AS_PREFIX
  821 
  822         if (this_key.used_as_suffix) // v1.0.41: Added this check to avoid doing all of the below when unnecessary.
  823         {
  824             // This new section was added May 30, 2004, to fix scenarios such as the following example:
  825             // a & b::Msgbox a & b
  826             // $^a::MsgBox a
  827             // Previously, the ^a hotkey would only fire on key-up (unless it was registered, in which
  828             // case it worked as intended on the down-event).  When the user presses A, it's okay (and
  829             // probably desirable) to have recorded that event as a prefix-key-down event (above).
  830             // But in addition to that, we now check if this is a normal, modified hotkey that should
  831             // fire now rather than waiting for the key-up event.  This is done because it makes sense,
  832             // it's more correct, and also it makes the behavior of a hooked ^a hotkey consistent with
  833             // that of a registered ^a.
  834 
  835             // non_ignored is always used when considering whether a key combination is in place to
  836             // trigger a hotkey:
  837             modifiersLRnew = g_modifiersLR_logical_non_ignored;
  838             if (this_key.as_modifiersLR) // This will always be false if our caller is the mouse hook.
  839                 // Hotkeys are not defined to modify themselves, so look for a match accordingly.
  840                 modifiersLRnew &= ~this_key.as_modifiersLR;
  841             // For this case to be checked, there must be at least one modifier key currently down (other
  842             // than this key itself if it's a modifier), because if there isn't and this prefix is also
  843             // a suffix, its suffix action should only fire on key-up (i.e. not here, but later on).
  844             // UPDATE: In v1.0.41, an exception to the above is when a prefix is disabled via
  845             // has_no_enabled_suffixes, in which case it seems desirable for most uses to have its
  846             // suffix action fire on key-down rather than key-up.
  847             // UPDATE: Another exception was added so that the no-suppress prefix allows the key to function
  848             // as if the custom combination wasn't defined.  For example, ~x & y:: allows x:: to retain its
  849             // normal behaviour, firing the subroutine on key-down and blocking the keystroke.  This is more
  850             // useful and intuitive/consistent than the old behaviour, which was to fire the suffix hotkey
  851             // on key-up even though the key-down wasn't suppressed (unless either of the first two conditions
  852             // below were met).
  853             if (modifiersLRnew || has_no_enabled_suffixes || (this_key.no_suppress & NO_SUPPRESS_PREFIX))
  854             {
  855                 // Check hook type too in case a script every explicitly specifies scan code zero as a hotkey:
  856                 hotkey_id_with_flags = (aHook == g_KeybdHook && sc_takes_precedence)
  857                     ? Kscm(modifiersLRnew, aSC) : Kvkm(modifiersLRnew, aVK);
  858                 if (hotkey_id_with_flags & HOTKEY_KEY_UP) // And it's okay even if it's is HOTKEY_ID_INVALID.
  859                 {
  860                     // Queue it for later, which is done here rather than upon release of the key so that
  861                     // the user can release the key's modifiers before releasing the key itself, which
  862                     // is likely to happen pretty often. v1.0.41: This is done even if the hotkey is subject
  863                     // to #IfWin because it seems more correct to check those criteria at the actual time
  864                     // the key is released rather than now:
  865                     this_key.hotkey_to_fire_upon_release = hotkey_id_with_flags;
  866                     hotkey_id_with_flags = HOTKEY_ID_INVALID;
  867                 }
  868                 else // hotkey_id_with_flags is either HOTKEY_ID_INVALID or a valid key-down hotkey.
  869                 {
  870                     hotkey_id_temp = hotkey_id_with_flags & HOTKEY_ID_MASK;
  871                     if (hotkey_id_temp < Hotkey::sHotkeyCount)
  872                         this_key.hotkey_to_fire_upon_release = hotkey_up[hotkey_id_temp]; // Might assign HOTKEY_ID_INVALID.
  873                     // Since this prefix key is being used in its capacity as a suffix instead,
  874                     // hotkey_id_with_flags now contains a hotkey ready for firing later below.
  875                     // v1.0.41: Above is done even if the hotkey is subject to #IfWin because:
  876                     // 1) The down-hotkey's #IfWin criteria might be different from that of the up's.
  877                     // 2) It seems more correct to check those criteria at the actual time the key is
  878                     // released rather than now (and also probably reduces code size).
  879                 }
  880             }
  881             // Alt-tab need not be checked here (like it is in the similar section below) because all
  882             // such hotkeys use (or were converted at load-time to use) a modifier_vk, not a set of
  883             // modifiers or modifierlr's.
  884         } // if (this_key.used_as_suffix)
  885 
  886         if (hotkey_id_with_flags == HOTKEY_ID_INVALID)
  887         {
  888             if (has_no_enabled_suffixes)
  889             {
  890                 this_key.no_suppress |= NO_SUPPRESS_NEXT_UP_EVENT; // Since the "down" is non-suppressed, so should the "up".
  891                 pKeyHistoryCurr->event_type = _T('#'); // '#' to indicate this prefix key is disabled due to #IfWin criterion.
  892             }
  893             // In this case, a key-down event can't trigger a suffix, so return immediately.
  894             // If our caller is the mouse hook, both of the following will always be false:
  895             // this_key.as_modifiersLR
  896             // this_toggle_key_can_be_toggled
  897             if (this_key.as_modifiersLR || (this_key.no_suppress & NO_SUPPRESS_PREFIX)
  898                 || this_toggle_key_can_be_toggled || has_no_enabled_suffixes)
  899                 return AllowKeyToGoToSystem;
  900             // Mark this key as having been suppressed.  This currently doesn't have any known effect
  901             // since the change to tilde (~) handling in v1.0.95 (commit 161162b8), but may in future.
  902             // Search for "SEND_NOSUPPRESS_PREFIX_KEY_ON_RELEASE" for related comments.
  903             //#define SEND_NOSUPPRESS_PREFIX_KEY_ON_RELEASE
  904             // Without this next assignment, the following issues occur if the above line is uncommented:
  905             //   1) ~prefixkey:: allows just a key-up to pass through, without first sending a key-down as
  906             //      originally intended.
  907             //   2) #if false .. ~prefixkey:: causes the key-up to pass through when it should be suppressed.
  908             this_key.hotkey_down_was_suppressed = true;
  909             return SuppressThisKey;
  910         }
  911         //else valid suffix hotkey has been found; this will now fall through to Case #4 by virtue of aKeyUp==false.
  912     }
  913 
  914     //////////////////////////////////////////////////////////////////////////////////
  915     // CASE #2 of 4: SUFFIX key (that's not a prefix, or is one but has just been used
  916     // in its capacity as a suffix instead) has been released.
  917     // This is done before Case #3 for performance reasons.
  918     //////////////////////////////////////////////////////////////////////////////////
  919     // v1.0.37.05: Added "|| down_performed_action" to the final check below because otherwise a
  920     // script such as the following would send two M's for +b, one upon down and one upon up:
  921     // +b::Send, M
  922     // b & z::return
  923     // I don't remember exactly what the "pPrefixKey != &this_key" check is for below, but it is kept
  924     // to minimize the chance of breaking other things:
  925     bool fell_through_from_case2 = false; // Set default.
  926     if (this_key.used_as_suffix && aKeyUp && (pPrefixKey != &this_key || down_performed_action)) // Note: hotkey_id_with_flags might be already valid due to this_key.hotkey_to_fire_upon_release.
  927     {
  928         if (pPrefixKey == &this_key) // v1.0.37.05: Added so that scripts such as the example above don't leave pPrefixKey wrongly non-NULL.
  929             pPrefixKey = NULL;       // Also, it seems unnecessary to check this_key.it_put_alt_down and such like is done in Case #3.
  930         // If it did perform an action, suppress this key-up event.  Do this even
  931         // if this key is a modifier because it's previous key-down would have
  932         // already been suppressed (since this case is for suffixes that aren't
  933         // also prefixes), thus the key-up can be safely suppressed as well.
  934         // It's especially important to do this for keys whose up-events are
  935         // special actions within the OS, such as AppsKey, Lwin, and Rwin.
  936         // Toggleable keys are also suppressed here on key-up because their
  937         // previous key-down event would have been suppressed in order for
  938         // down_performed_action to be true.  UPDATE: Added handling for
  939         // NO_SUPPRESS_NEXT_UP_EVENT and also applied this next part to both
  940         // mouse and keyboard.
  941         // v1.0.40.01: It was observed that a hotkey that consists of a mouse button as a prefix and
  942         // a keyboard key as a suffix can cause sticking keys in rare cases.  For example, when
  943         // "MButton & LShift" is a hotkey, if you hold down LShift long enough for it to begin
  944         // auto-repeating then press MButton, the hotkey fires the next time LShift auto-repeats (since
  945         // pressing a mouse button doesn't stop a keyboard key from auto-repeating).  Fixing that type
  946         // of firing seems likely to break more things than it fixes.  But since it isn't fixed, when
  947         // the user releases LShift, the up-event is suppressed here, which causes the key to get
  948         // stuck down.  That could be fixed in the following ways, but all of them seem likely to break
  949         // more things than they fix, especially given the rarity that both a hotkey of this type would
  950         // exist and its mirror image does something useful that isn't a hotkey (for example, Shift+MButton
  951         // is a meaningful action in few if any applications):
  952         // 1) Don't suppress the physical release of a suffix key if that key is logically down (as reported
  953         //    by GetKeyState/GetAsyncKeyState): Seems too broad in scope because there might be cases where
  954         //    the script or user wants the key to stay logically down (e.g. Send {Shift down}{a down}).
  955         // 2) Same as #1 but limit the non-suppression to only times when the suffix key was logically down
  956         //    when its first qualified physical down-event came in.  This is definitely better but like
  957         //    #1, the uncertainty of breaking existing scripts and/or causing more harm than good seems too
  958         //    high.
  959         // 3) Same as #2 but limit it only to cases where the suffix key is a keyboard key and its prefix
  960         //    is a mouse key.  Although very selective, it doesn't mitigate the fact it might still do more
  961         //    harm than good and/or break existing scripts.
  962         // In light of the above, it seems best to keep this documented here as a known limitation for now.
  963         //
  964         // v1.0.28: The following check is done to support certain keyboards whose keys or scroll wheels
  965         // generate up events without first having generated any down-event for the key.  UPDATE: I think
  966         // this check is now also needed to allow fall-through in cases like "b" and "b up" both existing.
  967         if (!this_key.used_as_key_up)
  968         {
  969             bool suppress_up_event;
  970             if (this_key.no_suppress & NO_SUPPRESS_NEXT_UP_EVENT)
  971             {
  972                 suppress_up_event = false;
  973                 this_key.no_suppress &= ~NO_SUPPRESS_NEXT_UP_EVENT;  // This ticket has been used up.
  974             }
  975             else // the default is to suppress the up-event.
  976                 suppress_up_event = true;
  977             return (down_performed_action && suppress_up_event) ? SuppressThisKey : AllowKeyToGoToSystem;
  978         }
  979         //else continue checking to see if the right modifiers are down to trigger one of this
  980         // suffix key's key-up hotkeys.
  981         fell_through_from_case2 = true;
  982     }
  983 
  984     //////////////////////////////////////////////
  985     // CASE #3 of 4: PREFIX key has been released.
  986     //////////////////////////////////////////////
  987     if (this_key.used_as_prefix && aKeyUp) // If these are true, hotkey_id_with_flags should be valid only by means of this_key.hotkey_to_fire_upon_release.
  988     {
  989         if (pPrefixKey == &this_key)
  990             pPrefixKey = NULL;
  991         // Else it seems best to keep the old one in effect.  This could happen, for example,
  992         // if the user holds down prefix1, holds down prefix2, then releases prefix1.
  993         // In that case, we would want to keep the most recent prefix (prefix2) in effect.
  994         // This logic would fail to work properly in a case like this if the user releases
  995         // prefix2 but still has prefix1 held down.  The user would then have to release
  996         // prefix1 and press it down again to get the hook to realize that it's in effect.
  997         // This seems very unlikely to be something commonly done by anyone, so for now
  998         // it's just documented here as a limitation.
  999 
 1000         if (this_key.it_put_alt_down) // key pushed ALT down, or relied upon it already being down, so go up:
 1001         {
 1002             this_key.it_put_alt_down = false;
 1003             KeyEvent(KEYUP, VK_MENU);
 1004         }
 1005         if (this_key.it_put_shift_down) // similar to above
 1006         {
 1007             this_key.it_put_shift_down = false;
 1008             KeyEvent(KEYUP, VK_SHIFT);
 1009         }
 1010 
 1011         // Section added in v1.0.41:
 1012         // Fix for v1.0.44.04: Defer use of the ticket and avoid returning here if hotkey_id_with_flags is valid,
 1013         // which only happens by means of this_key.hotkey_to_fire_upon_release.  This fixes custom combination
 1014         // hotkeys whose composite hotkey is also present such as:
 1015         //LShift & ~LAlt::
 1016         //LAlt & ~LShift::
 1017         //LShift & ~LAlt up::
 1018         //LAlt & ~LShift up::
 1019         //ToolTip %A_ThisHotkey%
 1020         //return
 1021         if (hotkey_id_with_flags == HOTKEY_ID_INVALID && this_key.no_suppress & NO_SUPPRESS_NEXT_UP_EVENT)
 1022         {
 1023             this_key.no_suppress &= ~NO_SUPPRESS_NEXT_UP_EVENT;  // This ticket has been used up.
 1024             return AllowKeyToGoToSystem; // This should handle pForceToggle for us, suppressing if necessary.
 1025         }
 1026 
 1027         if (this_toggle_key_can_be_toggled) // Always false if our caller is the mouse hook.
 1028         {
 1029             // It's done this way because CapsLock, for example, is a key users often
 1030             // press quickly while typing.  I suspect many users are like me in that
 1031             // they're in the habit of not having releasing the CapsLock key quite yet
 1032             // before they resume typing, expecting it's new mode to be in effect.
 1033             // This resolves that problem by always toggling the state of a toggleable
 1034             // key upon key-down.  If this key has just acted in its role of a prefix
 1035             // to trigger a suffix action, toggle its state back to what it was before
 1036             // because the firing of a hotkey should not have the side-effect of also
 1037             // toggling the key:
 1038             // Toggle the key by replacing this key-up event with a new sequence
 1039             // of our own.  This entire-replacement is done so that the system
 1040             // will see all three events in the right order:
 1041             if (this_key.was_just_used == AS_PREFIX_FOR_HOTKEY) // If this is true, it's probably impossible for hotkey_id_with_flags to be valid by means of this_key.hotkey_to_fire_upon_release.
 1042             {
 1043                 KEYEVENT_PHYS(KEYUP, aVK, aSC); // Mark it as physical for any other hook instances.
 1044                 KeyEvent(KEYDOWNANDUP, aVK, aSC);
 1045                 return SuppressThisKey;
 1046             }
 1047 
 1048             // Otherwise, if it was used to modify a non-suffix key, or it was just
 1049             // pressed and released without any keys in between, don't suppress its up-event
 1050             // at all.  UPDATE: Don't return here if it didn't modify anything because
 1051             // this prefix might also be a suffix. Let later sections handle it then.
 1052             if (this_key.was_just_used == AS_PREFIX)
 1053                 return AllowKeyToGoToSystem;
 1054         }
 1055         else // It's not a toggleable key, or it is but it's being kept forcibly on or off.
 1056             // Seems safest to suppress this key if the user pressed any non-modifier key while it
 1057             // was held down.  As a side-effect of this, if the user holds down numlock, for
 1058             // example, and then presses another key that isn't actionable (i.e. not a suffix),
 1059             // the numlock state won't be toggled even it's normally configured to do so.
 1060             // This is probably the right thing to do in most cases.
 1061             // Older note:
 1062             // In addition, this suppression is relied upon to prevent toggleable keys from toggling
 1063             // when they are used to modify other keys.  For example, if "Capslock & A" is a hotkey,
 1064             // the state of the Capslock key should not be changed when the hotkey is pressed.
 1065             // Do this check prior to the below check (give it precedence).
 1066             if (this_key.was_just_used  // AS_PREFIX or AS_PREFIX_FOR_HOTKEY.
 1067                 && hotkey_id_with_flags == HOTKEY_ID_INVALID) // v1.0.44.04: Must check this because this prefix might be being used in its role as a suffix instead.
 1068             {
 1069                 if (this_key.as_modifiersLR) // Always false if our caller is the mouse hook.
 1070                     return AllowKeyToGoToSystem; // Win/Alt will be disguised if needed.
 1071                 // Otherwise:
 1072                 return (this_key.no_suppress & NO_SUPPRESS_PREFIX) ? AllowKeyToGoToSystem : SuppressThisKey;
 1073             }
 1074 
 1075         // v1.0.41: This spot cannot be reached when a disabled prefix key's up-action fires on
 1076         // key-down instead (via Case #1).  This is because upon release, that prefix key would be
 1077         // returned from in Case #2 (by virtue of its check of down_performed_action).
 1078 
 1079         // Since above didn't return, this key-up for this prefix key wasn't used in it's role
 1080         // as a prefix.  If it's not a suffix, we're done, so just return.  Don't do
 1081         // "DisguiseWinAlt" because we want the key's native key-up function to take effect.
 1082         // Also, allow key-ups for toggleable keys that the user wants to be toggleable to
 1083         // go through to the system, because the prior key-down for this prefix key
 1084         // wouldn't have been suppressed and thus this up-event goes with it (and this
 1085         // up-event is also needed by the OS, at least WinXP, to properly set the indicator
 1086         // light and toggle state):
 1087         if (!this_key.used_as_suffix)
 1088             // If our caller is the mouse hook, both of the following will always be false:
 1089             // this_key.as_modifiersLR
 1090             // this_toggle_key_can_be_toggled
 1091             return (this_key.as_modifiersLR || (this_key.no_suppress & NO_SUPPRESS_PREFIX)
 1092                 // The order on this line important; it relies on short-circuit boolean:
 1093                 || this_toggle_key_can_be_toggled) ? AllowKeyToGoToSystem : SuppressThisKey;
 1094 
 1095         // Since the above didn't return, this key is both a prefix and a suffix, but
 1096         // is currently operating in its capacity as a suffix.
 1097         // If this key wasn't thought to be down prior to this up-event, it's probably because
 1098         // it is registered with another prefix by RegisterHotkey().  In this case, the keyup
 1099         // should be passed back to the system rather than performing it's key-up suffix
 1100         // action.  UPDATE: This can't happen with a low-level hook.  But if there's another
 1101         // low-level hook installed that receives events before us, and it's not
 1102         // well-implemented (i.e. it sometimes sends ups without downs), this check
 1103         // may help prevent unexpected behavior.  UPDATE: The check "!this_key.used_as_key_up"
 1104         // is now done too so that an explicit key-up hotkey can operate even if the key wasn't
 1105         // thought to be down before. One thing this helps with is certain keyboards (e.g. some
 1106         // Dells) that generate only up events for some of their special keys but no down events,
 1107         // even when *no* keyboard management software is installed). Some keyboards also have
 1108         // scroll wheels that generate a stream of up events in one direction and down in the other.
 1109         if (!(was_down_before_up || this_key.used_as_key_up)) // Verified correct.
 1110             return AllowKeyToGoToSystem;
 1111         //else v1.0.37.05: Since no suffix action was triggered while it was held down, fall through
 1112         // rather than returning so that the key's own unmodified/naked suffix action will be considered.
 1113         // For example:
 1114         // a & b::
 1115         // a::   // This fires upon release of "a".
 1116     }
 1117 
 1118     ////////////////////////////////////////////////////////////////////////////////////////////////////
 1119     // CASE #4 of 4: SUFFIX key has been pressed down (or released if it's a key-up event, in which case
 1120     // it fell through from CASE #3 or #2 above).  This case can also happen if it fell through from
 1121     // case #1 (i.e. it already determined the value of hotkey_id_with_flags).
 1122     ////////////////////////////////////////////////////////////////////////////////////////////////////
 1123     bool fire_with_no_suppress = false; // Set default.
 1124 
 1125     if (pPrefixKey && (!aKeyUp || this_key.used_as_key_up) && hotkey_id_with_flags == HOTKEY_ID_INVALID) // Helps performance by avoiding all the below checking.
 1126     {
 1127         // Action here is considered first, and takes precedence since a suffix's ModifierVK/SC should
 1128         // take effect regardless of whether any win/ctrl/alt/shift modifiers are currently down, even if
 1129         // those modifiers themselves form another valid hotkey with this suffix.  In other words,
 1130         // ModifierVK/SC combos take precedence over normally-modified combos:
 1131         Hotkey *found_hk = NULL;
 1132         for (hotkey_id_temp = this_key.first_hotkey; hotkey_id_temp != HOTKEY_ID_INVALID; )
 1133         {
 1134             Hotkey &this_hk = *Hotkey::shk[hotkey_id_temp]; // hotkey_id_temp does not include flags in this case.
 1135             if (!(this_hk.mModifierVK || this_hk.mModifierSC))
 1136                 break; // Not a custom combo.
 1137             hotkey_id_temp = this_hk.mNextHotkey;
 1138             key_type &this_modifier_key = this_hk.mModifierVK ? kvk[this_hk.mModifierVK] : ksc[this_hk.mModifierSC];
 1139             // The following check supports the prefix+suffix pairs that have both an up hotkey and a down,
 1140             // such as:
 1141             //a & b::     ; Down.
 1142             //a & b up::  ; Up.
 1143             //MsgBox %A_ThisHotkey%
 1144             //return
 1145             if (this_modifier_key.is_down) // A prefix key qualified to trigger this suffix is down.
 1146             {
 1147                 if (this_hk.mKeyUp)
 1148                 {
 1149                     if (!aKeyUp) // Key-up hotkey but the event is a down-event.
 1150                     {
 1151                         // Queue the up-hotkey for later so that the user is free to release the
 1152                         // prefix key prior to releasing the suffix (which seems quite common and
 1153                         // thus desirable).  v1.0.41: This is done even if the hotkey is subject
 1154                         // to #IfWin because it seems more correct to check those criteria at the actual time
 1155                         // the key is released rather than now:
 1156                         this_key.hotkey_to_fire_upon_release = this_hk.mID;
 1157                         if (found_hk) // i.e. a previous iteration already found the down-event to fire.
 1158                             break;
 1159                         //else continue searching for the down hotkey that goes with this up (if any).
 1160                     }
 1161                     else // this hotkey is qualified to fire.
 1162                     {
 1163                         found_hk = &this_hk;
 1164                         break;
 1165                     }
 1166                 }
 1167                 else // This is a normal hotkey that fires on suffix-key-down.
 1168                 {
 1169                     if (!aKeyUp)
 1170                     {
 1171                         if (!found_hk) // Use the first one found (especially important when both "a & Control" and "a & LControl" are present).
 1172                             found_hk = &this_hk;
 1173                         // and continue searching for the up hotkey (if any) to queue up for firing upon the key's release).
 1174                     }
 1175                     //else this key-down hotkey can't fire because the current event is a up-event.
 1176                     // But continue searching for an up-hotkey in case this key is of the type that never
 1177                     // generates down-events (e.g. certain Dell keyboards).
 1178                 }
 1179             } // qualified prefix is down
 1180         } // for each prefix of this suffix
 1181         if (found_hk)
 1182         {
 1183             // Update pPrefixKey, even though it was probably already done close to the top of the
 1184             // function, just in case this hotkey uses a different prefix key (perhaps because there
 1185             // is currently more than one prefix being held down).
 1186             // Since the hook is now designed to receive only left/right specific modifier keys
 1187             // -- never the neutral keys -- never indicate that a neutral prefix key is down because
 1188             // then it would never be released properly by the other main prefix/suffix handling
 1189             // cases of the hook.  Instead, always identify which prefix key (left or right) is
 1190             // in effect:
 1191             switch (found_hk->mModifierVK)
 1192             {
 1193             case VK_SHIFT: pPrefixKey = kvk + (kvk[VK_RSHIFT].is_down ? VK_RSHIFT : VK_LSHIFT); break;
 1194             case VK_CONTROL: pPrefixKey = kvk + (kvk[VK_RCONTROL].is_down ? VK_RCONTROL : VK_LCONTROL); break;
 1195             case VK_MENU: pPrefixKey = kvk + (kvk[VK_RMENU].is_down ? VK_RMENU : VK_LMENU); break;
 1196             case 0: pPrefixKey = ksc + found_hk->mModifierSC; break;
 1197             default: pPrefixKey = kvk + found_hk->mModifierVK;
 1198             }
 1199             if (found_hk->mHookAction)
 1200                 hotkey_id_with_flags = found_hk->mHookAction;
 1201             else // Don't call the below for Alt-tab hotkeys and similar.
 1202             {
 1203                 hotkey_id_with_flags = found_hk->mID; // Flags not needed.
 1204                 if (   !(firing_is_certain = Hotkey::CriterionFiringIsCertain(hotkey_id_with_flags
 1205                     , aKeyUp, aExtraInfo, this_key.no_suppress, fire_with_no_suppress, &pKeyHistoryCurr->event_type))   )
 1206                     return AllowKeyToGoToSystem; // This should handle pForceToggle for us, suppressing if necessary.
 1207             }
 1208             hotkey_id_temp = hotkey_id_with_flags;
 1209             pPrefixKey->was_just_used = AS_PREFIX_FOR_HOTKEY;
 1210         }
 1211 
 1212         // Alt-tab: Alt-tab actions that require a prefix key are handled directly here rather than via
 1213         // posting a message back to the main window.  In part, this is because it would be difficult
 1214         // to design a way to tell the main window when to release the alt-key.
 1215         if (hotkey_id_temp == HOTKEY_ID_ALT_TAB || hotkey_id_temp == HOTKEY_ID_ALT_TAB_SHIFT)
 1216         {
 1217             // Not sure if it's necessary to set this in this case.  Review.
 1218             if (!aKeyUp)
 1219                 this_key.down_performed_action = true; // aKeyUp is known to be false due to an earlier check.
 1220         
 1221             if (   !(g_modifiersLR_logical & (MOD_LALT | MOD_RALT))   )  // Neither ALT key is down.
 1222                 // Note: Don't set the ignore-flag in this case because we want the hook to notice it.
 1223                 // UPDATE: It might be best, after all, to have the hook ignore these keys.  That's because
 1224                 // we want to avoid any possibility that other hotkeys will fire off while the user is
 1225                 // alt-tabbing (though we can't stop that from happening if they were registered with
 1226                 // RegisterHotkey).  In other words, since the
 1227                 // alt-tab window is in the foreground until the user released the substitute-alt key,
 1228                 // don't allow other hotkeys to be activated.  One good example that this helps is the case
 1229                 // where <key1> & rshift is defined as alt-tab but <key1> & <key2> is defined as shift-alt-tab.
 1230                 // In that case, if we didn't ignore these events, one hotkey might unintentionally trigger
 1231                 // the other.
 1232                 KeyEvent(KEYDOWN, VK_MENU);
 1233                 // And leave it down until a key-up event on the prefix key occurs.
 1234 
 1235             if ((aVK == VK_LCONTROL || aVK == VK_RCONTROL) && !aKeyUp)
 1236                 // Even though this suffix key would have been suppressed, it seems that the
 1237                 // OS's alt-tab functionality sees that it's down somehow and thus this is necessary
 1238                 // to allow the alt-tab menu to appear.  This doesn't need to be done for any other
 1239                 // modifier than Control, nor any normal key since I don't think normal keys
 1240                 // being in a down-state causes any problems with alt-tab:
 1241                 KeyEvent(KEYUP, aVK, aSC);
 1242 
 1243             // Update the prefix key's
 1244             // flag to indicate that it was this key that originally caused the alt-key to go down,
 1245             // so that we know to set it back up again when the key is released.  UPDATE: Actually,
 1246             // it's probably better if this flag is set regardless of whether ALT is already down.
 1247             // That way, in case it's state go stuck down somehow, it will be reset by an Alt-TAB
 1248             // (i.e. alt-tab will always behave as expected even if ALT was down before starting).
 1249             // Note: pPrefixKey must already be non-NULL or this couldn't be an alt-tab event:
 1250             pPrefixKey->it_put_alt_down = true;
 1251             if (hotkey_id_temp == HOTKEY_ID_ALT_TAB_SHIFT)
 1252             {
 1253                 if (   !(g_modifiersLR_logical & (MOD_LSHIFT | MOD_RSHIFT))   ) // Neither SHIFT key is down.
 1254                     KeyEvent(KEYDOWN, VK_SHIFT);  // Same notes apply to this key.
 1255                 pPrefixKey->it_put_shift_down = true;
 1256             }
 1257             // And this may do weird things if VK_TAB itself is already assigned a as a naked hotkey, since
 1258             // it will recursively call the hook, resulting in the launch of some other action.  But it's hard
 1259             // to imagine someone ever reassigning the naked VK_TAB key (i.e. with no modifiers).
 1260             // UPDATE: The new "ignore" method should prevent that.  Or in the case of low-level hook:
 1261             // keystrokes sent by our own app by default will not fire hotkeys.  UPDATE: Even though
 1262             // the LL hook will have suppressed this key, it seems that the OS's alt-tab menu uses
 1263             // some weird method (apparently not GetAsyncState(), because then our attempt to put
 1264             // it up would fail) to determine whether the shift-key is down, so we need to still do this:
 1265             else if (hotkey_id_temp == HOTKEY_ID_ALT_TAB) // i.e. it's not shift-alt-tab
 1266             {
 1267                 // Force it to be alt-tab as the user intended.
 1268                 if ((aVK == VK_LSHIFT || aVK == VK_RSHIFT) && !aKeyUp)  // Needed.  See above comments. vk == VK_SHIFT not needed.
 1269                     // If a shift key is the suffix key, this must be done every time,
 1270                     // not just the first:
 1271                     KeyEvent(KEYUP, aVK, aSC);
 1272                 // UPDATE: Don't do "else" because sometimes the opposite key may be down, so the
 1273                 // below needs to be unconditional:
 1274                 //else
 1275 
 1276                 // In the below cases, it's not necessary to put the shift key back down because
 1277                 // the alt-tab menu only disappears after the prefix key has been released (and
 1278                 // it's not realistic that a user would try to trigger another hotkey while the
 1279                 // alt-tab menu is visible).  In other words, the user will be releasing the
 1280                 // shift key anyway as part of the alt-tab process, so it's not necessary to put
 1281                 // it back down for the user here (the shift stays in effect as a prefix for us
 1282                 // here because it's sent as an ignore event -- but the prefix will be correctly
 1283                 // canceled when the user releases the shift key).
 1284                 if (g_modifiersLR_logical & MOD_LSHIFT)
 1285                     KeyEvent(KEYUP, VK_LSHIFT);
 1286                 if (g_modifiersLR_logical & MOD_RSHIFT)
 1287                     KeyEvent(KEYUP, VK_RSHIFT);
 1288             }
 1289             // Any down control key prevents alt-tab from working.  This is similar to
 1290             // what's done for the shift-key above, so see those comments for details.
 1291             if (g_modifiersLR_logical & MOD_LCONTROL)
 1292                 KeyEvent(KEYUP, VK_LCONTROL);
 1293             if (g_modifiersLR_logical & MOD_RCONTROL)
 1294                 KeyEvent(KEYUP, VK_RCONTROL);
 1295 
 1296             KeyEvent(KEYDOWNANDUP, VK_TAB);
 1297 
 1298             if (hotkey_id_temp == HOTKEY_ID_ALT_TAB_SHIFT && pPrefixKey->it_put_shift_down
 1299                 && ((aVK >= VK_NUMPAD0 && aVK <= VK_NUMPAD9) || aVK == VK_DECIMAL)) // dual-state numpad key.
 1300             {
 1301                 // In this case, if there is a numpad key involved, it's best to put the shift key
 1302                 // back up in between every alt-tab to avoid problems caused due to the fact that
 1303                 // the shift key being down would CHANGE the VK being received when the key is
 1304                 // released (due to the fact that SHIFT temporarily disables numlock).
 1305                 KeyEvent(KEYUP, VK_SHIFT);
 1306                 pPrefixKey->it_put_shift_down = false;  // Reset for next time since we put it back up already.
 1307             }
 1308             pKeyHistoryCurr->event_type = 'h'; // h = hook hotkey (not one registered with RegisterHotkey)
 1309             if (!aKeyUp)
 1310                 this_key.hotkey_down_was_suppressed = true;
 1311             return SuppressThisKey;
 1312         } // end of alt-tab section.
 1313         // Since above didn't return, this isn't a prefix-triggered alt-tab action (though it might be
 1314         // a non-prefix alt-tab action, which is handled later below).
 1315     } // end of section that searches for a suffix modified by the prefix that's currently held down.
 1316 
 1317     if (hotkey_id_with_flags == HOTKEY_ID_INVALID)  // Since above didn't find a hotkey, check if modifiers+this_key qualifies a firing.
 1318     {
 1319         modifiersLRnew = g_modifiersLR_logical_non_ignored;
 1320         if (this_key.as_modifiersLR)
 1321             // Hotkeys are not defined to modify themselves, so look for a match accordingly.
 1322             modifiersLRnew &= ~this_key.as_modifiersLR;
 1323         // Check hook type too in case a script every explicitly specifies scan code zero as a hotkey:
 1324         hotkey_id_with_flags = (aHook == g_KeybdHook && sc_takes_precedence)
 1325             ? Kscm(modifiersLRnew, aSC) : Kvkm(modifiersLRnew, aVK);
 1326         // Bug fix for v1.0.20: The below second attempt is no longer made if the current keystroke
 1327         // is a tab-down/up  This is because doing so causes any naked TAB that has been defined as
 1328         // a hook hotkey to incorrectly fire when the user holds down ALT and presses tab two or more
 1329         // times to advance through the alt-tab menu.  Here is the sequence:
 1330         // $TAB is defined as a hotkey in the script.
 1331         // User holds down ALT and presses TAB two or more times.
 1332         // The Alt-tab menu becomes visible on the first TAB keystroke.
 1333         // The $TAB hotkey fires on the second keystroke because of the below (now-fixed) logic.
 1334         // By the way, the overall idea behind the below might be considered faulty because
 1335         // you could argue that non-modified hotkeys should never be allowed to fire while ALT is
 1336         // down just because the alt-tab menu is visible.  However, it seems justified because
 1337         // the benefit (which I believe was originally and particularly that an unmodified mouse button
 1338         // or wheel hotkey could be used to advance through the menu even though ALT is artificially
 1339         // down due to support displaying the menu) outweighs the cost, which seems low since
 1340         // it would be rare that anyone would press another hotkey while they are navigating through
 1341         // the Alt-Tab menu.
 1342         if (hotkey_id_with_flags == HOTKEY_ID_INVALID && sAltTabMenuIsVisible && aVK != VK_TAB)
 1343         {
 1344             // Try again, this time without the ALT key in case the user is trying to
 1345             // activate an alt-tab related key (i.e. a special hotkey action such as AltTab
 1346             // that relies on the Alt key being logically but not physically down).
 1347             modifiersLRnew &= ~(MOD_LALT | MOD_RALT);
 1348             hotkey_id_with_flags = (aHook == g_KeybdHook && sc_takes_precedence)
 1349                 ? Kscm(modifiersLRnew, aSC) : Kvkm(modifiersLRnew, aVK);
 1350             // Fix for v1.0.28: If the ID isn't an alt-tab type, don't consider it to be valid.
 1351             // Someone pointed out that pressing Alt-Tab and then pressing ESC while still holding
 1352             // down ALT fired the ~Esc hotkey even when it should just dismiss the alt-tab menu.
 1353             // Note: Both of the below checks must be done because the high-order bits of the
 1354             // hotkey_id_with_flags might be set to indicate no-suppress, etc:
 1355             hotkey_id_temp = hotkey_id_with_flags & HOTKEY_ID_MASK;
 1356             if (!IS_ALT_TAB(hotkey_id_temp))
 1357                 hotkey_id_with_flags = HOTKEY_ID_INVALID; // Since it's not an Alt-tab action, don't fire this hotkey.
 1358         }
 1359 
 1360         if (hotkey_id_with_flags & HOTKEY_KEY_UP)
 1361         {
 1362             if (!aKeyUp) // Key-up hotkey but the event is a down-event.
 1363             {
 1364                 // Fixed for v1.1.33.01: Any key-up hotkey already found by the custom combo section
 1365                 // should take precedence over this hotkey.  This fixes "a up::" erroneously taking
 1366                 // precedence over "b & a up::" when "a::" is not defined, which resulted in either
 1367                 // firing the wrong hotkey or firing the right hotkey but not suppressing the key.
 1368                 if (this_key.hotkey_to_fire_upon_release == HOTKEY_ID_INVALID)
 1369                     this_key.hotkey_to_fire_upon_release = hotkey_id_with_flags; // See comments above in other occurrences of this line.
 1370                 // v1.1.33.03: ChangeHookState now avoids pairing an up hotkey with a more permissive
 1371                 // down hotkey; e.g. "<^a up" and "^a" won't be paired, since that would cause "<^a up"
 1372                 // to fire when RCtrl+A is pressed.  To support them both firing on LCtrl+A, this looks
 1373                 // for any key-down hotkey which might be elegible to fire.  It's okay if this hotkey
 1374                 // has no eligible variants, because Hotkey::CriterionFiringIsCertain will handle that.
 1375                 hotkey_id_with_flags = Hotkey::FindPairedHotkey(this_key.first_hotkey, g_modifiersLR_logical_non_ignored, false);
 1376             }
 1377             //else hotkey_id_with_flags contains the up-hotkey that is now eligible for firing.
 1378         }
 1379         else if (hotkey_id_with_flags != HOTKEY_ID_INVALID) // hotkey_id_with_flags is a valid key-down hotkey.
 1380         {
 1381             hotkey_id_temp = hotkey_id_with_flags & HOTKEY_ID_MASK;
 1382             if (aKeyUp)
 1383             {
 1384                 // Even though the key is being released, a hotkey should fire unconditionally because
 1385                 // the only way we can reach this exact point for a non-key-up hotkey is when it fell
 1386                 // through from Case #3, in which case this hotkey_id_with_flags is implicitly a key-up
 1387                 // hotkey if there is no actual explicit key-up hotkey for it.  UPDATE: It is now possible
 1388                 // to fall through from Case #2, so that is checked below.
 1389                 if (hotkey_id_temp < Hotkey::sHotkeyCount && hotkey_up[hotkey_id_temp] != HOTKEY_ID_INVALID) // Relies on short-circuit boolean order.
 1390                 {
 1391                     if (  fell_through_from_case2
 1392                         || !(firing_is_certain = Hotkey::CriterionFiringIsCertain(hotkey_id_with_flags, aKeyUp, aExtraInfo, this_key.no_suppress, fire_with_no_suppress, &pKeyHistoryCurr->event_type))  )
 1393                     {
 1394                         // The key-down hotkey isn't eligible for firing, so fall back to the key-up hotkey:
 1395                         hotkey_id_with_flags = hotkey_up[hotkey_id_temp];
 1396                     }
 1397                     //else: the key-down hotkey is eligible for firing, so leave hotkey_id_with_flags as-is
 1398                     // and SuppressThisKeyFunc() or AllowIt() will post both hotkey-down and hotkey-up,
 1399                     // allowing remappings and other hotkey down-up pairs to work.
 1400                 }
 1401                 else // Leave it at its former value unless case#2.  See comments above and below.
 1402                     // Fix for v1.0.44.09: Since no key-up counterpart was found above (either in hotkey_up[]
 1403                     // or via the HOTKEY_KEY_UP flag), don't fire this hotkey when it fell through from Case #2.
 1404                     // This prevents a hotkey like $^b from firing TWICE (once on down and again on up) when a
 1405                     // key-up hotkey with different modifiers also exists, such as "#b" and "#b up" existing with $^b.
 1406                     if (fell_through_from_case2)
 1407                         hotkey_id_with_flags = HOTKEY_ID_INVALID;
 1408             }
 1409             else // hotkey_id_with_flags contains the down-hotkey that is now eligible for firing. But check if there's an up-event to queue up for later.
 1410                 if (hotkey_id_temp < Hotkey::sHotkeyCount)
 1411                 {
 1412                     // Fixed for v1.1.33.01: Any key-up hotkey already found by the custom combo section
 1413                     // should take precedence over this hotkey.  This fixes "b & a up::" not suppressing
 1414                     // "a" when "a::" is defined but disabled by #If and "b & a::" is not defined.
 1415                     if (this_key.hotkey_to_fire_upon_release == HOTKEY_ID_INVALID)
 1416                         this_key.hotkey_to_fire_upon_release = hotkey_up[hotkey_id_temp];
 1417                 }
 1418         }
 1419 
 1420         // Check hotkey_id_with_flags again now that the above possibly changed it:
 1421         if (hotkey_id_with_flags == HOTKEY_ID_INVALID)
 1422         {
 1423             // Even though at this point this_key is a valid suffix, no actionable ModifierVK/SC
 1424             // or modifiers were pressed down, so just let the system process this normally
 1425             // (except if it's a toggleable key).  This case occurs whenever a suffix key (which
 1426             // is also a prefix) is released but the key isn't configured to perform any action
 1427             // upon key-release.  Currently, I think the only way a key-up event will result
 1428             // in a hotkey action is for the release of a naked/modifierless prefix key.
 1429             // Example of a configuration that would result in this case whenever Rshift alone
 1430             // is pressed then released:
 1431             // RControl & RShift = Alt-Tab
 1432             // RShift & RControl = Shift-Alt-Tab
 1433             if (aKeyUp)
 1434                 // These sequence is basically the same as the one used in Case #3
 1435                 // when a prefix key that isn't a suffix failed to modify anything
 1436                 // and was then released, so consider any modifications made here
 1437                 // or there for inclusion in the other one.  UPDATE: Since
 1438                 // the previous sentence is a bit obsolete, describe this better:
 1439                 // If it's a toggleable key that the user wants to allow to be
 1440                 // toggled, just allow this up-event to go through because the
 1441                 // previous down-event for it (in its role as a prefix) would not
 1442                 // have been suppressed:
 1443                 // NO_SUPPRESS_PREFIX can occur if it fell through from Case #3 but the right
 1444                 // modifier keys aren't down to have triggered a key-up hotkey:
 1445                 return (this_key.as_modifiersLR || (this_key.no_suppress & NO_SUPPRESS_PREFIX)
 1446                     // The following line was added for v1.0.37.02 to take into account key-up hotkeys,
 1447                     // the release of which should never be suppressed if it didn't actually fire the
 1448                     // up-hotkey (due to the wrong modifiers being down):
 1449                     || !this_key.used_as_prefix
 1450                     // The order on this line important; it relies on short-circuit boolean:
 1451                     || this_toggle_key_can_be_toggled) ? AllowKeyToGoToSystem : SuppressThisKey;
 1452                 // v1.0.37.02: Added !this_key.used_as_prefix for mouse hook too (see comment above).
 1453 
 1454             // For execution to have reached this point, the following must be true:
 1455             // 1) aKeyUp==false
 1456             // 2) this_key must be both a prefix and suffix, but be acting in its capacity as a suffix.
 1457             // 3) No hotkey is eligible to fire.
 1458             // Since no hotkey action will fire, and since this_key wasn't used as a prefix, I think that
 1459             // must mean that not all of the required modifiers aren't present.  For example:
 1460             // a & b::Run calc
 1461             // LShift & a:: Run Notepad
 1462             // In that case, if the 'a' key is pressed and released by itself, perhaps its native
 1463             // function should be performed by suppressing this key-up event, replacing it with a
 1464             // down and up of our own.  However, it seems better not to do this, for now, since this
 1465             // is really just a subset of allowing all prefixes to perform their native functions
 1466             // upon key-release their value of was_just_used is false, which is probably
 1467             // a bad idea in many cases (e.g. if user configures VK_VOLUME_MUTE button to be a
 1468             // prefix, it might be undesirable for the volume to be muted if the button is pressed
 1469             // but the user changes his mind and doesn't use it to modify anything, so just releases
 1470             // it (at least it seems that I do this).  In any case, this default behavior can be
 1471             // changed by explicitly configuring 'a', in the example above, to be "Send, a".
 1472             // Here's a more complete example:
 1473             // a & b:: Run Notepad
 1474             // LControl & a:: Run Calc
 1475             // a::Send a
 1476             // So in summary, by default a prefix key's native function is always suppressed except if it's
 1477             // a toggleable key such as num/caps/scroll-lock.
 1478             if (this_key.hotkey_to_fire_upon_release == HOTKEY_ID_INVALID)
 1479                 return AllowKeyToGoToSystem;
 1480             // Otherwise (v1.0.44): Since there is a hotkey to fire upon release (somewhat rare under these conditions),
 1481             // check if any of its criteria will allow it to fire, and if so whether that variant is non-suppressed.
 1482             // If it is, this down-even should be non-suppressed too (for symmetry).  This check isn't 100% reliable
 1483             // because the active/existing windows checked by the criteria might change before the user actually
 1484             // releases the key, but there doesn't seem any way around that.
 1485             Hotkey::CriterionFiringIsCertain(this_key.hotkey_to_fire_upon_release // firing_is_certain==false under these conditions, so no need to check it.
 1486                 , true  // Always a key-up since it will fire upon release.
 1487                 , aExtraInfo // May affect the result due to #InputLevel.  Assume the key-up's SendLevel will be the same as the key-down.
 1488                 , this_key.no_suppress // Unused and won't be altered because above is "true".
 1489                 , fire_with_no_suppress, NULL); // fire_with_no_suppress is the value we really need to get back from it.
 1490             this_key.hotkey_down_was_suppressed = !fire_with_no_suppress; // Fixed for v1.1.33.01: If this isn't set, the key-up won't be suppressed even after the key-down is.
 1491             return fire_with_no_suppress ? AllowKeyToGoToSystem : SuppressThisKey;
 1492         }
 1493         //else an eligible hotkey was found.
 1494     } // Final attempt to find hotkey based on suffix have the right combo of modifiers.
 1495 
 1496     // Since above didn't return, hotkey_id_with_flags is now a valid hotkey.  The only thing that can
 1497     // stop it from firing now is CriterionFiringIsCertain().
 1498 
 1499     // v1.0.41: Below should be done prior to the next section's "return AllowKeyToGoToSystem" so that the
 1500     // NO_SUPPRESS_NEXT_UP_EVENT ticket is used up rather than staying around to possibly take effect for
 1501     // a future key-up for which it wasn't intended.
 1502     // Handling for NO_SUPPRESS_NEXT_UP_EVENT was added because it seems more correct that key-up
 1503     // hotkeys should obey NO_SUPPRESS_NEXT_UP_EVENT too.  The absence of this might have been inconsequential
 1504     // due to other safety/redundancies; but it seems more maintainable this way.
 1505     if ((this_key.no_suppress & NO_SUPPRESS_NEXT_UP_EVENT) && aKeyUp)
 1506     {
 1507         fire_with_no_suppress = true; // In spite of this being a key-up, there may be circumstances in which this was already true due to action above.
 1508         this_key.no_suppress &= ~NO_SUPPRESS_NEXT_UP_EVENT; // This ticket has been used up, so remove it.
 1509     }
 1510 
 1511     // v1.0.41: This must be done prior to the setting of sDisguiseNextMenu below.
 1512     hotkey_id_temp = hotkey_id_with_flags & HOTKEY_ID_MASK;
 1513     if (hotkey_id_temp < Hotkey::sHotkeyCount // i.e. don't call the below for Alt-tab hotkeys and similar.
 1514         && !firing_is_certain  // i.e. CriterionFiringIsCertain() wasn't already called earlier.
 1515         && !(firing_is_certain = Hotkey::CriterionFiringIsCertain(hotkey_id_with_flags, aKeyUp, aExtraInfo, this_key.no_suppress, fire_with_no_suppress, &pKeyHistoryCurr->event_type)))
 1516     {
 1517         if (pKeyHistoryCurr->event_type == 'i') // This non-zero SendLevel event is being ignored due to #InputLevel, so unconditionally pass it through, like with is_ignored.
 1518             return AllowKeyToGoToSystem;
 1519         // v1.1.08: Although the hotkey corresponding to this event is disabled, it may need to
 1520         // be suppressed if it has a counterpart (key-down or key-up) hotkey which is enabled.
 1521         // This can be broken down into two cases:
 1522         //  1) This is a key-up event and the key-down event was already suppressed.
 1523         //     Prior to v1.1.08, the key-up was passed through; this caused problems in a
 1524         //     few specific cases, such as XButton1 and XButton2 (which act when released).
 1525         //  2) This is a key-down event, but there is also a key-up hotkey which is enabled.
 1526         //     In that case, the documentation indicates the key-down will be suppressed.
 1527         //     Prior to v1.1.08, neither event was suppressed.
 1528         if (aKeyUp)
 1529             return this_key.hotkey_down_was_suppressed ? SuppressThisKey : AllowKeyToGoToSystem;
 1530         if (this_key.hotkey_to_fire_upon_release == HOTKEY_ID_INVALID)
 1531             return AllowKeyToGoToSystem;
 1532         // Otherwise, this is a key-down event with a corresponding key-up hotkey.
 1533         fire_with_no_suppress = false; // Reset it for the check below.
 1534         // This check should be identical to the section above dealing with hotkey_to_fire_upon_release:
 1535         Hotkey::CriterionFiringIsCertain(this_key.hotkey_to_fire_upon_release // firing_is_certain==false under these conditions, so no need to check it.
 1536             , true  // Always a key-up since it will fire upon release.
 1537             , aExtraInfo // May affect the result due to #InputLevel.  Assume the key-up's SendLevel will be the same as the key-down.
 1538             , this_key.no_suppress // Unused and won't be altered because above is "true".
 1539             , fire_with_no_suppress, NULL); // fire_with_no_suppress is the value we really need to get back from it.
 1540         if (fire_with_no_suppress)
 1541             return AllowKeyToGoToSystem;
 1542         // Both this down event and the corresponding up event should be suppressed, so
 1543         // unset the flag which was set by the first call to CriterionFiringIsCertain():
 1544         this_key.no_suppress &= ~NO_SUPPRESS_NEXT_UP_EVENT;
 1545         this_key.hotkey_down_was_suppressed = true;
 1546         return SuppressThisKey;
 1547     }
 1548     hotkey_id_temp = hotkey_id_with_flags & HOTKEY_ID_MASK; // Update in case CriterionFiringIsCertain() changed the naked/raw ID.
 1549 
 1550     // Now above has ensured that everything is in place for an action to be performed.
 1551     // Determine the final ID at this late stage to improve maintainability:
 1552     HotkeyIDType hotkey_id_to_fire = hotkey_id_temp;
 1553 
 1554     // Check if the WIN or ALT key needs to be masked:
 1555     if (   (g_modifiersLR_logical & (MOD_LALT|MOD_RALT|MOD_LWIN|MOD_RWIN)) // ALT and/or WIN is down.
 1556         && !fire_with_no_suppress // This hotkey will be suppressed (hotkeys with ~no-suppress should not require masking).
 1557         && (sUndisguisedMenuInEffect || aHook == g_MouseHook)   ) // Menu has not already been disguised (as tracked by the keyboard hook), or this is the mouse hook, which may require masking anyway.
 1558     {
 1559         // If only a windows key was held down to activate this hotkey, suppress the next win-up
 1560         // event so that the Start Menu won't appear.  The appearance of the Start Menu would be
 1561         // caused by the fact that the hotkey's suffix key was suppressed, therefore the OS doesn't
 1562         // see that the WIN key "modified" anything while it was held down.
 1563         // Although having other modifiers present prevents the Start Menu from appearing, that's
 1564         // handled by later checks since the WIN key can auto-repeat, putting an unmodified WIN
 1565         // back into effect after the other mods are released.  This only happens if the WIN key
 1566         // is the most recently pressed physical key, such as if this hotkey is a mouse button.
 1567         // When the user finally releases the WIN key, that release will be disguised if called
 1568         // for by the logic below and in AllowIt().
 1569         if (   (g_modifiersLR_logical & (MOD_LWIN|MOD_RWIN)) // One or both are down and may require disguising.
 1570             && ((g_modifiersLR_physical & (MOD_LWIN|MOD_RWIN)) // Always disguise if physically down, for backward compatibility.
 1571                 || Hotkey::HotkeyRequiresModLR(hotkey_id_to_fire, MOD_LWIN|MOD_RWIN))   ) // If not physically down, avoid masking hotkeys which could be intended to send {LWin up}, such as for AppsKey::RWin.
 1572         {
 1573             sDisguiseNextMenu = true;
 1574             // An earlier stage has ensured that the keyboard hook is installed for suppression of LWin/RWin if
 1575             // this is a mouse hotkey, because the sending of CTRL directly (here) would otherwise not suppress
 1576             // the Start Menu (though it does supress menu bar activation for ALT hotkeys, as described below).
 1577         }
 1578 
 1579         // For maximum reliability on the maximum range of systems, it seems best to do the above
 1580         // for ALT keys also, to prevent them from invoking the icon menu or menu bar of the
 1581         // foreground window (rarer than the Start Menu problem, above, I think).
 1582         // Update for v1.0.25: This is usually only necessary for hotkeys whose only modifier is ALT.
 1583         // For example, Shift-Alt hotkeys do not need it if Shift is pressed after Alt because Alt
 1584         // "modified" the shift so the OS knows it's not a naked ALT press to activate the menu bar.
 1585         // Conversely, if Shift is pressed prior to Alt, but released before Alt, I think the shift-up
 1586         // counts as a "modification" and the same rule applies.  However, if shift is released after Alt,
 1587         // that would activate the menu bar unless the ALT key is disguised below.  This issue does
 1588         // not apply to the WIN key above because apparently it is disguised automatically
 1589         // whenever some other modifier was involved with it in any way and at any time during the
 1590         // keystrokes that comprise the hotkey.
 1591         if (   !sDisguiseNextMenu // It's not already going to be disguised due to the section above or a previous hotkey.
 1592             && (g_modifiersLR_logical & (MOD_LALT|MOD_RALT)) // If RAlt==AltGr, it should never need disguising, but in that case LCtrl is also down, so ActiveWindowLayoutHasAltGr() isn't checked.
 1593             && !(g_modifiersLR_logical & (MOD_LCONTROL|MOD_RCONTROL)) // No need to mask if Ctrl is down (the key-repeat issue that affects the WIN key does not affect ALT).
 1594             && ((g_modifiersLR_physical & (MOD_LALT|MOD_RALT)) // Always disguise if physically down, for backward compatibility.
 1595                 || Hotkey::HotkeyRequiresModLR(hotkey_id_to_fire, MOD_LALT|MOD_RALT))   ) // If not physically down, avoid masking hotkeys which could be intended to send {Alt up}, such as for AppsKey::Alt.
 1596         {
 1597             if (g_KeybdHook)
 1598                 sDisguiseNextMenu = true;
 1599             else
 1600                 // Since no keyboard hook, no point in setting the variable because it would never be acted upon.
 1601                 // Instead, disguise the key now with a CTRL keystroke. Note that this is not done for
 1602                 // mouse buttons that use the WIN key as a prefix because it does not work reliably for them
 1603                 // (i.e. sometimes the Start Menu appears, even if two CTRL keystrokes are sent rather than one).
 1604                 // Therefore, as of v1.0.25.05, mouse button hotkeys that use only the WIN key as a modifier cause
 1605                 // the keyboard hook to be installed.  This determination is made during the hotkey loading stage.
 1606                 KeyEventMenuMask(KEYDOWNANDUP);
 1607         }
 1608     }
 1609 
 1610     switch (hotkey_id_to_fire)
 1611     {
 1612         case HOTKEY_ID_ALT_TAB_MENU_DISMISS: // This case must occur before HOTKEY_ID_ALT_TAB_MENU due to non-break.
 1613             if (!sAltTabMenuIsVisible)
 1614                 return AllowKeyToGoToSystem;  // Let the key do its native function.
 1615             // else fall through to the next case.
 1616         case HOTKEY_ID_ALT_TAB_MENU:  // These cases must occur before the Alt-tab ones due to conditional break.
 1617         case HOTKEY_ID_ALT_TAB_AND_MENU:
 1618         {
 1619             vk_type which_alt_down = 0;
 1620             if (g_modifiersLR_logical & MOD_LALT)
 1621                 which_alt_down = VK_LMENU;
 1622             else if (g_modifiersLR_logical & MOD_RALT)
 1623                 which_alt_down = VK_RMENU;
 1624 
 1625             if (sAltTabMenuIsVisible)  // Can be true even if which_alt_down is zero.
 1626             {
 1627                 if (hotkey_id_to_fire != HOTKEY_ID_ALT_TAB_AND_MENU) // then it is MENU or DISMISS.
 1628                 {
 1629                     // Since it is possible for the menu to be visible when neither ALT
 1630                     // key is down, always send an alt-up event if one isn't down
 1631                     // so that the menu is dismissed as intended:
 1632                     KeyEvent(KEYUP, which_alt_down ? which_alt_down : VK_MENU);
 1633                     if (this_key.as_modifiersLR && aVK != VK_LWIN && aVK != VK_RWIN && !aKeyUp)
 1634                         // Something strange seems to happen with the foreground app
 1635                         // thinking the modifier is still down (even though it was suppressed
 1636                         // entirely [confirmed!]).  For example, if the script contains
 1637                         // the line "lshift::AltTabMenu", pressing lshift twice would
 1638                         // otherwise cause the newly-activated app to think the shift
 1639                         // key is down.  Sending an extra UP here seems to fix that,
 1640                         // hopefully without breaking anything else.  Note: It's not
 1641                         // done for Lwin/Rwin because most (all?) apps don't care whether
 1642                         // LWin/RWin is down, and sending an up event might risk triggering
 1643                         // the start menu in certain hotkey configurations.  This policy
 1644                         // might not be the right one for everyone, however:
 1645                         KeyEvent(KEYUP, aVK); // Can't send sc here since it's not defined for the mouse hook.
 1646                     sAltTabMenuIsVisible = false;
 1647                     break;
 1648                 }
 1649                 // else HOTKEY_ID_ALT_TAB_AND_MENU, do nothing (don't break) because we want
 1650                 // the switch to fall through to the Alt-Tab case.
 1651             }
 1652             else // alt-tab menu is not visible
 1653             {
 1654                 // Unlike CONTROL, SHIFT, AND ALT, the LWIN/RWIN keys don't seem to need any
 1655                 // special handling to make them work with the alt-tab features.
 1656 
 1657                 bool vk_is_alt = aVK == VK_LMENU || aVK == VK_RMENU;  // Translated & no longer needed: || vk == VK_MENU;
 1658                 bool vk_is_shift = aVK == VK_LSHIFT || aVK == VK_RSHIFT;  // || vk == VK_SHIFT;
 1659                 bool vk_is_control = aVK == VK_LCONTROL || aVK == VK_RCONTROL;  // || vk == VK_CONTROL;
 1660 
 1661                 vk_type which_shift_down = 0;
 1662                 if (g_modifiersLR_logical & MOD_LSHIFT)
 1663                     which_shift_down = VK_LSHIFT;
 1664                 else if (g_modifiersLR_logical & MOD_RSHIFT)
 1665                     which_shift_down = VK_RSHIFT;
 1666                 else if (!aKeyUp && vk_is_shift)
 1667                     which_shift_down = aVK;
 1668 
 1669                 vk_type which_control_down = 0;
 1670                 if (g_modifiersLR_logical & MOD_LCONTROL)
 1671                     which_control_down = VK_LCONTROL;
 1672                 else if (g_modifiersLR_logical & MOD_RCONTROL)
 1673                     which_control_down = VK_RCONTROL;
 1674                 else if (!aKeyUp && vk_is_control)
 1675                     which_control_down = aVK;
 1676 
 1677                 bool shift_put_up = false;
 1678                 if (which_shift_down)
 1679                 {
 1680                     KeyEvent(KEYUP, which_shift_down);
 1681                     shift_put_up = true;
 1682                 }
 1683 
 1684                 bool control_put_up = false;
 1685                 if (which_control_down)
 1686                 {
 1687                     // In this case, the control key must be put up because the OS, at least
 1688                     // WinXP, knows the control key is down even though the down event was
 1689                     // suppressed by the hook.  So put it up and leave it up, because putting
 1690                     // it back down would cause it to be down even after the user releases
 1691                     // it (since the up-event of a hotkey is also suppressed):
 1692                     KeyEvent(KEYUP, which_control_down);
 1693                     control_put_up = true;
 1694                 }
 1695 
 1696                 // Alt-tab menu is not visible, or was not made visible by us.  In either case,
 1697                 // try to make sure it's displayed:
 1698                 // Don't put alt down if it's already down, it might mess up cases where the
 1699                 // ALT key itself is assigned to be one of the alt-tab actions:
 1700                 if (vk_is_alt)
 1701                     if (aKeyUp)
 1702                         // The system won't see it as down for the purpose of alt-tab, so remove this
 1703                         // modifier from consideration.  This is necessary to allow something like this
 1704                         // to work:
 1705                         // LAlt & WheelDown::AltTab
 1706                         // LAlt::AltTabMenu   ; Since LAlt is a prefix key above, it will be a key-up hotkey here.
 1707                         which_alt_down = 0;
 1708                     else // Because there hasn't been a chance to update g_modifiersLR_logical yet:
 1709                         which_alt_down = aVK;
 1710                 if (!which_alt_down)
 1711                     KeyEvent(KEYDOWN, VK_MENU);
 1712 
 1713                 KeyEvent(KEYDOWNANDUP, VK_TAB); // v1.0.28: KEYDOWNANDUP vs. KEYDOWN.
 1714 
 1715                 // Only put it put it back down if it wasn't the hotkey itself, because
 1716                 // the system would never have known it was down because the down-event
 1717                 // on the hotkey would have been suppressed.  And since the up-event
 1718                 // will also be suppressed, putting it down like this would result in
 1719                 // it being permanently down even after the user releases the key!:
 1720                 if (shift_put_up && !vk_is_shift) // Must do this regardless of the value of aKeyUp.
 1721                     KeyEvent(KEYDOWN, which_shift_down);
 1722                 
 1723                 // Update: Can't do this one because going down on control will instantly
 1724                 // dismiss the alt-tab menu, which we don't want if we're here.
 1725                 //if (control_put_up && !vk_is_control) // Must do this regardless of the value of aKeyUp.
 1726                 //  KeyEvent(KEYDOWN, which_control_down);
 1727 
 1728                 // At this point, the alt-tab menu has displayed and advanced by one icon
 1729                 // (to the next window in the z-order).  Rather than sending a shift-tab to
 1730                 // go back to the first icon in the menu, it seems best to leave it where
 1731                 // it is because usually the user will want to go forward at least one item.
 1732                 // Going backward through the menu is a lot more rare for most people.
 1733                 sAltTabMenuIsVisible = true;
 1734                 break;
 1735             }
 1736         }
 1737         case HOTKEY_ID_ALT_TAB:
 1738         case HOTKEY_ID_ALT_TAB_SHIFT:
 1739         {
 1740             // Since we're here, this ALT-TAB hotkey didn't have a prefix or it would have
 1741             // already been handled and we would have returned above.  Therefore, this
 1742             // hotkey is defined as taking effect only if the alt-tab menu is currently
 1743             // displayed, otherwise it will just be passed through to perform it's native
 1744             // function.  Example:
 1745             // MButton::AltTabMenu
 1746             // WheelDown::AltTab     ; But if the menu is displayed, the wheel will function normally.
 1747             // WheelUp::ShiftAltTab  ; But if the menu is displayed, the wheel will function normally.
 1748             if (!sAltTabMenuIsVisible)
 1749                 return AllowKeyToGoToSystem;
 1750 
 1751             // Unlike CONTROL, SHIFT, AND ALT, the LWIN/RWIN keys don't seem to need any
 1752             // special handling to make them work with the alt-tab features.
 1753 
 1754             // Must do this to prevent interference with Alt-tab when these keys
 1755             // are used to do the navigation.  Don't put any of these back down
 1756             // after putting them up since that would probably cause them to become
 1757             // stuck down due to the fact that the user's physical release of the
 1758             // key will be suppressed (since it's a hotkey):
 1759             if (!aKeyUp && (aVK == VK_LCONTROL || aVK == VK_RCONTROL || aVK == VK_LSHIFT || aVK == VK_RSHIFT))
 1760                 // Don't do the ALT key because it causes more problems than it solves
 1761                 // (in fact, it might not solve any at all).
 1762                 KeyEvent(KEYUP, aVK); // Can't send sc here since it's not defined for the mouse hook.
 1763 
 1764             // Even when the menu is visible, it's possible that neither of the ALT keys
 1765             // is down (such as if Ctrl+Alt+Tab was used, and perhaps other cases):
 1766             if (   !(g_modifiersLR_logical & (MOD_LALT | MOD_RALT))   // Neither ALT key is down 
 1767                 || (aKeyUp && (aVK == VK_LMENU || aVK == VK_RMENU))   ) // Or the suffix key for Alt-tab *is* an ALT key and it's being released: must push ALT down for upcoming TAB to work.
 1768                 KeyEvent(KEYDOWN, VK_MENU);
 1769                 // And never put it back up because that would dismiss the menu.
 1770             // Otherwise, use keystrokes to navigate through the menu:
 1771             bool shift_put_down = false;
 1772             if (hotkey_id_to_fire == HOTKEY_ID_ALT_TAB_SHIFT && !(g_modifiersLR_logical & (MOD_LSHIFT | MOD_RSHIFT))) // Neither SHIFT key is down.
 1773             {
 1774                 KeyEvent(KEYDOWN, VK_SHIFT);
 1775                 shift_put_down = true;
 1776             }
 1777             KeyEvent(KEYDOWNANDUP, VK_TAB);
 1778             if (shift_put_down)
 1779                 KeyEvent(KEYUP, VK_SHIFT);
 1780             break;
 1781         }
 1782         default:
 1783             // Notify the main thread (via its main window) of which hotkey has been pressed.
 1784             // Post the message rather than sending it, because Send would need
 1785             // SendMessageTimeout(), which is undesirable because the whole point of
 1786             // making this hook thread separate from the main thread is to have it be
 1787             // maximally responsive (especially to prevent mouse cursor lag).
 1788             // v1.0.42: The hotkey variant is not passed via the message below because
 1789             // upon receipt of the message, the variant is recalculated in case conditions
 1790             // have changed between msg-post and arrival.  See comments in the message loop for details.
 1791             // v1.0.42.01: the message is now posted at the latest possible moment to avoid
 1792             // situations in which the message arrives and is processed by the main thread
 1793             // before we finish processing the hotkey's final keystroke here.  This avoids
 1794             // problems with a script calling GetKeyState() and getting an inaccurate value
 1795             // because the hook thread is either pre-empted or is running in parallel
 1796             // (multiprocessor) and hasn't yet returned 1 or 0 to determine whether the final
 1797             // keystroke is suppressed or passed through to the active window.  Similarly, this solves
 1798             // the fact that previously, g_PhysicalKeyState was not updated for modifier keys until after
 1799             // the hotkey message was posted, which on some PCs caused the hotkey subroutine to see
 1800             // the wrong key state via KeyWait (which defaults to detecting the physical key state).
 1801             // For example, the following hotkeys would be a problem on certain PCs, presumably due to
 1802             // split-second timing where the hook thread gets preempted and the main thread gets a
 1803             // timeslice that allows it to launch a script subroutine before the hook can get
 1804             // another timeslice to finish up:
 1805             //$LAlt::
 1806             //if not GetKeyState("LAlt", "P")
 1807             //  ToolTip `nProblem 1`n
 1808             //return
 1809             //
 1810             //~LControl::
 1811             //if not (DllCall("GetAsyncKeyState", int, 0xA2) & 0x8000)
 1812             //    ToolTip `nProblem 2`n
 1813             //return
 1814             hotkey_id_to_post = hotkey_id_to_fire; // Set this only when it is certain that this ID should be sent to the main thread via msg.
 1815             if (firing_is_certain->mHotCriterion && HOT_IF_REQUIRES_EVAL(firing_is_certain->mHotCriterion->Type))
 1816             {
 1817                 // To avoid evaluating the expression twice, indicate to the main thread that the appropriate variant
 1818                 // has already been determined, by packing the variant's index into the high word of the param:
 1819                 hotkey_id_to_post |= firing_is_certain->mIndex << 16;
 1820             }
 1821             // Otherwise CriterionFiringIsCertain() might have returned a global variant (not necessarily the one
 1822             // that will actually fire), so if we ever decide to do the above for other criterion types rather than
 1823             // just re-evaluating the criterion later, must make sure not to send the mIndex of a global variant.
 1824             //if (firing_is_certain->mHotCriterion) // i.e. a specific variant has already been determined.
 1825     }
 1826 
 1827     pKeyHistoryCurr->event_type = 'h'; // h = hook hotkey (not one registered with RegisterHotkey)
 1828 
 1829     if (this_toggle_key_can_be_toggled && aKeyUp && this_key.used_as_prefix)
 1830     {
 1831         // In this case, since all the above conditions are true, the key-down
 1832         // event for this key-up (which fired a hotkey) would not have been
 1833         // suppressed.  Thus, we should toggle the state of the key back
 1834         // the what it was before the user pressed it (due to the policy that
 1835         // the natural function of a key should never take effect when that
 1836         // key is used as a hotkey suffix).  You could argue that instead
 1837         // of doing this, we should change *pForceToggle's value to make the
 1838         // key untoggleable whenever it's both a prefix and a naked
 1839         // (key-up triggered) suffix.  However, this isn't too much harder
 1840         // and has the added benefit of allowing the key to be toggled if
 1841         // a modifier is held down before it (e.g. alt-CapsLock would then
 1842         // be able to toggle the CapsLock key):
 1843         KEYEVENT_PHYS(KEYUP, aVK, aSC); // Mark it as physical for any other hook instances.
 1844         KeyEvent(KEYDOWNANDUP, aVK, aSC);
 1845         return SuppressThisKey;
 1846     }
 1847 
 1848     if (aKeyUp)
 1849     {
 1850         if (this_key.as_modifiersLR)
 1851             // Since this hotkey is fired on a key-up event, and since it's a modifier, must
 1852             // not suppress the key because otherwise the system's state for this modifier
 1853             // key would be stuck down due to the fact that the previous down-event for this
 1854             // key (which is presumably a prefix *and* a suffix) was not suppressed. UPDATE:
 1855             // For v1.0.28, if the new field hotkey_down_was_suppressed is true, also suppress
 1856             // this up event, one purpose of which is to allow a pair of remappings such
 1857             // as the following to display the Start Menu (because otherwise the non-suppressed
 1858             // Alt key events would prevent it):
 1859             // *LAlt up::Send {LWin up}
 1860             // *LAlt::Send {LWin down}
 1861             return this_key.hotkey_down_was_suppressed ? SuppressThisKey : AllowKeyToGoToSystem;
 1862 
 1863         if (fire_with_no_suppress) // Plus we know it's not a modifier since otherwise it would've returned above.
 1864         {
 1865             // Currently not supporting the mouse buttons for the above method, because KeyEvent()
 1866             // doesn't support the translation of a mouse-VK into a mouse_event() call.
 1867             // Such a thing might not work anyway because the hook probably received extra
 1868             // info such as the location where the mouse click should occur and other things.
 1869             // That info plus anything else relevant in MSLLHOOKSTRUCT would have to be
 1870             // translated into the correct info for a call to mouse_event().
 1871             if (aHook == g_MouseHook)
 1872                 return AllowKeyToGoToSystem;
 1873             // Otherwise, our caller is the keyboard hook.
 1874             
 1875             // The following section is currently disabled because it hasn't been working as intended
 1876             // for quite some time, and doesn't seem to be what users expect.  It also contains some
 1877             // contradictions; for instance, explicit key-up hotkeys such as the one in the example
 1878             // were excluded, apparently by design (since v1.0.36.02).  Explicit key-up hotkeys which
 1879             // are turned on after the key is pressed were erroneously included, but this has been
 1880             // fixed in the code below.  Implicit key-up hotkeys (which act on key-up because the key
 1881             // is used as a prefix key) did not work because this_key.hotkey_down_was_suppressed was
 1882             // not set when the prefix key was suppressed -- and later because it was not suppressed
 1883             // at all due to a change in v1.0.95 (commit 161162b8).
 1884             #ifdef SEND_NOSUPPRESS_PREFIX_KEY_ON_RELEASE
 1885             // Since this hotkey is firing on key-up but the user specified not to suppress its native
 1886             // function, send a down event to make up for the fact that the original down event was
 1887             // suppressed (since key-up hotkeys' down events are always suppressed because they
 1888             // are also prefix keys by definition).  UPDATE: Now that it is possible for a prefix key
 1889             // to be non-suppressed, this is done only if the prior down event wasn't suppressed.
 1890             // Note that for a pair of hotkeys such as:
 1891             // *capslock::Send {Ctrl Down}
 1892             // *~capslock up:: Send {Ctrl Up}  ; Specify tilde to allow caps lock to be toggled upon release.
 1893             // ... the following key history is produced (see note):
 1894             //14  03A   h   d   3.46    Caps Lock       
 1895             //A2  01D   i   d   0.00    Ctrl            
 1896             //14  03A   h   u   0.10    Caps Lock       
 1897             //14  03A   i   d   0.00    Caps Lock    <<< This actually came before the prior due to re-entrancy.
 1898             //A2  01D   i   u   0.00    Ctrl            
 1899             // Can't use this_toggle_key_can_be_toggled in this case. Relies on short-circuit boolean order:
 1900             bool suppress_to_prevent_toggle = this_key.pForceToggle && *this_key.pForceToggle != NEUTRAL;
 1901             // The following isn't checked as part of the above because this_key.was_just_used would
 1902             // never be true with hotkeys such as the Capslock pair shown above. That's because
 1903             // Capslock isn't a prefix in that case, it's just a suffix. Even if it were a prefix, it would
 1904             // never reach this point in the execution because places higher above return early if the value of
 1905             // this_key.was_just_used is AS_PREFIX/AS_PREFIX_FOR_HOTKEY.
 1906             // Used as either a prefix for a hotkey or just a plain modifier for another key.
 1907             // ... && (*this_key.pForceToggle != NEUTRAL || this_key.was_just_used);
 1908             if (this_key.hotkey_down_was_suppressed // Down was suppressed.
 1909                 && !(hotkey_id_with_flags & HOTKEY_KEY_UP) // v1.0.36.02: Prevents a hotkey such as "~5 up::" from generating double characters, regardless of whether it's paired with a "~5::" hotkey.
 1910                 && !suppress_to_prevent_toggle) // Mouse vs. keybd hook was already checked higher above.
 1911                 KeyEvent(KEYDOWN, aVK, aSC); // Substitute this to make up for the suppression (a check higher above has already determined that no_supress==true).
 1912                 // Now allow the up-event to go through.  The DOWN should always wind up taking effect
 1913                 // before the UP because the above should already have "finished" by now, since
 1914                 // it resulted in a recursive call to this function (using our hook-thread
 1915                 // rather than our main thread or some other thread):
 1916             return suppress_to_prevent_toggle ? SuppressThisKey : AllowKeyToGoToSystem;
 1917             #else
 1918             // Although it seems more sensible to suppress the key-up if the key-down was suppressed,
 1919             // it probably does no harm to let the key-up pass through, and in this case, it's exactly
 1920             // what the script is asking to happen (by prefixing the key-up hotkey with '~').
 1921             // this_key.pForceToggle isn't checked because AllowIt() handles that.
 1922             return AllowKeyToGoToSystem;
 1923             #endif
 1924         } // No suppression.
 1925     }
 1926     else // Key Down
 1927     {
 1928         // Do this only for DOWN (not UP) events that triggered an action:
 1929         this_key.down_performed_action = true;
 1930 
 1931         // Fix for v1.0.26: The below is now done only if pPrefixKey is a modifier.
 1932         // This is because otherwise, a prefix key would not perform its normal function when it
 1933         // modifies a hook suffix that doesn't belong to it.  For example, if "Capslock & A"
 1934         // and "MButton" are both hotkeys, clicking the middle button while holding down Capslock
 1935         // should turn CapsLock On or Off as expected.  This should be okay because
 1936         // AS_PREFIX_FOR_HOTKEY is set in other places it needs to be except the following,
 1937         // which are still correctly handled here:
 1938         // 1) Fall through from Case #1, in which case this hotkey is one that uses normal
 1939         //    modifiers (i.e. not something like "Capslock & A").
 1940         // 2) Any hotkey similar to Case #1 that isn't actually handled by Case #1.
 1941         // In both of the above situations, if pPrefixKey is not a modifier, it can't be
 1942         // part of the reason for this hotkey firing (because both of the above do not
 1943         // consider the state of any prefix keys other than those that happen to be modifiers).
 1944         // In other words, pPrefixKey is down only incidentally and has nothing to do with
 1945         // triggering this hotkey.
 1946         // Update pPrefixKey in case the currently-down prefix key is both a modifier
 1947         // and a normal prefix key (in which case it isn't stored in this_key's array
 1948         // of VK and SC prefixes, so this value wouldn't have yet been set).
 1949         // Update: The below is done even if pPrefixKey != &this_key, which happens
 1950         // when we reached this point after having fallen through from Case #1 above.
 1951         // The reason for this is that we just fired a hotkey action for this key,
 1952         // so we don't want it's action to fire again upon key-up:
 1953         if (pPrefixKey && pPrefixKey->as_modifiersLR)
 1954             pPrefixKey->was_just_used = AS_PREFIX_FOR_HOTKEY;
 1955 
 1956         if (fire_with_no_suppress)
 1957         {
 1958             // Since this hotkey is firing on key-down but the user specified not to suppress its native
 1959             // function, substitute an DOWN+UP pair of events for this event, since we want the
 1960             // DOWN to precede the UP.  It's necessary to send the UP because the user's physical UP
 1961             // will be suppressed automatically when this function is called for that event.
 1962             // UPDATE: The below method causes side-effects due to the fact that it is simulated
 1963             // input vs. physical input, e.g. when used with the Input command, which distinguishes
 1964             // between "ignored" and physical input.  Therefore, let this down event pass through
 1965             // and set things up so that the corresponding up-event is also not suppressed:
 1966             //KeyEvent(KEYDOWNANDUP, aVK, aSC);
 1967             // No longer relevant due to the above change:
 1968             // Now let it just fall through to suppress this down event, because we can't use it
 1969             // since doing so would result in the UP event having preceded the DOWN, which would
 1970             // be the wrong order.
 1971             this_key.no_suppress |= NO_SUPPRESS_NEXT_UP_EVENT;
 1972             return AllowKeyToGoToSystem;
 1973         }
 1974         else if (aVK == VK_LMENU || aVK == VK_RMENU)
 1975         {
 1976             // Fix for v1.1.26.01: Added KEY_BLOCK_THIS to suppress the Alt key-up, which fixes an issue
 1977             // which could be reproduced as follows:
 1978             //  - Test with an Alt-blocking hotkey such as LAlt::return or LAlt::LCtrl.
 1979             //  - Open Notepad and alt-tab away using the other Alt key or a remapping such as LCtrl::LAlt.
 1980             //  - Reactivate Notepad and note that the keyboard accelerators (underlined letters) are still
 1981             //    visible in the menus (usually).
 1982             //  - Press LAlt and the menus are activated once, even though LAlt is supposed to be blocked.
 1983             // Additionally, a Windows 10 check was added because the original issue this workaround was
 1984             // intended for doesn't appear to occur on Windows 10 (tested on 10.0.15063).  This check was
 1985             // removed for v1.1.27.00 to ensure consistent behaviour of AltGr hotkeys across OS versions.
 1986             // (Sending RAlt up on a layout with AltGr causes the system to send LCtrl up.)
 1987             // Testing on XP, Vista and 8.1 showed that the #LAlt issue below only occurred if the key-up
 1988             // was allowed to pass through to the active window.  It appeared to be a non-issue on Win 10
 1989             // even when the Alt key-up was passed through.
 1990             // Fix for v1.0.34: For some reason, the release of the ALT key here causes the Start Menu
 1991             // to appear instantly for the hotkey #LAlt (and probably #RAlt), even when the hotkey does
 1992             // nothing other than return.  This seems like an OS quirk since it doesn't conform to any
 1993             // known Start Menu activation sequence.  This happens only when neither Shift nor Control is
 1994             // down.  To work around it, send the menu-suppressing Control keystroke here.  Another one
 1995             // will probably be sent later when the WIN key is physically released, but it seems best
 1996             // for simplicity and avoidance of side-effects not to make this one prevent that one.
 1997             //if (   (g_modifiersLR_logical & (MOD_LWIN | MOD_RWIN))   // At least one WIN key is down.
 1998             //  && !(g_modifiersLR_logical & (MOD_LSHIFT | MOD_RSHIFT | MOD_LCONTROL | MOD_RCONTROL))   ) // But no SHIFT or CONTROL key is down to help us.
 1999             //  KeyEventMenuMask(KEYDOWNANDUP);
 2000             // Since this is a hotkey that fires on ALT-DOWN and it's a normal (suppressed) hotkey,
 2001             // send an up-event to "turn off" the OS's low-level handling for the alt key with
 2002             // respect to having it modify keypresses.  For example, the following hotkeys would
 2003             // fail to work properly without this workaround because the OS apparently sees that
 2004             // the ALT key is physically down even though it is not logically down:
 2005             // RAlt::Send f  ; Actually triggers !f, which activates the FILE menu if the active window has one.
 2006             // RAlt::Send {PgDn}  ; Fails to work because ALT-PgDn usually does nothing.
 2007             KeyEvent(KEYUP, aVK, aSC, NULL, false, KEY_BLOCK_THIS);
 2008         }
 2009     }
 2010     
 2011     // Otherwise:
 2012     if (!aKeyUp)
 2013         this_key.hotkey_down_was_suppressed = true;
 2014     return SuppressThisKey;
 2015 }
 2016 
 2017 
 2018 
 2019 LRESULT SuppressThisKeyFunc(const HHOOK aHook, LPARAM lParam, const vk_type aVK, const sc_type aSC, bool aKeyUp
 2020     , ULONG_PTR aExtraInfo, KeyHistoryItem *pKeyHistoryCurr, WPARAM aHotkeyIDToPost, WPARAM aHSwParamToPost, LPARAM aHSlParamToPost)
 2021 // Always use the parameter vk rather than event.vkCode because the caller or caller's caller
 2022 // might have adjusted vk, namely to make it a left/right specific modifier key rather than a
 2023 // neutral one.
 2024 {
 2025     if (pKeyHistoryCurr->event_type == ' ') // then it hasn't been already set somewhere else
 2026         pKeyHistoryCurr->event_type = 's';
 2027     // This handles the troublesome Numlock key, which on some (most/all?) keyboards
 2028     // will change state independent of the keyboard's indicator light even if its
 2029     // keydown and up events are suppressed.  This is certainly true on the
 2030     // MS Natural Elite keyboard using default drivers on WinXP.  SetKeyboardState()
 2031     // doesn't resolve this, so the only alternative to the below is to use the
 2032     // Win9x method of setting the Numlock state explicitly whenever the key is released.
 2033     // That might be complicated by the fact that the unexpected state change described
 2034     // here can't be detected by GetKeyboardState() and such (it sees the state indicated
 2035     // by the numlock light on the keyboard, which is wrong).  In addition, doing it this
 2036     // way allows Numlock to be a prefix key for something like Numpad7, which would
 2037     // otherwise be impossible because Numpad7 would become NumpadHome the moment
 2038     // Numlock was pressed down.  Note: this problem doesn't appear to affect Capslock
 2039     // or Scrolllock for some reason, possibly hardware or driver related.
 2040     // Note: the check for KEY_IGNORE isn't strictly necessary, but here just for safety
 2041     // in case this is ever called for a key that should be ignored.  If that were
 2042     // to happen and we didn't check for it, and endless loop of keyboard events
 2043     // might be caused due to the keybd events sent below.
 2044     if (aHook == g_KeybdHook)
 2045     {
 2046         KBDLLHOOKSTRUCT &event = *(PKBDLLHOOKSTRUCT)lParam;
 2047         if (aVK == VK_NUMLOCK && !aKeyUp && !IsIgnored(event.dwExtraInfo))
 2048         {
 2049             // This seems to undo the faulty indicator light problem and toggle
 2050             // the key back to the state it was in prior to when the user pressed it.
 2051             // Originally, I had two keydowns and before that some keyups too, but
 2052             // testing reveals that only a single key-down is needed.  UPDATE:
 2053             // It appears that all 4 of these key events are needed to make it work
 2054             // in every situation, especially the case when ForceNumlock is on but
 2055             // numlock isn't used for any hotkeys.
 2056             // Note: The only side-effect I've discovered of this method is that the
 2057             // indicator light can't be toggled after the program is exitted unless the
 2058             // key is pressed twice:
 2059             KeyEvent(KEYUP, VK_NUMLOCK);
 2060             KeyEvent(KEYDOWNANDUP, VK_NUMLOCK);
 2061             KeyEvent(KEYDOWN, VK_NUMLOCK);
 2062         }
 2063         UpdateKeybdState(event, aVK, aSC, aKeyUp, true);
 2064     }
 2065 
 2066 #ifdef ENABLE_KEY_HISTORY_FILE
 2067     if (g_KeyHistoryToFile)
 2068         KeyHistoryToFile(NULL, pKeyHistoryCurr->event_type, pKeyHistoryCurr->key_up
 2069             , pKeyHistoryCurr->vk, pKeyHistoryCurr->sc);  // A fairly low overhead operation.
 2070 #endif
 2071 
 2072     // These should be posted only at the last possible moment before returning in order to
 2073     // minimize the chance that the main thread will receive and process the message before
 2074     // our thread can finish updating key states and other maintenance.  This has been proven
 2075     // to be a problem on single-processor systems when the hook thread gets preempted
 2076     // before it can return.  Apparently, the fact that the hook thread is much higher in priority
 2077     // than the main thread is not enough to prevent the main thread from getting a timeslice
 2078     // before the hook thread gets back another (at least on some systems, perhaps due to their
 2079     // system settings of the same ilk as "favor background processes").
 2080     if (aHotkeyIDToPost != HOTKEY_ID_INVALID)
 2081     {
 2082         int input_level = InputLevelFromInfo(aExtraInfo);
 2083         PostMessage(g_hWnd, AHK_HOOK_HOTKEY, aHotkeyIDToPost, MAKELONG(pKeyHistoryCurr->sc, input_level)); // v1.0.43.03: sc is posted currently only to support the number of wheel turns (to store in A_EventInfo).
 2084         if (aKeyUp && hotkey_up[aHotkeyIDToPost & HOTKEY_ID_MASK] != HOTKEY_ID_INVALID)
 2085         {
 2086             // This is a key-down hotkey being triggered by releasing a prefix key.
 2087             // There's also a corresponding key-up hotkey, so fire it too:
 2088             PostMessage(g_hWnd, AHK_HOOK_HOTKEY, hotkey_up[aHotkeyIDToPost & HOTKEY_ID_MASK], MAKELONG(pKeyHistoryCurr->sc, input_level));
 2089         }
 2090     }
 2091     if (aHSwParamToPost != HOTSTRING_INDEX_INVALID)
 2092         PostMessage(g_hWnd, AHK_HOTSTRING, aHSwParamToPost, aHSlParamToPost);
 2093     return 1;
 2094 }
 2095 
 2096 
 2097 
 2098 LRESULT AllowIt(const HHOOK aHook, int aCode, WPARAM wParam, LPARAM lParam, const vk_type aVK, const sc_type aSC
 2099     , bool aKeyUp, ULONG_PTR aExtraInfo, KeyHistoryItem *pKeyHistoryCurr, WPARAM aHotkeyIDToPost)
 2100 // Always use the parameter vk rather than event.vkCode because the caller or caller's caller
 2101 // might have adjusted vk, namely to make it a left/right specific modifier key rather than a
 2102 // neutral one.
 2103 {
 2104     WPARAM hs_wparam_to_post = HOTSTRING_INDEX_INVALID; // Set default.
 2105     LPARAM hs_lparam_to_post; // Not initialized because the above is the sole indicator of whether its contents should even be examined.
 2106 
 2107     // Prevent toggleable keys from being toggled (if the user wanted that) by suppressing it.
 2108     // Seems best to suppress key-up events as well as key-down, since a key-up by itself,
 2109     // if seen by the system, doesn't make much sense and might have unwanted side-effects
 2110     // in rare cases (e.g. if the foreground app takes note of these types of key events).
 2111     // Don't do this for ignored keys because that could cause an endless loop of
 2112     // numlock events due to the keybd events that SuppressThisKey sends.
 2113     // It's a little more readable and comfortable not to rely on short-circuit
 2114     // booleans and instead do these conditions as separate IF statements.
 2115     if (aHook == g_MouseHook)
 2116     {
 2117         // Since a mouse button that is physically down is not necessarily logically down -- such as
 2118         // when the mouse button is a suppressed hotkey -- only update the logical state (which is the
 2119         // state the OS believes the key to be in) when this event is non-supressed (i.e. allowed to
 2120         // go to the system):
 2121 #ifdef FUTURE_USE_MOUSE_BUTTONS_LOGICAL
 2122         // THIS ENTIRE SECTION might never be necessary if it's true that GetAsyncKeyState() and
 2123         // GetKeyState() can retrieve the logical mouse button state on Windows NT/2000/XP, which are
 2124         // the only OSes that matter for this purpose because the hooks aren't supported on Win9x.
 2125         KBDLLHOOKSTRUCT &event = *(PMSDLLHOOKSTRUCT)lParam;  // For convenience, maintainability, and possibly performance.
 2126         switch (wParam)
 2127         {
 2128             case WM_LBUTTONUP: g_mouse_buttons_logical &= ~MK_LBUTTON; break;
 2129             case WM_RBUTTONUP: g_mouse_buttons_logical &= ~MK_RBUTTON; break;
 2130             case WM_MBUTTONUP: g_mouse_buttons_logical &= ~MK_MBUTTON; break;
 2131             // WM_NCXBUTTONUP is a click in the non-client area of a window.  MSDN implies this message can be
 2132             // received by the mouse hook  but it seems doubtful because its counterparts, such as WM_NCLBUTTONUP,
 2133             // are apparently never received:
 2134             case WM_NCXBUTTONUP:
 2135             case WM_XBUTTONUP:
 2136                 g_mouse_buttons_logical &= ~(   (HIWORD(event.mouseData)) == XBUTTON1 ? MK_XBUTTON1 : MK_XBUTTON2   );
 2137                 break;
 2138             case WM_LBUTTONDOWN: g_mouse_buttons_logical |= MK_LBUTTON; break;
 2139             case WM_RBUTTONDOWN: g_mouse_buttons_logical |= MK_RBUTTON; break;
 2140             case WM_MBUTTONDOWN: g_mouse_buttons_logical |= MK_MBUTTON; break;
 2141             case WM_NCXBUTTONDOWN:
 2142             case WM_XBUTTONDOWN:
 2143                 g_mouse_buttons_logical |= (HIWORD(event.mouseData) == XBUTTON1) ? MK_XBUTTON1 : MK_XBUTTON2;
 2144                 break;
 2145         }
 2146 #endif
 2147 #ifdef ENABLE_KEY_HISTORY_FILE
 2148         if (g_KeyHistoryToFile)
 2149             KeyHistoryToFile(NULL, pKeyHistoryCurr->event_type, pKeyHistoryCurr->key_up
 2150                 , pKeyHistoryCurr->vk, pKeyHistoryCurr->sc);  // A fairly low overhead operation.
 2151 #endif
 2152     }
 2153     else // Our caller is the keyboard hook.
 2154     {
 2155         KBDLLHOOKSTRUCT &event = *(PKBDLLHOOKSTRUCT)lParam;
 2156 
 2157         bool is_ignored = IsIgnored(event.dwExtraInfo);
 2158         if (!is_ignored)
 2159         {
 2160             if (kvk[aVK].pForceToggle) // Key is a toggleable key.
 2161             {
 2162                 // Dereference to get the global var's value:
 2163                 if (*(kvk[aVK].pForceToggle) != NEUTRAL) // Prevent toggle.
 2164                     return SuppressThisKeyFunc(aHook, lParam, aVK, aSC, aKeyUp, aExtraInfo, pKeyHistoryCurr, aHotkeyIDToPost);
 2165             }
 2166         }
 2167 
 2168         if ((Hotstring::sEnabledCount && !is_ignored) || g_input)
 2169             if (!CollectInput(event, aVK, aSC, aKeyUp, is_ignored, pKeyHistoryCurr, hs_wparam_to_post, hs_lparam_to_post)) // Key should be invisible (suppressed).
 2170                 return SuppressThisKeyFunc(aHook, lParam, aVK, aSC, aKeyUp, aExtraInfo, pKeyHistoryCurr, aHotkeyIDToPost, hs_wparam_to_post, hs_lparam_to_post);
 2171 
 2172         // Do these here since the above "return SuppressThisKey" will have already done it in that case.
 2173 #ifdef ENABLE_KEY_HISTORY_FILE
 2174         if (g_KeyHistoryToFile)
 2175             KeyHistoryToFile(NULL, pKeyHistoryCurr->event_type, pKeyHistoryCurr->key_up
 2176                 , pKeyHistoryCurr->vk, pKeyHistoryCurr->sc);  // A fairly low overhead operation.
 2177 #endif
 2178 
 2179         UpdateKeybdState(event, aVK, aSC, aKeyUp, false);
 2180 
 2181         // UPDATE: The Win-L and Ctrl-Alt-Del workarounds below are still kept in effect in spite of the
 2182         // anti-stick workaround done via GetModifierLRState().  This is because ResetHook() resets more
 2183         // than just the modifiers and physical key state, which seems appropriate since the user might
 2184         // be away for a long period of time while the computer is locked or the security screen is displayed.
 2185         // Win-L uses logical keys, unlike Ctrl-Alt-Del which uses physical keys (i.e. Win-L can be simulated,
 2186         // but Ctrl-Alt-Del must be physically pressed by the user):
 2187         if (   aVK == 'L' && !aKeyUp && (g_modifiersLR_logical == MOD_LWIN  // i.e. *no* other keys but WIN.
 2188             || g_modifiersLR_logical == MOD_RWIN || g_modifiersLR_logical == (MOD_LWIN | MOD_RWIN))
 2189             && g_os.IsWinXPorLater())
 2190         {
 2191             // Since the user has pressed Win-L with *no* other modifier keys held down, and since
 2192             // this key isn't being suppressed (since we're here in this function), the computer
 2193             // is about to be locked.  When that happens, the hook is apparently disabled or
 2194             // deinstalled until the user logs back in.  Because it is disabled, it will not be
 2195             // notified when the user releases the LWIN or RWIN key, so we should assume that
 2196             // it's now not in the down position.  This avoids it being thought to be down when the
 2197             // user logs back in, which might cause hook hotkeys to accidentally fire.
 2198             // Update: I've received an indication from a single Win2k user (unconfirmed from anyone
 2199             // else) that the Win-L hotkey doesn't work on Win2k.  AutoIt3 docs confirm this.
 2200             // Thus, it probably doesn't work on NT either.  So it's been changed to happen only on XP:
 2201             ResetHook(true); // We already know that *only* the WIN key is down.
 2202             // Above will reset g_PhysicalKeyState, especially for the windows keys and the 'L' key
 2203             // (in our case), in preparation for re-logon:
 2204         }
 2205 
 2206         // Although the delete key itself can be simulated (logical or physical), the user must be physically
 2207         // (not logically) holding down CTRL and ALT for the ctrl-alt-del sequence to take effect,
 2208         // which is why g_modifiersLR_physical is used vs. g_modifiersLR_logical (which is used above since
 2209         // it's different).  Also, this is now done for XP -- in addition to NT4 & Win2k -- in case XP is
 2210         // configured to display the NT/2k style security window instead of the task manager.  This is
 2211         // probably very common because whenever the welcome screen is disabled, that's the default behavior?:
 2212         // Control Panel > User Accounts > Use the welcome screen for fast and easy logon
 2213         if (   (aVK == VK_DELETE || aVK == VK_DECIMAL) && !aKeyUp         // Both of these qualify, see notes.
 2214             // Below: At least one CTRL key is physically down.  physical and ctrlaltdel_mask are combined
 2215             // because ctrlaltdel_mask excludes fake LCtrl (from AltGr) but might not be tracked as reliably.
 2216             && (g_modifiersLR_physical & g_modifiersLR_ctrlaltdel_mask & (MOD_LCONTROL | MOD_RCONTROL))
 2217             && (g_modifiersLR_physical & (MOD_LALT | MOD_RALT))         // At least one ALT key is physically down.
 2218             && !(g_modifiersLR_physical & (MOD_LSHIFT | MOD_RSHIFT))   )// Neither shift key is phys. down (WIN is ok).
 2219         {
 2220             // Similar to the above case except for Windows 2000.  I suspect it also applies to NT,
 2221             // but I'm not sure.  It seems safer to apply it to NT until confirmed otherwise.
 2222             // Note that Ctrl-Alt-Delete works with *either* delete key, and it works regardless
 2223             // of the state of Numlock (at least on XP, so it's probably that way on Win2k/NT also,
 2224             // though it would be nice if this too is someday confirmed).  Here's the key history
 2225             // someone for when the pressed ctrl-alt-del and then pressed esc to dismiss the dialog
 2226             // on Win2k (Win2k invokes a 6-button dialog, with choices such as task manager and lock
 2227             // workstation, if I recall correctly -- unlike XP which invokes task mgr by default):
 2228             // A4  038      d   21.24   Alt             
 2229             // A2  01D      d   0.00    Ctrl            
 2230             // A2  01D      d   0.52    Ctrl            
 2231             // 2E  053      d   0.02    Num Del         <-- notice how there's no following up event
 2232             // 1B  001      u   2.80    Esc             <-- notice how there's no preceding down event
 2233             // Other notes: On XP at least, shift key must not be down, otherwise Ctrl-Alt-Delete does
 2234             // not take effect.  Windows key can be down, however.
 2235             // Since the user will be gone for an unknown amount of time, it seems best just to reset
 2236             // all hook tracking of the modifiers to the "up" position.  The user can always press them
 2237             // down again upon return.  It also seems best to reset both logical and physical, just for
 2238             // peace of mind and simplicity:
 2239             ResetHook(true);
 2240             // The above will also reset g_PhysicalKeyState so that especially the following will not
 2241             // be thought to be physically down:CTRL, ALT, and DEL keys.  This is done in preparation
 2242             // for returning from the security screen.  The neutral keys (VK_MENU and VK_CONTROL)
 2243             // must also be reset -- not just because it's correct but because CollectInput() relies on it.
 2244         }
 2245 
 2246         // Bug-fix for v1.0.20: The below section was moved out of LowLevelKeybdProc() to here because
 2247         // sAltTabMenuIsVisible should not be set to true prior to knowing whether the current tab-down
 2248         // event will be suppressed.  This is because if it is suppressed, the menu will not become visible
 2249         // after all since the system will never see the tab-down event.
 2250         // Having this extra check here, in addition to the other(s) that set sAltTabMenuIsVisible to be
 2251         // true, allows AltTab and ShiftAltTab hotkeys to function even when the AltTab menu was invoked by
 2252         // means other than an AltTabMenu or AltTabAndMenu hotkey.  The alt-tab menu becomes visible only
 2253         // under these exact conditions, at least under WinXP:
 2254         if (aVK == VK_TAB && !aKeyUp && !sAltTabMenuIsVisible
 2255             && (g_modifiersLR_logical & (MOD_LALT | MOD_RALT)) // At least one ALT key is down.
 2256             && !(g_modifiersLR_logical & (MOD_LCONTROL | MOD_RCONTROL))) // Neither CTRL key is down.
 2257             sAltTabMenuIsVisible = true;
 2258 
 2259         if (modLR_type modLR = kvk[aVK].as_modifiersLR) // It's a modifier key.
 2260         {
 2261             // Don't do it this way because then the alt key itself can't be reliable used as "AltTabMenu"
 2262             // (due to ShiftAltTab causing sAltTabMenuIsVisible to become false):
 2263             //if (   sAltTabMenuIsVisible && !((g_modifiersLR_logical & MOD_LALT) || (g_modifiersLR_logical & MOD_RALT))
 2264             //  && !(aKeyUp && pKeyHistoryCurr->event_type == 'h')   )  // In case the alt key itself is "AltTabMenu"
 2265             if (sAltTabMenuIsVisible && // Release of Alt key (the check above confirmed it is a modifier):
 2266                 (aKeyUp && (aVK == VK_LMENU || aVK == VK_RMENU || aVK == VK_MENU))
 2267                 // In case the alt key itself is "AltTabMenu":
 2268                 && pKeyHistoryCurr->event_type != 'h' && pKeyHistoryCurr->event_type != 's'   )
 2269                 // It's important to reset in this case because if sAltTabMenuIsVisible were to
 2270                 // stay true and the user presses ALT in the future for a purpose other than to
 2271                 // display the Alt-tab menu, we would incorrectly believe the menu to be displayed:
 2272                 sAltTabMenuIsVisible = false;
 2273 
 2274             if (!aKeyUp) // Key-down.
 2275             {
 2276                 // sUndisguisedMenuInEffect can be true or false prior to this.
 2277                 //  LAlt (true) + LWin = both disguised (false).
 2278                 //  LWin (true) + LAlt = both disguised (false).
 2279                 if (modLR & (MOD_LWIN | MOD_RWIN))
 2280                     sUndisguisedMenuInEffect = !(g_modifiersLR_logical & ~(MOD_LWIN | MOD_RWIN)); // If any other modifier is down, disguise is already in effect.
 2281                 else if (modLR & (MOD_LALT | MOD_RALT))
 2282                     sUndisguisedMenuInEffect = !(g_modifiersLR_logical & (MOD_LCONTROL | MOD_RCONTROL)); // If Ctrl is down (including if this Alt is AltGr), disguise is already in effect.
 2283                 else // Shift or Ctrl: pressing either serves to disguise any previous Alt or Win.
 2284                     sUndisguisedMenuInEffect = false;
 2285             }
 2286             else if (sDisguiseNextMenu)
 2287             {
 2288                 // If a menu key is still physically down (or down due to an explicit Send, such as a remapping),
 2289                 // keep watching until it is released so that if key-repeat puts it back into effect, it will be
 2290                 // disguised again.  _non_ignored is used to ignore temporary modifier changes made during a
 2291                 // Send which aren't explicit, such as `Send x` temporarily releasing LWin/RWin.  Without this,
 2292                 // something like AppsKey::RWin would not work well with other hotkeys which Send.
 2293                 // v1.1.27.01: This section now also handles Ctrl-up and Shift-up events, which not only fail to
 2294                 // disguise Win but actually cause the Start menu to immediately appear even though the Win key
 2295                 // has not been released.  This only occurs if it was not already disguised by the Ctrl/Shift down
 2296                 // event; i.e. when an isolated Ctrl/Shift up event is received without a corresponding down event.
 2297                 // "Physical" events of this kind can be sent by the system when switching from a window with UK
 2298                 // layout to a window with US layout.  This is likely related to the UK layout having AltGr.
 2299                 // v1.1.33.03: This is now applied to LAlt/RAlt, to fix issues with hotkeys like !WheelUp:: in
 2300                 // programs with non-standard handling of the Alt key, such as Firefox.
 2301                 if (  !(g_modifiersLR_logical_non_ignored & (MOD_LWIN | MOD_RWIN | MOD_LALT | MOD_RALT))  )
 2302                 {
 2303                     if (modLR & (MOD_LCONTROL | MOD_RCONTROL | MOD_LSHIFT | MOD_RSHIFT))
 2304                     {
 2305                         // v1.1.27.01: Since this key being released is Ctrl/Shift and Win is not down, this must
 2306                         // be in combination with Alt, which can be disguised by this event.  By contrast, if the
 2307                         // Win key was down and sUndisguisedMenuInEffect == true (meaning there was no Ctrl/Shift
 2308                         // down event prior to this up event), this event needs to be disguised for the reason
 2309                         // described above.
 2310                         sUndisguisedMenuInEffect = false;
 2311                     }
 2312                     sDisguiseNextMenu = false;
 2313                 }
 2314                 // Since the below call to KeyEvent() calls the keybd hook recursively, a quick down-and-up
 2315                 // is all that is necessary to disguise the key.  This is because the OS will see that the
 2316                 // keystroke occurred while ALT or WIN is still down because we haven't done CallNextHookEx() yet.
 2317                 if (sUndisguisedMenuInEffect)
 2318                     KeyEventMenuMask(KEYDOWNANDUP); // This should also cause sUndisguisedMenuInEffect to be reset.
 2319             }
 2320             else // A modifier key was released and sDisguiseNextMenu was false.
 2321             {
 2322                 // Now either no menu keys are down or they have been disguised by this keyup event.
 2323                 // Key-repeat may put the menu key back into effect, but that will be detected above.
 2324                 sUndisguisedMenuInEffect = false;
 2325             }
 2326         } // It's a modifier key.
 2327         else // It's not a modifier key.
 2328         {
 2329             // Any key press or release serves to disguise the menu key.
 2330             sUndisguisedMenuInEffect = false;
 2331         }
 2332     } // Keyboard vs. mouse hook.
 2333 
 2334     // Since above didn't return, this keystroke is being passed through rather than suppressed.
 2335     if (g_HSResetUponMouseClick && (aVK == VK_LBUTTON || aVK == VK_RBUTTON)) // v1.0.42.03
 2336     {
 2337         *g_HSBuf = '\0';
 2338         g_HSBufLength = 0;
 2339     }
 2340     // In case CallNextHookEx() is high overhead or can sometimes take a long time to return,
 2341     // call it before posting the messages.  This solves conditions in which the main thread is
 2342     // able to launch a script subroutine before the hook thread can finish updating its key state.
 2343     // Search on AHK_HOOK_HOTKEY in this file for more comments.
 2344     LRESULT result_to_return = CallNextHookEx(aHook, aCode, wParam, lParam);
 2345     if (aHotkeyIDToPost != HOTKEY_ID_INVALID)
 2346     {
 2347         int input_level = InputLevelFromInfo(aExtraInfo);
 2348         PostMessage(g_hWnd, AHK_HOOK_HOTKEY, aHotkeyIDToPost, MAKELONG(pKeyHistoryCurr->sc, input_level)); // v1.0.43.03: sc is posted currently only to support the number of wheel turns (to store in A_EventInfo).
 2349         if (aKeyUp && hotkey_up[aHotkeyIDToPost & HOTKEY_ID_MASK] != HOTKEY_ID_INVALID)
 2350         {
 2351             // This is a key-down hotkey being triggered by releasing a prefix key.
 2352             // There's also a corresponding key-up hotkey, so fire it too:
 2353             PostMessage(g_hWnd, AHK_HOOK_HOTKEY, hotkey_up[aHotkeyIDToPost & HOTKEY_ID_MASK], MAKELONG(pKeyHistoryCurr->sc, input_level));
 2354         }
 2355     }
 2356     if (hs_wparam_to_post != HOTSTRING_INDEX_INVALID)
 2357         PostMessage(g_hWnd, AHK_HOTSTRING, hs_wparam_to_post, hs_lparam_to_post);
 2358     return result_to_return;
 2359 }
 2360 
 2361 
 2362 
 2363 bool CollectInput(KBDLLHOOKSTRUCT &aEvent, const vk_type aVK, const sc_type aSC, bool aKeyUp, bool aIsIgnored
 2364     , KeyHistoryItem *pKeyHistoryCurr, WPARAM &aHotstringWparamToPost, LPARAM &aHotstringLparamToPost)
 2365 // Caller is responsible for having initialized aHotstringWparamToPost to HOTSTRING_INDEX_INVALID.
 2366 // Returns true if the caller should treat the key as visible (non-suppressed).
 2367 // Always use the parameter vk rather than event.vkCode because the caller or caller's caller
 2368 // might have adjusted vk, namely to make it a left/right specific modifier key rather than a
 2369 // neutral one.
 2370 {
 2371     // Transcription is done only once for all layers, so do this if any layer requests it:
 2372     bool transcribe_modified_keys = false;
 2373 
 2374     for (auto *input = g_input; input; input = input->Prev)
 2375     {
 2376         if (input->InProgress() && input->IsInteresting(aEvent))
 2377         {
 2378             if (   aKeyUp && input->ScriptObject && input->ScriptObject->onKeyUp
 2379                 && ( ((input->KeySC[aSC] | input->KeyVK[aVK]) & INPUT_KEY_NOTIFY)
 2380                     || input->NotifyNonText && !((input->KeyVK[aVK]) & INPUT_KEY_IS_TEXT) )   )
 2381             {
 2382                 PostMessage(g_hWnd, AHK_INPUT_KEYUP, (WPARAM)input, (aSC << 16) | aVK);
 2383             }
 2384             if (aKeyUp && (input->KeySC[aSC] & INPUT_KEY_DOWN_SUPPRESSED))
 2385             {
 2386                 input->KeySC[aSC] &= ~INPUT_KEY_DOWN_SUPPRESSED;
 2387                 return false;
 2388             }
 2389             if (aKeyUp && (input->KeyVK[aVK] & INPUT_KEY_DOWN_SUPPRESSED))
 2390             {
 2391                 input->KeyVK[aVK] &= ~INPUT_KEY_DOWN_SUPPRESSED;
 2392                 return false;
 2393             }
 2394 
 2395             if (input->TranscribeModifiedKeys)
 2396                 transcribe_modified_keys = true;
 2397         }
 2398     }
 2399 
 2400     // The checks above suppress key-up if key-down was suppressed and the Input is still active.
 2401     // Otherwise, avoid suppressing key-up since it may result in the key getting stuck down.
 2402     // At the very least, this is needed for cases where a user presses a #z hotkey, for example,
 2403     // to initiate an Input.  When the user releases the LWIN/RWIN key during the input, that
 2404     // up-event should not be suppressed otherwise the modifier key would get "stuck down".  
 2405     if (aKeyUp)
 2406         return true;
 2407 
 2408     static vk_type sPendingDeadKeyVK = 0;
 2409     static sc_type sPendingDeadKeySC = 0; // Need to track this separately because sometimes default VK-to-SC mapping isn't correct.
 2410     static bool sPendingDeadKeyUsedShift = false;
 2411     static bool sPendingDeadKeyUsedAltGr = false;
 2412     
 2413     bool transcribe_key = true;
 2414     
 2415     // Don't unconditionally transcribe modified keys such as Ctrl-C because calling ToAsciiEx() on
 2416     // some such keys (e.g. Ctrl-LeftArrow or RightArrow if I recall correctly), disrupts the native
 2417     // function of those keys.  That is the reason for the existence of the
 2418     // g_input.TranscribeModifiedKeys option.
 2419     // Fix for v1.0.38: Below now uses g_modifiersLR_logical vs. g_modifiersLR_physical because
 2420     // it's the logical state that determines what will actually be produced on the screen and
 2421     // by ToAsciiEx() below.  This fixes the Input command to properly capture simulated
 2422     // keystrokes even when they were sent via hotkey such #c or a hotstring for which the user
 2423     // might still be holding down a modifier, such as :*:<t>::Test (if '>' requires shift key).
 2424     // It might also fix other issues.
 2425     if ((g_modifiersLR_logical & ~(MOD_LSHIFT | MOD_RSHIFT)) // At least one non-Shift modifier is down (Shift may also be down).
 2426         && !transcribe_modified_keys
 2427         && !((g_modifiersLR_logical & (MOD_LALT | MOD_RALT)) && (g_modifiersLR_logical & (MOD_LCONTROL | MOD_RCONTROL))))
 2428         // Since in some keybd layouts, AltGr (Ctrl+Alt) will produce valid characters (such as the @ symbol,
 2429         // which is Ctrl+Alt+Q in the German/IBM layout and Ctrl+Alt+2 in the Spanish layout), an attempt
 2430         // will now be made to transcribe all of the following modifier combinations:
 2431         // - Anything with no modifiers at all.
 2432         // - Anything that uses ONLY the shift key.
 2433         // - Anything with Ctrl+Alt together in it, including Ctrl+Alt+Shift, etc. -- but don't do
 2434         //   "anything containing the Alt key" because that causes weird side-effects with
 2435         //   Alt+LeftArrow/RightArrow and maybe other keys too).
 2436         // Older comment: If any modifiers except SHIFT are physically down, don't transcribe the key since
 2437         // most users wouldn't want that.  An additional benefit of this policy is that registered hotkeys will
 2438         // normally be excluded from the input (except those rare ones that have only SHIFT as a modifier).
 2439         // Note that ToAsciiEx() will translate ^i to a tab character, !i to plain i, and many other modified
 2440         // letters as just the plain letter key, which we don't want.
 2441         transcribe_key = false;
 2442 
 2443     // v1.1.28.00: active_window is set to the focused control, if any, so that the hotstring buffer is reset
 2444     // when the focus changes between controls, not just between windows.
 2445     // v1.1.28.01: active_window is left as the active window; the above is not done because it disrupts
 2446     // hotstrings when the first keypress causes a change in focus, such as to enter editing mode in Excel.
 2447     // See Get_active_window_keybd_layout macro definition for related comments.
 2448     HWND active_window = GetForegroundWindow(); // Set default in case there's no focused control.
 2449     HKL active_window_keybd_layout = GetKeyboardLayout(GetFocusedCtrlThread(NULL, active_window));
 2450 
 2451     // Univeral Windows Platform apps apparently have their own handling for dead keys:
 2452     //  - Dead key followed by Esc produces Chr(27), unlike non-UWP apps.
 2453     //  - Pressing a dead key in a UWP app does not leave it in the keyboard layout's buffer,
 2454     //    so to get the correct result here we must translate the dead key again, first.
 2455     //  - Pressing a non-dead key disregards any dead key which was placed into the buffer by
 2456     //    calling ToUnicodeEx, and it is left in the buffer.  To get the correct result for the
 2457     //    next call, we must NOT reinsert it into the buffer (see dead_key_sequence_complete).
 2458     static bool sUwpAppFocused = false;
 2459     static HWND sUwpHwndChecked = 0;
 2460     if (sUwpHwndChecked != active_window)
 2461     {
 2462         sUwpHwndChecked = active_window;
 2463         TCHAR class_name[28];
 2464         GetClassName(active_window, class_name, _countof(class_name));
 2465         sUwpAppFocused = !_tcsicmp(class_name, _T("ApplicationFrameWindow"));
 2466     }
 2467 
 2468     int char_count;
 2469     TCHAR ch[3] = { 0 };
 2470     BYTE key_state[256];
 2471     memcpy(key_state, g_PhysicalKeyState, 256);
 2472 
 2473     if (sPendingDeadKeyVK && sUwpAppFocused && aVK != VK_PACKET)
 2474     {
 2475         AdjustKeyState(key_state
 2476             , (sPendingDeadKeyUsedAltGr ? MOD_LCONTROL|MOD_RALT : 0)
 2477             | (sPendingDeadKeyUsedShift ? MOD_RSHIFT : 0)); // Left vs Right Shift probably doesn't matter in this context.
 2478         // If it turns out there was already a dead key in the buffer, the second call puts it back.
 2479         if (ToUnicodeOrAsciiEx(sPendingDeadKeyVK, sPendingDeadKeySC, key_state, ch, 0, active_window_keybd_layout) > 0)
 2480             ToUnicodeOrAsciiEx(sPendingDeadKeyVK, sPendingDeadKeySC, key_state, ch, 0, active_window_keybd_layout);
 2481         sPendingDeadKeyVK = 0; // Don't reinsert it afterward (see above).
 2482     }
 2483 
 2484     // Provide the correct logical modifier and CapsLock state for any translation below.
 2485     AdjustKeyState(key_state, g_modifiersLR_logical);
 2486     if (IsKeyToggledOn(VK_CAPITAL))
 2487         key_state[VK_CAPITAL] |= STATE_ON;
 2488     else
 2489         key_state[VK_CAPITAL] &= ~STATE_ON;
 2490 
 2491     if (aVK == VK_PACKET)
 2492     {
 2493         // VK_PACKET corresponds to a SendInput event with the KEYEVENTF_UNICODE flag.
 2494 #ifdef UNICODE
 2495         char_count = 1; // SendInput only supports a single 16-bit character code.
 2496         ch[0] = (WCHAR)aEvent.scanCode; // No translation needed.
 2497 #else
 2498         // Convert the Unicode character to ANSI, dropping any that can't be converted.
 2499         char_count = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, (WCHAR *)&aEvent.scanCode, 1, (CHAR *)ch, _countof(ch), NULL, NULL);
 2500 #endif
 2501     }
 2502     else if (transcribe_key)
 2503     {
 2504         char_count = ToUnicodeOrAsciiEx(aVK, aEvent.scanCode  // Uses the original scan code, not the adjusted "sc" one.
 2505             , key_state, ch, g_MenuIsVisible ? 1 : 0, active_window_keybd_layout);
 2506 
 2507         if ((g_modifiersLR_logical & (MOD_LCONTROL | MOD_RCONTROL)) == 0) // i.e. must not replace '\r' with '\n' if it is the result of Ctrl+M.
 2508         {
 2509             if (ch[0] == '\r')  // Translate \r to \n since \n is more typical and useful in Windows.
 2510                 ch[0] = '\n';
 2511             if (ch[1] == '\r')  // But it's never referred to if byte_count < 2
 2512                 ch[1] = '\n';
 2513         }
 2514     }
 2515     else
 2516     {
 2517         char_count = 0;
 2518     }
 2519 
 2520     // If Backspace is pressed after a dead key, ch[0] is the "dead" char and ch[1] is '\b'.
 2521     // Testing shows that this can be handled a number of ways (we only support 1 & 2):
 2522     // 1. Most Win32 apps perform backspacing and THEN insert ch[0].
 2523     // 2. UWP apps perform backspacing and discard the pending dead key.
 2524     // 3. VS2015 performs backspacing and leaves the dead key in the buffer.
 2525     // 4. MarkdownPad 2 prints the dead char as if Space was pressed, and does no backspacing.
 2526     // 5. Unconfirmed: some apps might do nothing; i.e. print the dead char and then delete it.
 2527     if (aVK == VK_BACK && char_count /*&& !g_modifiersLR_logical*/) // Modifier state is checked mostly for backward-compatibility.
 2528     {
 2529         if (sUwpAppFocused)
 2530         {
 2531             char_count = 0;
 2532             sPendingDeadKeyVK = 0;
 2533         }
 2534         else // Assume standard Win32 behaviour as described above.
 2535             --char_count; // Remove '\b' to simplify the backspacing and collection stages.
 2536     }
 2537     
 2538     if (!CollectInputHook(aEvent, aVK, aSC, ch, char_count, aIsIgnored))
 2539         return false; // Suppress.
 2540     
 2541     // More notes about dead keys: The dead key behavior of Enter/Space/Backspace is already properly
 2542     // maintained when an Input or hotstring monitoring is in effect.  In addition, keys such as the
 2543     // following already work okay (i.e. the user can press them in between the pressing of a dead
 2544     // key and it's finishing/base/trigger key without disrupting the production of diacritical letters)
 2545     // because ToAsciiEx() finds no translation-to-char for them:
 2546     // pgup/dn/home/end/ins/del/arrowkeys/f1-f24/etc.
 2547     // Note that if a pending dead key is followed by the press of another dead key (including itself),
 2548     // the sequence should be triggered and both keystrokes should appear in the active window.
 2549     // That case has been tested too, and works okay with the layouts tested so far.
 2550 
 2551     // Dead keys in Danish layout as they appear on a US English keyboard: Equals and Plus /
 2552     // Right bracket & Brace / probably others.
 2553 
 2554     // SUMMARY OF DEAD KEY ISSUE:
 2555     // Calling ToAsciiEx() on the dead key itself doesn't disrupt anything. The disruption occurs on the next key
 2556     // (for which the dead key is pending): ToAsciiEx() consumes previous/pending dead key, which causes the
 2557     // active window's call of ToAsciiEx() to fail to see a dead key. So unless the program reinserts the dead key
 2558     // after the call to ToAsciiEx() but before allowing the dead key's successor key to pass through to the
 2559     // active window, that window would see a non-diacritic like "u" instead of û.  In other words, the program
 2560     // "uses up" the dead key to populate its own hotstring buffer, depriving the active window of the dead key.
 2561     //
 2562     // JAVA ISSUE: Hotstrings are known to disrupt dead keys in Java apps on some systems (though not my XP one).
 2563     // I spent several hours on it but was unable to solve it using anything other than a Sleep(20) after the
 2564     // reinsertion of the dead key (and PhiLho reports that even that didn't fully solve it).  A Sleep here in the
 2565     // hook would probably do more harm than good, so is avoided for now.  Other approaches:
 2566     // 1) Send a simulated substitute for the successor key rather than allowing the hook to pass it through.
 2567     //    Maybe that would somehow put things in a better order for Java.  However, there might be side-effects to
 2568     //    that, such as in DirectX games.
 2569     // 2) Have main thread (rather than hook thread) reinsert the dead key and its successor key (hook would have
 2570     //    suppressed both), which allows the main thread to do a Sleep or MsgSleep.  Such a Sleep be more effective
 2571     //    because the main thread's priority is lower than that of the hook's, allowing better round-robin.
 2572     // 
 2573     // If this key is a dead key or there's a dead key pending and this incoming key is capable of
 2574     // completing/triggering it, do a workaround for the side-effects of ToAsciiEx().  This workaround
 2575     // allows dead keys to continue to operate properly in the user's foreground window, while still
 2576     // being capturable by the Input command and recognizable by any defined hotstrings whose
 2577     // abbreviations use diacritical letters:
 2578     bool dead_key_sequence_complete = sPendingDeadKeyVK && char_count > 0;
 2579     if (char_count < 0) // It's a dead key, and it doesn't complete a sequence since in that case char_count would be >= 1.
 2580     {
 2581         // Since above did not return, treat_as_visible must be true.
 2582         sPendingDeadKeyVK = aVK;
 2583         sPendingDeadKeySC = aSC;
 2584         sPendingDeadKeyUsedShift = g_modifiersLR_logical & (MOD_LSHIFT | MOD_RSHIFT);
 2585         // Detect AltGr as fully and completely as possible in case the current keyboard layout
 2586         // doesn't even have an AltGr key.  The section above which references sPendingDeadKeyUsedAltGr
 2587         // relies on this check having been done here.  UPDATE:
 2588         // v1.0.35.10: Allow Ctrl+Alt to be seen as AltGr too, which allows users to press Ctrl+Alt+Deadkey
 2589         // rather than AltGr+Deadkey.  It might also resolve other issues.  This change seems okay since
 2590         // the mere fact that this IS a dead key (as checked above) should mean that it's a deadkey made
 2591         // manifest through AltGr.
 2592         // Previous method:
 2593         //sPendingDeadKeyUsedAltGr = (g_modifiersLR_logical & (MOD_LCONTROL | MOD_RALT)) == (MOD_LCONTROL | MOD_RALT);
 2594         sPendingDeadKeyUsedAltGr = (g_modifiersLR_logical & (MOD_LCONTROL | MOD_RCONTROL))
 2595             && (g_modifiersLR_logical & (MOD_LALT | MOD_RALT));
 2596 
 2597         // Lexikos: Testing shows that calling ToUnicodeEx with the VK/SC of a dead key
 2598         // acts the same as actually pressing that key.  Calling it once when there is
 2599         // no pending dead key places the dead key in the keyboard layout's buffer and
 2600         // returns -1; calling it again consumes the dead key and returns either 1 or 2,
 2601         // depending on the keyboard layout.  For instance:
 2602         //  - Passing vkC0 twice with US-International gives the string "``".
 2603         //  - Passing vkBA twice with Neo2 gives just the combining version of "^".
 2604         // 
 2605         // Normally ToUnicodeEx would be called by the active window (after the hook
 2606         // returns), thus placing the dead key in the buffer.  Since our call above
 2607         // has already done that, we need to remove the dead key from the buffer
 2608         // before returning.  The benefits of this over the old method include:
 2609         //  - The hook is not called recursively since no extra keystrokes are generated.
 2610         //  - It's probably faster for the same reason.
 2611         //  - It works correctly even when there are multiple scripts with hotstrings,
 2612         //    all calling ToUnicodeEx in sequence.
 2613         //
 2614         // The other half of this workaround can be found by searching for "if (dead_key_sequence_complete)".
 2615         //
 2616         ToUnicodeOrAsciiEx(aVK, aEvent.scanCode, key_state, ch, g_MenuIsVisible ? 1 : 0, active_window_keybd_layout);
 2617         return true; // Visible.
 2618     }
 2619     
 2620     // Hotstrings monitor neither ignored input nor input that is invisible due to suppression by
 2621     // the Input command.  One reason for not monitoring ignored input is to avoid any chance of
 2622     // an infinite loop of keystrokes caused by one hotstring triggering itself directly or
 2623     // indirectly via a different hotstring:
 2624     if (Hotstring::sEnabledCount && !aIsIgnored)
 2625     {
 2626         switch (aVK)
 2627         {
 2628         case VK_LEFT:
 2629         case VK_RIGHT:
 2630         case VK_DOWN:
 2631         case VK_UP:
 2632         case VK_NEXT:
 2633         case VK_PRIOR:
 2634         case VK_HOME:
 2635         case VK_END:
 2636             // Reset hotstring detection if the user seems to be navigating within an editor.  This is done
 2637             // so that hotstrings do not fire in unexpected places.
 2638             if (g_HSBufLength)
 2639             {
 2640                 *g_HSBuf = '\0';
 2641                 g_HSBufLength = 0;
 2642             }
 2643             break;
 2644         case VK_BACK:
 2645             // v1.0.21: Only true (unmodified) backspaces are recognized by the below.  Another reason to do
 2646             // this is that ^backspace has a native function (delete word) different than backspace in many editors.
 2647             // Fix for v1.0.38: Below now uses g_modifiersLR_logical vs. physical because it's the logical state
 2648             // that determines whether the backspace behaves like an unmodified backspace.  This solves the issue
 2649             // of the Input command collecting simulated backspaces as real characters rather than recognizing
 2650             // them as a means to erase the previous character in the buffer.
 2651             if (!g_modifiersLR_logical && g_HSBufLength)
 2652                 g_HSBuf[--g_HSBufLength] = '\0';
 2653             // Fall through to the check below in case this {BS} completed a dead key sequence.
 2654             break;
 2655         }
 2656         if (char_count > 0
 2657             && !CollectHotstring(aEvent, ch, char_count, active_window, pKeyHistoryCurr, aHotstringWparamToPost, aHotstringLparamToPost))
 2658             return false; // Suppress.
 2659     }
 2660 
 2661     // Fix for v1.0.37.06: The following section was moved beneath the hotstring section so that
 2662     // the hotstring section has a chance to bypass reinsertion of the dead key below. This fixes
 2663     // wildcard hotstrings whose final character is diacritic, which would otherwise have the
 2664     // dead key reinserted below, which in turn would cause the hotstring's first backspace to fire
 2665     // the dead key (which kills the backspace, turning it into the dead key character itself).
 2666     // For example:
 2667     // :*:jsá::jsmith@somedomain.com
 2668     // On the Spanish (Mexico) keyboard layout, one would type accent (English left bracket) followed by
 2669     // the letter "a" to produce á.
 2670     if (dead_key_sequence_complete)
 2671     {
 2672         // Since our call to ToUnicodeOrAsciiEx above has removed the pending dead key from the
 2673         // buffer, we need to put it back for the active window or the next hook in the chain.
 2674         // This is not needed when ch (the character or characters produced by combining the dead
 2675         // key with the last keystroke) is being suppressed, since in that case we don't want the
 2676         // dead key back in the buffer.
 2677         ZeroMemory(key_state, 256);
 2678         AdjustKeyState(key_state
 2679             , (sPendingDeadKeyUsedAltGr ? MOD_LCONTROL|MOD_RALT : 0)
 2680             | (sPendingDeadKeyUsedShift ? MOD_RSHIFT : 0)); // Left vs Right Shift probably doesn't matter in this context.
 2681         TCHAR temp_ch[2];
 2682         ToUnicodeOrAsciiEx(sPendingDeadKeyVK, sPendingDeadKeySC, key_state, temp_ch, 0, active_window_keybd_layout);
 2683         sPendingDeadKeyVK = 0;
 2684     }
 2685 
 2686     return true; // Visible.
 2687 }
 2688 
 2689 
 2690 
 2691 bool CollectHotstring(KBDLLHOOKSTRUCT &aEvent, TCHAR ch[], int char_count, HWND active_window
 2692     , KeyHistoryItem *pKeyHistoryCurr, WPARAM &aHotstringWparamToPost, LPARAM &aHotstringLparamToPost)
 2693 {
 2694     bool suppress_hotstring_final_char = false; // Set default.
 2695 
 2696     if (active_window != g_HShwnd)
 2697     {
 2698         // Since the buffer tends to correspond to the text to the left of the caret in the
 2699         // active window, if the active window changes, it seems best to reset the buffer
 2700         // to avoid misfires.
 2701         g_HShwnd = active_window;
 2702         *g_HSBuf = '\0';
 2703         g_HSBufLength = 0;
 2704     }
 2705     else if (HS_BUF_SIZE - g_HSBufLength < 3) // Not enough room for up-to-2 chars.
 2706     {
 2707         // Make room in buffer by removing chars from the front that are no longer needed for HS detection:
 2708         // Bug-fixed the below for v1.0.21:
 2709         g_HSBufLength = (int)_tcslen(g_HSBuf + HS_BUF_DELETE_COUNT);  // The new length.
 2710         tmemmove(g_HSBuf, g_HSBuf + HS_BUF_DELETE_COUNT, g_HSBufLength + 1); // +1 to include the zero terminator.
 2711     }
 2712 
 2713     g_HSBuf[g_HSBufLength++] = ch[0];
 2714     if (char_count > 1)
 2715         // MSDN: "This usually happens when a dead-key character (accent or diacritic) stored in the
 2716         // keyboard layout cannot be composed with the specified virtual key to form a single character."
 2717         g_HSBuf[g_HSBufLength++] = ch[1];
 2718     g_HSBuf[g_HSBufLength] = '\0';
 2719 
 2720     if (g_HSBufLength)
 2721     {
 2722         TCHAR *cphs, *cpbuf, *cpcase_start, *cpcase_end;
 2723         int case_capable_characters;
 2724         bool first_char_with_case_is_upper, first_char_with_case_has_gone_by;
 2725         CaseConformModes case_conform_mode;
 2726 
 2727         // Searching through the hot strings in the original, physical order is the documented
 2728         // way in which precedence is determined, i.e. the first match is the only one that will
 2729         // be triggered.
 2730         for (HotstringIDType u = 0; u < Hotstring::sHotstringCount; ++u)
 2731         {
 2732             Hotstring &hs = *Hotstring::shs[u];  // For performance and convenience.
 2733             if (hs.mSuspended)
 2734                 continue;
 2735             if (hs.mEndCharRequired)
 2736             {
 2737                 if (g_HSBufLength <= hs.mStringLength) // Ensure the string is long enough for loop below.
 2738                     continue;
 2739                 if (!_tcschr(g_EndChars, g_HSBuf[g_HSBufLength - 1])) // It's not an end-char, so no match.
 2740                     continue;
 2741                 cpbuf = g_HSBuf + g_HSBufLength - 2; // Init once for both loops. -2 to omit end-char.
 2742             }
 2743             else // No ending char required.
 2744             {
 2745                 if (g_HSBufLength < hs.mStringLength) // Ensure the string is long enough for loop below.
 2746                     continue;
 2747                 cpbuf = g_HSBuf + g_HSBufLength - 1; // Init once for both loops.
 2748             }
 2749             cphs = hs.mString + hs.mStringLength - 1; // Init once for both loops.
 2750             // Check if this item is a match:
 2751             if (hs.mCaseSensitive)
 2752             {
 2753                 for (; cphs >= hs.mString; --cpbuf, --cphs)
 2754                     if (*cpbuf != *cphs)
 2755                         break;
 2756             }
 2757             else // case insensitive
 2758                 // v1.0.43.03: Using CharLower vs. tolower seems the best default behavior (even though slower)
 2759                 // so that languages in which the higher ANSI characters are common will see "Ä" == "ä", etc.
 2760                 for (; cphs >= hs.mString; --cpbuf, --cphs)
 2761                     if (ltolower(*cpbuf) != ltolower(*cphs)) // v1.0.43.04: Fixed crash by properly casting to UCHAR (via macro).
 2762                         break;
 2763 
 2764             // Check if one of the loops above found a matching hotstring (relies heavily on
 2765             // short-circuit boolean order):
 2766             if (   cphs >= hs.mString // One of the loops above stopped early due discovering "no match"...
 2767                 // ... or it did but the "?" option is not present to protect from the fact that
 2768                 // what lies to the left of this hotstring abbreviation is an alphanumeric character:
 2769                 || !hs.mDetectWhenInsideWord && cpbuf >= g_HSBuf && IsHotstringWordChar(*cpbuf)
 2770                 // ... v1.0.41: Or it's a perfect match but the right window isn't active or doesn't exist.
 2771                 // In that case, continue searching for other matches in case the script contains
 2772                 // hotstrings that would trigger simultaneously were it not for the "only one" rule.
 2773                 || !HotCriterionAllowsFiring(hs.mHotCriterion, hs.mName)   )
 2774                 continue; // No match or not eligible to fire.
 2775                 // v1.0.42: The following scenario defeats the ability to give criterion hotstrings
 2776                 // precedence over non-criterion:
 2777                 // A global/non-criterion hotstring is higher up in the file than some criterion hotstring,
 2778                 // but both are eligible to fire at the same instant.  In v1.0.41, the global one would
 2779                 // take precedence because it's higher up (and this behavior is preserved not just for
 2780                 // backward compatibility, but also because it might be more flexible -- this is because
 2781                 // unlike hotkeys, variants aren't stored under a parent hotstring, so we don't know which
 2782                 // ones are exact dupes of each other (same options+abbreviation).  Thus, it would take
 2783                 // extra code to determine this at runtime; and even if it were added, it might be
 2784                 // more flexible not to do it; instead, to let the script determine (even by resorting to
 2785                 // #IfWinNOTActive) what precedence hotstrings have with respect to each other.
 2786 
 2787             //////////////////////////////////////////////////////////////
 2788             // MATCHING HOTSTRING WAS FOUND (since above didn't continue).
 2789             //////////////////////////////////////////////////////////////
 2790 
 2791             // Now that we have a match, see if its InputLevel is allowed. If not,
 2792             // consider the key ignored (rather than continuing to search for more matches).
 2793             if (!HotInputLevelAllowsFiring(hs.mInputLevel, aEvent.dwExtraInfo, &pKeyHistoryCurr->event_type))
 2794                 break;
 2795 
 2796             // Since default KeyDelay is 0, and since that is expected to be typical, it seems
 2797             // best to unconditionally post a message rather than trying to handle the backspacing
 2798             // and replacing here.  This is because a KeyDelay of 0 might be fairly slow at
 2799             // sending keystrokes if the system is under heavy load, in which case we would
 2800             // not be returning to our caller in a timely fashion, which would case the OS to
 2801             // think the hook is unresponsive, which in turn would cause it to timeout and
 2802             // route the key through anyway (testing confirms this).
 2803             if (!hs.mConformToCase)
 2804                 case_conform_mode = CASE_CONFORM_NONE;
 2805             else
 2806             {
 2807                 // Find out what case the user typed the string in so that we can have the
 2808                 // replacement produced in similar case:
 2809                 cpcase_end = g_HSBuf + g_HSBufLength;
 2810                 if (hs.mEndCharRequired)
 2811                     --cpcase_end;
 2812                 // Bug-fix for v1.0.19: First find out how many of the characters in the abbreviation
 2813                 // have upper and lowercase versions (i.e. exclude digits, punctuation, etc):
 2814                 for (case_capable_characters = 0, first_char_with_case_is_upper = first_char_with_case_has_gone_by = false
 2815                     , cpcase_start = cpcase_end - hs.mStringLength
 2816                     ; cpcase_start < cpcase_end; ++cpcase_start)
 2817                     if (IsCharLower(*cpcase_start) || IsCharUpper(*cpcase_start)) // A case-capable char.
 2818                     {
 2819                         if (!first_char_with_case_has_gone_by)
 2820                         {
 2821                             first_char_with_case_has_gone_by = true;
 2822                             if (IsCharUpper(*cpcase_start))
 2823                                 first_char_with_case_is_upper = true; // Override default.
 2824                         }
 2825                         ++case_capable_characters;
 2826                     }
 2827                 if (!case_capable_characters) // All characters in the abbreviation are caseless.
 2828                     case_conform_mode = CASE_CONFORM_NONE;
 2829                 else if (case_capable_characters == 1)
 2830                     // Since there is only a single character with case potential, it seems best as
 2831                     // a default behavior to capitalize the first letter of the replacement whenever
 2832                     // that character was typed in uppercase.  The behavior can be overridden by
 2833                     // turning off the case-conform mode.
 2834                     case_conform_mode = first_char_with_case_is_upper ? CASE_CONFORM_FIRST_CAP : CASE_CONFORM_NONE;
 2835                 else // At least two characters have case potential. If all of them are upper, use ALL_CAPS.
 2836                 {
 2837                     if (!first_char_with_case_is_upper) // It can't be either FIRST_CAP or ALL_CAPS.
 2838                         case_conform_mode = CASE_CONFORM_NONE;
 2839                     else // First char is uppercase, and if all the others are too, this will be ALL_CAPS.
 2840                     {
 2841                         case_conform_mode = CASE_CONFORM_FIRST_CAP; // Set default.
 2842                         // Bug-fix for v1.0.19: Changed !IsCharUpper() below to IsCharLower() so that
 2843                         // caseless characters such as the @ symbol do not disqualify an abbreviation
 2844                         // from being considered "all uppercase":
 2845                         for (cpcase_start = cpcase_end - hs.mStringLength; cpcase_start < cpcase_end; ++cpcase_start)
 2846                             if (IsCharLower(*cpcase_start)) // Use IsCharLower to better support chars from non-English languages.
 2847                                 break; // Any lowercase char disqualifies CASE_CONFORM_ALL_CAPS.
 2848                         if (cpcase_start == cpcase_end) // All case-possible characters are uppercase.
 2849                             case_conform_mode = CASE_CONFORM_ALL_CAPS;
 2850                         //else leave it at the default set above.
 2851                     }
 2852                 }
 2853             }
 2854 
 2855             if (hs.mDoBackspace || hs.mOmitEndChar) // Fix for v1.0.37.07: Added hs.mOmitEndChar so that B0+O will omit the ending character.
 2856             {
 2857                 // Have caller suppress this final key pressed by the user, since it would have
 2858                 // to be backspaced over anyway.  Even if there is a visible Input command in
 2859                 // progress, this should still be okay since the input will still see the key,
 2860                 // it's just that the active window won't see it, which is okay since once again
 2861                 // it would have to be backspaced over anyway.  UPDATE: If an Input is in progress,
 2862                 // it should not receive this final key because otherwise the hotstring's backspacing
 2863                 // would backspace one too few times from the Input's point of view, thus the input
 2864                 // would have one extra, unwanted character left over (namely the first character
 2865                 // of the hotstring's abbreviation).  However, this method is not a complete
 2866                 // solution because it fails to work under a situation such as the following:
 2867                 // A hotstring script is started, followed by a separate script that uses the
 2868                 // Input command.  The Input script's hook will take precedence (since it was
 2869                 // started most recently), thus when the Hotstring's script's hook does sends
 2870                 // its replacement text, the Input script's hook will get a hold of it first
 2871                 // before the Hotstring's script has a chance to suppress it.  In other words,
 2872                 // The Input command will capture the ending character and then there will
 2873                 // be insufficient backspaces sent to clear the abbreviation out of it.  This
 2874                 // situation is quite rare so for now it's just mentioned here as a known limitation.
 2875                 suppress_hotstring_final_char = true;
 2876             }
 2877 
 2878             // Post the message rather than sending it, because Send would need
 2879             // SendMessageTimeout(), which is undesirable because the whole point of
 2880             // making this hook thread separate from the main thread is to have it be
 2881             // maximally responsive (especially to prevent mouse cursor lag).
 2882             // Put the end char in the LOWORD and the case_conform_mode in the HIWORD.
 2883             // Casting to UCHAR might be necessary to avoid problems when MAKELONG
 2884             // casts a signed char to an unsigned WORD.
 2885             // UPDATE: In v1.0.42.01, the message is posted later (by our caller) to avoid
 2886             // situations in which the message arrives and is processed by the main thread
 2887             // before we finish processing the hotstring's final keystroke here.  This avoids
 2888             // problems with a script calling GetKeyState() and getting an inaccurate value
 2889             // because the hook thread is either pre-empted or is running in parallel
 2890             // (multiprocessor) and hasn't yet returned 1 or 0 to determine whether the final
 2891             // keystroke is suppressed or passed through to the active window.
 2892             // UPDATE: In v1.0.43, the ending character is not put into the Lparam when
 2893             // hs.mDoBackspace is false.  This is because:
 2894             // 1) When not backspacing, it's more correct that the ending character appear where the
 2895             //    user typed it rather than appearing at the end of the replacement.
 2896             // 2) Two ending characters would appear in pre-1.0.43 versions: one where the user typed
 2897             //    it and one at the end, which is clearly incorrect.
 2898             aHotstringWparamToPost = u; // Override the default set by caller.
 2899             aHotstringLparamToPost = MAKELONG(
 2900                 hs.mEndCharRequired  // v1.0.48.04: Fixed to omit "&& hs.mDoBackspace" so that A_EndChar is set properly even for option "B0" (no backspacing).
 2901                     ? g_HSBuf[g_HSBufLength - 1]  // Used by A_EndChar and Hotstring::DoReplace().
 2902                     : 0
 2903                 , case_conform_mode);
 2904 
 2905             // Clean up.
 2906             // The keystrokes to be sent by the other thread upon receiving the message prepared above
 2907             // will not be received by this function because:
 2908             // 1) CollectInput() is not called for simulated keystrokes.
 2909             // 2) The keyboard hook is absent during a SendInput hotstring.
 2910             // 3) The keyboard hook does not receive SendPlay keystrokes (if hotstring is of that type).
 2911             // Consequently, the buffer should be adjusted below to ensure it's in the right state to work
 2912             // in situations such as the user typing two hotstrings consecutively where the ending
 2913             // character of the first is used as a valid starting character (non-alphanumeric) for the next.
 2914             if (hs.mReplacement)
 2915             {
 2916                 // Since the buffer no longer reflects what is actually on screen to the left
 2917                 // of the caret position (since a replacement is about to be done), reset the
 2918                 // buffer, except for any end-char (since that might legitimately form part
 2919                 // of another hot string adjacent to the one just typed).  The end-char
 2920                 // sent by DoReplace() won't be captured (since it's "ignored input", which
 2921                 // is why it's put into the buffer manually here):
 2922                 if (hs.mEndCharRequired)
 2923                 {
 2924                     *g_HSBuf = g_HSBuf[g_HSBufLength - 1];
 2925                     g_HSBufLength = 1; // The buffer will be terminated to reflect this length later below.
 2926                 }
 2927                 else
 2928                     g_HSBufLength = 0; // The buffer will be terminated to reflect this length later below.
 2929             }
 2930             else if (hs.mDoBackspace)
 2931             {
 2932                 // It's *not* a replacement, but we're doing backspaces, so adjust buf for backspaces
 2933                 // and the fact that the final char of the HS (if no end char) or the end char
 2934                 // (if end char required) will have been suppressed and never made it to the
 2935                 // active window.  A simpler way to understand is to realize that the buffer now
 2936                 // contains (for recognition purposes, in its right side) the hotstring and its
 2937                 // end char (if applicable), so remove both:
 2938                 g_HSBufLength -= hs.mStringLength;
 2939                 if (hs.mEndCharRequired)
 2940                     --g_HSBufLength; // The buffer will be terminated to reflect this length later below.
 2941             }
 2942 
 2943             // v1.0.38.04: Fixed the following mDoReset section by moving it beneath the above because
 2944             // the above relies on the fact that the buffer has not yet been reset.
 2945             // v1.0.30: mDoReset was added to prevent hotstrings such as the following
 2946             // from firing twice in a row, if you type 11 followed by another 1 afterward:
 2947             //:*?B0:11::
 2948             //MsgBox,0,test,%A_ThisHotkey%,1 ; Show which key was pressed and close the window after a second.
 2949             //return
 2950             // There are probably many other uses for the reset option (albeit obscure, but they have
 2951             // been brought up in the forum at least twice).
 2952             if (hs.mDoReset)
 2953                 g_HSBufLength = 0; // Further below, the buffer will be terminated to reflect this change.
 2954 
 2955             // In case the above changed the value of g_HSBufLength, terminate the buffer at that position:
 2956             g_HSBuf[g_HSBufLength] = '\0';
 2957 
 2958             break; // Somewhere above would have done "continue" if a match wasn't found.
 2959         } // for()
 2960     } // if buf not empty
 2961     return !suppress_hotstring_final_char;
 2962 }
 2963 
 2964 
 2965 
 2966 bool CollectInputHook(KBDLLHOOKSTRUCT &aEvent, const vk_type aVK, const sc_type aSC, TCHAR aChar[], int aCharCount
 2967     , bool aIsIgnored)
 2968 {
 2969     auto *input = g_input;
 2970     for (; input; input = input->Prev)
 2971     {
 2972         if (!input->InProgress() || !input->IsInteresting(aEvent))
 2973             continue;
 2974         
 2975         UCHAR key_flags = input->KeyVK[aVK] | input->KeySC[aSC];
 2976         
 2977         // aCharCount is negative for dead keys, which are treated as text but not collected.
 2978         bool treat_as_text = aCharCount && !(key_flags & INPUT_KEY_IGNORE_TEXT);
 2979         bool collect_chars = treat_as_text && aCharCount > 0;
 2980 
 2981         // Determine visibility based on options and whether the key produced text.
 2982         // Negative aCharCount (dead key) is treated as text in this context.
 2983         bool visible;
 2984         if (key_flags & INPUT_KEY_VISIBILITY_MASK)
 2985             visible = key_flags & INPUT_KEY_VISIBLE;
 2986         else if (kvk[aVK].as_modifiersLR || kvk[aVK].pForceToggle)
 2987             visible = true; // Do not suppress modifiers or toggleable keys unless specified by KeyOpt().
 2988         else
 2989             visible = treat_as_text ? input->VisibleText : input->VisibleNonText;
 2990 
 2991         if (key_flags & END_KEY_ENABLED) // A terminating keystroke has now occurred unless the shift state isn't right.
 2992         {
 2993             bool end_if_shift_is_down = key_flags & END_KEY_WITH_SHIFT;
 2994             bool end_if_shift_is_not_down = key_flags & END_KEY_WITHOUT_SHIFT;
 2995             bool shift_is_down = g_modifiersLR_logical & (MOD_LSHIFT | MOD_RSHIFT);
 2996             if (shift_is_down ? end_if_shift_is_down : end_if_shift_is_not_down)
 2997             {
 2998                 // The shift state is correct to produce the desired end-key.
 2999                 input->EndByKey(aVK, aSC, input->KeySC[aSC] && (aSC || !input->KeyVK[aVK]), shift_is_down && !end_if_shift_is_not_down);
 3000                 if (!visible)
 3001                     break;
 3002                 continue;
 3003             }
 3004         }
 3005         
 3006         if (aVK == VK_BACK && !g_modifiersLR_logical && input->BackspaceIsUndo)
 3007         {
 3008             if (input->BufferLength)
 3009                 input->Buffer[--input->BufferLength] = '\0';
 3010             visible = input->VisibleText; // Override VisibleNonText.
 3011             // Fall through to the check below in case this {BS} completed a dead key sequence.
 3012         }
 3013 
 3014         if (collect_chars)
 3015             input->CollectChar(aChar, aCharCount);
 3016 
 3017         if (input->NotifyNonText)
 3018         {
 3019             // These flags enable key-up events to be classified as text or non-text based on
 3020             // whether key-down produced text.
 3021             if (treat_as_text)
 3022                 input->KeyVK[aVK] |= INPUT_KEY_IS_TEXT;
 3023             else
 3024                 input->KeyVK[aVK] &= ~INPUT_KEY_IS_TEXT; // In case keyboard layout has changed or similar.
 3025         }
 3026         
 3027         // Posting the notifications after CollectChar() might reduce the odds of a race condition.
 3028         if (((key_flags & INPUT_KEY_NOTIFY) || input->NotifyNonText && !treat_as_text)
 3029             && input->ScriptObject && input->ScriptObject->onKeyDown)
 3030         {
 3031             // input is passed because the alternative would require the main thread to
 3032             // iterate through the Input chain and determine which ones should be notified.
 3033             // This would mean duplicating much of the logic that's used here, and would be
 3034             // complicated by the possibility of an Input being terminated while OnKeyDown
 3035             // is being executed (and thereby breaking the list).
 3036             // This leaves room only for the bare essential parameters: aVK and aSC.
 3037             PostMessage(g_hWnd, AHK_INPUT_KEYDOWN, (WPARAM)input, (aSC << 16) | aVK);
 3038         }
 3039         // Seems best to not collect dead key chars by default; if needed, OnDeadChar
 3040         // could be added, or the script could mark each dead key for OnKeyDown.
 3041         if (collect_chars && input->ScriptObject && input->ScriptObject->onChar)
 3042         {
 3043             PostMessage(g_hWnd, AHK_INPUT_CHAR, (WPARAM)input, ((TBYTE)aChar[1] << 16) | (TBYTE)aChar[0]);
 3044         }
 3045 
 3046         if (!visible)
 3047             break;
 3048     }
 3049     if (input) // Early break (invisible input).
 3050     {
 3051         if (aSC)
 3052             input->KeySC[aSC] |= INPUT_KEY_DOWN_SUPPRESSED;
 3053         else
 3054             input->KeyVK[aVK] |= INPUT_KEY_DOWN_SUPPRESSED;
 3055         return false;
 3056     }
 3057     return true;
 3058 }
 3059 
 3060 
 3061 
 3062 bool input_type::IsInteresting(KBDLLHOOKSTRUCT &aEvent)
 3063 {
 3064     return MinSendLevel == 0 ? true : HotInputLevelAllowsFiring(MinSendLevel - 1, aEvent.dwExtraInfo, NULL);
 3065 }
 3066 
 3067 
 3068 
 3069 void input_type::CollectChar(TCHAR *ch, int char_count)
 3070 {
 3071     const auto buffer = Buffer; // Marginally reduces code size.
 3072     const auto match = this->match;
 3073 
 3074     for (int i = 0; i < char_count; ++i)
 3075     {
 3076         if (CaseSensitive ? _tcschr(EndChars, ch[i]) : ltcschr(EndChars, ch[i]))
 3077         {
 3078             EndByChar(ch[i]);
 3079             return;
 3080         }
 3081         if (BufferLength == BufferLengthMax)
 3082         {
 3083             if (!BufferLength) // For L0, collect nothing but allow OnChar, etc.
 3084                 return;
 3085             break;
 3086         }
 3087         buffer[BufferLength++] = ch[i];
 3088         buffer[BufferLength] = '\0';
 3089     }
 3090 
 3091     // Check if the buffer now matches any of the key phrases, if there are any:
 3092     if (FindAnywhere)
 3093     {
 3094         if (CaseSensitive)
 3095         {
 3096             for (UINT i = 0; i < MatchCount; ++i)
 3097             {
 3098                 if (_tcsstr(buffer, match[i]))
 3099                 {
 3100                     EndByMatch(i);
 3101                     return;
 3102                 }
 3103             }
 3104         }
 3105         else // Not case sensitive.
 3106         {
 3107             for (UINT i = 0; i < MatchCount; ++i)
 3108             {
 3109                 // v1.0.43.03: Changed lstrcasestr to strcasestr because it seems unlikely to break any existing
 3110                 // scripts and is also more useful given that Input with match-list is pretty rarely used,
 3111                 // and even when it is used, match lists are usually short (so performance isn't impacted much
 3112                 // by this change).
 3113                 if (lstrcasestr(buffer, match[i]))
 3114                 {
 3115                     EndByMatch(i);
 3116                     return;
 3117                 }
 3118             }
 3119         }
 3120     }
 3121     else // Exact match is required
 3122     {
 3123         if (CaseSensitive)
 3124         {
 3125             for (UINT i = 0; i < MatchCount; ++i)
 3126             {
 3127                 if (!_tcscmp(buffer, match[i]))
 3128                 {
 3129                     EndByMatch(i);
 3130                     return;
 3131                 }
 3132             }
 3133         }
 3134         else // Not case sensitive.
 3135         {
 3136             for (UINT i = 0; i < MatchCount; ++i)
 3137             {
 3138                 // v1.0.43.03: Changed to locale-insensitive search.  See similar v1.0.43.03 comment above for more details.
 3139                 if (!lstrcmpi(buffer, match[i]))
 3140                 {
 3141                     EndByMatch(i);
 3142                     return;
 3143                 }
 3144             }
 3145         }
 3146     }
 3147 
 3148     // Otherwise, no match found.
 3149     if (BufferLength >= BufferLengthMax)
 3150         EndByLimit();
 3151 }
 3152 
 3153 
 3154 
 3155 bool IsHotstringWordChar(TCHAR aChar)
 3156 // Returns true if aChar would be part of a word if followed by a word char.
 3157 // aChar itself may be a word char or a nonspacing mark which combines with
 3158 // the next character (the first character of a potential hotstring match).
 3159 {
 3160     // IsCharAlphaNumeric is used for simplicity and to preserve old behaviour
 3161     // (with the only exception being the one added below), in case it's what
 3162     // users have come to expect.  Note that checking for C1_ALPHA or C3_ALPHA
 3163     // and C1_DIGIT is not equivalent: Michael S. Kaplan wrote that the real
 3164     // conditions are "(C1_ALPHA && ! (C3_HIRAGANA | C3_KATAKANA) || C1_DIGIT)" -- https://web.archive.org/web/20130627015450/http://blogs.msdn.com/b/michkap/archive/2007/06/19/3396819.aspx
 3165     if (IsCharAlphaNumeric(aChar))
 3166         return true;
 3167     WORD char_type;
 3168     if (GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE3, &aChar, 1, &char_type))
 3169     {
 3170         // Nonspacing marks combine with the following character, so would visually
 3171         // appear to be part of the word.  This should fix detection of words beginning
 3172         // with or containing Arabic nonspacing diacritics, for example.
 3173         if (char_type & C3_NONSPACING)
 3174             return true;
 3175     }
 3176     return false;
 3177 }
 3178 
 3179 
 3180 
 3181 void UpdateKeybdState(KBDLLHOOKSTRUCT &aEvent, const vk_type aVK, const sc_type aSC, bool aKeyUp, bool aIsSuppressed)
 3182 // Caller has ensured that vk has been translated from neutral to left/right if necessary.
 3183 // Always use the parameter vk rather than event.vkCode because the caller or caller's caller
 3184 // might have adjusted vk, namely to make it a left/right specific modifier key rather than a
 3185 // neutral one.
 3186 {
 3187     // If this function was called from SuppressThisKey(), these comments apply:
 3188     // Currently SuppressThisKey is only called with a modifier in the rare case
 3189     // when sDisguiseNextLWinUp/RWinUp is in effect.  But there may be other cases in the
 3190     // future, so we need to make sure the physical state of the modifiers is updated
 3191     // in our tracking system even though the key is being suppressed:
 3192     modLR_type modLR;
 3193     if (modLR = kvk[aVK].as_modifiersLR) // Update our tracking of LWIN/RWIN/RSHIFT etc.
 3194     {
 3195         // Caller has ensured that vk has been translated from neutral to left/right if necessary
 3196         // (e.g. VK_CONTROL -> VK_LCONTROL). For this reason, always use the parameter vk rather
 3197         // than the raw event.vkCode.
 3198         // Below excludes KEY_IGNORE_ALL_EXCEPT_MODIFIER since that type of event shouldn't be ignored by
 3199         // this function.  UPDATE: KEY_PHYS_IGNORE is now considered to be something that shouldn't be
 3200         // ignored in this case because if more than one instance has the hook installed, it is
 3201         // possible for g_modifiersLR_logical_non_ignored to say that a key is down in one instance when
 3202         // that instance's g_modifiersLR_logical doesn't say it's down, which is definitely wrong.  So it
 3203         // is now omitted below:
 3204         bool is_not_ignored = (aEvent.dwExtraInfo != KEY_IGNORE);
 3205         bool is_fake_shift = aEvent.scanCode == SC_FAKE_LSHIFT || aEvent.scanCode == SC_FAKE_RSHIFT;
 3206         bool is_fake_ctrl = aEvent.scanCode == SC_FAKE_LCTRL; // AltGr.
 3207         // For backward-compatibility, fake LCtrl is marked as physical.
 3208         bool event_is_physical = !is_fake_shift && KeybdEventIsPhysical(aEvent.flags, aVK, aKeyUp);
 3209 
 3210         if (aKeyUp)
 3211         {
 3212             // Keep track of system-generated Shift-up events (as part of a workaround for
 3213             // Shift becoming stuck due to interaction between Send and the system handling
 3214             // of shift-numpad combinations).  Find "fake shift" for more details.
 3215             if (is_fake_shift)
 3216                 g_modifiersLR_numpad_mask |= modLR;
 3217             if (!aIsSuppressed)
 3218             {
 3219                 g_modifiersLR_logical &= ~modLR;
 3220                 // Even if is_not_ignored == true, this is updated unconditionally on key-up events
 3221                 // to ensure that g_modifiersLR_logical_non_ignored never says a key is down when
 3222                 // g_modifiersLR_logical says its up, which might otherwise happen in cases such
 3223                 // as alt-tab.  See this comment further below, where the operative word is "relied":
 3224                 // "key pushed ALT down, or relied upon it already being down, so go up".  UPDATE:
 3225                 // The above is no longer a concern because KeyEvent() now defaults to the mode
 3226                 // which causes our var "is_not_ignored" to be true here.  Only the Send command
 3227                 // overrides this default, and it takes responsibility for ensuring that the older
 3228                 // comment above never happens by forcing any down-modifiers to be up if they're
 3229                 // not logically down as reflected in g_modifiersLR_logical.  There's more
 3230                 // explanation for g_modifiersLR_logical_non_ignored in keyboard_mouse.h:
 3231                 if (is_not_ignored)
 3232                     g_modifiersLR_logical_non_ignored &= ~modLR;
 3233             }
 3234             if (event_is_physical) // Note that ignored events can be physical via KEYEVENT_PHYS()
 3235             {
 3236                 g_modifiersLR_physical &= ~modLR;
 3237                 g_PhysicalKeyState[aVK] = 0;
 3238                 if (!is_fake_ctrl)
 3239                     g_modifiersLR_ctrlaltdel_mask &= ~modLR;
 3240                 // If a modifier with an available neutral VK has been released, update the state
 3241                 // of the neutral VK to be that of the opposite key (the one that wasn't released):
 3242                 switch (aVK)
 3243                 {
 3244                 case VK_LSHIFT:   g_PhysicalKeyState[VK_SHIFT] = g_PhysicalKeyState[VK_RSHIFT]; break;
 3245                 case VK_RSHIFT:   g_PhysicalKeyState[VK_SHIFT] = g_PhysicalKeyState[VK_LSHIFT]; break;
 3246                 case VK_LCONTROL: g_PhysicalKeyState[VK_CONTROL] = g_PhysicalKeyState[VK_RCONTROL]; break;
 3247                 case VK_RCONTROL: g_PhysicalKeyState[VK_CONTROL] = g_PhysicalKeyState[VK_LCONTROL]; break;
 3248                 case VK_LMENU:    g_PhysicalKeyState[VK_MENU] = g_PhysicalKeyState[VK_RMENU]; break;
 3249                 case VK_RMENU:    g_PhysicalKeyState[VK_MENU] = g_PhysicalKeyState[VK_LMENU]; break;
 3250                 }
 3251             }
 3252         }
 3253         else // Modifier key was pressed down.
 3254         {
 3255             g_modifiersLR_numpad_mask &= ~modLR;
 3256             if (!aIsSuppressed)
 3257             {
 3258                 g_modifiersLR_logical |= modLR;
 3259                 if (is_not_ignored)
 3260                     g_modifiersLR_logical_non_ignored |= modLR;
 3261             }
 3262             if (event_is_physical)
 3263             {
 3264                 g_modifiersLR_physical |= modLR;
 3265                 g_PhysicalKeyState[aVK] = STATE_DOWN;
 3266                 if (!is_fake_ctrl)
 3267                     g_modifiersLR_ctrlaltdel_mask |= modLR;
 3268                 // If a modifier with an available neutral VK has been pressed down (unlike LWIN & RWIN),
 3269                 // update the state of the neutral VK to be down also:
 3270                 switch (aVK)
 3271                 {
 3272                 case VK_LSHIFT:
 3273                 case VK_RSHIFT:   g_PhysicalKeyState[VK_SHIFT] = STATE_DOWN; break;
 3274                 case VK_LCONTROL:
 3275                 case VK_RCONTROL: g_PhysicalKeyState[VK_CONTROL] = STATE_DOWN; break;
 3276                 case VK_LMENU:
 3277                 case VK_RMENU:    g_PhysicalKeyState[VK_MENU] = STATE_DOWN; break;
 3278                 }
 3279             }
 3280         }
 3281     } // vk is a modifier key.
 3282 }
 3283 
 3284 
 3285 
 3286 bool KeybdEventIsPhysical(DWORD aEventFlags, const vk_type aVK, bool aKeyUp)
 3287 // Always use the parameter vk rather than event.vkCode because the caller or caller's caller
 3288 // might have adjusted vk, namely to make it a left/right specific modifier key rather than a
 3289 // neutral one.
 3290 {
 3291     // MSDN: "The keyboard input can come from the local keyboard driver or from calls to the keybd_event
 3292     // function. If the input comes from a call to keybd_event, the input was "injected"".
 3293     // My: This also applies to mouse events, so use it for them too:
 3294     if (aEventFlags & LLKHF_INJECTED)
 3295         return false;
 3296     // So now we know it's a physical event.  But certain SHIFT key-down events are driver-generated.
 3297     // We want to be able to tell the difference because the Send command and other aspects
 3298     // of keyboard functionality need us to be accurate about which keys the user is physically
 3299     // holding down at any given time:
 3300     if (   (aVK == VK_LSHIFT || aVK == VK_RSHIFT) && !aKeyUp   )
 3301     {
 3302         // If the corresponding mask bit is set, the key was temporarily "released" by the system
 3303         // as part of translating a shift-numpad combination to its unshifted counterpart, and this
 3304         // event is the fake key-down which follows the release of the numpad key.  The system uses
 3305         // standard scancodes for this specific case, not SC_FAKE_LSHIFT or SC_FAKE_RSHIFT.
 3306         if (g_modifiersLR_numpad_mask & (aVK == VK_LSHIFT ? MOD_LSHIFT : MOD_RSHIFT))
 3307             return false;
 3308     }
 3309 
 3310     // Otherwise, it's physical.
 3311     // v1.0.42.04:
 3312     // The time member of the incoming event struct has been observed to be wrongly zero sometimes, perhaps only
 3313     // for AltGr keyboard layouts that generate LControl events when RAlt is pressed (but in such cases, I think
 3314     // it's only sometimes zero, not always).  It might also occur during simulation of Alt+Numpad keystrokes
 3315     // to support {Asc NNNN}.  In addition, SendInput() is documented to have the ability to set its own timestamps;
 3316     // if it's callers put in a bad timestamp, it will probably arrive here that way too.  Thus, use GetTickCount().
 3317     // More importantly, when a script or other application simulates an AltGr keystroke (either down or up),
 3318     // the LControl event received here is marked as physical by the OS or keyboard driver.  This is undesirable
 3319     // primarily because it makes g_TimeLastInputPhysical inaccurate, but also because falsely marked physical
 3320     // events can impact the script's calls to GetKeyState("LControl", "P"), etc.
 3321     g_TimeLastInputPhysical = g_TimeLastInputKeyboard = GetTickCount();
 3322     return true;
 3323 }
 3324 
 3325 
 3326 /////////////////////////////////////////////////////////////////////////////////////////
 3327 
 3328 
 3329 struct hk_sorted_type
 3330 {
 3331     mod_type modifiers;
 3332     modLR_type modifiersLR;
 3333     // Keep sub-32-bit members contiguous to save memory without having to sacrifice performance of
 3334     // 32-bit alignment:
 3335     bool AllowExtraModifiers;
 3336     vk_type vk;
 3337     sc_type sc;
 3338     HotkeyIDType id_with_flags;
 3339 };
 3340 
 3341 
 3342 
 3343 int sort_most_general_before_least(const void *a1, const void *a2)
 3344 // The only items whose order are important are those with the same suffix.  For a given suffix,
 3345 // we want the most general modifiers (e.g. CTRL) to appear closer to the top of the list than
 3346 // those with more specific modifiers (e.g. CTRL-ALT).  To make qsort() perform properly, it seems
 3347 // best to sort by vk/sc then by generality.
 3348 {
 3349     hk_sorted_type &b1 = *(hk_sorted_type *)a1; // For performance and convenience.
 3350     hk_sorted_type &b2 = *(hk_sorted_type *)a2;
 3351     if (b1.vk != b2.vk)
 3352         return b1.vk - b2.vk;
 3353     if (b1.sc != b2.sc)
 3354         return b1.sc - b2.sc;
 3355 
 3356     // If the above didn't return, we now know that a1 and a2 have the same vk's or sc's.  So
 3357     // we use a tie-breaker to cause the most general keys to appear closer to the top of the
 3358     // list than less general ones.  This should result in a given suffix being grouped together
 3359     // after the sort.  Within each suffix group, the most general modifiers should appear first.
 3360 
 3361     // This part is basically saying that keys that don't allow extra modifiers can always be processed
 3362     // after all other keys:
 3363     if (b1.AllowExtraModifiers && !b2.AllowExtraModifiers)
 3364         return -1;  // Indicate that a1 is smaller, so that it will go to the top.
 3365     if (!b1.AllowExtraModifiers && b2.AllowExtraModifiers)
 3366         return 1;
 3367 
 3368     // However the order of suffixes that don't allow extra modifiers, among themselves, may be important.
 3369     // Thus we don't return a zero if both have AllowExtraModifiers = 0.
 3370     // Example: User defines ^a, but also defines >^a.  What should probably happen is that >^a forces ^a
 3371     // to fire only when <^a occurs.
 3372 
 3373     // v1.1.33.03: Compare number of modifiers.  This supersedes some previous checks for when
 3374     // a1's modifiers are a subset of a2's or vice versa (since the subset would always have
 3375     // fewer bits).  This new method helps prioritize combinations which overlap but have a
 3376     // different number of modifiers, such as "*<^a" vs. "*<^>^a".
 3377     UINT nmodLR_a1 = popcount8(b1.modifiersLR);
 3378     UINT nmodLR_a2 = popcount8(b2.modifiersLR);
 3379     UINT nmod_a1 = popcount8(b1.modifiers) + nmodLR_a1;
 3380     UINT nmod_a2 = popcount8(b2.modifiers) + nmodLR_a2;
 3381     if (nmod_a1 != nmod_a2)
 3382         return nmod_a1 - nmod_a2;
 3383     if (nmodLR_a1 != nmodLR_a2)
 3384         return nmodLR_a1 - nmodLR_a2;
 3385     // v1.1.33.03: Sort by modifier value so that key-up hotkeys end up immediately after their
 3386     // counterparts, otherwise we get odd results like Alt+Shift+A firing "*!a" and "*+a up"
 3387     // instead of "*!a" and "*!a up" or "*+a" and "*+a up".
 3388     if (b1.modifiers != b2.modifiers)
 3389         return b1.modifiers - b2.modifiers; // !^+#
 3390     if (b1.modifiersLR != b2.modifiersLR)
 3391         return b1.modifiersLR - b2.modifiersLR; // <^>^<!>!<+>+<#>#
 3392 
 3393     // v1.0.38.03: The following check is added to handle a script containing hotkeys
 3394     // such as the following (in this order):
 3395     // *MButton::
 3396     // *Mbutton Up::
 3397     // MButton::
 3398     // MButton Up::
 3399     // What would happen before is that the qsort() would sometimes cause "MButton Up" from the
 3400     // list above to be processed prior to "MButton", which would set hotkey_up[*MButton's ID]
 3401     // to be MButton Up's ID.  Then when "MButton" was processed, it would set its_table_entry
 3402     // to MButton's ID, but hotkey_up[MButton's ID] would be wrongly left INVALID when it should
 3403     // have received a copy of the asterisk hotkey ID's counterpart key-up ID.  However, even
 3404     // giving it a copy would not be quite correct because then *MButton's ID would wrongly
 3405     // be left associated with MButton's Up's ID rather than *MButton Up's.  By solving the
 3406     // problem here in the sort rather than copying the ID, both bugs are resolved.
 3407     // v1.1.33.03: The scenario above would now also be prevented by checks in ChangeHookState
 3408     // which avoid pairing a key-up hotkey with a more permissive key-down hotkey, but keeping
 3409     // this might help ensure key-up hotkeys are matched optimally when there is overlap.
 3410     //if ((b1.id_with_flags & HOTKEY_KEY_UP) != (b2.id_with_flags & HOTKEY_KEY_UP))
 3411     //  return (b1.id_with_flags & HOTKEY_KEY_UP) ? 1 : -1; // Put key-up hotkeys higher in the list than their down counterparts (see comment above).
 3412 
 3413     // v1.1.33.03: Getting to this point should mean that a1 and a2 have the same modifiers,
 3414     // vk and sc, but they might have different up/down status and key name (Esc/Escape/vk1B).
 3415     // Ensure predictability by putting them in an order based on id_with_flags.
 3416     return b1.id_with_flags - b2.id_with_flags;
 3417 }
 3418 
 3419 
 3420 
 3421 void SetModifierAsPrefix(vk_type aVK, sc_type aSC, bool aAlwaysSetAsPrefix = false)
 3422 // The caller has already ensured that vk and/or sc is a modifier such as VK_CONTROL.
 3423 {
 3424     if (aVK)
 3425     {
 3426         switch (aVK)
 3427         {
 3428         case VK_MENU:
 3429         case VK_SHIFT:
 3430         case VK_CONTROL:
 3431             // Since the user is configuring both the left and right counterparts of a key to perform a suffix action,
 3432             // it seems best to always consider those keys to be prefixes so that their suffix action will only fire
 3433             // when the key is released.  That way, those keys can still be used as normal modifiers.
 3434             // UPDATE for v1.0.29: But don't do it if there is a corresponding key-up hotkey for this neutral
 3435             // modifier, which allows a remap such as the following to succeed:
 3436             // Control::Send {LWin down}
 3437             // Control up::Send {LWin up}
 3438             if (!aAlwaysSetAsPrefix)
 3439             {
 3440                 for (int i = 0; i < Hotkey::sHotkeyCount; ++i)
 3441                 {
 3442                     Hotkey &h = *Hotkey::shk[i]; // For performance and convenience.
 3443                     if (h.mVK == aVK && h.mKeyUp && !h.mModifiersConsolidatedLR && !h.mModifierVK && !h.mModifierSC
 3444                         && !h.IsCompletelyDisabled())
 3445                         return; // Since caller didn't specify aAlwaysSetAsPrefix==true, don't make this key a prefix.
 3446                 }
 3447             }
 3448             switch (aVK)
 3449             {
 3450             case VK_MENU:
 3451                 kvk[VK_MENU].used_as_prefix = PREFIX_FORCED;
 3452                 kvk[VK_LMENU].used_as_prefix = PREFIX_FORCED;
 3453                 kvk[VK_RMENU].used_as_prefix = PREFIX_FORCED;
 3454                 ksc[SC_LALT].used_as_prefix = PREFIX_FORCED;
 3455                 ksc[SC_RALT].used_as_prefix = PREFIX_FORCED;
 3456                 break;
 3457             case VK_SHIFT:
 3458                 kvk[VK_SHIFT].used_as_prefix = PREFIX_FORCED;
 3459                 kvk[VK_LSHIFT].used_as_prefix = PREFIX_FORCED;
 3460                 kvk[VK_RSHIFT].used_as_prefix = PREFIX_FORCED;
 3461                 ksc[SC_LSHIFT].used_as_prefix = PREFIX_FORCED;
 3462                 ksc[SC_RSHIFT].used_as_prefix = PREFIX_FORCED;
 3463                 break;
 3464             case VK_CONTROL:
 3465                 kvk[VK_CONTROL].used_as_prefix = PREFIX_FORCED;
 3466                 kvk[VK_LCONTROL].used_as_prefix = PREFIX_FORCED;
 3467                 kvk[VK_RCONTROL].used_as_prefix = PREFIX_FORCED;
 3468                 ksc[SC_LCONTROL].used_as_prefix = PREFIX_FORCED;
 3469                 ksc[SC_RCONTROL].used_as_prefix = PREFIX_FORCED;
 3470                 break;
 3471             }
 3472             break;
 3473 
 3474         default:  // vk is a left/right modifier key such as VK_LCONTROL or VK_LWIN:
 3475             if (aAlwaysSetAsPrefix)
 3476                 kvk[aVK].used_as_prefix = PREFIX_ACTUAL;
 3477             else
 3478                 if (Hotkey::FindHotkeyContainingModLR(kvk[aVK].as_modifiersLR)) // Fixed for v1.0.35.13 (used to be aSC vs. aVK).
 3479                     kvk[aVK].used_as_prefix = PREFIX_ACTUAL;
 3480                 // else allow its suffix action to fire when key is pressed down,
 3481                 // under the fairly safe assumption that the user hasn't configured
 3482                 // the opposite key to also be a key-down suffix-action (but even
 3483                 // if the user has done this, it's an explicit override of the
 3484                 // safety checks here, so probably best to allow it).
 3485         }
 3486         return;
 3487     }
 3488     // Since above didn't return, using scan code instead of virtual key:
 3489     if (aAlwaysSetAsPrefix)
 3490         ksc[aSC].used_as_prefix = PREFIX_ACTUAL;
 3491     else
 3492         if (Hotkey::FindHotkeyContainingModLR(ksc[aSC].as_modifiersLR))
 3493             ksc[aSC].used_as_prefix = PREFIX_ACTUAL;
 3494 }
 3495 
 3496 
 3497 
 3498 void ChangeHookState(Hotkey *aHK[], int aHK_count, HookType aWhichHook, HookType aWhichHookAlways)
 3499 // Caller must verify that aWhichHook and aWhichHookAlways accurately reflect the hooks that should
 3500 // be active when we return.  For example, the caller must have already taken into account which
 3501 // hotkeys/hotstrings are suspended, disabled, etc.
 3502 //
 3503 // Caller should always be the main thread, never the hook thread.
 3504 // One reason is that this function isn't thread-safe.  Another is that new/delete/malloc/free
 3505 // themselves might not be thread-safe when the single-threaded CRT libraries are in effect
 3506 // (not using multi-threaded libraries due to a 3.5 KB increase in compressed code size).
 3507 //
 3508 // The input params are unnecessary because could just access directly by using Hotkey::shk[].
 3509 // But aHK is a little more concise.
 3510 // aWhichHookAlways was added to force the hooks to be installed (or stay installed) in the case
 3511 // of #InstallKeybdHook and #InstallMouseHook.  This is so that these two commands will always
 3512 // still be in effect even if hotkeys are suspended, so that key history can still be monitored via
 3513 // the hooks.
 3514 // Returns the set of hooks that are active after processing is complete.
 3515 {
 3516     // Determine the set of hooks that should be activated or deactivated.
 3517     HookType hooks_to_be_active = aWhichHook | aWhichHookAlways; // Bitwise union.
 3518 
 3519     if (!hooks_to_be_active) // No need to check any further in this case.  Just remove all hooks.
 3520     {
 3521         AddRemoveHooks(0); // Remove all hooks.
 3522         return;
 3523     }
 3524 
 3525     // Even if hooks_to_be_active indicates no change to hook status, we still need to continue in case
 3526     // this is a suspend or unsuspend operation.  In both of those cases, though the hook(s)
 3527     // may already be active, the hotkey configuration probably needs to be updated.
 3528     // Related: Even if aHK_count is zero, still want to install the hook(s) whenever
 3529     // aWhichHookAlways specifies that they should be.  This is done so that the
 3530     // #InstallKeybdHook and #InstallMouseHook directives can have the hooks installed just
 3531     // for use with something such as the KeyHistory feature, or for Hotstrings, Numlock AlwaysOn,
 3532     // the Input command, and possibly others.
 3533 
 3534     // Now we know that at least one of the hooks is a candidate for activation.
 3535     // Set up the arrays process all of the hook hotkeys even if the corresponding hook won't
 3536     // become active (which should only happen if g_IsSuspended is true
 3537     // and it turns out there are no suspend-hotkeys that are handled by the hook).
 3538 
 3539     // These arrays are dynamically allocated so that memory is conserved in cases when
 3540     // the user doesn't need the hook at all (i.e. just normal registered hotkeys).
 3541     // This is a waste of memory if there are no hook hotkeys, but currently the operation
 3542     // of the hook relies upon these being allocated, even if the arrays are all clean
 3543     // slates with nothing in them (it could check if the arrays are NULL but then the
 3544     // performance would be slightly worse for the "average" script).  Presumably, the
 3545     // caller is requesting the keyboard hook with zero hotkeys to support the forcing
 3546     // of Num/Caps/ScrollLock always on or off (a fairly rare situation, probably):
 3547     if (!kvk)  // Since it's an initialized global, this indicates that all 4 objects are not yet allocated.
 3548     {
 3549         if (   !(kvk = new key_type[VK_ARRAY_COUNT])
 3550             || !(ksc = new key_type[SC_ARRAY_COUNT])
 3551             || !(kvkm = new HotkeyIDType[KVKM_SIZE])
 3552             || !(kscm = new HotkeyIDType[KSCM_SIZE])
 3553             || !(hotkey_up = (HotkeyIDType *)malloc(Hotkey::shkMax * sizeof(HotkeyIDType)))   )
 3554         {
 3555             // At least one of the allocations failed.
 3556             // Keep all 4 objects in sync with one another (i.e. either all allocated, or all not allocated):
 3557             FreeHookMem(); // Since none of the hooks is active, just free any of the above memory that was partially allocated.
 3558             return;
 3559         }
 3560 
 3561         // Done once immediately after allocation to init attributes such as pForceToggle and as_modifiersLR,
 3562         // which are zero for most keys:
 3563         ZeroMemory(kvk, VK_ARRAY_COUNT * sizeof(key_type));
 3564         ZeroMemory(ksc, SC_ARRAY_COUNT * sizeof(key_type));
 3565 
 3566         // Below is also a one-time-only init:
 3567         // This attribute is exists for performance reasons (avoids a function call in the hook
 3568         // procedure to determine this value):
 3569         kvk[VK_CONTROL].as_modifiersLR = MOD_LCONTROL | MOD_RCONTROL;
 3570         kvk[VK_LCONTROL].as_modifiersLR = MOD_LCONTROL;
 3571         kvk[VK_RCONTROL].as_modifiersLR = MOD_RCONTROL;
 3572         kvk[VK_MENU].as_modifiersLR = MOD_LALT | MOD_RALT;
 3573         kvk[VK_LMENU].as_modifiersLR = MOD_LALT;
 3574         kvk[VK_RMENU].as_modifiersLR = MOD_RALT;
 3575         kvk[VK_SHIFT].as_modifiersLR = MOD_LSHIFT | MOD_RSHIFT;
 3576         kvk[VK_LSHIFT].as_modifiersLR = MOD_LSHIFT;
 3577         kvk[VK_RSHIFT].as_modifiersLR = MOD_RSHIFT;
 3578         kvk[VK_LWIN].as_modifiersLR = MOD_LWIN;
 3579         kvk[VK_RWIN].as_modifiersLR = MOD_RWIN;
 3580 
 3581         // This is a bit iffy because it's far from certain that these particular scan codes
 3582         // are really modifier keys on anything but a standard English keyboard.  However,
 3583         // long years of use haven't shown this to be a problem, and there are certainly other
 3584         // parts of the code that do not support custom layouts remapping the modifier keys.
 3585         ksc[SC_LCONTROL].as_modifiersLR = MOD_LCONTROL;
 3586         ksc[SC_RCONTROL].as_modifiersLR = MOD_RCONTROL;
 3587         ksc[SC_LALT].as_modifiersLR = MOD_LALT;
 3588         ksc[SC_RALT].as_modifiersLR = MOD_RALT;
 3589         ksc[SC_LSHIFT].as_modifiersLR = MOD_LSHIFT;
 3590         ksc[SC_RSHIFT].as_modifiersLR = MOD_RSHIFT;
 3591         ksc[SC_LWIN].as_modifiersLR = MOD_LWIN;
 3592         ksc[SC_RWIN].as_modifiersLR = MOD_RWIN;
 3593 
 3594         // Use the address rather than the value, so that if the global var's value
 3595         // changes during runtime, ours will too:
 3596         kvk[VK_SCROLL].pForceToggle = &g_ForceScrollLock;
 3597         kvk[VK_CAPITAL].pForceToggle = &g_ForceCapsLock;
 3598         kvk[VK_NUMLOCK].pForceToggle = &g_ForceNumLock;
 3599     }
 3600 
 3601     // Init only those attributes which reflect the hotkey's definition, not those that reflect
 3602     // the key's current status (since those are initialized only if the hook state is changing
 3603     // from OFF to ON (later below):
 3604     int i;
 3605     for (i = 0; i < VK_ARRAY_COUNT; ++i)
 3606         RESET_KEYTYPE_ATTRIB(kvk[i])
 3607     for (i = 0; i < SC_ARRAY_COUNT; ++i)
 3608         RESET_KEYTYPE_ATTRIB(ksc[i]) // Note: ksc not kvk.
 3609 
 3610     // Indicate here which scan codes should override their virtual keys:
 3611     for (i = 0; i < g_key_to_sc_count; ++i)
 3612         if (g_key_to_sc[i].sc > 0 && g_key_to_sc[i].sc <= SC_MAX)
 3613             ksc[g_key_to_sc[i].sc].sc_takes_precedence = true;
 3614 
 3615     // These have to be initialized with element value INVALID.
 3616     // Don't use FillMemory because the array elements are too big (bigger than bytes):
 3617     for (i = 0; i < KVKM_SIZE; ++i) // Simplify by viewing 2-dimensional array as a 1-dimensional array.
 3618         kvkm[i] = HOTKEY_ID_INVALID;
 3619     for (i = 0; i < KSCM_SIZE; ++i) // Simplify by viewing 2-dimensional array as a 1-dimensional array.
 3620         kscm[i] = HOTKEY_ID_INVALID;
 3621     for (i = 0; i < Hotkey::shkMax; ++i)
 3622         hotkey_up[i] = HOTKEY_ID_INVALID;
 3623 
 3624     hk_sorted_type *hk_sorted = new hk_sorted_type[Hotkey::sHotkeyCount];
 3625     int hk_sorted_count = 0;
 3626     key_type *pThisKey = NULL;
 3627     for (i = 0; i < aHK_count; ++i)
 3628     {
 3629         Hotkey &hk = *aHK[i]; // For performance and convenience.
 3630 
 3631         // If it's not a hook hotkey (e.g. it was already registered with RegisterHotkey() or it's a joystick
 3632         // hotkey) don't process it here.  Similarly, if g_IsSuspended is true, we won't include it unless it's
 3633         // exempt from suspension:
 3634         if (   !HK_TYPE_IS_HOOK(hk.mType)
 3635             || (g_IsSuspended && !hk.IsExemptFromSuspend())
 3636             || hk.IsCompletelyDisabled()   ) // Listed last for short-circuit performance.
 3637             continue;
 3638 
 3639         // Rule out the possibility of obnoxious values right away, preventing array-out-of bounds, etc.:
 3640         if ((!hk.mVK && !hk.mSC) || hk.mVK > VK_MAX || hk.mSC > SC_MAX)
 3641             continue;
 3642 
 3643         if (!hk.mVK)
 3644         {
 3645             // scan codes don't need something like the switch stmt below because they can't be neutral.
 3646             // In other words, there's no scan code equivalent for something like VK_CONTROL.
 3647             // In addition, SC_LCONTROL, for example, doesn't also need to change the kvk array
 3648             // for VK_LCONTROL because the hook knows to give the scan code precedence, and thus
 3649             // look it up only in the ksc array in that case.
 3650             pThisKey = ksc + hk.mSC;
 3651             // For some scan codes this was already set above.  But to support explicit scan code hotkeys,
 3652             // such as "SC102::MsgBox", make sure it's set for every hotkey that uses an explicit scan code.
 3653             pThisKey->sc_takes_precedence = true;
 3654         }
 3655         else
 3656         {
 3657             pThisKey = kvk + hk.mVK;
 3658             // Keys that have a neutral as well as a left/right counterpart must be
 3659             // fully initialized since the hook can receive the left, the right, or
 3660             // the neutral (neutral only if another app calls KeyEvent(), probably).
 3661             // There are several other switch stmts in this function like the below
 3662             // that serve a similar purpose.  The alternative to doing all these
 3663             // switch stmts is to always translate left/right vk's (whose sc's don't
 3664             // take precedence) in the KeyboardProc() itself.  But that would add
 3665             // the overhead of a switch stmt to *every* keypress ever made on the
 3666             // system, so it seems better to set up everything correctly here since
 3667             // this init section is only done once.
 3668             switch (hk.mVK)
 3669             {
 3670             case VK_MENU:
 3671                 // It's not strictly necessary to init all of these, since the
 3672                 // hook currently never handles VK_RMENU, for example, by its
 3673                 // vk (it uses sc instead).  But it's safest to do all of them
 3674                 // in case future changes ever ruin that assumption:
 3675                 kvk[VK_LMENU].used_as_suffix = true;
 3676                 kvk[VK_RMENU].used_as_suffix = true;
 3677                 ksc[SC_LALT].used_as_suffix = true;
 3678                 ksc[SC_RALT].used_as_suffix = true;
 3679                 if (hk.mKeyUp) // Fix for v1.1.07.03: Set only if true in case there was already an "up" hotkey.
 3680                 {
 3681                     kvk[VK_LMENU].used_as_key_up = true;
 3682                     kvk[VK_RMENU].used_as_key_up = true;
 3683                     ksc[SC_LALT].used_as_key_up = true;
 3684                     ksc[SC_RALT].used_as_key_up = true;
 3685                 }
 3686                 break;
 3687             case VK_SHIFT:
 3688                 // The neutral key itself is also set to be a suffix further below.
 3689                 kvk[VK_LSHIFT].used_as_suffix = true;
 3690                 kvk[VK_RSHIFT].used_as_suffix = true;
 3691                 ksc[SC_LSHIFT].used_as_suffix = true;
 3692                 ksc[SC_RSHIFT].used_as_suffix = true;
 3693                 if (hk.mKeyUp) // Fix for v1.1.07.03: Set only if true in case there was already an "up" hotkey.
 3694                 {
 3695                     kvk[VK_LSHIFT].used_as_key_up = true;
 3696                     kvk[VK_RSHIFT].used_as_key_up = true;
 3697                     ksc[SC_LSHIFT].used_as_key_up = true;
 3698                     ksc[SC_RSHIFT].used_as_key_up = true;
 3699                 }
 3700                 break;
 3701             case VK_CONTROL:
 3702                 kvk[VK_LCONTROL].used_as_suffix = true;
 3703                 kvk[VK_RCONTROL].used_as_suffix = true;
 3704                 ksc[SC_LCONTROL].used_as_suffix = true;
 3705                 ksc[SC_RCONTROL].used_as_suffix = true;
 3706                 if (hk.mKeyUp) // Fix for v1.1.07.03: Set only if true in case there was already an "up" hotkey.
 3707                 {
 3708                     kvk[VK_LCONTROL].used_as_key_up = true;
 3709                     kvk[VK_RCONTROL].used_as_key_up = true;
 3710                     ksc[SC_LCONTROL].used_as_key_up = true;
 3711                     ksc[SC_RCONTROL].used_as_key_up = true;
 3712                 }
 3713                 break;
 3714             // Later might want to add cases for VK_LCONTROL and such, but for right now,
 3715             // these keys should never come up since they're done by scan code?
 3716             }
 3717         }
 3718 
 3719         pThisKey->used_as_suffix = true;
 3720         HotkeyIDType hotkey_id_with_flags = hk.mID;
 3721 
 3722         if (hk.mKeyUp)
 3723         {
 3724             pThisKey->used_as_key_up = true;
 3725             hotkey_id_with_flags |= HOTKEY_KEY_UP;
 3726         }
 3727 
 3728         bool hk_is_custom_combo = hk.mModifierVK || hk.mModifierSC;
 3729 
 3730         // If this is a naked (unmodified) modifier key, make it a prefix if it ever modifies any
 3731         // other hotkey.  This processing might be later combined with the hotkeys activation function
 3732         // to eliminate redundancy / improve efficiency, but then that function would probably need to
 3733         // init everything else here as well:
 3734         if (pThisKey->as_modifiersLR && !hk.mModifiersConsolidatedLR && !hk_is_custom_combo
 3735             && !(hk.mNoSuppress & AT_LEAST_ONE_VARIANT_HAS_TILDE)) // v1.0.45.02: ~Alt, ~Control, etc. should fire upon press-down, not release (broken by 1.0.44's PREFIX_FORCED, but I think it was probably broken in pre-1.0.41 too).
 3736             SetModifierAsPrefix(hk.mVK, hk.mSC);
 3737 
 3738         if (hk_is_custom_combo)
 3739         {
 3740             if (hk.mModifierVK)
 3741             {
 3742                 if (kvk[hk.mModifierVK].as_modifiersLR)
 3743                     // The hotkey's ModifierVK is itself a modifier.
 3744                     SetModifierAsPrefix(hk.mModifierVK, 0, true);
 3745                 else
 3746                 {
 3747                     kvk[hk.mModifierVK].used_as_prefix = PREFIX_ACTUAL;
 3748                     if (hk.mNoSuppress & NO_SUPPRESS_PREFIX)
 3749                         kvk[hk.mModifierVK].no_suppress |= NO_SUPPRESS_PREFIX;
 3750                 }
 3751             }
 3752             else //if (hk.mModifierSC)
 3753             {
 3754                 if (ksc[hk.mModifierSC].as_modifiersLR)  // Fixed for v1.0.35.13 (used to be kvk vs. ksc).
 3755                     // The hotkey's ModifierSC is itself a modifier.
 3756                     SetModifierAsPrefix(0, hk.mModifierSC, true);
 3757                 else
 3758                 {
 3759                     ksc[hk.mModifierSC].used_as_prefix = PREFIX_ACTUAL;
 3760                     if (hk.mNoSuppress & NO_SUPPRESS_PREFIX)
 3761                         ksc[hk.mModifierSC].no_suppress |= NO_SUPPRESS_PREFIX;
 3762                     // For some scan codes this was already set above.  But to support explicit scan code prefixes,
 3763                     // such as "SC118 & SC122::MsgBox", make sure it's set for every prefix that uses an explicit
 3764                     // scan code:
 3765                     ksc[hk.mModifierSC].sc_takes_precedence = true;
 3766                 }
 3767             }
 3768             // Insert this hotkey at the front of the linked list of hotkeys which use this suffix key.
 3769             hk.mNextHotkey = pThisKey->first_hotkey;
 3770             pThisKey->first_hotkey = hk.mID;
 3771             continue;
 3772         }
 3773         #ifndef SEND_NOSUPPRESS_PREFIX_KEY_ON_RELEASE // Search for this symbol for details.
 3774         else
 3775         {
 3776             // If this hotkey is a lone key with ~ prefix such as "~a::", the following ensures that
 3777             // the ~ prefix is respected even if the key is also used as a prefix in a custom combo,
 3778             // such as "a & b::".  This is consistent with the behaviour of "~a & b::".
 3779             if (!hk.mModifiersConsolidatedLR && (hk.mNoSuppress & AT_LEAST_ONE_VARIANT_HAS_TILDE))
 3780                 pThisKey->no_suppress |= NO_SUPPRESS_PREFIX;
 3781         }
 3782         #endif
 3783 
 3784         // At this point, since the above didn't "continue", this hotkey is one without a ModifierVK/SC.
 3785         // Put it into a temporary array, which will be later sorted:
 3786         hk_sorted[hk_sorted_count].id_with_flags = hk.mHookAction ? hk.mHookAction : hotkey_id_with_flags;
 3787         hk_sorted[hk_sorted_count].vk = hk.mVK;
 3788         hk_sorted[hk_sorted_count].sc = hk.mSC;
 3789         hk_sorted[hk_sorted_count].modifiers = hk.mModifiers;
 3790         hk_sorted[hk_sorted_count].modifiersLR = hk.mModifiersLR;
 3791         hk_sorted[hk_sorted_count].AllowExtraModifiers = hk.mAllowExtraModifiers;
 3792         ++hk_sorted_count;
 3793     }
 3794 
 3795     if (hk_sorted_count)
 3796     {
 3797         // It's necessary to get them into this order to avoid problems that would be caused by
 3798         // AllowExtraModifiers:
 3799         qsort((void *)hk_sorted, hk_sorted_count, sizeof(hk_sorted_type), sort_most_general_before_least);
 3800 
 3801         // For each hotkey without a ModifierVK/SC (which override normal modifiers), expand its modifiers and
 3802         // modifiersLR into its column in the kvkm or kscm arrays.
 3803 
 3804         mod_type modifiers, i_modifiers_merged;
 3805         modLR_type i_modifiersLR_excluded;
 3806         int modifiersLR;  // Don't make this modLR_type to avoid integer overflow, since it's a loop-counter.
 3807         bool prev_hk_is_key_up, this_hk_is_key_up;
 3808         HotkeyIDType prev_hk_id, this_hk_id;
 3809 
 3810         for (i = 0; i < hk_sorted_count; ++i)
 3811         {
 3812             hk_sorted_type &this_hk = hk_sorted[i]; // For performance and convenience.
 3813             this_hk_is_key_up = this_hk.id_with_flags & HOTKEY_KEY_UP;
 3814             this_hk_id = this_hk.id_with_flags & HOTKEY_ID_MASK;
 3815 
 3816             if (this_hk_id <= HOTKEY_ID_MAX) // It's a valid ID and not an ALT_TAB action.
 3817             {
 3818                 // Insert this hotkey at the front of the list of hotkeys that use this suffix key.
 3819                 // This enables fallback between overlapping hotkeys, such as LCtrl & a, <^+a, ^+a.
 3820                 pThisKey = this_hk.vk ? kvk + this_hk.vk : ksc + this_hk.sc;
 3821                 // Insert after any custom combos.
 3822                 HotkeyIDType *first = &pThisKey->first_hotkey;
 3823                 while (*first != HOTKEY_ID_INVALID && (aHK[*first]->mModifierVK || aHK[*first]->mModifierSC))
 3824                     first = &aHK[*first]->mNextHotkey;
 3825                 aHK[this_hk_id]->mNextHotkey = *first;
 3826                 *first = this_hk_id;
 3827             }
 3828 
 3829             i_modifiers_merged = this_hk.modifiers;
 3830             if (this_hk.modifiersLR)
 3831                 i_modifiers_merged |= ConvertModifiersLR(this_hk.modifiersLR);
 3832             
 3833             // Fixed for v1.1.27.00: Calculate the modifiersLR bits which are NOT allowed to be set.
 3834             // This fixes <^A erroneously taking over <>^A, and reduces the work that must be done
 3835             // on each iteration of the loop below.
 3836             i_modifiersLR_excluded = this_hk.AllowExtraModifiers ? 0
 3837                 : ~(this_hk.modifiersLR | ConvertModifiers(this_hk.modifiers));
 3838 
 3839             for (modifiersLR = 0; modifiersLR <= MODLR_MAX; ++modifiersLR)  // For each possible LR value.
 3840             {
 3841                 if (modifiersLR & i_modifiersLR_excluded) // Checked first to avoid the ConvertModifiersLR call in many cases.
 3842                     continue;
 3843                 modifiers = ConvertModifiersLR(modifiersLR);
 3844                 // Below is true if modifiersLR is a superset of i's modifier value.  In other words,
 3845                 // modifiersLR has the minimum required keys.  It may also have some extraneous keys,
 3846                 // but only if they were not excluded by the check above, in which case they are allowed.
 3847                 if (i_modifiers_merged != (modifiers & i_modifiers_merged))
 3848                     continue;
 3849 
 3850                 // In addition to the above, modifiersLR must also have the *specific* left or right keys
 3851                 // found in i's modifiersLR.  In other words, i's modifiersLR must be a perfect subset
 3852                 // of modifiersLR:
 3853                 if (this_hk.modifiersLR) // make sure that any more specific left/rights are also present.
 3854                     if (this_hk.modifiersLR != (modifiersLR & this_hk.modifiersLR))
 3855                         continue;
 3856 
 3857                 // scan codes don't need the switch() stmt below because, for example,
 3858                 // the hook knows to look up left-control by only SC_LCONTROL, not VK_LCONTROL.
 3859                 bool do_cascade = this_hk.vk;
 3860 
 3861                 // If above didn't "continue", modifiersLR is a valid hotkey combination so set it as such:
 3862                 HotkeyIDType &its_table_entry = this_hk.vk ? Kvkm(modifiersLR, this_hk.vk) : Kscm(modifiersLR, this_hk.sc);
 3863                 if (its_table_entry == HOTKEY_ID_INVALID) // Since there is no ID currently in the slot, key-up/down doesn't matter.
 3864                     its_table_entry = this_hk.id_with_flags;
 3865                 else
 3866                 {
 3867                     prev_hk_id = its_table_entry & HOTKEY_ID_MASK;
 3868                     if (this_hk_id >= Hotkey::sHotkeyCount || prev_hk_id >= Hotkey::sHotkeyCount) // AltTab hotkey.
 3869                         continue; // Exclude AltTab hotkeys since hotkey_up[] and shk[] can't be used.
 3870                     prev_hk_is_key_up = its_table_entry & HOTKEY_KEY_UP;
 3871                     if (this_hk_is_key_up && !prev_hk_is_key_up) // Override any existing key-up hotkey for this down hotkey ID, e.g. "LButton Up" takes precedence over "*LButton Up".
 3872                     {
 3873                         Hotkey &prev_hk = *Hotkey::shk[prev_hk_id];
 3874                         // v1.1.33.03: Since modifiers aren't checked when hotkey_to_fire_upon_release is used
 3875                         // to fire a key-up hotkey, avoid setting setting this_hk as prev_hk's up hotkey when:
 3876                         //   a) prev_hk permits modifiers that this_hk does not permit (i.e. requires to be up).
 3877                         //   b) this_hk requires modifiers that prev_hk does not require (i.e. might not be pressed).
 3878                         //
 3879                         //  a up::    ; Doesn't permit any modifiers.
 3880                         //  *a::      ; Permits all modifiers, so shouldn't necessarily fire "a up".
 3881                         //  <^b up::  ; Doesn't permit RCtrl.
 3882                         //  ^b::      ; Permits RCtrl, so shouldn't necessarily fire "<^b up".
 3883                         //  *^c up::  ; Requires Ctrl.
 3884                         //  *+c::     ; Doesn't require Ctrl, so shouldn't necessarily fire "^c up".
 3885                         //
 3886                         // Note that prev_hk.mModifiersConsolidatedLR includes all LR modifiers that CAN be down,
 3887                         // but some might not be required, so might not be down (e.g. ^b has MOD_LCTRL|MOD_RCTRL).
 3888                         // However, if either LCTRL or RCTRL is set there, we know CTRL will be down, so the result
 3889                         // of ConvertModifiersLR() tells us which neutral modifiers will definitely be down.
 3890                         // prev_hk.mModifiers is checked first to avoid the function call where possible.
 3891                         if (  !((prev_hk.mAllowExtraModifiers ? MODLR_MAX : prev_hk.mModifiersConsolidatedLR) & i_modifiersLR_excluded)
 3892                             && !(modLR_type)(this_hk.modifiersLR & ~prev_hk.mModifiersLR)
 3893                             && (!(mod_type)(this_hk.modifiers & ~prev_hk.mModifiers)
 3894                              || !(mod_type)(this_hk.modifiers & ~ConvertModifiersLR(prev_hk.mModifiersConsolidatedLR)))  )
 3895                         {
 3896                             hotkey_up[prev_hk_id] = this_hk.id_with_flags;
 3897                             do_cascade = false;  // Every place the down-hotkey ID already appears, it will point to this same key-up hotkey.
 3898                         }
 3899                         else
 3900                         {
 3901                             // v1.1.33.03: Override the lower-priority key-down hotkey which was already present.
 3902                             // Hotkey::FindPairedHotkey will be used to locate a key-down hotkey to fire based on
 3903                             // current modifier state.
 3904                             its_table_entry = this_hk.id_with_flags;
 3905                         }
 3906                     }
 3907                     else 
 3908                     {
 3909                         HotkeyIDType new_up_id;
 3910                         if (!this_hk_is_key_up && prev_hk_is_key_up)
 3911                             // Swap them so that the down-hotkey is in the main array and the up in the secondary:
 3912                             new_up_id = its_table_entry;
 3913                         else
 3914                             if (prev_hk_is_key_up || hotkey_up[this_hk_id] != HOTKEY_ID_INVALID)
 3915                                 // Both are key-up hotkeys, or this_hk already has a key-up hotkey, in which case it
 3916                                 // isn't overwritten since there's no guarantee the new one is more appropriate, and
 3917                                 // it can cause the effect of swapping hotkey_up[] between two values repeatedly.
 3918                                 new_up_id = HOTKEY_ID_INVALID;
 3919                             else // Both are key-down hotkeys.
 3920                                 // Fix for v1.0.40.09: Also copy the previous hotkey's corresponding up-hotkey (if any)
 3921                                 // so that this hotkey will have that same one.  This also solves the issue of a hotkey
 3922                                 // such as "^!F1" firing twice (once for down and once for up) when "*F1" and "*F1 up"
 3923                                 // are both hotkeys.  Instead, the "*F1 up" hotkey should fire upon release of "^!F1"
 3924                                 // so that the behavior is consistent with the case where "*F1" isn't present as a hotkey.
 3925                                 // This fix doesn't appear to break anything else, most notably it still allows a hotkey
 3926                                 // such as "^!F1 up" to take precedence over "*F1 up" because in such a case, this
 3927                                 // code would never have executed because prev_hk_is_key_up would be true but
 3928                                 // this_hk_is_key_up would be false.  Note also that sort_most_general_before_least()
 3929                                 // has put key-up hotkeys after their key-down counterparts in the list.
 3930                                 // v1.1.33.03: Without this "^!F1" won't fire twice, but it also won't fire "*F1 up".
 3931                                 new_up_id = hotkey_up[prev_hk_id];
 3932 
 3933                         if (new_up_id != HOTKEY_ID_INVALID)
 3934                         {
 3935                             Hotkey &new_up_hk = *Hotkey::shk[new_up_id & HOTKEY_ID_MASK];
 3936                             // v1.1.33.03: Since modifiers aren't checked when hotkey_to_fire_upon_release is used
 3937                             // to fire a key-up hotkey, avoid setting setting new_up_hk as this_hk's up hotkey when:
 3938                             //   a) this_hk permits modifiers that new_up_hk does not.
 3939                             //   b) new_up_hk requires modifiers that this_hk does not.
 3940                             //
 3941                             //  <^a up::  ; Does not permit RCtrl.
 3942                             //  ^a::      ; Permits RCtrl, so shouldn't necessarily fire "<^a up".
 3943                             //  *!1 up::  ; Requires Alt.
 3944                             //  *<^1::    ; Doesn't require Alt, so shouldn't necessarily fire "*!1 up".
 3945                             //
 3946                             // ~i_modifiersLR_excluded already accounts for this_hk.AllowExtraModifiers.
 3947                             //if (  !(modLR_type)(~i_modifiersLR_excluded & (new_up_hk.mAllowExtraModifiers ? 0 : ~new_up_hk.mModifiersConsolidatedLR))  )
 3948                             if (  (new_up_hk.mAllowExtraModifiers || !(modLR_type)(~i_modifiersLR_excluded & ~new_up_hk.mModifiersConsolidatedLR))
 3949                                 && !(new_up_hk.mModifiers & ~i_modifiers_merged) && !(new_up_hk.mModifiersLR & ~this_hk.modifiersLR)  )
 3950                                 hotkey_up[this_hk_id] = new_up_id;
 3951                         }
 3952 
 3953                         // Either both are key-up hotkeys or both are key-down hotkeys.  this overrides prev.
 3954                         its_table_entry = this_hk.id_with_flags;
 3955                     }
 3956                 }
 3957 
 3958                 if (do_cascade)
 3959                 {
 3960                     switch (this_hk.vk)
 3961                     {
 3962                     case VK_MENU:
 3963                     case VK_LMENU: // In case the program is ever changed to support these VKs directly.
 3964                         Kvkm(modifiersLR, VK_LMENU) = this_hk.id_with_flags;
 3965                         Kscm(modifiersLR, SC_LALT) = this_hk.id_with_flags;
 3966                         if (this_hk.vk == VK_LMENU)
 3967                             break;
 3968                         //else fall through so that VK_MENU also gets the right side set below:
 3969                     case VK_RMENU:
 3970                         Kvkm(modifiersLR, VK_RMENU) = this_hk.id_with_flags;
 3971                         Kscm(modifiersLR, SC_RALT) = this_hk.id_with_flags;
 3972                         break;
 3973                     case VK_SHIFT:
 3974                     case VK_LSHIFT:
 3975                         Kvkm(modifiersLR, VK_LSHIFT) = this_hk.id_with_flags;
 3976                         Kscm(modifiersLR, SC_LSHIFT) = this_hk.id_with_flags;
 3977                         if (this_hk.vk == VK_LSHIFT)
 3978                             break;
 3979                         //else fall through so that VK_SHIFT also gets the right side set below:
 3980                     case VK_RSHIFT:
 3981                         Kvkm(modifiersLR, VK_RSHIFT) = this_hk.id_with_flags;
 3982                         Kscm(modifiersLR, SC_RSHIFT) = this_hk.id_with_flags;
 3983                         break;
 3984                     case VK_CONTROL:
 3985                     case VK_LCONTROL:
 3986                         Kvkm(modifiersLR, VK_LCONTROL) = this_hk.id_with_flags;
 3987                         Kscm(modifiersLR, SC_LCONTROL) = this_hk.id_with_flags;
 3988                         if (this_hk.vk == VK_LCONTROL)
 3989                             break;
 3990                         //else fall through so that VK_CONTROL also gets the right side set below:
 3991                     case VK_RCONTROL:
 3992                         Kvkm(modifiersLR, VK_RCONTROL) = this_hk.id_with_flags;
 3993                         Kscm(modifiersLR, SC_RCONTROL) = this_hk.id_with_flags;
 3994                         break;
 3995                     } // switch()
 3996                 } // if (do_cascade)
 3997             }
 3998         }
 3999     }
 4000 
 4001     delete[] hk_sorted;
 4002 
 4003     // Support "Control", "Alt" and "Shift" as suffix keys by appending their lists of
 4004     // custom combos to the lists used by their left and right versions.  This avoids the
 4005     // need for the hook to detect these keys and perform a search through a second list.
 4006     // This must be done after all custom combos have been processed above, since they
 4007     // might be defined in any order, but the neutral hotkeys must be placed last.
 4008     if (kvk[VK_SHIFT].used_as_suffix) // Skip the following unless Shift, LShift or RShift was used as a suffix.
 4009         LinkKeysForCustomCombo(VK_SHIFT, VK_LSHIFT, VK_RSHIFT);
 4010     if (kvk[VK_CONTROL].used_as_suffix)
 4011         LinkKeysForCustomCombo(VK_CONTROL, VK_LCONTROL, VK_RCONTROL);
 4012     if (kvk[VK_MENU].used_as_suffix)
 4013         LinkKeysForCustomCombo(VK_MENU, VK_LMENU, VK_RMENU);
 4014 
 4015     // Add or remove hooks, as needed.  No change is made if the hooks are already in the correct state.
 4016     AddRemoveHooks(hooks_to_be_active);
 4017 }
 4018 
 4019 
 4020 
 4021 bool HookAdjustMaxHotkeys(Hotkey **&aHK, int &aCurrentMax, int aNewMax)
 4022 {
 4023     Hotkey **new_shk = (Hotkey **)malloc(aNewMax * sizeof(Hotkey *));
 4024     if (!new_shk)
 4025         return false;
 4026     HotkeyIDType *new_hotkey_up = NULL;
 4027     if (   hotkey_up // No allocation needed if the hooks haven't been active yet.
 4028         && !(new_hotkey_up = (HotkeyIDType *)malloc(aNewMax * sizeof(HotkeyIDType)))   )
 4029     {
 4030         free(new_shk);
 4031         return false;
 4032     }
 4033     // From here on, success is certain.
 4034     if (aCurrentMax)
 4035     {
 4036         memcpy(new_shk, aHK, aCurrentMax * sizeof(Hotkey *));
 4037         if (hotkey_up)
 4038             memcpy(new_hotkey_up, hotkey_up, aCurrentMax * sizeof(HotkeyIDType));
 4039             // No initialization is needed for the new portion since the hook won't be aware
 4040             // of any new hotkeys prior to ChangeHookState(), which also refreshes hotkey_up.
 4041     }
 4042     Hotkey **old_shk = aHK;
 4043     HotkeyIDType *old_hotkey_up = hotkey_up;
 4044     aHK = new_shk;
 4045     hotkey_up = new_hotkey_up;
 4046     // At this stage, old_shk and new_shk are interchangeable.  To avoid race conditions with
 4047     // the hook thread, wait for it to reach a known idle state before freeing the old array.
 4048     WaitHookIdle();
 4049     aCurrentMax = aNewMax;
 4050     free(old_shk);
 4051     free(old_hotkey_up);
 4052     return true;
 4053 }
 4054 
 4055 
 4056 
 4057 HotkeyIDType &CustomComboLast(HotkeyIDType *aFirst)
 4058 {
 4059     for (; *aFirst != HOTKEY_ID_INVALID; aFirst = &Hotkey::shk[*aFirst]->mNextHotkey);
 4060     return *aFirst;
 4061 }
 4062 
 4063 void LinkKeysForCustomCombo(vk_type aNeutral, vk_type aLeft, vk_type aRight)
 4064 {
 4065     HotkeyIDType first_neutral = kvk[aNeutral].first_hotkey;
 4066     if (first_neutral == HOTKEY_ID_INVALID)
 4067         return;
 4068     // Append the neutral key's list to the lists of the left and right keys.
 4069     CustomComboLast(&kvk[aLeft].first_hotkey) = first_neutral;
 4070     CustomComboLast(&kvk[aRight].first_hotkey) = first_neutral;
 4071 }
 4072 
 4073 
 4074 
 4075 void AddRemoveHooks(HookType aHooksToBeActive, bool aChangeIsTemporary)
 4076 // Caller has ensured that any static memory arrays used by the hook functions have been allocated.
 4077 // Caller is always the main thread, never the hook thread because this function isn't thread-safe
 4078 // and it also calls PeekMessage() for the main thread.
 4079 {
 4080     HookType hooks_active_orig = GetActiveHooks();
 4081     if (aHooksToBeActive == hooks_active_orig) // It's already in the right state.
 4082         return;
 4083 
 4084     if (!hooks_active_orig) // Neither hook is active now but at least one will be or the above would have returned.
 4085     {
 4086         // Assert: sThreadHandle should be NULL at this point.  The only way this isn't true is if
 4087         // a previous call to AddRemoveHooks() timed out while waiting for the hook thread to exit,
 4088         // which seems far too rare to add extra code for.
 4089 
 4090         // CreateThread() vs. _beginthread():
 4091         // It's not necessary to link to the multi-threading C runtime (which bloats the code by 3.5 KB
 4092         // compressed) as long as the new thread doesn't call any C-library functions that aren't thread-safe
 4093         // (in addition to the C functions that obviously use static data, calls to things like malloc(),
 4094         // new, and other memory management functions probably aren't thread-safe unless the multi-threaded
 4095         // library is used). The memory leak described in MSDN for ExitThread() applies only to the
 4096         // multi-threaded libraries (multiple sources confirm this), so it isn't a concern either.
 4097         // That's true even if the program is linked against the multi-threaded DLLs (MSVCRT.dll) rather
 4098         // than the libraries (e.g. for a minimum-sized SC.bin file), as confirmed by the following quotes:
 4099         // "This applies only to the static-link version of the runtime. For this and other reasons, I
 4100         // *highly* recommend using the DLL runtime, which lets you use CreateThread() without prejudice.
 4101         // Confirmation from MSDN: "Another work around is to link the *executable* to the CRT in a *DLL*
 4102         // instead of the static CRT."
 4103         //
 4104         // The hooks are designed to make minimal use of C-library calls, currently calling only things
 4105         // like memcpy() and strlen(), which are thread safe in the single-threaded library (according to
 4106         // their source code).  However, the hooks may indirectly call other library functions via calls
 4107         // to KeyEvent() and other functions, which has already been reviewed for thread-safety but needs
 4108         // to be kept in mind as changes are made in the future.
 4109         //
 4110         // CreateThread's second parameter is the new thread's initial stack size. The stack will grow
 4111         // automatically if more is needed, so it's kept small here to greatly reduce the amount of
 4112         // memory used by the hook thread.  The XP Task Manager's "VM Size" column (which seems much
 4113         // more accurate than "Mem Usage") indicates that a new thread consumes 28 KB + its stack size.
 4114         if (!aChangeIsTemporary) // Caller has ensured that thread already exists when aChangeIsTemporary==true.
 4115             if (sThreadHandle = CreateThread(NULL, 8*1024, HookThreadProc, NULL, 0, &g_HookThreadID))
 4116                 SetThreadPriority(sThreadHandle, THREAD_PRIORITY_TIME_CRITICAL); // See below for explanation.
 4117             // The above priority level seems optimal because if some other process has high priority,
 4118             // the keyboard and mouse hooks will still take precedence, which avoids the mouse cursor
 4119             // and keystroke lag that would otherwise occur (confirmed through testing).  Due to their
 4120             // return-ASAP nature, the hooks are an ideal candidate for almost-realtime priority because
 4121             // they run only rarely and only for tiny bursts of time.
 4122             // Note that the above must also be done in such a way that it works on NT4, which doesn't support
 4123             // below-normal and above-normal process priorities, nor perhaps other aspects of priority.
 4124             // So what is the actual priority given to the hooks by the OS?  Assuming that the script's
 4125             // process is set to NORMAL_PRIORITY_CLASS (which is the default), the following applies:
 4126             // First of all, a definition: "base priority" is the actual/net priority of the thread.
 4127             // It determines how the OS will schedule a thread relative to all other threads on the system.
 4128             // So in a sense, if you look only at base priority, the thread's process's priority has no
 4129             // bearing on how the thread will get scheduled (except to the extent that it contributes
 4130             // to the calculation of the base priority itself).  Here are some common base priorities
 4131             // along with where the hook priority (15) fits in:
 4132             // 7 = NORMAL_PRIORITY_CLASS process + THREAD_PRIORITY_NORMAL thread.
 4133             // 9 = NORMAL_PRIORITY_CLASS process + THREAD_PRIORITY_HIGHEST thread.
 4134             // 13 = HIGH_PRIORITY_CLASS process + THREAD_PRIORITY_NORMAL thread.
 4135             // 15 = (ANY)_PRIORITY_CLASS process + THREAD_PRIORITY_TIME_CRITICAL thread. <-- Seems like the optimal compromise.
 4136             // 15 = HIGH_PRIORITY_CLASS process + THREAD_PRIORITY_HIGHEST thread.
 4137             // 24 = REALTIME_PRIORITY_CLASS process + THREAD_PRIORITY_NORMAL thread.
 4138         else // Failed to create thread.  Seems to rare to justify the display of an error.
 4139         {
 4140             FreeHookMem(); // If everything's designed right, there should be no hooks now (even if there is, they can't be functional because their thread is nonexistent).
 4141             return;
 4142         }
 4143     }
 4144     //else there is at least one hook already active, which guarantees that the hook thread exists (assuming
 4145     // everything is designed right).
 4146 
 4147     // Above has ensured that the hook thread now exists, so send it the status-change message.
 4148 
 4149     // Post the AHK_CHANGE_HOOK_STATE message to the new thread to put the right hooks into effect.
 4150     // If both hooks are to be deactivated, AHK_CHANGE_HOOK_STATE also causes the hook thread to exit.
 4151     // PostThreadMessage() has been observed to fail, such as when a script replaces a previous instance
 4152     // of itself via #SingleInstance.  I think this happens because the new thread hasn't yet had a
 4153     // chance to create its message queue via GetMessage().  So rather than using something like
 4154     // WaitForSingleObject() -- which might not be reliable due to split-second timing of when the
 4155     // queue actually gets created -- just keep retrying until time-out or PostThreadMessage() succeeds.
 4156     for (int i = 0; i < 50 && !PostThreadMessage(g_HookThreadID, AHK_CHANGE_HOOK_STATE, aHooksToBeActive, !aChangeIsTemporary); ++i)
 4157         Sleep(10); // Should never execute if thread already existed before this function was called.
 4158         // Above: Sleep(10) seems better than Sleep(0), which would max the CPU while waiting.
 4159         // MUST USE Sleep vs. MsgSleep, otherwise an infinite recursion of ExitApp is possible.
 4160         // This can be reproduced by running a script consisting only of the line #InstallMouseHook
 4161         // and then exiting via the tray menu.  I tried fixing it in TerminateApp with the following,
 4162         // but it's just not enough.  So rather than spend a long time on it, it's fixed directly here:
 4163             // Because of the below, our callers must NOT assume that an exit will actually take place.
 4164             //static is_running = false;
 4165             //if (is_running)
 4166             //  return OK;
 4167             //is_running = true; // Since we're exiting, there should be no need to set it to false further below.
 4168 
 4169     // If it times out I think it's realistically impossible that the new thread really exists because
 4170     // if it did, it certainly would have had time to execute GetMessage() in all but extreme/theoretical
 4171     // cases.  Therefore, no thread check/termination attempt is done.  Alternatively, a check for
 4172     // GetExitCodeThread() could be done followed by closing the handle and setting it to NULL, but once
 4173     // again the code size doesn't seem worth it for a situation that is probably impossible.
 4174     //
 4175     // Also, a timeout itself seems too rare (perhaps even impossible) to justify a warning dialog.
 4176     // So do nothing, which retains the current values of g_KeybdHook and g_MouseHook.
 4177 
 4178     // For safety, serialize the termination of the hook thread so that this function can't be called
 4179     // again by the main thread before the hook thread has had a chance to exit in response to the
 4180     // previous call.  This improves reliability, especially by ensuring a clean exit (if our caller
 4181     // is about to exit the app via exit(), which otherwise might not cleanly close all threads).
 4182     // UPDATE: Also serialize all changes to the hook status so that our caller can rely on the new
 4183     // hook state being in effect immediately.  For example, the Input command installs the keyboard
 4184     // hook and it's more maintainable if we ensure the status is correct prior to returning.
 4185     MSG msg;
 4186     DWORD exit_code, start_time;
 4187     bool problem_activating_hooks;
 4188     for (problem_activating_hooks = false, start_time = GetTickCount();;) // For our caller, wait for hook thread to update the status of the hooks.
 4189     {
 4190         if (aHooksToBeActive) // Wait for the hook thread to activate the specified hooks.
 4191         {
 4192             // In this mode, the hook thread knows we want a report of success or failure via message.
 4193             if (PeekMessage(&msg, NULL, AHK_CHANGE_HOOK_STATE, AHK_CHANGE_HOOK_STATE, PM_REMOVE))
 4194             {
 4195                 if (msg.wParam) // The hook thread indicated failure to activate one or both of the hooks.
 4196                 {
 4197                     // This is done so that the MsgBox warning won't be shown until after these loops finish,
 4198                     // which seems safer to prevent any parts of the script from running as a result
 4199                     // the MsgBox pumping hotkey messages and such, which could result in a script
 4200                     // subroutine launching while we're in here:
 4201                     problem_activating_hooks = true;
 4202                     if (!GetActiveHooks() && !aChangeIsTemporary) // The failure is such that no hooks are now active, and thus (due to the mode) the hook thread will exit.
 4203                     {
 4204                         // Convert this loop into the mode that waits for the hook thread to exit.
 4205                         // This allows the thread handle to be closed and the memory to be freed.
 4206                         aHooksToBeActive = 0;
 4207                         continue;
 4208                     }
 4209                     // It failed but one hook is still active, or the change is temporary.  Either way,
 4210                     // we're done waiting.  Fall through to "break" below.
 4211                 }
 4212                 //else it successfully changed the state.
 4213                 // In either case, we're done waiting:
 4214                 break;
 4215             }
 4216             //else no AHK_CHANGE_HOOK_STATE message has arrived yet, so keep waiting until it does or timeout occurs.
 4217         }
 4218         else // The hook thread has been asked to deactivate both hooks.
 4219         {
 4220             if (aChangeIsTemporary) // The thread will not terminate in this mode, it will just remove its hooks.
 4221             {
 4222                 if (!GetActiveHooks()) // The hooks have been deactivated.
 4223                     break; // Don't call FreeHookMem() because caller doesn't want that when aChangeIsTemporary==true.
 4224             }
 4225             else // Wait for the thread to terminate.
 4226             {
 4227                 GetExitCodeThread(sThreadHandle, &exit_code);
 4228                 if (exit_code != STILL_ACTIVE) // The hook thread is now gone.
 4229                 {
 4230                     // Do the following only if it actually exited (i.e. not if this loop timed out):
 4231                     CloseHandle(sThreadHandle); // Release our reference to it to allow the OS to delete the thread object.
 4232                     sThreadHandle = NULL;
 4233                     FreeHookMem(); // There should be no hooks now (even if there is, they can't be functional because their thread is nonexistent).
 4234                     break;
 4235                 }
 4236             }
 4237         }
 4238         if (GetTickCount() - start_time > 500) // DWORD subtraction yields correct result even when TickCount has wrapped.
 4239             break;
 4240         // v1.0.43: The following sleeps for 0 rather than some longer time because:
 4241         // 1) In nearly all cases, this loop should do only one iteration because a Sleep(0) should guaranty
 4242         //    that the hook thread will get a timeslice before our thread gets another.  In fact, it might not
 4243         //    do any iterations if the system preempts the main thread immediately when a message is posted to
 4244         //    a higher priority thread (especially one in its own process).
 4245         // 2) SendKeys()'s SendInput mode relies on fast removal of hook to prevent a 10ms or longer delay before
 4246         //    the keystrokes get sent.  Such a delay would be quite undesirable in cases where response time is
 4247         //    critical, such as in games.
 4248         // Testing shows that removing the Sleep() entirely does not help performance.  The following was measured
 4249         // when the CPU was under heavy load from a cpu-maxing utility:
 4250         //   Loop 10  ; Keybd hook must be installed for this test to be meaningful.
 4251         //      SendInput {Shift}
 4252         Sleep(0); // Not MsgSleep (see the "Sleep(10)" above for why).
 4253     }
 4254     // If the above loop timed out without the hook thread exiting (if it was asked to exit), sThreadHandle
 4255     // is left as non-NULL to reflect this condition.
 4256 
 4257     // In case mutex create/open/close can be a high-overhead operation, do it only when the hook isn't
 4258     // being quickly/temporarily removed then added back again.
 4259     if (!aChangeIsTemporary)
 4260     {
 4261         if (g_KeybdHook && !(hooks_active_orig & HOOK_KEYBD)) // The keyboard hook has been newly added.
 4262             sKeybdMutex = CreateMutex(NULL, FALSE, KEYBD_MUTEX_NAME); // Create-or-open this mutex and have it be unowned.
 4263         else if (!g_KeybdHook && (hooks_active_orig & HOOK_KEYBD))  // The keyboard hook has been newly removed.
 4264         {
 4265             CloseHandle(sKeybdMutex);
 4266             sKeybdMutex = NULL;
 4267         }
 4268         if (g_MouseHook && !(hooks_active_orig & HOOK_MOUSE)) // The mouse hook has been newly added.
 4269             sMouseMutex = CreateMutex(NULL, FALSE, MOUSE_MUTEX_NAME); // Create-or-open this mutex and have it be unowned.
 4270         else if (!g_MouseHook && (hooks_active_orig & HOOK_MOUSE))  // The mouse hook has been newly removed.
 4271         {
 4272             CloseHandle(sMouseMutex);
 4273             sMouseMutex = NULL;
 4274         }
 4275     }
 4276 
 4277     // For maintainability, it seems best to display the MsgBox only at the very end.
 4278     if (problem_activating_hooks)
 4279     {
 4280         // Prevent hotkeys and other subroutines from running (which could happen via MsgBox's message pump)
 4281         // to avoid the possibility that the script will continue to call this function recursively, resulting
 4282         // in an infinite stack of MsgBoxes. This approach is similar to that used in Hotkey::Perform()
 4283         // for the #MaxHotkeysPerInterval warning dialog:
 4284         g_AllowInterruption = FALSE; 
 4285         // Below is a generic message to reduce code size.  Failure is rare, but has been known to happen when
 4286         // certain types of games are running).
 4287         MsgBox(_T("Warning: The keyboard and/or mouse hook could not be activated; ")
 4288             _T("some parts of the script will not function."));
 4289         g_AllowInterruption = TRUE;
 4290     }
 4291 }
 4292 
 4293 
 4294 
 4295 bool SystemHasAnotherKeybdHook()
 4296 {
 4297     if (sKeybdMutex)
 4298         CloseHandle(sKeybdMutex); // But don't set it to NULL because we need its value below as a flag.
 4299     HANDLE mutex = CreateMutex(NULL, FALSE, KEYBD_MUTEX_NAME); // Create() vs. Open() has enough access to open the mutex if it exists.
 4300     DWORD last_error = GetLastError();
 4301     // Don't check g_KeybdHook because in the case of aChangeIsTemporary, it might be NULL even though
 4302     // we want a handle to the mutex maintained here.
 4303     if (sKeybdMutex) // It was open originally, so update the handle the the newly opened one.
 4304         sKeybdMutex = mutex;
 4305     else if (mutex) // Keep it closed because the system tracks how many handles there are, deleting the mutex when zero.
 4306         CloseHandle(mutex);  // This facilitates other instances of the program getting the proper last_error value.
 4307     return last_error == ERROR_ALREADY_EXISTS;
 4308 }
 4309 
 4310 
 4311 
 4312 bool SystemHasAnotherMouseHook()
 4313 {
 4314     if (sMouseMutex)
 4315         CloseHandle(sMouseMutex); // But don't set it to NULL because we need its value below as a flag.
 4316     HANDLE mutex = CreateMutex(NULL, FALSE, MOUSE_MUTEX_NAME); // Create() vs. Open() has enough access to open the mutex if it exists.
 4317     DWORD last_error = GetLastError();
 4318     // Don't check g_MouseHook because in the case of aChangeIsTemporary, it might be NULL even though
 4319     // we want a handle to the mutex maintained here.
 4320     if (sMouseMutex) // It was open originally, so update the handle the the newly opened one.
 4321         sMouseMutex = mutex;
 4322     else if (mutex) // Keep it closed because the system tracks how many handles there are, deleting the mutex when zero.
 4323         CloseHandle(mutex);  // This facilitates other instances of the program getting the proper last_error value.
 4324     return last_error == ERROR_ALREADY_EXISTS;
 4325 }
 4326 
 4327 
 4328 
 4329 DWORD WINAPI HookThreadProc(LPVOID aUnused)
 4330 // The creator of this thread relies on the fact that this function always exits its thread
 4331 // when both hooks are deactivated.
 4332 {
 4333     MSG msg;
 4334     bool problem_activating_hooks;
 4335 
 4336     for (;;) // Infinite loop for pumping messages in this thread. This thread will exit via any use of "return" below.
 4337     {
 4338         if (GetMessage(&msg, NULL, 0, 0) == -1) // -1 is an error, 0 means WM_QUIT.
 4339             continue; // Probably happens only when bad parameters are passed to GetMessage().
 4340 
 4341         switch (msg.message)
 4342         {
 4343         case WM_QUIT:
 4344             // After this message, fall through to the next case below so that the hooks will be removed before
 4345             // exiting this thread.
 4346             msg.wParam = 0; // Indicate to AHK_CHANGE_HOOK_STATE that both hooks should be deactivated.
 4347         // ********
 4348         // NO BREAK IN ABOVE, FALL INTO NEXT CASE:
 4349         // ********
 4350         case AHK_CHANGE_HOOK_STATE: // No blank line between this in the above to indicate fall-through.
 4351             // In this case, wParam contains the bitwise set of hooks that should be active.
 4352             problem_activating_hooks = false;
 4353             if (msg.wParam & HOOK_KEYBD) // Activate the keyboard hook (if it isn't already).
 4354             {
 4355                 if (!g_KeybdHook)
 4356                 {
 4357                     // v1.0.39: Reset *before* hook is installed to avoid any chance that events can
 4358                     // flow into the hook prior to the reset:
 4359                     if (msg.lParam) // Sender of msg. is signaling that reset should be done.
 4360                         ResetHook(false, HOOK_KEYBD, true);
 4361                     if (   !(g_KeybdHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeybdProc, g_hInstance, 0))   )
 4362                         problem_activating_hooks = true;
 4363                 }
 4364             }
 4365             else // Caller specified that the keyboard hook is to be deactivated (if it isn't already).
 4366                 if (g_KeybdHook)
 4367                     if (UnhookWindowsHookEx(g_KeybdHook))
 4368                         g_KeybdHook = NULL;
 4369 
 4370             if (msg.wParam & HOOK_MOUSE) // Activate the mouse hook (if it isn't already).
 4371             {
 4372                 if (!g_MouseHook)
 4373                 {
 4374                     if (msg.lParam) // Sender of msg. is signaling that reset should be done.
 4375                         ResetHook(false, HOOK_MOUSE, true);
 4376                     if (   !(g_MouseHook = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, g_hInstance, 0))   )
 4377                         problem_activating_hooks = true;
 4378                 }
 4379             }
 4380             else // Caller specified that the mouse hook is to be deactivated (if it isn't already).
 4381                 if (g_MouseHook)
 4382                     if (UnhookWindowsHookEx(g_MouseHook))
 4383                         g_MouseHook = NULL;
 4384 
 4385             // Upon failure, don't display MsgBox here because although MsgBox's own message pump would
 4386             // service the hook that didn't fail (if it's active), it's best to avoid any blocking calls
 4387             // here so that this event loop will continue to run.  For example, the script or OS might
 4388             // ask this thread to terminate, which it couldn't do cleanly if it was in a blocking call.
 4389             // Instead, send a reply back to the caller.
 4390             // It's safe to post directly to thread because the creator of this thread should be
 4391             // explicitly waiting for this message (so there's no chance that a MsgBox msg pump
 4392             // will discard the message unless the caller has timed out, which seems impossible
 4393             // in this case).
 4394             if (msg.wParam) // The caller wants a reply only when it didn't ask us to terminate via deactivating both hooks.
 4395                 PostThreadMessage(g_MainThreadID, AHK_CHANGE_HOOK_STATE, problem_activating_hooks, 0);
 4396             //else this is WM_QUIT or the caller wanted this thread to terminate.  Send no reply.
 4397 
 4398             // If caller passes true for msg.lParam, it wants a permanent change to hook state; so in that case, terminate this
 4399             // thread whenever neither hook is no longer present.
 4400             if (msg.lParam && !(g_KeybdHook || g_MouseHook)) // Both hooks are inactive (for whatever reason).
 4401                 return 0; // Thread is no longer needed. The "return" automatically calls ExitThread().
 4402                 // 1) Due to this thread's non-GUI nature, there doesn't seem to be any need to call
 4403                 // the somewhat mysterious PostQuitMessage() here.
 4404                 // 2) For thread safety and maintainability, it seems best to have the caller take
 4405                 // full responsibility for freeing the hook's memory.
 4406             break;
 4407 
 4408         case AHK_HOOK_SYNC:
 4409             sHookSyncd = true;
 4410             break;
 4411 
 4412         } // switch (msg.message)
 4413     } // for(;;)
 4414 }
 4415 
 4416 
 4417 
 4418 void ResetHook(bool aAllModifiersUp, HookType aWhichHook, bool aResetKVKandKSC)
 4419 // Caller should ensure that aWhichHook indicates at least one of the hooks (not none).
 4420 {
 4421     // Reset items common to both hooks:
 4422     pPrefixKey = NULL;
 4423 
 4424     if (aWhichHook & HOOK_MOUSE)
 4425     {
 4426         // Initialize some things, a very limited subset of what is initialized when the
 4427         // keyboard hook is installed (see its comments).  This is might not everything
 4428         // we should initialize, so further study is justified in the future:
 4429 #ifdef FUTURE_USE_MOUSE_BUTTONS_LOGICAL
 4430         g_mouse_buttons_logical = 0;
 4431 #endif
 4432         g_PhysicalKeyState[VK_LBUTTON] = 0;
 4433         g_PhysicalKeyState[VK_RBUTTON] = 0;
 4434         g_PhysicalKeyState[VK_MBUTTON] = 0;
 4435         g_PhysicalKeyState[VK_XBUTTON1] = 0;
 4436         g_PhysicalKeyState[VK_XBUTTON2] = 0;
 4437         // These are not really valid, since they can't be in a physically down state, but it's
 4438         // probably better to have a false value in them:
 4439         g_PhysicalKeyState[VK_WHEEL_DOWN] = 0;
 4440         g_PhysicalKeyState[VK_WHEEL_UP] = 0;
 4441         // Lexikos: Support horizontal scrolling in Windows Vista and later.
 4442         g_PhysicalKeyState[VK_WHEEL_LEFT] = 0;
 4443         g_PhysicalKeyState[VK_WHEEL_RIGHT] = 0;
 4444 
 4445         if (aResetKVKandKSC)
 4446         {
 4447             ResetKeyTypeState(kvk[VK_LBUTTON]);
 4448             ResetKeyTypeState(kvk[VK_RBUTTON]);
 4449             ResetKeyTypeState(kvk[VK_MBUTTON]);
 4450             ResetKeyTypeState(kvk[VK_XBUTTON1]);
 4451             ResetKeyTypeState(kvk[VK_XBUTTON2]);
 4452             ResetKeyTypeState(kvk[VK_WHEEL_DOWN]);
 4453             ResetKeyTypeState(kvk[VK_WHEEL_UP]);
 4454             // Lexikos: Support horizontal scrolling in Windows Vista and later.
 4455             ResetKeyTypeState(kvk[VK_WHEEL_LEFT]);
 4456             ResetKeyTypeState(kvk[VK_WHEEL_RIGHT]);
 4457         }
 4458     }
 4459 
 4460     if (aWhichHook & HOOK_KEYBD)
 4461     {
 4462         // Doesn't seem necessary to ever init g_KeyHistory or g_KeyHistoryNext here, since they were
 4463         // zero-filled on startup.  But we do want to reset the below whenever the hook is being
 4464         // installed after a (probably long) period during which it wasn't installed.  This is
 4465         // because we don't know the current physical state of the keyboard and such:
 4466 
 4467         g_modifiersLR_physical = 0;  // Best to make this zero, otherwise keys might get stuck down after a Send.
 4468         g_modifiersLR_numpad_mask = 0;
 4469         g_modifiersLR_ctrlaltdel_mask = 0;
 4470         g_modifiersLR_logical = g_modifiersLR_logical_non_ignored = (aAllModifiersUp ? 0 : GetModifierLRState(true));
 4471 
 4472         ZeroMemory(g_PhysicalKeyState, sizeof(g_PhysicalKeyState));
 4473 
 4474         sDisguiseNextMenu = false;
 4475         sUndisguisedMenuInEffect = false;
 4476 
 4477         // On Windows Vista and later, this definitely only works if the classic alt-tab menu
 4478         // has been restored via the registry.  A non-NULL result is probably only helpful for
 4479         // enabling the Esc key workaround in the hook (even though that isn't as critical on
 4480         // Windows 7 as it was on XP, since on 7 the user can dismiss it with physical Esc).
 4481         // A NULL result is probably more common, such as if it's been a while since the hook
 4482         // was removed (or Alt was released).  If the *classic* alt-tab menu isn't in use,
 4483         // this at least serves to reset sAltTabMenuIsVisible to false:
 4484         sAltTabMenuIsVisible = (FindWindow(_T("#32771"), NULL) != NULL);
 4485 
 4486         *g_HSBuf = '\0';
 4487         g_HSBufLength = 0;
 4488         g_HShwnd = 0; // It isn't necessary to determine the actual window/control at this point since the buffer is already empty.
 4489 
 4490         if (aResetKVKandKSC)
 4491         {
 4492             int i;
 4493             for (i = 0; i < VK_ARRAY_COUNT; ++i)
 4494                 if (!IsMouseVK(i))  // Don't do mouse VKs since those must be handled by the mouse section.
 4495                     ResetKeyTypeState(kvk[i]);
 4496             for (i = 0; i < SC_ARRAY_COUNT; ++i)
 4497                 ResetKeyTypeState(ksc[i]);
 4498         }
 4499     }
 4500 }
 4501 
 4502 
 4503 
 4504 HookType GetActiveHooks()
 4505 {
 4506     HookType hooks_currently_active = 0;
 4507     if (g_KeybdHook)
 4508         hooks_currently_active |= HOOK_KEYBD;
 4509     if (g_MouseHook)
 4510         hooks_currently_active |= HOOK_MOUSE;
 4511     return hooks_currently_active;
 4512 }
 4513 
 4514 
 4515 
 4516 void FreeHookMem()
 4517 // For maintainability, only the main thread should ever call this function.
 4518 // This is because new/delete/malloc/free themselves might not be thread-safe
 4519 // when the single-threaded CRT libraries are in effect (not using multi-threaded
 4520 // libraries due to a 3.5 KB increase in compressed code size).
 4521 {
 4522     if (kvk)
 4523     {
 4524         delete [] kvk;
 4525         kvk = NULL;
 4526     }
 4527     if (ksc)
 4528     {
 4529         delete [] ksc;
 4530         ksc = NULL;
 4531     }
 4532     if (kvkm)
 4533     {
 4534         delete [] kvkm;
 4535         kvkm = NULL;
 4536     }
 4537     if (kscm)
 4538     {
 4539         delete [] kscm;
 4540         kscm = NULL;
 4541     }
 4542     if (hotkey_up)
 4543     {
 4544         free(hotkey_up);
 4545         hotkey_up = NULL;
 4546     }
 4547 }
 4548 
 4549 
 4550 
 4551 void ResetKeyTypeState(key_type &key)
 4552 {
 4553     key.is_down = false;
 4554     key.it_put_alt_down = false;
 4555     key.it_put_shift_down = false;
 4556     key.down_performed_action = false;
 4557     key.was_just_used = 0;
 4558     key.hotkey_to_fire_upon_release = HOTKEY_ID_INVALID;
 4559     // ABOVE line was added in v1.0.48.03 to fix various ways in which the hook didn't receive the key-down
 4560     // hotkey that goes with this key-up, resulting in hotkey_to_fire_upon_release being left at its initial
 4561     // value of zero (which is a valid hotkey ID).  Examples include:
 4562     // The hotkey command being used to create a key-up hotkey while that key is being held down.
 4563     // The script being reloaded or (re)started while the key is being held down.
 4564 }
 4565 
 4566 
 4567 
 4568 void GetHookStatus(LPTSTR aBuf, int aBufSize)
 4569 // aBufSize is an int so that any negative values passed in from caller are not lost.
 4570 {
 4571     TCHAR LRhText[128], LRpText[128];
 4572     sntprintfcat(aBuf, aBufSize,
 4573         _T("Modifiers (Hook's Logical) = %s\r\n")
 4574         _T("Modifiers (Hook's Physical) = %s\r\n") // Font isn't fixed-width, so don't bother trying to line them up.
 4575         _T("Prefix key is down: %s\r\n")
 4576         , ModifiersLRToText(g_modifiersLR_logical, LRhText)
 4577         , ModifiersLRToText(g_modifiersLR_physical, LRpText)
 4578         , pPrefixKey ? _T("yes") : _T("no"));
 4579 
 4580     if (!g_KeybdHook)
 4581         sntprintfcat(aBuf, aBufSize, _T("\r\n")
 4582             _T("NOTE: Only the script's own keyboard events are shown\r\n")
 4583             _T("(not the user's), because the keyboard hook isn't installed.\r\n"));
 4584 
 4585     // Add the below even if key history is already disabled so that the column headings can be seen.
 4586     sntprintfcat(aBuf, aBufSize, 
 4587         _T("\r\nNOTE: To disable the key history shown below, add the line \"#KeyHistory 0\" ")
 4588         _T("anywhere in the script.  The same method can be used to change the size ")
 4589         _T("of the history buffer.  For example: #KeyHistory 100  (Default is 40, Max is 500)")
 4590         _T("\r\n\r\nThe oldest are listed first.  VK=Virtual Key, SC=Scan Code, Elapsed=Seconds since the previous event")
 4591         _T(".  Types: h=Hook Hotkey, s=Suppressed (blocked), i=Ignored because it was generated by an AHK script")
 4592         _T(", a=Artificial, #=Disabled via #IfWinActive/Exist, U=Unicode character (SendInput).\r\n\r\n")
 4593         _T("VK  SC\tType\tUp/Dn\tElapsed\tKey\t\tWindow\r\n")
 4594         _T("-------------------------------------------------------------------------------------------------------------"));
 4595 
 4596     if (g_KeyHistory)
 4597     {
 4598         // Start at the oldest key, which is KeyHistoryNext:
 4599         TCHAR KeyName[128];
 4600         int item, i;
 4601         LPTSTR title_curr = _T(""), title_prev = _T("");
 4602         for (item = g_KeyHistoryNext, i = 0; i < g_MaxHistoryKeys; ++i, ++item)
 4603         {
 4604             if (item >= g_MaxHistoryKeys)
 4605                 item = 0;
 4606             title_prev = title_curr;
 4607             title_curr = g_KeyHistory[item].target_window;
 4608             if (g_KeyHistory[item].vk == VK_PACKET) // Unicode character probably sent via SendInput.
 4609             {
 4610                 sntprintfcat(aBuf, aBufSize, _T("\r\nE7 %04X\t%c\t%c\t%0.2f\t%c              \t%s")
 4611                     , g_KeyHistory[item].sc
 4612                     , g_KeyHistory[item].event_type
 4613                     , g_KeyHistory[item].key_up ? _T('u') : _T('d')
 4614                     , g_KeyHistory[item].elapsed_time
 4615 #ifdef UNICODE
 4616                     , (wchar_t)g_KeyHistory[item].sc
 4617 #else
 4618                     , g_KeyHistory[item].sc & ~0x7f ? ' ' : (char)g_KeyHistory[item].sc
 4619 #endif
 4620                     , _tcscmp(title_curr, title_prev) ? title_curr : _T("") // Display title only when it changes.
 4621                     );
 4622             }
 4623             else if (g_KeyHistory[item].vk || g_KeyHistory[item].sc)
 4624                 sntprintfcat(aBuf, aBufSize, _T("\r\n%02X  %03X\t%c\t%c\t%0.2f\t%-15s\t%s")
 4625                     , g_KeyHistory[item].vk, g_KeyHistory[item].sc
 4626                     // It can't be both ignored and suppressed, so display only one:
 4627                     , g_KeyHistory[item].event_type
 4628                     , g_KeyHistory[item].key_up ? _T('u') : _T('d')
 4629                     , g_KeyHistory[item].elapsed_time
 4630                     , GetKeyName(g_KeyHistory[item].vk, g_KeyHistory[item].sc, KeyName, _countof(KeyName))
 4631                     , _tcscmp(title_curr, title_prev) ? title_curr : _T("") // Display title only when it changes.
 4632                     );
 4633         }
 4634     }
 4635 }
 4636 
 4637 
 4638 
 4639 void WaitHookIdle()
 4640 // Wait until the hook has reached a known idle state (i.e. finished any processing
 4641 // that it was in the middle of, though it could start something new immediately after).
 4642 {
 4643     if (!sThreadHandle)
 4644         return;
 4645     sHookSyncd = false;
 4646     PostThreadMessage(g_HookThreadID, AHK_HOOK_SYNC, 0, 0);
 4647     while (!sHookSyncd)
 4648         SLEEP_WITHOUT_INTERRUPTION(0);
 4649 }