home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Open Source / AutoHotKey / Source / AutoHotkey104705_source.exe / source / keyboard_mouse.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2007-02-05  |  236.7 KB  |  4,151 lines

  1. /*
  2. AutoHotkey
  3.  
  4. Copyright 2003-2007 Chris Mallett (support@autohotkey.com)
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15. */
  16.  
  17. #include "stdafx.h" // pre-compiled headers
  18. #include "keyboard_mouse.h"
  19. #include "globaldata.h" // for g.KeyDelay
  20. #include "application.h" // for MsgSleep()
  21. #include "util.h"  // for strlicmp()
  22. #include "window.h" // for IsWindowHung()
  23.  
  24.  
  25.  
  26. // Added for v1.0.25.  Search on sPrevEventType for more comments:
  27. static KeyEventTypes sPrevEventType;
  28. static vk_type sPrevVK = 0;
  29. // For v1.0.25, the below is static to track it in between sends, so that the below will continue
  30. // to work:
  31. // Send {LWinDown}
  32. // Send {LWinUp}  ; Should still open the Start Menu even though it's a separate Send.
  33. static vk_type sPrevEventModifierDown = 0;
  34. static modLR_type sModifiersLR_persistent = 0; // Tracks this script's own lifetime/persistent modifiers (the ones it caused to be persistent and thus is responsible for tracking).
  35.  
  36. // v1.0.44.03: Below supports multiple keyboard layouts better by having script adapt to active window's layout.
  37. #define MAX_CACHED_LAYOUTS 10  // Hard to imagine anyone using more languages/layouts than this, but even if they do it will still work; performance would just be a little worse due to being uncached.
  38. static CachedLayoutType sCachedLayout[MAX_CACHED_LAYOUTS] = {{0}};
  39. static HKL sTargetKeybdLayout;           // Set by SendKeys() for use by the functions it calls directly and indirectly.
  40. static ResultType sTargetLayoutHasAltGr; //
  41.  
  42. // v1.0.43: Support for SendInput() and journal-playback hook:
  43. #define MAX_INITIAL_EVENTS_SI 500UL  // sizeof(INPUT) == 28 as of 2006. Since Send is called so often, and since most Sends are short, reducing the load on the stack is also a deciding factor for these.
  44. #define MAX_INITIAL_EVENTS_PB 1500UL // sizeof(PlaybackEvent) == 8, so more events are justified before resorting to malloc().
  45. static LPINPUT sEventSI;        // No init necessary.  An array that's allocated/deallocated by SendKeys().
  46. static PlaybackEvent *&sEventPB = (PlaybackEvent *&)sEventSI;
  47. static UINT sEventCount, sMaxEvents; // Number of items in the above arrays and the current array capacity.
  48. static UINT sCurrentEvent;
  49. static modLR_type sEventModifiersLR; // Tracks the modifier state to following the progress/building of the SendInput array.
  50. static POINT sSendInputCursorPos;    // Tracks/predicts cursor position as SendInput array is built.
  51. static HookType sHooksToRemoveDuringSendInput;
  52. static SendModes sSendMode = SM_EVENT; // Whether a SendInput or Hook array is currently being constructed.
  53. static bool sAbortArraySend;         // No init needed.
  54. static bool sFirstCallForThisEvent;  //
  55. static DWORD sThisEventTime;         //
  56.  
  57. // Dyamically resolve SendInput() because otherwise the app won't launch at all on Windows 95/NT-pre-SP3:
  58. typedef UINT (WINAPI *MySendInputType)(UINT, LPINPUT, int);
  59. static MySendInputType sMySendInput = (MySendInputType)GetProcAddress(GetModuleHandle("user32"), "SendInput");
  60. // Above will be NULL for Win95/NT-pre-SP3.
  61.  
  62.  
  63. void DisguiseWinAltIfNeeded(vk_type aVK, bool aInBlindMode)
  64. // For v1.0.25, the following situation is fixed by the code below: If LWin or LAlt
  65. // becomes a persistent modifier (e.g. via Send {LWin down}) and the user physically
  66. // releases LWin immediately before: 1) the {LWin up} is scheduled; and 2) SendKey()
  67. // returns.  Then SendKey() will push the modifier back down so that it is in effect
  68. // for other things done by its caller (SendKeys) and also so that if the Send
  69. // operation ends, the key will still be down as the user intended (to modify future
  70. // keystrokes, physical or simulated).  However, since that down-event is followed
  71. // immediately by an up-event, the Start Menu appears for WIN-key or the active
  72. // window's menu bar is activated for ALT-key.  SOLUTION: Disguise Win-up and Alt-up
  73. // events in these cases.  This workaround has been successfully tested.  It's also
  74. // limited is scope so that a script can still explicitly invoke the Start Menu with
  75. // "Send {LWin}", or activate the menu bar with "Send {Alt}".
  76. // The check of sPrevEventModifierDown allows "Send {LWinDown}{LWinUp}" etc., to
  77. // continue to work.
  78. // v1.0.40: For maximum flexibility and minimum interference while in blind mode,
  79. // don't disguise Win and Alt keystrokes then.
  80. {
  81.     // Caller has ensured that aVK is about to have a key-up event, so if the event immediately
  82.     // prior to this one is a key-down of the same type of modifier key, it's our job here
  83.     // to send the disguising keystrokes now (if appropriate).
  84.     if (sPrevEventType == KEYDOWN && sPrevEventModifierDown != aVK && !aInBlindMode
  85.         // SendPlay mode can't display Start Menu, so no need for disguise keystrokes (such keystrokes might cause
  86.         // unwanted effects in certain games):
  87.         && ((aVK == VK_LWIN || aVK == VK_RWIN) && (sPrevVK == VK_LWIN || sPrevVK == VK_RWIN) && sSendMode != SM_PLAY
  88.             || (aVK == VK_LMENU || (aVK == VK_RMENU && sTargetLayoutHasAltGr != CONDITION_TRUE)) && (sPrevVK == VK_LMENU || sPrevVK == VK_RMENU)))
  89.         KeyEvent(KEYDOWNANDUP, VK_CONTROL); // Disguise it to suppress Start Menu or prevent activation of active window's menu bar.
  90. }
  91.  
  92.  
  93.  
  94. void SendKeys(char *aKeys, bool aSendRaw, SendModes aSendModeOrig, HWND aTargetWindow)
  95. // The aKeys string must be modifiable (not constant), since for performance reasons,
  96. // it's allowed to be temporarily altered by this function.  mThisHotkeyModifiersLR, if non-zero,
  97. // shoul be the set of modifiers used to trigger the hotkey that called the subroutine
  98. // containing the Send that got us here.  If any of those modifiers are still down,
  99. // they will be released prior to sending the batch of keys specified in <aKeys>.
  100. // v1.0.43: aSendModeOrig was added.
  101. {
  102.     if (!*aKeys)
  103.         return;
  104.  
  105.     // Might be better to do this prior to changing capslock state.  UPDATE: In v1.0.44.03, the following section
  106.     // has been moved to the top of the function because:
  107.     // 1) For ControlSend, GetModifierLRState() might be more accurate if the threads are attached beforehand.
  108.     // 2) Determines sTargetKeybdLayout and sTargetLayoutHasAltGr early (for maintainability).
  109.     bool threads_are_attached = false; // Set default.
  110.     DWORD keybd_layout_thread = 0;     //
  111.     DWORD target_thread; // Doesn't need init.
  112.     if (aTargetWindow) // Caller has ensured this is NULL for SendInput and SendPlay modes.
  113.     {
  114.         if ((target_thread = GetWindowThreadProcessId(aTargetWindow, NULL)) // Assign.
  115.             && target_thread != g_MainThreadID && !IsWindowHung(aTargetWindow))
  116.         {
  117.             threads_are_attached = AttachThreadInput(g_MainThreadID, target_thread, TRUE) != 0;
  118.             keybd_layout_thread = target_thread; // Testing shows that ControlSend benefits from the adapt-to-layout technique too.
  119.         }
  120.         //else no target thread, or it's our thread, or it's hung; so keep keybd_layout_thread at its default.
  121.     }
  122.     else
  123.     {
  124.         // v1.0.44.03: The following change is meaningful only to people who use more than one keyboard layout.
  125.         // It seems that the vast majority of them would want the Send command (as well as other features like
  126.         // Hotstrings and the Input command) to adapt to the keyboard layout of the active window (or target window
  127.         // in the case of ControlSend) rather than sticking with the script's own keyboard layout.  In addition,
  128.         // testing shows that this adapt-to-layout method costs almost nothing in performance, especially since
  129.         // the active window, its thread, and its layout are retrieved only once for each Send rather than once
  130.         // for each keystroke.
  131.         HWND active_window;
  132.         if (active_window = GetForegroundWindow())
  133.             keybd_layout_thread = GetWindowThreadProcessId(active_window, NULL);
  134.         //else no foreground window, so keep keybd_layout_thread at default.
  135.     }
  136.     sTargetKeybdLayout = GetKeyboardLayout(keybd_layout_thread); // If keybd_layout_thread==0, this will get our thread's own layout, which seems like the best/safest default.
  137.     sTargetLayoutHasAltGr = LayoutHasAltGr(sTargetKeybdLayout);  // Note that WM_INPUTLANGCHANGEREQUEST is not monitored by MsgSleep for the purpose of caching our thread's keyboard layout.  This is because it would be unreliable if another msg pump such as MsgBox is running.  Plus it hardly helps perf. at all, and hurts maintainability.
  138.  
  139.     // Below is now called with "true" so that the hook's modifier state will be corrected (if necessary)
  140.     // prior to every send.
  141.     modLR_type mods_current = GetModifierLRState(true); // Current "logical" modifier state.
  142.  
  143.     // Make a best guess of what the physical state of the keys is prior to starting (there's no way
  144.     // to be certain without the keyboard hook). Note: We only want those physical
  145.     // keys that are also logically down (it's possible for a key to be down physically
  146.     // but not logically such as when R-control, for example, is a suffix hotkey and the
  147.     // user is physically holding it down):
  148.     modLR_type mods_down_physically_orig, mods_down_physically_and_logically
  149.         , mods_down_physically_but_not_logically_orig;
  150.     if (g_KeybdHook)
  151.     {
  152.         // Since hook is installed, use its more reliable tracking to determine which
  153.         // modifiers are down.
  154.         mods_down_physically_orig = g_modifiersLR_physical;
  155.         mods_down_physically_and_logically = g_modifiersLR_physical & g_modifiersLR_logical; // intersect
  156.         mods_down_physically_but_not_logically_orig = g_modifiersLR_physical & ~g_modifiersLR_logical;
  157.     }
  158.     else // Use best-guess instead.
  159.     {
  160.         // Even if TickCount has wrapped due to system being up more than about 49 days,
  161.         // DWORD math still gives the right answer as long as g_script.mThisHotkeyStartTime
  162.         // itself isn't more than about 49 days ago:
  163.         if ((GetTickCount() - g_script.mThisHotkeyStartTime) < (DWORD)g_HotkeyModifierTimeout) // Elapsed time < timeout-value
  164.             mods_down_physically_orig = mods_current & g_script.mThisHotkeyModifiersLR; // Bitwise AND is set intersection.
  165.         else
  166.             // Since too much time as passed since the user pressed the hotkey, it seems best,
  167.             // based on the action that will occur below, to assume that no hotkey modifiers
  168.             // are physically down:
  169.             mods_down_physically_orig = 0;
  170.         mods_down_physically_and_logically = mods_down_physically_orig;
  171.         mods_down_physically_but_not_logically_orig = 0; // There's no way of knowing, so assume none.
  172.     }
  173.  
  174.     // Any of the external modifiers that are down but NOT due to the hotkey are probably
  175.     // logically down rather than physically (perhaps from a prior command such as
  176.     // "Send, {CtrlDown}".  Since there's no way to be sure without the keyboard hook or some
  177.     // driver-level monitoring, it seems best to assume that
  178.     // they are logically vs. physically down.  This value contains the modifiers that
  179.     // we will not attempt to change (e.g. "Send, A" will not release the LWin
  180.     // before sending "A" if this value indicates that LWin is down).  The below sets
  181.     // the value to be all the down-keys in mods_current except any that are physically
  182.     // down due to the hotkey itself.  UPDATE: To improve the above, we now exclude from
  183.     // the set of persistent modifiers any that weren't made persistent by this script.
  184.     // Such a policy seems likely to do more good than harm as there have been cases where
  185.     // a modifier was detected as persistent just because #HotkeyModifier had timed out
  186.     // while the user was still holding down the key, but then when the user released it,
  187.     // this logic here would think it's still persistent and push it back down again
  188.     // to enforce it as "always-down" during the send operation.  Thus, the key would
  189.     // basically get stuck down even after the send was over:
  190.     sModifiersLR_persistent &= mods_current & ~mods_down_physically_and_logically;
  191.     modLR_type persistent_modifiers_for_this_SendKeys, extra_persistent_modifiers_for_blind_mode;
  192.     bool in_blind_mode; // For performance and also to reserve future flexibility, recognize {Blind} only when it's the first item in the string.
  193.     if (in_blind_mode = !aSendRaw && !strnicmp(aKeys, "{Blind}", 7)) // Don't allow {Blind} while in raw mode due to slight chance {Blind} is intended to be sent as a literal string.
  194.     {
  195.         // Blind Mode (since this seems too obscure to document, it's mentioned here):  Blind Mode relies
  196.         // on modifiers already down for something like ^c because ^c is saying "manifest a ^c", which will
  197.         // happen if ctrl is already down.  By contrast, Blind does not release shift to produce lowercase
  198.         // letters because avoiding that adds flexibility that couldn't be achieved otherwise.
  199.         // Thus, ^c::Send {Blind}c produces the same result when ^c is substituted for the final c.
  200.         // But Send {Blind}{LControl down} will generate the extra events even if ctrl already down.
  201.         aKeys += 7; // Remove "{Blind}" from further consideration (essential for "SendRaw {Blind}").
  202.         // The following value is usually zero unless the user is currently holding down
  203.         // some modifiers as part of a hotkey. These extra modifiers are the ones that
  204.         // this send operation (along with all its calls to SendKey and similar) should
  205.         // consider to be down for the duration of the Send (unless they go up via an
  206.         // explicit {LWin up}, etc.)
  207.         extra_persistent_modifiers_for_blind_mode = mods_current & ~sModifiersLR_persistent;
  208.         persistent_modifiers_for_this_SendKeys = mods_current;
  209.     }
  210.     else
  211.     {
  212.         extra_persistent_modifiers_for_blind_mode = 0;
  213.         persistent_modifiers_for_this_SendKeys = sModifiersLR_persistent;
  214.     }
  215.     // Above:
  216.     // Keep sModifiersLR_persistent and persistent_modifiers_for_this_SendKeys in sync with each other from now on.
  217.     // By contrast to persistent_modifiers_for_this_SendKeys, sModifiersLR_persistent is the lifetime modifiers for
  218.     // this script that stay in effect between sends.  For example, "Send {LAlt down}" leaves the alt key down
  219.     // even after the Send ends, by design.
  220.     //
  221.     // It seems best not to change persistent_modifiers_for_this_SendKeys in response to the user making physical
  222.     // modifier changes during the course of the Send.  This is because it seems more often desirable that a constant
  223.     // state of modifiers be kept in effect for the entire Send rather than having the user's release of a hotkey
  224.     // modifier key, which typically occurs at some unpredictable time during the Send, to suddenly alter the nature
  225.     // of the Send in mid-stride.  Another reason is to make the behavior of Send consistent with that of SendInput.
  226.  
  227.     // The default behavior is to turn the capslock key off prior to sending any keys
  228.     // because otherwise lowercase letters would come through as uppercase and vice versa.
  229.     ToggleValueType prior_capslock_state;
  230.     if (threads_are_attached || !g_os.IsWin9x())
  231.     {
  232.         // Only under either of the above conditions can the state of Capslock be reliably
  233.         // retrieved and changed.  Remember that apps like MS Word have an auto-correct feature that
  234.         // might make it wrongly seem that the turning off of Capslock below needs a Sleep(0) to take effect.
  235.         prior_capslock_state = g.StoreCapslockMode && !in_blind_mode
  236.             ? ToggleKeyState(VK_CAPITAL, TOGGLED_OFF)
  237.             : TOGGLE_INVALID; // In blind mode, don't do store capslock (helps remapping and also adds flexibility).
  238.     }
  239.     else // OS is Win9x and threads are not attached.
  240.     {
  241.         // Attempt to turn off capslock, but never attempt to turn it back on because we can't
  242.         // reliably detect whether it was on beforehand.  Update: This didn't do any good, so
  243.         // it's disabled for now:
  244.         //CapslockOffWin9x();
  245.         prior_capslock_state = TOGGLE_INVALID;
  246.     }
  247.  
  248.     int orig_key_delay = g.KeyDelay;
  249.     int orig_press_duration = g.PressDuration;
  250.     if (aSendModeOrig == SM_INPUT || aSendModeOrig == SM_INPUT_FALLBACK_TO_PLAY)
  251.     {
  252.         // Both of these modes fall back to a different mode depending on whether some other script
  253.         // is running with a keyboard/mouse hook active.  Of course, the detection of this isn't foolproof
  254.         // because older versions of AHK may be running and/or other apps with LL keyboard hooks. It's
  255.         // just designed to add a lot of value for typical usage because SendInput is prefered due to it
  256.         // being considerably faster than SendPlay, especially for long replacements when the CPU is under
  257.         // heavy load.
  258.         if (   !sMySendInput // Win95/NT-pre-SP3 don't support SendInput, so fall back to the specified mode.
  259.             || SystemHasAnotherKeybdHook() // This function has been benchmarked to ensure it doesn't yield our timeslice, etc.  200 calls take 0ms according to tick-count, even when CPU is maxed.
  260.             || !aSendRaw && SystemHasAnotherMouseHook() && strcasestr(aKeys, "{Click")   ) // Ordered for short-circuit boolean performance.  v1.0.43.09: Fixed to be strcasestr vs. !strcasestr
  261.         {
  262.             // Need to detect in advance what type of array to build (for performance and code size).  That's why
  263.             // it done this way, and here are the comments about it:
  264.             // strcasestr() above has an unwanted amount of overhead if aKeys is huge, but it seems acceptable
  265.             // because it's called only when system has another mouse hook but *not* another keybd hook (very rare).
  266.             // Also, for performance reasons, {LButton and such are not checked for, which is documented and seems
  267.             // justified because the new {Click} method is expected to become prevalent, especially since this
  268.             // whole section only applies when the new SendInput mode is in effect.
  269.             // Finally, checking aSendRaw isn't foolproof because the string might contain {Raw} prior to {Click,
  270.             // but the complexity and performance of checking for that seems unjustified given the rarity,
  271.             // especially since there are almost never any consequences to reverting to hook mode vs. SendInput.
  272.             if (aSendModeOrig == SM_INPUT_FALLBACK_TO_PLAY)
  273.                 aSendModeOrig = SM_PLAY;
  274.             else // aSendModeOrig == SM_INPUT, so fall back to EVENT.
  275.             {
  276.                 aSendModeOrig = SM_EVENT;
  277.                 // v1.0.43.08: When SendInput reverts to SendEvent mode, the majority of users would want
  278.                 // a fast sending rate that is more comparable to SendInput's speed that the default KeyDelay
  279.                 // of 10ms.  PressDuration may be generally superior to KeyDelay because it does a delay after
  280.                 // each changing of modifier state (which tends to improve reliability for certain apps).
  281.                 // The following rules seem likely to be the best benefit in terms of speed and reliability:
  282.                 // KeyDelay 0+,-1+ --> -1, 0
  283.                 // KeyDelay -1, 0+ --> -1, 0
  284.                 // KeyDelay -1,-1 --> -1, -1
  285.                 g.PressDuration = (g.KeyDelay < 0 && g.PressDuration < 0) ? -1 : 0;
  286.                 g.KeyDelay = -1; // Above line must be done before this one.
  287.             }
  288.         }
  289.         else // SendInput is available and no other impacting hooks are obviously present on the system, so use SendInput unconditionally.
  290.             aSendModeOrig = SM_INPUT; // Resolve early so that other sections don't have to consider SM_INPUT_FALLBACK_TO_PLAY a valid value.
  291.     }
  292.  
  293.     // sSendMode must be set only after setting Capslock state above, because the hook method
  294.     // is incapable of changing the on/off state of toggleable keys like Capslock.
  295.     // However, it can change Capslock state as seen in the window to which playback events are being
  296.     // sent; but the behavior seems inconsistent and might vary depending on OS type, so it seems best
  297.     // not to rely on it.
  298.     sSendMode = aSendModeOrig;
  299.     if (sSendMode) // Build an array.  We're also responsible for setting sSendMode to SM_EVENT prior to returning.
  300.     {
  301.         size_t mem_size;
  302.         if (sSendMode == SM_INPUT)
  303.         {
  304.             mem_size = MAX_INITIAL_EVENTS_SI * sizeof(INPUT);
  305.             sMaxEvents = MAX_INITIAL_EVENTS_SI;
  306.         }
  307.         else // Playback type.
  308.         {
  309.             mem_size = MAX_INITIAL_EVENTS_PB * sizeof(PlaybackEvent);
  310.             sMaxEvents = MAX_INITIAL_EVENTS_PB;
  311.         }
  312.         // _alloca() is used to avoid the overhead of malloc/free (99% of Sends will thus fit in stack memory).
  313.         // _alloca() never returns a failure code, it just raises an exception (e.g. stack overflow).
  314.         InitEventArray(_alloca(mem_size), sMaxEvents, mods_current);
  315.     }
  316.  
  317.     bool blockinput_prev = g_BlockInput;
  318.     bool do_selective_blockinput = (g_BlockInputMode == TOGGLE_SEND || g_BlockInputMode == TOGGLE_SENDANDMOUSE)
  319.         && !sSendMode && !aTargetWindow && g_os.IsWinNT4orLater();
  320.     if (do_selective_blockinput)
  321.         Line::ScriptBlockInput(true); // Turn it on unconditionally even if it was on, since Ctrl-Alt-Del might have disabled it.
  322.  
  323.     vk_type vk;
  324.     sc_type sc;
  325.     modLR_type key_as_modifiersLR = 0;
  326.     modLR_type mods_for_next_key = 0;
  327.     // Above: For v1.0.35, it was changed to modLR vs. mod so that AltGr keys such as backslash and '{'
  328.     // are supported on layouts such as German when sending to apps such as Putty that are fussy about
  329.     // which ALT key is held down to produce the character.
  330.     vk_type this_event_modifier_down;
  331.     size_t key_text_length, key_name_length;
  332.     char *end_pos, *space_pos, *next_word, old_char, single_char_string[2];
  333.     KeyEventTypes event_type;
  334.     int repeat_count, click_x, click_y;
  335.     bool move_offset, key_down_is_persistent;
  336.     DWORD placeholder;
  337.     single_char_string[1] = '\0'; // Terminate in advance.
  338.  
  339.     LONG_OPERATION_INIT  // Needed even for SendInput/Play.
  340.  
  341.     for (; *aKeys; ++aKeys, sPrevEventModifierDown = this_event_modifier_down)
  342.     {
  343.         this_event_modifier_down = 0; // Set default for this iteration, overridden selectively below.
  344.         if (!sSendMode)
  345.             LONG_OPERATION_UPDATE_FOR_SENDKEYS // This does not measurably affect the performance of SendPlay/Event.
  346.  
  347.         if (!aSendRaw && strchr("^+!#{}", *aKeys))
  348.         {
  349.             switch (*aKeys)
  350.             {
  351.             case '^':
  352.                 if (!(persistent_modifiers_for_this_SendKeys & (MOD_LCONTROL|MOD_RCONTROL)))
  353.                     mods_for_next_key |= MOD_LCONTROL;
  354.                 // else don't add it, because the value of mods_for_next_key may also used to determine
  355.                 // which keys to release after the key to which this modifier applies is sent.
  356.                 // We don't want persistent modifiers to ever be released because that's how
  357.                 // AutoIt2 behaves and it seems like a reasonable standard.
  358.                 continue;
  359.             case '+':
  360.                 if (!(persistent_modifiers_for_this_SendKeys & (MOD_LSHIFT|MOD_RSHIFT)))
  361.                     mods_for_next_key |= MOD_LSHIFT;
  362.                 continue;
  363.             case '!':
  364.                 if (!(persistent_modifiers_for_this_SendKeys & (MOD_LALT|MOD_RALT)))
  365.                     mods_for_next_key |= MOD_LALT;
  366.                 continue;
  367.             case '#':
  368.                 if (g_script.mIsAutoIt2) // Since AutoIt2 ignores these, ignore them if script is in AutoIt2 mode.
  369.                     continue;
  370.                 if (!(persistent_modifiers_for_this_SendKeys & (MOD_LWIN|MOD_RWIN)))
  371.                     mods_for_next_key |= MOD_LWIN;
  372.                 continue;
  373.             case '}': continue;  // Important that these be ignored.  Be very careful about changing this, see below.
  374.             case '{':
  375.             {
  376.                 if (   !(end_pos = strchr(aKeys + 1, '}'))   ) // Ignore it and due to rarity, don't reset mods_for_next_key.
  377.                     continue; // This check is relied upon by some things below that assume a '}' is preset prior to the terminator.
  378.                 aKeys = omit_leading_whitespace(aKeys + 1); // v1.0.43: Skip leading whitespace inside the braces to be more flexible.
  379.                 if (   !(key_text_length = end_pos - aKeys)   )
  380.                 {
  381.                     if (end_pos[1] == '}')
  382.                     {
  383.                         // The literal string "{}}" has been encountered, which is interpreted as a single "}".
  384.                         ++end_pos;
  385.                         key_text_length = 1;
  386.                     }
  387.                     else // Empty braces {} were encountered (or all whitespace, but literal whitespace isn't sent).
  388.                         goto brace_case_end;  // The loop's ++aKeys will now skip over the '}', ignoring it.
  389.                 }
  390.  
  391.                 if (!strnicmp(aKeys, "Click", 5))
  392.                 {
  393.                     *end_pos = '\0';  // Temporarily terminate the string here to omit the closing brace from consideration below.
  394.                     ParseClickOptions(omit_leading_whitespace(aKeys + 5), click_x, click_y, vk
  395.                         , event_type, repeat_count, move_offset);
  396.                     *end_pos = '}';  // Undo temp termination.
  397.                     if (repeat_count < 1) // Allow {Click 100, 100, 0} to do a mouse-move vs. click (but modifiers like ^{Click..} aren't supported in this case.
  398.                         MouseMove(click_x, click_y, placeholder, g.DefaultMouseSpeed, move_offset);
  399.                     else // Use SendKey because it supports modifiers (e.g. ^{Click}) SendKey requires repeat_count>=1.
  400.                         SendKey(vk, 0, mods_for_next_key, persistent_modifiers_for_this_SendKeys
  401.                             , repeat_count, event_type, 0, aTargetWindow, click_x, click_y, move_offset);
  402.                     goto brace_case_end; // This {} item completely handled, so move on to next.
  403.                 }
  404.                 else if (!strnicmp(aKeys, "Raw", 3)) // This is used by auto-replace hotstrings too.
  405.                 {
  406.                     // As documented, there's no way to switch back to non-raw mode afterward since there's no
  407.                     // correct way to support special (non-literal) strings such as {Raw Off} while in raw mode.
  408.                     aSendRaw = true;
  409.                     goto brace_case_end; // This {} item completely handled, so move on to next.
  410.                 }
  411.  
  412.                 // Since above didn't "goto", this item isn't {Click}.
  413.                 event_type = KEYDOWNANDUP;         // Set defaults.
  414.                 repeat_count = 1;                  //
  415.                 key_name_length = key_text_length; //
  416.                 *end_pos = '\0';  // Temporarily terminate the string here to omit the closing brace from consideration below.
  417.  
  418.                 if (space_pos = StrChrAny(aKeys, " \t")) // Assign. Also, it relies on the fact that {} key names contain no spaces.
  419.                 {
  420.                     old_char = *space_pos;
  421.                     *space_pos = '\0';  // Temporarily terminate here so that TextToVK() can properly resolve a single char.
  422.                     key_name_length = space_pos - aKeys; // Override the default value set above.
  423.                     next_word = omit_leading_whitespace(space_pos + 1);
  424.                     UINT next_word_length = (UINT)(end_pos - next_word);
  425.                     if (next_word_length > 0)
  426.                     {
  427.                         if (!strnicmp(next_word, "Down", 4))
  428.                         {
  429.                             event_type = KEYDOWN;
  430.                             // v1.0.44.05: Added key_down_is_persistent (which is not initialized except here because
  431.                             // it's only applicable when event_type==KEYDOWN).  It avoids the following problem:
  432.                             // When a key is remapped to become a modifier (such as F1::Control), launching one of
  433.                             // the script's own hotkeys via F1 would lead to bad side-effects if that hotkey uses
  434.                             // the Send command. This is because the Send command assumes that any modifiers pressed
  435.                             // down by the script itself (such as Control) are intended to stay down during all
  436.                             // keystrokes generated by that script. To work around this, something like KeyWait F1
  437.                             // would otherwise be needed. within any hotkey triggered by the F1 key.
  438.                             key_down_is_persistent = strnicmp(next_word + 4, "Temp", 4); // "DownTemp" means non-persistent.
  439.                         }
  440.                         else if (!stricmp(next_word, "Up"))
  441.                             event_type = KEYUP;
  442.                         else
  443.                             repeat_count = ATOI(next_word);
  444.                             // Above: If negative or zero, that is handled further below.
  445.                             // There is no complaint for values <1 to support scripts that want to conditionally send
  446.                             // zero keystrokes, e.g. Send {a %Count%}
  447.                     }
  448.                 }
  449.  
  450.                 vk = TextToVK(aKeys, &mods_for_next_key, true, false, sTargetKeybdLayout); // false must be passed due to below.
  451.                 sc = vk ? 0 : TextToSC(aKeys);  // If sc is 0, it will be resolved by KeyEvent() later.
  452.                 if (!vk && !sc && toupper(aKeys[0]) == 'V' && toupper(aKeys[1]) == 'K')
  453.                 {
  454.                     char *sc_string = StrChrAny(aKeys + 2, "Ss"); // Look for the "SC" that demarks the scan code.
  455.                     if (sc_string && toupper(sc_string[1]) == 'C')
  456.                         sc = (sc_type)strtol(sc_string + 2, NULL, 16);  // Convert from hex.
  457.                     // else leave sc set to zero and just get the specified VK.  This supports Send {VKnn}.
  458.                     vk = (vk_type)strtol(aKeys + 2, NULL, 16);  // Convert from hex.
  459.                 }
  460.  
  461.                 if (space_pos)  // undo the temporary termination
  462.                     *space_pos = old_char;
  463.                 *end_pos = '}';  // undo the temporary termination
  464.                 if (repeat_count < 1)
  465.                     goto brace_case_end; // Gets rid of one level of indentation. Well worth it.
  466.  
  467.                 if (vk || sc)
  468.                 {
  469.                     if (key_as_modifiersLR = KeyToModifiersLR(vk, sc)) // Assign
  470.                     {
  471.                         if (!aTargetWindow)
  472.                         {
  473.                             if (event_type == KEYDOWN) // i.e. make {Shift down} have the same effect {ShiftDown}
  474.                             {
  475.                                 this_event_modifier_down = vk;
  476.                                 if (key_down_is_persistent) // v1.0.44.05.
  477.                                     sModifiersLR_persistent |= key_as_modifiersLR;
  478.                                 persistent_modifiers_for_this_SendKeys |= key_as_modifiersLR; // v1.0.44.06: Added this line to fix the fact that "DownTemp" should keep the key pressed down after the send.
  479.                             }
  480.                             else if (event_type == KEYUP) // *not* KEYDOWNANDUP, since that would be an intentional activation of the Start Menu or menu bar.
  481.                             {
  482.                                 DisguiseWinAltIfNeeded(vk, in_blind_mode);
  483.                                 sModifiersLR_persistent &= ~key_as_modifiersLR;
  484.                                 // By contrast with KEYDOWN, KEYUP should also remove this modifier
  485.                                 // from extra_persistent_modifiers_for_blind_mode if it happens to be
  486.                                 // in there.  For example, if "#i::Send {LWin Up}" is a hotkey,
  487.                                 // LWin should become persistently up in every respect.
  488.                                 extra_persistent_modifiers_for_blind_mode &= ~key_as_modifiersLR;
  489.                                 // Fix for v1.0.43: Also remove LControl if this key happens to be AltGr.
  490.                                 if (vk == VK_RMENU && sTargetLayoutHasAltGr == CONDITION_TRUE) // It is AltGr.
  491.                                     extra_persistent_modifiers_for_blind_mode &= ~MOD_LCONTROL;
  492.                                 // Since key_as_modifiersLR isn't 0, update to reflect any changes made above:
  493.                                 persistent_modifiers_for_this_SendKeys = sModifiersLR_persistent | extra_persistent_modifiers_for_blind_mode;
  494.                             }
  495.                             // else must never change sModifiersLR_persistent in response to KEYDOWNANDUP
  496.                             // because that would break existing scripts.  This is because that same
  497.                             // modifier key may have been pushed down via {ShiftDown} rather than "{Shift Down}".
  498.                             // In other words, {Shift} should never undo the effects of a prior {ShiftDown}
  499.                             // or {Shift down}.
  500.                         }
  501.                         //else don't add this event to sModifiersLR_persistent because it will not be
  502.                         // manifest via keybd_event.  Instead, it will done via less intrusively
  503.                         // (less interference with foreground window) via SetKeyboardState() and
  504.                         // PostMessage().  This change is for ControlSend in v1.0.21 and has been
  505.                         // documented.
  506.                     }
  507.                     // Below: sModifiersLR_persistent stays in effect (pressed down) even if the key
  508.                     // being sent includes that same modifier.  Surprisingly, this is how AutoIt2
  509.                     // behaves also, which is good.  Example: Send, {AltDown}!f  ; this will cause
  510.                     // Alt to still be down after the command is over, even though F is modified
  511.                     // by Alt.
  512.                     SendKey(vk, sc, mods_for_next_key, persistent_modifiers_for_this_SendKeys
  513.                         , repeat_count, event_type, key_as_modifiersLR, aTargetWindow);
  514.                 }
  515.  
  516.                 else if (key_name_length == 1) // No vk/sc means a char of length one is sent via special method.
  517.                 {
  518.                     // v1.0.40: SendKeySpecial sends only keybd_event keystrokes, not ControlSend style
  519.                     // keystrokes.
  520.                     // v1.0.43.07: Added check of event_type!=KEYUP, which causes something like Send {≡ up} to
  521.                     // do nothing if the curr. keyboard layout lacks such a key.  This is relied upon by remappings
  522.                     // such as F1::≡ (i.e. a destination key that doesn't have a VK, at least in English).
  523.                     if (!aTargetWindow && event_type != KEYUP) // In this mode, mods_for_next_key and event_type are ignored due to being unsupported.
  524.                         SendKeySpecial(aKeys[0], repeat_count);
  525.                     //else do nothing since it's there's no known way to send the keystokes.
  526.                 }
  527.  
  528.                 // See comment "else must never change sModifiersLR_persistent" above about why
  529.                 // !aTargetWindow is used below:
  530.                 else if (vk = TextToSpecial(aKeys, (UINT)key_text_length, event_type
  531.                     , persistent_modifiers_for_this_SendKeys, !aTargetWindow)) // Assign.
  532.                 {
  533.                     if (!aTargetWindow)
  534.                     {
  535.                         if (event_type == KEYDOWN)
  536.                             this_event_modifier_down = vk;
  537.                         else // It must be KEYUP because TextToSpecial() never returns KEYDOWNANDUP.
  538.                             DisguiseWinAltIfNeeded(vk, in_blind_mode);
  539.                     }
  540.                     // Since we're here, repeat_count > 0.
  541.                     // v1.0.42.04: A previous call to SendKey() or SendKeySpecial() might have left modifiers
  542.                     // in the wrong state (e.g. Send +{F1}{ControlDown}).  Since modifiers can sometimes affect
  543.                     // each other, make sure they're in the state intended by the user before beginning:
  544.                     SetModifierLRState(persistent_modifiers_for_this_SendKeys
  545.                         , sSendMode ? sEventModifiersLR : GetModifierLRState()
  546.                         , aTargetWindow, false, false); // It also does DoKeyDelay(g.PressDuration).
  547.                     for (int i = 0; i < repeat_count; ++i)
  548.                     {
  549.                         // Don't tell it to save & restore modifiers because special keys like this one
  550.                         // should have maximum flexibility (i.e. nothing extra should be done so that the
  551.                         // user can have more control):
  552.                         KeyEvent(event_type, vk, 0, aTargetWindow, true);
  553.                         if (!sSendMode)
  554.                             LONG_OPERATION_UPDATE_FOR_SENDKEYS
  555.                     }
  556.                 }
  557.  
  558.                 else if (key_text_length > 4 && !strnicmp(aKeys, "ASC ", 4) && !aTargetWindow) // {ASC nnnnn}
  559.                 {
  560.                     // Include the trailing space in "ASC " to increase uniqueness (selectivity).
  561.                     // Also, sending the ASC sequence to window doesn't work, so don't even try:
  562.                     SendASC(omit_leading_whitespace(aKeys + 3));
  563.                     // Do this only once at the end of the sequence:
  564.                     DoKeyDelay(); // It knows not to do the delay for SM_INPUT.
  565.                 }
  566.                 //else do nothing since it isn't recognized as any of the above "else if" cases (see below).
  567.  
  568.                 // If what's between {} is unrecognized, such as {Bogus}, it's safest not to send
  569.                 // the contents literally since that's almost certainly not what the user intended.
  570.                 // In addition, reset the modifiers, since they were intended to apply only to
  571.                 // the key inside {}.  Also, the below is done even if repeat-count is zero.
  572.  
  573. brace_case_end: // This label is used to simplify the code without sacrificing performance.
  574.                 aKeys = end_pos;  // In prep for aKeys++ done by the loop.
  575.                 mods_for_next_key = 0;
  576.                 continue;
  577.             } // case '{'
  578.             } // switch()
  579.         } // if (!aSendRaw && strchr("^+!#{}", *aKeys))
  580.  
  581.         else // Encountered a character other than ^+!#{} ... or we're in raw mode.
  582.         {
  583.             // Best to call this separately, rather than as first arg in SendKey, since it changes the
  584.             // value of modifiers and the updated value is *not* guaranteed to be passed.
  585.             // In other words, SendKey(TextToVK(...), modifiers, ...) would often send the old
  586.             // value for modifiers.
  587.             single_char_string[0] = *aKeys; // String was pre-terminated earlier.
  588.             if (vk = TextToVK(single_char_string, &mods_for_next_key, true, true, sTargetKeybdLayout))
  589.                 // TextToVK() takes no measurable time compared to the amount of time SendKey takes.
  590.                 SendKey(vk, 0, mods_for_next_key, persistent_modifiers_for_this_SendKeys, 1, KEYDOWNANDUP
  591.                     , 0, aTargetWindow);
  592.             else // Try to send it by alternate means.
  593.             {
  594.                 // v1.0.40: SendKeySpecial sends only keybd_event keystrokes, not ControlSend style keystrokes:
  595.                 if (!aTargetWindow) // In this mode, mods_for_next_key is ignored due to being unsupported.
  596.                     SendKeySpecial(*aKeys, 1);
  597.                 //else do nothing since it's there's no known way to send the keystokes.
  598.             }
  599.             mods_for_next_key = 0;  // Safest to reset this regardless of whether a key was sent.
  600.         }
  601.     } // for()
  602.  
  603.     modLR_type mods_to_set;
  604.     if (sSendMode)
  605.     {
  606.         int final_key_delay = -1;  // Set default.
  607.         if (!sAbortArraySend && sEventCount > 0) // Check for zero events for performance, but more importantly because playback hook will not operate correctly with zero.
  608.         {
  609.             // Add more events to the array (prior to sending) to support the following:
  610.             // Restore the modifiers to match those the user is physically holding down, but do it as *part*
  611.             // of the single SendInput/Play call.  The reasons it's done here as part of the array are:
  612.             // 1) It avoids the need for #HotkeyModifierTimeout (and it's superior to it) for both SendInput
  613.             //    and SendPlay.
  614.             // 2) The hook will not be present during the SendInput, nor can it be reinstalled in time to
  615.             //    catch any physical events generated by the user during the Send. Consequently, there is no
  616.             //    known way to reliably detect physical keystate changes.
  617.             // 3) Changes made to modifier state by SendPlay are seen only by the active window's thread.
  618.             //    Thus, it would be inconsistent and poasibly incorrect to adjust global modifier state
  619.             //    after (or during) a SendPlay.
  620.             // So rather than resorting to #HotkeyModifierTimeout, we can restore the modifiers within the
  621.             // protection of SendInput/Play's uninterruptibility, allowing the user's buffered keystrokes
  622.             // (if any) to hit against the correct modifier state when the SendInput/Play completes.
  623.             // For example, if #c:: is a hotkey and the user releases Win during the SendInput/Play, that
  624.             // release would hit after SendInput/Play restores Win to the down position, and thus Win would
  625.             // not be stuck down.  Furthermore, if the user didn't release Win, Win would be in the
  626.             // correct/intended position.
  627.             // This approach has a few weaknesses (but the strengths appear to outweigh them):
  628.             // 1) Hitting SendInput's 5000 char limit would omit the tail-end keystrokes, which would mess up
  629.             //    all the assumptions here.  But hitting that limit should be very rare, especially since it's
  630.             //    documented and thus scripts will avoid it.
  631.             // 2) SendInput's assumed uninterruptibility is false if any other app or script has an LL hook
  632.             //    installed.  This too is documented, so scripts should generally avoid using SendInput when
  633.             //    they know there are other LL hooks in the system.  In any case, there's no known solution
  634.             //    for it, so nothing can be done.
  635.             mods_to_set = persistent_modifiers_for_this_SendKeys
  636.                 | (in_blind_mode ? 0 : (mods_down_physically_orig & ~mods_down_physically_but_not_logically_orig)); // The last item is usually 0.
  637.             // Above: When in blind mode, don't restore physical modifiers.  This is done to allow a hotkey
  638.             // such as the following to release Shift:
  639.             //    +space::SendInput/Play {Blind}{Shift up}
  640.             // Note that SendPlay can make such a change only from the POV of the target window; i.e. it can
  641.             // release shift as seen by the target window, but not by any other thread; so the shift key would
  642.             // still be considered to be down for the purpose of firing hotkeys (it can't change global key state
  643.             // as seen by GetAsyncKeyState).
  644.             // For more explanation of above, see a similar section for the non-array/old Send below.
  645.             SetModifierLRState(mods_to_set, sEventModifiersLR, NULL, true, true); // Disguise in case user released or pressed Win/Alt during the Send (seems best to do it even for SendPlay, though it probably needs only Alt, not Win).
  646.             // mods_to_set is used further below as the set of modifiers that were explicitly put into effect at the tail end of SendInput.
  647.             SendEventArray(final_key_delay, mods_to_set);
  648.         }
  649.         CleanupEventArray(final_key_delay);
  650.     }
  651.     else // A non-array send is in effect, so a more elaborate adjustment to logical modifiers is called for.
  652.     {
  653.         // Determine (or use best-guess, if necessary) which modifiers are down physically now as opposed
  654.         // to right before the Send began.
  655.         modLR_type mods_down_physically; // As compared to mods_down_physically_orig.
  656.         if (g_KeybdHook)
  657.             mods_down_physically = g_modifiersLR_physical;
  658.         else // No hook, so consult g_HotkeyModifierTimeout to make the determination.
  659.             // Assume that the same modifiers that were phys+logically down before the Send are still
  660.             // physically down (though not necessarily logically, since the Send may have released them),
  661.             // but do this only if the timeout period didn't expire (or the user specified that it never
  662.             // times out; i.e. elapsed time < timeout-value; DWORD math gives the right answer even if
  663.             // tick-count has wrapped around).
  664.             mods_down_physically = (g_HotkeyModifierTimeout < 0 // It never times out or...
  665.                 || (GetTickCount() - g_script.mThisHotkeyStartTime) < (DWORD)g_HotkeyModifierTimeout) // It didn't time out.
  666.                 ? mods_down_physically_orig : 0;
  667.  
  668.         // Restore the state of the modifiers to be those the user is physically holding down right now.
  669.         // Any modifiers that are logically "persistent", as detected upon entrance to this function
  670.         // (e.g. due to something such as a prior "Send, {LWinDown}"), are also pushed down if they're not already.
  671.         // Don't press back down the modifiers that were used to trigger this hotkey if there's
  672.         // any doubt that they're still down, since doing so when they're not physically down
  673.         // would cause them to be stuck down, which might cause unwanted behavior when the unsuspecting
  674.         // user resumes typing.
  675.         // v1.0.42.04: Now that SendKey() is lazy about releasing Ctrl and/or Shift (but not Win/Alt),
  676.         // the section below also releases Ctrl/Shift if appropriate.  See SendKey() for more details.
  677.         mods_to_set = persistent_modifiers_for_this_SendKeys; // Set default.
  678.         if (in_blind_mode) // This section is not needed for the array-sending modes because they exploit uninterruptibility to perform a more reliable restoration.
  679.         {
  680.             // At the end of a blind-mode send, modifiers are restored differently than normal. One
  681.             // reason for this is to support the explicit ability for a Send to turn off a hotkey's
  682.             // modifiers even if the user is still physically holding them down.  For example:
  683.             //   #space::Send {LWin up}  ; Fails to release it, by design and for backward compatibility.
  684.             //   #space::Send {Blind}{LWin up}  ; Succeeds, allowing LWin to be logically up even though it's physically down.
  685.             modLR_type mods_changed_physically_during_send = mods_down_physically_orig ^ mods_down_physically;
  686.             // Fix for v1.0.42.04: To prevent keys from getting stuck down, compensate for any modifiers
  687.             // the user physically pressed or released during the Send (especially those released).
  688.             // Remove any modifiers physically released during the send so that they don't get pushed back down:
  689.             mods_to_set &= ~(mods_changed_physically_during_send & mods_down_physically_orig); // Remove those that changed from down to up.
  690.             // Conversely, add any modifiers newly, physically pressed down during the Send, because in
  691.             // most cases the user would want such modifiers to be logically down after the Send.
  692.             // Obsolete comment from v1.0.40: For maximum flexibility and minimum interference while
  693.             // in blind mode, never restore modifiers to the down position then.
  694.             mods_to_set |= mods_changed_physically_during_send & mods_down_physically; // Add those that changed from up to down.
  695.         }
  696.         else // Regardless of whether the keyboard hook is present, the following formula applies.
  697.             mods_to_set |= mods_down_physically & ~mods_down_physically_but_not_logically_orig; // The second item is usually 0.
  698.             // Above takes into account the fact that the user may have pressed and/or released some modifiers
  699.             // during the Send.
  700.             // So it includes all keys that are physically down except those that were down physically but not
  701.             // logically at the *start* of the send operation (since the send operation may have changed the
  702.             // logical state).  In other words, we want to restore the keys to their former logical-down
  703.             // position to match the fact that the user is still holding them down physically.  The
  704.             // previously-down keys we don't do this for are those that were physically but not logically down,
  705.             // such as a naked Control key that's used as a suffix without being a prefix.  More details:
  706.             // mods_down_physically_but_not_logically_orig is used to distinguish between the following two cases,
  707.             // allowing modifiers to be properly restored to the down position when the hook is installed:
  708.             // 1) A naked modifier key used only as suffix: when the user phys. presses it, it isn't
  709.             //    logically down because the hook suppressed it.
  710.             // 2) A modifier that is a prefix, that triggers a hotkey via a suffix, and that hotkey sends
  711.             //    that modifier.  The modifier will go back up after the SEND, so the key will be physically
  712.             //    down but not logically.
  713.  
  714.         // Use KEY_IGNORE_ALL_EXCEPT_MODIFIER to tell the hook to adjust g_modifiersLR_logical_non_ignored
  715.         // because these keys being put back down match the physical pressing of those same keys by the
  716.         // user, and we want such modifiers to be taken into account for the purpose of deciding whether
  717.         // other hotkeys should fire (or the same one again if auto-repeating):
  718.         // v1.0.42.04: A previous call to SendKey() might have left Shift/Ctrl in the down position
  719.         // because by procrastinatating, extraneous keystrokes in examples such as "Send ABCD" are
  720.         // eliminated (previously, such that example released the shift key after sending each key,
  721.         // only to have to press it down again for the next one.  For this reason, some modifiers
  722.         // might get released here in addition to any that need to get pressed down.  That's why
  723.         // SetModifierLRState() is called rather than the old method of pushing keys down only,
  724.         // never releasing them.
  725.         // Put the modifiers in mods_to_set into effect.  Although "true" is passed to disguise up-events,
  726.         // there generally shouldn't be any up-events for Alt or Win because SendKey() would have already
  727.         // released them.  One possible exception to this is when the user physically released Alt or Win
  728.         // during the send (perhaps only during specific sensitive/vulnerable moments).
  729.         SetModifierLRState(mods_to_set, GetModifierLRState(), aTargetWindow, true, true); // It also does DoKeyDelay(g.PressDuration).
  730.     } // End of non-array Send.
  731.  
  732.     // For peace of mind and because that's how it was tested originally, the following is done
  733.     // only after adjusting the modifier state above (since that adjustment might be able to
  734.     // affect the global variables used below in a meaningful way).
  735.     if (g_KeybdHook)
  736.     {
  737.         // Ensure that g_modifiersLR_logical_non_ignored does not contain any down-modifiers
  738.         // that aren't down in g_modifiersLR_logical.  This is done mostly for peace-of-mind,
  739.         // since there might be ways, via combinations of physical user input and the Send
  740.         // commands own input (overlap and interference) for one to get out of sync with the
  741.         // other.  The below uses ^ to find the differences between the two, then uses & to
  742.         // find which are down in non_ignored that aren't in logical, then inverts those bits
  743.         // in g_modifiersLR_logical_non_ignored, which sets those keys to be in the up position:
  744.         g_modifiersLR_logical_non_ignored &= ~((g_modifiersLR_logical ^ g_modifiersLR_logical_non_ignored)
  745.             & g_modifiersLR_logical_non_ignored);
  746.     }
  747.  
  748.     if (prior_capslock_state == TOGGLED_ON) // The current user setting requires us to turn it back on.
  749.         ToggleKeyState(VK_CAPITAL, TOGGLED_ON);
  750.  
  751.     // Might be better to do this after changing capslock state, since having the threads attached
  752.     // tends to help with updating the global state of keys (perhaps only under Win9x in this case):
  753.     if (threads_are_attached)
  754.         AttachThreadInput(g_MainThreadID, target_thread, FALSE);
  755.  
  756.     if (do_selective_blockinput && !blockinput_prev) // Turn it back off only if it was off before we started.
  757.         Line::ScriptBlockInput(false);
  758.  
  759.     // v1.0.43.03: Someone reported that when a non-autoreplace hotstring calls us to do its backspacing, the
  760.     // hotstring's subroutine can execute a command that activates another window owned by the script before
  761.     // the original window finished receiving its backspaces.  Although I can't reproduce it, this behavior
  762.     // fits with expectations since our thread won't necessarily have a chance to process the incoming
  763.     // keystrokes before executing the command that comes after SendInput.  If those command(s) activate
  764.     // another of this thread's windows, that window will most likely intercept the keystrokes (assuming
  765.     // that the message pump dispatches buffered keystrokes to whichever window is active at the time the
  766.     // message is processed).
  767.     // This fix does not apply to the SendPlay or SendEvent modes, the former due to the fact that it sleeps
  768.     // a lot while the playback is running, and the latter due to key-delay and because testing has never shown
  769.     // a need for it.
  770.     if (aSendModeOrig == SM_INPUT && GetWindowThreadProcessId(GetForegroundWindow(), NULL) == g_MainThreadID) // GetWindowThreadProcessId() tolerates a NULL hwnd.
  771.         SLEEP_WITHOUT_INTERRUPTION(-1);
  772.  
  773.     // v1.0.43.08: Restore the original thread key-delay values in case above temporarily overrode them.
  774.     g.KeyDelay = orig_key_delay;
  775.     g.PressDuration = orig_press_duration;
  776. }
  777.  
  778.  
  779.  
  780. void SendKey(vk_type aVK, sc_type aSC, modLR_type aModifiersLR, modLR_type aModifiersLRPersistent
  781.     , int aRepeatCount, KeyEventTypes aEventType, modLR_type aKeyAsModifiersLR, HWND aTargetWindow
  782.     , int aX, int aY, bool aMoveOffset)
  783. // Caller has ensured that: 1) vk or sc may be zero, but not both; 2) aRepeatCount > 0.
  784. // This function is reponsible for first setting the correct state of the modifier keys
  785. // (as specified by the caller) before sending the key.  After sending, it should put the
  786. // modifier keys  back to the way they were originally (UPDATE: It does this only for Win/Alt
  787. // for the reasons described near the end of this function).
  788. {
  789.     // Caller is now responsible for verifying this:
  790.     // Avoid changing modifier states and other things if there is nothing to be sent.
  791.     // Otherwise, menu bar might activated due to ALT keystrokes that don't modify any key,
  792.     // the Start Menu might appear due to WIN keystrokes that don't modify anything, etc:
  793.     //if ((!aVK && !aSC) || aRepeatCount < 1)
  794.     //    return;
  795.  
  796.     // I thought maybe it might be best not to release unwanted modifier keys that are already down
  797.     // (perhaps via something like "Send, {altdown}{esc}{altup}"), but that harms the case where
  798.     // modifier keys are down somehow, unintentionally: The send command wouldn't behave as expected.
  799.     // e.g. "Send, abc" while the control key is held down by other means, would send ^a^b^c,
  800.     // possibly dangerous.  So it seems best to default to making sure all modifiers are in the
  801.     // proper down/up position prior to sending any Keybd events.  UPDATE: This has been changed
  802.     // so that only modifiers that were actually used to trigger that hotkey are released during
  803.     // the send.  Other modifiers that are down may be down intentially, e.g. due to a previous
  804.     // call to Send such as: Send {ShiftDown}.
  805.     // UPDATE: It seems best to save the initial state only once, prior to sending the key-group,
  806.     // because only at the beginning can the original state be determined without having to
  807.     // save and restore it in each loop iteration.
  808.     // UPDATE: Not saving and restoring at all anymore, due to interference (side-effects)
  809.     // caused by the extra keybd events.
  810.  
  811.     // The combination of aModifiersLR and aModifiersLRPersistent are the modifier keys that
  812.     // should be down prior to sending the specified aVK/aSC. aModifiersLR are the modifiers
  813.     // for this particular aVK keystroke, but aModifiersLRPersistent are the ones that will stay
  814.     // in pressed down even after it's sent.
  815.     modLR_type modifiersLR_specified = aModifiersLR | aModifiersLRPersistent;
  816.     bool vk_is_mouse = IsMouseVK(aVK); // Caller has ensured that VK is non-zero when it wants a mouse click.
  817.  
  818.     LONG_OPERATION_INIT
  819.     for (int i = 0; i < aRepeatCount; ++i)
  820.     {
  821.         if (!sSendMode)
  822.             LONG_OPERATION_UPDATE_FOR_SENDKEYS  // This does not measurably affect the performance of SendPlay/Event.
  823.         // These modifiers above stay in effect for each of these keypresses.
  824.         // Always on the first iteration, and thereafter only if the send won't be essentially
  825.         // instantaneous.  The modifiers are checked before every key is sent because
  826.         // if a high repeat-count was specified, the user may have time to release one or more
  827.         // of the modifier keys that were used to trigger a hotkey.  That physical release
  828.         // will cause a key-up event which will cause the state of the modifiers, as seen
  829.         // by the system, to change.  For example, if user releases control-key during the operation,
  830.         // some of the D's won't be control-D's:
  831.         // ^c::Send,^{d 15}
  832.         // Also: Seems best to do SetModifierLRState() even if Keydelay < 0:
  833.         // Update: If this key is itself a modifier, don't change the state of the other
  834.         // modifier keys just for it, since most of the time that is unnecessary and in
  835.         // some cases, the extra generated keystrokes would cause complications/side-effects.
  836.         if (!aKeyAsModifiersLR)
  837.         {
  838.             // DISGUISE UP: Pass "true" to disguise UP-events on WIN and ALT due to hotkeys such as:
  839.             // !a::Send test
  840.             // !a::Send {LButton}
  841.             // v1.0.40: It seems okay to tell SetModifierLRState to disguise Win/Alt regardless of
  842.             // whether our caller is in blind mode.  This is because our caller already put any extra
  843.             // blind-mode modifiers into modifiersLR_specified, which prevents any actual need to
  844.             // disguise anything (only the release of Win/Alt is ever disguised).
  845.             // DISGUISE DOWN: Pass "false" to avoid disguising DOWN-events on Win and Alt because Win/Alt
  846.             // will be immediately followed by some key for them to "modify".  The exceptions to this are
  847.             // when aVK is a mouse button (e.g. sending !{LButton} or #{LButton}).  But both of those are
  848.             // so rare that the flexibility of doing exactly what the script specifies seems better than
  849.             // a possibly unwanted disguising.  Also note that hotkeys such as #LButton automatically use
  850.             // both hooks so that the Start Menu doesn't appear when the Win key is released, so we're
  851.             // not responsible for that type of disguising here.
  852.             SetModifierLRState(modifiersLR_specified, sSendMode ? sEventModifiersLR : GetModifierLRState()
  853.                 , aTargetWindow, false, true, KEY_IGNORE); // See keyboard_mouse.h for explantion of KEY_IGNORE.
  854.             // SetModifierLRState() also does DoKeyDelay(g.PressDuration).
  855.         }
  856.  
  857.         // v1.0.42.04: Mouse clicks are now handled here in the same loop as keystrokes so that the modifiers
  858.         // will be readjusted (above) if the user presses/releases modifier keys during the mouse clicks.
  859.         if (vk_is_mouse && !aTargetWindow)
  860.             MouseClick(aVK, aX, aY, 1, g.DefaultMouseSpeed, aEventType, aMoveOffset);
  861.             // Above: Since it's rare to send more than one click, it seems best to simplify and reduce code size
  862.             // by not doing more than one click at a time event when mode is SendInput/Play.
  863.         else
  864.             // Sending mouse clicks via ControlSend is not supported, so in that case fall back to the
  865.             // old method of sending the VK directly (which probably has no effect 99% of the time):
  866.             KeyEvent(aEventType, aVK, aSC, aTargetWindow, true);
  867.     } // for() [aRepeatCount]
  868.  
  869.     // The final iteration by the above loop does a key or mouse delay (KeyEvent and MouseClick do it internally)
  870.     // prior to us changing the modifiers below.  This is a good thing because otherwise the modifiers would
  871.     // sometimes be released so soon after the keys they modify that the modifiers are not in effect.
  872.     // This can be seen sometimes when/ ctrl-shift-tabbing back through a multi-tabbed dialog:
  873.     // The last ^+{tab} might otherwise not take effect because the CTRL key would be released too quickly.
  874.  
  875.     // Release any modifiers that were pressed down just for the sake of the above
  876.     // event (i.e. leave any persistent modifiers pressed down).  The caller should
  877.     // already have verified that aModifiersLR does not contain any of the modifiers
  878.     // in aModifiersLRPersistent.  Also, call GetModifierLRState() again explicitly
  879.     // rather than trying to use a saved value from above, in case the above itself
  880.     // changed the value of the modifiers (i.e. aVk/aSC is a modifier).  Admittedly,
  881.     // that would be pretty strange but it seems the most correct thing to do (another
  882.     // reason is that the user may have pressed or released modifier keys during the
  883.     // final mouse/key delay that was done above).
  884.     if (!aKeyAsModifiersLR) // See prior use of this var for explanation.
  885.     {
  886.         // It seems best not to use KEY_IGNORE_ALL_EXCEPT_MODIFIER in this case, though there's
  887.         // a slight chance that a script or two might be broken by not doing so.  The chance
  888.         // is very slight because the only thing KEY_IGNORE_ALL_EXCEPT_MODIFIER would allow is
  889.         // something like the following example.  Note that the hotkey below must be a hook
  890.         // hotkey (even more rare) because registered hotkeys will still see the logical modifier
  891.         // state and thus fire regardless of whether g_modifiersLR_logical_non_ignored says that
  892.         // they shouldn't:
  893.         // #b::Send, {CtrlDown}{AltDown}
  894.         // $^!a::MsgBox You pressed the A key after pressing the B key.
  895.         // In the above, making ^!a a hook hotkey prevents it from working in conjunction with #b.
  896.         // UPDATE: It seems slightly better to have it be KEY_IGNORE_ALL_EXCEPT_MODIFIER for these reasons:
  897.         // 1) Persistent modifiers are fairly rare.  When they're in effect, it's usually for a reason
  898.         //    and probably a pretty good one and from a user who knows what they're doing.
  899.         // 2) The condition that g_modifiersLR_logical_non_ignored was added to fix occurs only when
  900.         //    the user physically presses a suffix key (or auto-repeats one by holding it down)
  901.         //    during the course of a SendKeys() operation.  Since the persistent modifiers were
  902.         //    (by definition) already in effect prior to the Send, putting them back down for the
  903.         //    purpose of firing hook hotkeys does not seem unreasonable, and may in fact add value.
  904.         // DISGUISE DOWN: When SetModifierLRState() is called below, it should only release keys, not press
  905.         // any down (except if the user's physical keystrokes interferred).  Therefore, passing true or false
  906.         // for the disguise-down-events paramater doesn't matter much (but pass "true" in case the user's
  907.         // keystrokes did interfere in a way that requires a Alt or Win to be pressed back down, because
  908.         // disguising it seems best).
  909.         // DISGUISE UP: When SetModifierLRState() is called below, it is passed "false" for disguise-up
  910.         // to avoid generating unnecessary disguise-keystrokes.  They are not needed because if our keystrokes
  911.         // were modified by either WIN or ALT, the release of the WIN or ALT key will already be disguised due to
  912.         // its having modified something while it was down.  The exceptions to this are when aVK is a mouse button
  913.         // (e.g. sending !{LButton} or #{LButton}).  But both of those are so rare that the flexibility of doing
  914.         // exactly what the script specifies seems better than a possibly unwanted disguising.
  915.         // UPDATE for v1.0.42.04: Only release Win and Alt (if appropriate), not Ctrl and Shift, since we know
  916.         // Win/Alt don't have to be disguised but our caller would have trouble tracking that info or making that
  917.         // determination.  This avoids extra keystrokes, while still procrastinating the release of Ctrl/Shift so
  918.         // that those can be left down if the caller's next keystroke happens to need them.
  919.         modLR_type state_now = sSendMode ? sEventModifiersLR : GetModifierLRState();
  920.         modLR_type win_alt_to_be_released = ((state_now ^ aModifiersLRPersistent) & state_now) // The modifiers to be released...
  921.             & (MOD_LWIN|MOD_RWIN|MOD_LALT|MOD_RALT); // ... but restrict them to only Win/Alt.
  922.         if (win_alt_to_be_released)
  923.             SetModifierLRState(state_now & ~win_alt_to_be_released
  924.                 , state_now, aTargetWindow, true, false); // It also does DoKeyDelay(g.PressDuration).
  925.     }
  926. }
  927.  
  928.  
  929.  
  930. void SendKeySpecial(char aChar, int aRepeatCount)
  931. // Caller must be aware that keystrokes are sent directly (i.e. never to a target window via ControlSend mode).
  932. // It must also be aware that the event type KEYDOWNANDUP is always what's used since there's no way
  933. // to support anything else.  Furthermore, there's no way to support "modifiersLR_for_next_key" such as ^Ç
  934. // (assuming Ã‡ is a character for which SendKeySpecial() is required in the current layout).
  935. // This function uses some of the same code as SendKey() above, so maintain them together.
  936. {
  937.     // Caller must verify that aRepeatCount > 1.
  938.     // Avoid changing modifier states and other things if there is nothing to be sent.
  939.     // Otherwise, menu bar might activated due to ALT keystrokes that don't modify any key,
  940.     // the Start Menu might appear due to WIN keystrokes that don't modify anything, etc:
  941.     //if (aRepeatCount < 1)
  942.     //    return;
  943.  
  944.     // v1.0.40: This function was heavily simplified because the old method of simulating
  945.     // characters via dead keys apparently never executed under any keyboard layout.  It never
  946.     // got past the following on the layouts I tested (Russian, German, Danish, Spanish):
  947.     //        if (!send1 && !send2) // Can't simulate aChar.
  948.     //            return;
  949.     // This might be partially explained by the fact that the following old code always exceeded
  950.     // the bounds of the array (because aChar was always between 0 and 127), so it was never valid
  951.     // in the first place:
  952.     //        asc_int = cAnsiToAscii[(int)((aChar - 128) & 0xff)] & 0xff;
  953.  
  954.     // Producing ANSI characters via Alt+Numpad and a leading zero appears standard on most languages
  955.     // and layouts (at least those whose active code page is 1252/Latin 1 US/Western Europe).  However,
  956.     // Russian (code page 1251 Cyrillic) is apparently one exception as shown by the fact that sending
  957.     // all of the characters above Chr(127) while under Russian layout produces Cyrillic characters
  958.     // if the active window's focused control is an Edit control (even if its an ANSI app).
  959.     // I don't know the difference between how such characters are actually displayed as opposed to how
  960.     // they're stored stored in memory (in notepad at least, there appears to be some kind of on-the-fly
  961.     // translation to Unicode as shown when you try to save such a file).  But for now it doesn't matter
  962.     // because for backward compatibility, it seems best not to change it until some alternative is
  963.     // discovered that's high enough in value to justify breaking existing scripts that run under Russian
  964.     // and other non-code-page-1252 layouts.
  965.     //
  966.     // Production of ANSI characters above 127 has been tested on both Windows XP and 98se (but not the
  967.     // Win98 command prompt).
  968.  
  969.     char asc_string[16], *cp = asc_string;
  970.  
  971.     // The following range isn't checked because this function appears never to be called for such
  972.     // characters (tested in English and Russian so far), probably because VkKeyScan() finds a way to
  973.     // manifest them via Control+VK combinations:
  974.     //if (aChar > -1 && aChar < 32)
  975.     //    return;
  976.     if (aChar < 0)    // Try using ANSI.
  977.         *cp++ = '0';  // ANSI mode is achieved via leading zero in the Alt+Numpad keystrokes.
  978.     //else use Alt+Numpad without the leading zero, which allows the characters a-z, A-Z, and quite
  979.     // a few others to be produced in Russian and perhaps other layouts, which was impossible in versions
  980.     // prior to 1.0.40.
  981.     _itoa((int)(UCHAR)aChar, cp, 10); // Convert to UCHAR in case aChar < 0.
  982.  
  983.     LONG_OPERATION_INIT
  984.     for (int i = 0; i < aRepeatCount; ++i)
  985.     {
  986.         if (!sSendMode)
  987.             LONG_OPERATION_UPDATE_FOR_SENDKEYS
  988.         SendASC(asc_string);
  989.         DoKeyDelay(); // It knows not to do the delay for SM_INPUT.
  990.     }
  991.     // It is not necessary to do SetModifierLRState() to put a caller-specified set of persistent modifier
  992.     // keys back into effect because:
  993.     // 1) Our call to SendASC above (if any) at most would have released some of the modifiers (though never
  994.     //    WIN because it isn't necessary); but never pusheed any new modifiers down (it even releases ALT
  995.     //    prior to returning).
  996.     // 2) Our callers, if they need to push ALT back down because we didn't do it, will either disguise it
  997.     //    or avoid doing so because they're about to send a keystroke (just about anything) that ALT will
  998.     //    modify and thus not need to be disguised.
  999. }
  1000.  
  1001.  
  1002.  
  1003. void SendASC(char *aAscii)
  1004. // Caller must be aware that keystrokes are sent directly (i.e. never to a target window via ControlSend mode).
  1005. // aAscii is a string to support explicit leading zeros because sending 216, for example, is not the same as
  1006. // sending 0216.  The caller is also responsible for restoring any desired modifier keys to the down position
  1007. // (this function needs to release some of them if they're down).
  1008. {
  1009.     // UPDATE: In v1.0.42.04, the left Alt key is always used below because:
  1010.     // 1) It might be required on Win95/NT (though testing shows that RALT works okay on Windows 98se).
  1011.     // 2) It improves maintainability because if the keyboard layout has AltGr, and the Control portion
  1012.     //    of AltGr is released without releasing the RAlt portion, anything that expects LControl to
  1013.     //    be down whenever RControl is down would be broken.
  1014.     // The following test demonstrates that on previous versions under German layout, the right-Alt key
  1015.     // portion of AltGr could be used to manifest Alt+Numpad combinations:
  1016.     //   Send {RAlt down}{Asc 67}{RAlt up}  ; Should create a C character even when both the active window an AHK are set to German layout.
  1017.     //   KeyHistory  ; Shows that the right-Alt key was successfully used rather than the left.
  1018.     // Changing the modifier state via SetModifierLRState() (rather than some more error-prone multi-step method)
  1019.     // also ensures that the ALT key is pressed down only after releasing any shift key that needed it above.
  1020.     // Otherwise, the OS's switch-keyboard-layout hotkey would be triggered accidentally; e.g. the following
  1021.     // in English layout: Send ~~Γ┬{^}.
  1022.     //
  1023.     // Make sure modifier state is correct: ALT pressed down and other modifiers UP
  1024.     // because CTRL and SHIFT seem to interfere with this technique if they are down,
  1025.     // at least under WinXP (though the Windows key doesn't seem to be a problem).
  1026.     // Specify KEY_IGNORE so that this action does not affect the modifiers that the
  1027.     // hook uses to determine which hotkey should be triggered for a suffix key that
  1028.     // has more than one set of triggering modifiers (for when the user is holding down
  1029.     // that suffix to auto-repeat it -- see keyboard_mouse.h for details).
  1030.     modLR_type modifiersLR_now = sSendMode ? sEventModifiersLR : GetModifierLRState();
  1031.     SetModifierLRState((modifiersLR_now | MOD_LALT) & ~(MOD_RALT | MOD_LCONTROL | MOD_RCONTROL | MOD_LSHIFT | MOD_RSHIFT)
  1032.         , modifiersLR_now, NULL, false // Pass false because there's no need to disguise the down-event of LALT.
  1033.         , true, KEY_IGNORE); // Pass true so that any release of RALT is disguised (Win is never released here).
  1034.     // Note: It seems best never to press back down any key released above because the
  1035.     // act of doing so may do more harm than good (i.e. the keystrokes may caused
  1036.     // unexpected side-effects.
  1037.  
  1038.     // Known limitation (but obscure): There appears to be some OS limitation that prevents the following
  1039.     // AltGr hotkey from working more than once in a row:
  1040.     // <^>!i::Send {ASC 97}
  1041.     // Key history indicates it's doing what it should, but it doesn't actually work.  You have to press the
  1042.     // left-Alt key (not RAlt) once to get the hotkey working again.
  1043.  
  1044.     // This is not correct because it is possible to generate unicode characters by typing
  1045.     // Alt+256 and beyond:
  1046.     // int value = ATOI(aAscii);
  1047.     // if (value < 0 || value > 255) return 0; // Sanity check.
  1048.  
  1049.     // Known issue: If the hotkey that triggers this Send command is CONTROL-ALT
  1050.     // (and maybe either CTRL or ALT separately, as well), the {ASC nnnn} method
  1051.     // might not work reliably due to strangeness with that OS feature, at least on
  1052.     // WinXP.  I already tried adding delays between the keystrokes and it didn't help.
  1053.  
  1054.     // Caller relies upon us to stop upon reaching the first non-digit character:
  1055.     for (char *cp = aAscii; *cp >= '0' && *cp <= '9'; ++cp)
  1056.         // A comment from AutoIt3: ASCII 0 is 48, NUMPAD0 is 96, add on 48 to the ASCII.
  1057.         // Also, don't do WinDelay after each keypress in this case because it would make
  1058.         // such keys take up to 3 or 4 times as long to send (AutoIt3 avoids doing the
  1059.         // delay also).  Note that strings longer than 4 digits are allowed because
  1060.         // some or all OSes support Unicode characters 0 through 65535.
  1061.         KeyEvent(KEYDOWNANDUP, *cp + 48);
  1062.  
  1063.     // Must release the key regardless of whether it was already down, so that the sequence will take effect
  1064.     // immediately.  Otherwise, our caller might not release the Alt key (since it might need to stay down for
  1065.     // other purposes), in which case Alt+Numpad character would never appear and the caller's subsequent
  1066.     // keystrokes might get absorbed by the OS's special state of "waiting for Alt+Numpad sequence to complete".
  1067.     // Another reason is that the user may be physically holding down Alt, in which case the caller might never
  1068.     // release it.  In that case, we want the Alt+Numpad character to appear immediately rather than waiting for
  1069.     // the user to release Alt (in the meantime, the caller will likely press Alt back down to match the physical
  1070.     // state).
  1071.     KeyEvent(KEYUP, VK_MENU);
  1072. }
  1073.  
  1074.  
  1075.  
  1076. LRESULT CALLBACK PlaybackProc(int aCode, WPARAM wParam, LPARAM lParam)
  1077. // Journal playback hook.
  1078. {
  1079.     static bool sThisEventHasBeenLogged, sThisEventIsScreenCoord;
  1080.  
  1081.     switch (aCode)
  1082.     {
  1083.     case HC_GETNEXT:
  1084.     {
  1085.         if (sFirstCallForThisEvent)
  1086.         {
  1087.             // Gather the delay(s) for this event, if any, and calculate the time the keystroke should be sent.
  1088.             // NOTE: It must be done this way because testing shows that simply returning the desired delay
  1089.             // for the first call of each event is not reliable, at least not for the first few events (they
  1090.             // tend to get sent much more quickly than specified).  More details:
  1091.             // MSDN says, "When the system ...calls the hook procedure [after the first time] with code set to
  1092.             // HC_GETNEXT to retrieve the same message... the return value... should be zero."
  1093.             // Apparently the above is overly cautious wording with the intent to warn people not to write code
  1094.             // that gets stuck in infinite playback due to never returning 0, because returning non-zero on
  1095.             // calls after the first works fine as long as 0 is eventually returned.  Furthermore, I've seen
  1096.             // other professional code examples that uses this "countdown" approach, so it seems valid.
  1097.             sFirstCallForThisEvent = false;
  1098.             sThisEventHasBeenLogged = false;
  1099.             sThisEventIsScreenCoord = false;
  1100.             for (sThisEventTime = GetTickCount()
  1101.                 ; !sEventPB[sCurrentEvent].message // HC_SKIP has ensured there is a non-delay event, so no need to check sCurrentEvent < sEventCount.
  1102.                 ; sThisEventTime += sEventPB[sCurrentEvent++].time_to_wait); // Overflow is okay.
  1103.         }
  1104.         // Above has ensured that sThisEventTime is valid regardless of whether this is the first call
  1105.         // for this event.  It has also incremented sCurrentEvent, if needed, for use below.
  1106.  
  1107.         // Copy the current mouse/keyboard event to the EVENTMSG structure (lParam).
  1108.         // MSDN says that HC_GETNEXT can be received multiple times consecutively, in which case the
  1109.         // same event should be copied into the structure each time.
  1110.         PlaybackEvent &source_event = sEventPB[sCurrentEvent];
  1111.         EVENTMSG &event = *(PEVENTMSG)lParam;  // For convenience, maintainability, and possibly performance.
  1112.         // Currently, the following isn't documented entirely accurately at MSDN, but other sources confirm
  1113.         // the below are the proper values to store.  In addition, the extended flag as set below has been
  1114.         // confirmed to work properly by monitoring the resulting WM_KEYDOWN message in a main message loop.
  1115.         //
  1116.         // Strip off extra bits early for maintainability.  It must be stripped off the source event itself
  1117.         // because if HC_GETNEXT is called again for this same event, don't want to apply the offset again.
  1118.         bool has_coord_offset;
  1119.         if (has_coord_offset = source_event.message & MSG_OFFSET_MOUSE_MOVE)
  1120.             source_event.message &= ~MSG_OFFSET_MOUSE_MOVE;
  1121.         event.message = source_event.message;
  1122.         // The following members are not set because testing confirms that they're ignored:
  1123.         // event.hwnd: ignored even if assigned the HWND of an existing window or control.
  1124.         // event.time: Apparently ignored in favor of this playback proc's return value.  Furthermore,
  1125.         // testing shows that the posted keystroke message (e.g. WM_KEYDOWN) has the correct timestamp
  1126.         // even when event.time is left as a random time, which shows that the member is completely
  1127.         // ignored during playback, at least on XP.
  1128.         bool is_keyboard_not_mouse;
  1129.         if (is_keyboard_not_mouse = (source_event.message >= WM_KEYFIRST && source_event.message <= WM_KEYLAST)) // Keyboard event.
  1130.         {
  1131.             event.paramL = (source_event.sc << 8) | source_event.vk;
  1132.             event.paramH = source_event.sc & 0xFF; // 0xFF omits the extended-key-bit, if present.
  1133.             if (source_event.sc & 0x100) // It's an extended key.
  1134.                 event.paramH |= 0x8000; // So mark it that way using EVENTMSG's convention.
  1135.             // Notes about inability of playback to simulate LWin and RWin in a way that performs their native funcion:
  1136.             // For the following reasons, it seems best not to send LWin/RWin via keybd_event inside the playback hook:
  1137.             // 1) Complexities such as having to check for an array that consists entirely of LWin/RWin events,
  1138.             //    in which case the playback hook mustn't be activated because it requires that we send
  1139.             //    at least one event through it.  Another complexity is that all keys modified by Win would
  1140.             //    have to be flagged in the array as needing to be sent via keybd_event.
  1141.             // 2) It might preserve some flexibilility to be able to send LWin/RWin events directly to awindow,
  1142.             //    similiar to ControlSend (perhaps for shells other than Explorer, who might allow apps to make
  1143.             //    use of LWin/RWin internally). The window should receive LWIN/RWIN as WM_KEYDOWN messages when
  1144.             //    sent via playback.  Note: unlike the neutral SHIFT/ALT/CTRL keys, which are detectible via the
  1145.             //    target thread's call to GetKeyState(), LWin and RWin aren't detectible that way.
  1146.             // 3) Code size and complexity.
  1147.             //
  1148.             // Related: LWin and RWin are released and pressed down during playback for simplicity and also
  1149.             // on the off-chance the target window takes note of the incoming WM_KEYDOWN on VK_LWIN/RWIN and
  1150.             // changes state until the up-event is received (however, the target thread's call of GetKeyState
  1151.             // can't see a any effect for hook-sent LWin/RWin).
  1152.             //
  1153.             // Related: If LWin or RWin is logically down at start of SendPlay, SendPlay's events won't be
  1154.             // able to release it from the POV of the target thread's calls to GetKeyState().  That might mess
  1155.             // things up for apps that check the logical state of the Win keys.  But due to rarity: in those
  1156.             // cases, a workaround would be to do an explicit old-style Send {Blind} (as the first line of the
  1157.             // hotkey) to release the modifier logically prior to SendPlay commands.
  1158.             //
  1159.             // Related: Although some apps might not like receiving SendPlay's LWin/RWin if shell==Explorer
  1160.             // (since there may be no normal way for such keystrokes to arrive as WM_KEYDOWN events) maybe it's
  1161.             // best not to omit/ignore LWin/RWin if it is possible in other shells, or adds flexibility.
  1162.             // After all, sending {LWin/RWin} via hook should be rare, especially if it has no effect (except
  1163.             // for cases where a Win hotkey releases LWin as part of SendPlay, but even that can be worked
  1164.             // around via an explicit Send {Blind}{LWin up} beforehand).
  1165.         }
  1166.         else // MOUSE EVENT.
  1167.         {
  1168.             // Unlike keybd_event() and SendInput(), explicit coordintes must be specified for each mouse event.
  1169.             // The builder of this array must ensure that coordinates are valid or set to COORD_UNSPECIFIED_SHORT.
  1170.             if (source_event.x == COORD_UNSPECIFIED_SHORT || has_coord_offset)
  1171.             {
  1172.                 // For simplicity with calls such as WindowToScreen(), the one who set up this array has ensured
  1173.                 // that both X and Y are either COORD_UNSPECIFIED_SHORT or not so (i.e. not a combination).
  1174.                 // Since the user nor anything else can move the cursor during our playback, GetCursorPos()
  1175.                 // should accurately reflect the position set by any previous mouse-move done by this playback.
  1176.                 // This seems likely to be true even for DirectInput games, though hasn't been tested yet.
  1177.                 POINT cursor;
  1178.                 GetCursorPos(&cursor);
  1179.                 event.paramL = cursor.x;
  1180.                 event.paramH = cursor.y;
  1181.                 if (has_coord_offset) // The specified coordinates are offsets to be applied to the cursor's current position.
  1182.                 {
  1183.                     event.paramL += source_event.x;
  1184.                     event.paramH += source_event.y;
  1185.                     // Update source array in case HC_GETNEXT is called again for this same event, in which case
  1186.                     // don't want to apply the offset again (the has-offset flag has already been removed from the
  1187.                     // source event higher above).
  1188.                     source_event.x = event.paramL;
  1189.                     source_event.y = event.paramH;
  1190.                     sThisEventIsScreenCoord = true; // Mark the above as absolute vs. relative in case HC_GETNEXT is called again for this event.
  1191.                 }
  1192.             }
  1193.             else
  1194.             {
  1195.                 event.paramL = source_event.x;
  1196.                 event.paramH = source_event.y;
  1197.                 if (!(g.CoordMode & COORD_MODE_MOUSE) && !sThisEventIsScreenCoord) // Coordinates are relative to the window that is active now (during realtime playback).
  1198.                     WindowToScreen((int &)event.paramL, (int &)event.paramH); // Playback uses screen coords.
  1199.             }
  1200.         }
  1201.         LRESULT time_until_event = (int)(sThisEventTime - GetTickCount()); // Cast to int to avoid loss of negatives from DWORD math.
  1202.         if (time_until_event > 0)
  1203.             return time_until_event;
  1204.         // Otherwise, the event is scheduled to occur immediately (or is overdue).  In case HC_GETNEXT can be
  1205.         // called multiple times even when we previously returned 0, ensure the event is logged only once.
  1206.         if (!sThisEventHasBeenLogged && is_keyboard_not_mouse) // Mouse events aren't currently logged for consistency with other send methods.
  1207.         {
  1208.             // The event is logged here rather than higher above so that its timestamp is accurate.
  1209.             // It's also so that events aren't logged if the user cancel's the operation in the middle
  1210.             // (by pressing Ctrl-Alt-Del or Ctrl-Esc).
  1211.             UpdateKeyEventHistory(source_event.message == WM_KEYUP || source_event.message == WM_SYSKEYUP
  1212.                 , source_event.vk, source_event.sc);
  1213.             sThisEventHasBeenLogged = true;
  1214.         }
  1215.         return 0; // No CallNextHookEx(). See comments further below.
  1216.     } // case HC_GETNEXT.
  1217.  
  1218.     case HC_SKIP: // Advance to the next mouse/keyboard event, if any.
  1219.         // Advance to the next item, which is either a delay or an event (preps for next HC_GETNEXT).
  1220.         ++sCurrentEvent;
  1221.         // Although caller knows it has to do the tail-end delay (if any) since there's no way to
  1222.         // do a trailing delay at the end of playback, it may have put a delay at the end of the
  1223.         // array anyway for code simplicity.  For that reason and maintainability:
  1224.         // Skip over any delays that are present to discover if there is a next event.
  1225.         UINT u;
  1226.         for (u = sCurrentEvent; u < sEventCount && !sEventPB[u].message; ++u);
  1227.         if (u == sEventCount) // No more events.
  1228.         {
  1229.             // MSDN implies in the following statement that it's acceptable (and perhaps preferable in
  1230.             // the case of a playback hook) for the hook to unhook itself: "The hook procedure can be in the
  1231.             // state of being called by another thread even after UnhookWindowsHookEx returns."
  1232.             UnhookWindowsHookEx(g_PlaybackHook);
  1233.             g_PlaybackHook = NULL; // Signal the installer of the hook that it's gone now.
  1234.             // The following is an obsolete method from pre-v1.0.44.  Do not reinstate it without adding handling
  1235.             // to MainWindowProc() to do "g_PlaybackHook = NULL" upon receipt of WM_CANCELJOURNAL.
  1236.             // PostMessage(g_hWnd, WM_CANCELJOURNAL, 0, 0); // v1.0.44: Post it to g_hWnd vs. NULL because it's a little safer (SEE COMMENTS in MsgSleep's WM_CANCELJOURNAL for why it's almost completely safe with NULL).
  1237.             // Above: By using WM_CANCELJOURNAL instead of a custom message, the creator of this hook can easily
  1238.             // use a message filter to watch for both a system-generated removal of the hook (via the user
  1239.             // pressing Ctrl-Esc. or Ctrl-Alt-Del) or one we generate here (though it's currently not implemented
  1240.             // that way because it would prevent journal playback to one of our thread's own windows).
  1241.         }
  1242.         else
  1243.             sFirstCallForThisEvent = true; // Reset to prepare for next HC_GETNEXT.
  1244.         return 0; // MSDN: The return value is used only if the hook code is HC_GETNEXT; otherwise, it is ignored.
  1245.  
  1246.     default:
  1247.         // Covers the following cases:
  1248.         //case HC_NOREMOVE: // MSDN: An application has called the PeekMessage function with wRemoveMsg set to PM_NOREMOVE, indicating that the message is not removed from the message queue after PeekMessage processing.
  1249.         //case HC_SYSMODALON:  // MSDN: A system-modal dialog box is being displayed. Until the dialog box is destroyed, the hook procedure must stop playing back messages.
  1250.         //case HC_SYSMODALOFF: // MSDN: A system-modal dialog box has been destroyed. The hook procedure must resume playing back the messages.
  1251.         //case(...aCode < 0...): MSDN docs specify that the hook should return in this case.
  1252.         //
  1253.         // MS gives some sample code at http://support.microsoft.com/default.aspx?scid=KB;EN-US;124835
  1254.         // about the proper values to return to avoid hangs on NT (it seems likely that this implementation
  1255.         // is compliant enough if you read between the lines).  Their sample code indicates that
  1256.         // "return CallNextHook()"  should be done for basically everything except HC_SKIP/HC_GETNEXT, so
  1257.         // as of 1.0.43.08, that is what is done here.
  1258.         // Testing shows that when a so-called system modial dialog is displayed (even if it isn't the
  1259.         // active window) playback stops automatically, probably because the system doesn't call the hook
  1260.         // during such times (only a "MsgBox 4096" has been tested so far).
  1261.         //
  1262.         // The first parameter uses g_PlaybackHook rather than NULL because MSDN says it's merely
  1263.         // "currently ignored", but in the older "Win32 hooks" article, it says that the behavior
  1264.         // may change in the future.
  1265.         return CallNextHookEx(g_PlaybackHook, aCode, wParam, lParam);
  1266.         // Except for the cases above, CallNextHookEx() is not called for performance and also because from
  1267.         // what I can tell from the MSDN docs and other examples, it is neither required nor desirable to do so
  1268.         // during playback's SKIP/GETNEXT.
  1269.         // MSDN: The return value is used only if the hook code is HC_GETNEXT; otherwise, it is ignored.
  1270.     } // switch().
  1271.  
  1272.     // Execution should never reach since all cases do their own custom return above.
  1273. }
  1274.  
  1275.  
  1276.  
  1277. #ifdef JOURNAL_RECORD_MODE
  1278. LRESULT CALLBACK RecordProc(int aCode, WPARAM wParam, LPARAM lParam)
  1279. {
  1280.     switch (aCode)
  1281.     {
  1282.     case HC_ACTION:
  1283.     {
  1284.         EVENTMSG &event = *(PEVENTMSG)lParam;
  1285.         PlaybackEvent &dest_event = sEventPB[sEventCount];
  1286.         dest_event.message = event.message;
  1287.         if (event.message >= WM_MOUSEFIRST && event.message <= WM_MOUSELAST) // Mouse event, including wheel.
  1288.         {
  1289.             if (event.message != WM_MOUSEMOVE)
  1290.             {
  1291.                 // WHEEL: No info comes in about which direction the wheel was turned (nor by how many notches).
  1292.                 // In addition, it appears impossible to specify such info when playing back the event.
  1293.                 // Therefore, playback usually produces downward wheel movement (but upward in some apps like
  1294.                 // Visual Studio).
  1295.                 dest_event.x = event.paramL;
  1296.                 dest_event.y = event.paramH;
  1297.                 ++sEventCount;
  1298.             }
  1299.         }
  1300.         else // Keyboard event.
  1301.         {
  1302.             dest_event.vk = event.paramL & 0x00FF;
  1303.             dest_event.sc = (event.paramL & 0xFF00) >> 8;
  1304.             if (event.paramH & 0x8000) // Extended key.
  1305.                 dest_event.sc |= 0x100;
  1306.             if (dest_event.vk == VK_CANCEL) // Ctrl+Break.
  1307.             {
  1308.                 UnhookWindowsHookEx(g_PlaybackHook);
  1309.                 g_PlaybackHook = NULL; // Signal the installer of the hook that it's gone now.
  1310.                 // Obsolete method, pre-v1.0.44:
  1311.                 //PostMessage(g_hWnd, WM_CANCELJOURNAL, 0, 0); // v1.0.44: Post it to g_hWnd vs. NULL so that it isn't lost when script is displaying a MsgBox or other dialog.
  1312.             }
  1313.             ++sEventCount;
  1314.         }
  1315.         break;
  1316.     }
  1317.  
  1318.     //case HC_SYSMODALON:  // A system-modal dialog box is being displayed. Until the dialog box is destroyed, the hook procedure must stop playing back messages.
  1319.     //case HC_SYSMODALOFF: // A system-modal dialog box has been destroyed. The hook procedure must resume playing back the messages.
  1320.     //    break;
  1321.     }
  1322.  
  1323.     // Unlike the playback hook, it seems more correct to call CallNextHookEx() unconditionally so that
  1324.     // any other journal record hooks can also record the event.  But MSDN is quite vague about this.
  1325.     return CallNextHookEx(g_PlaybackHook, aCode, wParam, lParam);
  1326.     // Return value is ignored, except possibly when aCode < 0 (MSDN is unclear).
  1327. }
  1328. #endif
  1329.  
  1330.  
  1331.  
  1332. void KeyEvent(KeyEventTypes aEventType, vk_type aVK, sc_type aSC, HWND aTargetWindow
  1333.     , bool aDoKeyDelay, DWORD aExtraInfo)
  1334. // aSC or aVK (but not both), can be zero to cause the default to be used.
  1335. // For keys like NumpadEnter -- that have have a unique scancode but a non-unique virtual key --
  1336. // caller can just specify the sc.  In addition, the scan code should be specified for keys
  1337. // like NumpadPgUp and PgUp.  In that example, the caller would send the same scan code for
  1338. // both except that PgUp would be extended.   sc_to_vk() would map both of them to the same
  1339. // virtual key, which is fine since it's the scan code that matters to apps that can
  1340. // differentiate between keys with the same vk.
  1341. //
  1342. // Thread-safe: This function is not fully thread-safe because keystrokes can get interleaved,
  1343. // but that's always a risk with anything short of SendInput.  In fact,
  1344. // when the hook ISN'T installed, keystrokes can occur in another thread, causing the key state to
  1345. // change in the middle of KeyEvent, which is the same effect as not having thread-safe key-states
  1346. // such as GetKeyboardState in here.  Also, the odds of both our threads being in here simultaneously
  1347. // is greatly reduced by the fact that the hook thread never passes "true" for aDoKeyDelay, thus
  1348. // its calls should always be very fast.  Even if a collision does occur, there are thread-safety
  1349. // things done in here that should reduce the impact to nearly as low as having a dedicated
  1350. // KeyEvent function solely for calling by the hook thread (which might have other problems of its own).
  1351. {
  1352.     if (!(aVK | aSC)) // MUST USE BITWISE-OR (see comment below).
  1353.         return;
  1354.     // The above implements the rule "if neither VK nor SC was specified, return".  But they must be done as
  1355.     // bitwise-OR rather than logical-AND/OR, otherwise MSVC++ 7.1 generates 16KB of extra OBJ size for some reason.
  1356.     // That results in an 2 KB increase in compressed EXE size, and I think about 6 KB uncompressed.
  1357.     // I tried all kids of variations and reconfigurations, but the above is the only simple one that works.
  1358.     // Strangely, the same logic above (but with the preferred logical-AND/OR operator) appears elsewhere in the
  1359.     // code but doesn't bloat there.  Examples:
  1360.     //   !aVK && !aSC
  1361.     //   !vk && !sc
  1362.     //   !(aVK || aSC)
  1363.  
  1364.     if (!aExtraInfo) // Shouldn't be called this way because 0 is considered false in some places below (search on " = aExtraInfo" to find them).
  1365.         aExtraInfo = KEY_IGNORE_ALL_EXCEPT_MODIFIER; // Seems slightly better to use a standard default rather than something arbitrary like 1.
  1366.  
  1367.     // Since calls from the hook thread could come in even while the SendInput array is being constructed,
  1368.     // don't let those events get interspersed with the script's explicit use of SendInput.
  1369.     bool caller_is_keybd_hook = (GetCurrentThreadId() == g_HookThreadID);
  1370.     bool put_event_into_array = sSendMode && !caller_is_keybd_hook;
  1371.     if (sSendMode == SM_INPUT || caller_is_keybd_hook) // First check is necessary but second is just for maintainability.
  1372.         aDoKeyDelay = false;
  1373.  
  1374.     // Even if the sc_to_vk() mapping results in a zero-value vk, don't return.
  1375.     // I think it may be valid to send keybd_events    that have a zero vk.
  1376.     // In any case, it's unlikely to hurt anything:
  1377.     if (!aVK)
  1378.         aVK = sc_to_vk(aSC);
  1379.     else
  1380.         if (!aSC)
  1381.             // In spite of what the MSDN docs say, the scan code parameter *is* used, as evidenced by
  1382.             // the fact that the hook receives the proper scan code as sent by the below, rather than
  1383.             // zero like it normally would.  Even though the hook would try to use MapVirtualKey() to
  1384.             // convert zero-value scan codes, it's much better to send it here also for full compatibility
  1385.             // with any apps that may rely on scan code (and such would be the case if the hook isn't
  1386.             // active because the user doesn't need it; also for some games maybe).  In addition, if the
  1387.             // current OS is Win9x, we must map it here manually (above) because otherwise the hook
  1388.             // wouldn't be able to differentiate left/right on keys such as RControl, which is detected
  1389.             // via its scan code.
  1390.             aSC = vk_to_sc(aVK);
  1391.  
  1392.     BYTE aSC_lobyte = LOBYTE(aSC);
  1393.     DWORD event_flags = HIBYTE(aSC) ? KEYEVENTF_EXTENDEDKEY : 0;
  1394.  
  1395.     // Do this only after the above, so that the SC is left/right specific if the VK was such,
  1396.     // even on Win9x (though it's probably never called that way for Win9x; it's probably aways
  1397.     // called with either just the proper left/right SC or that plus the neutral VK).
  1398.     // Under WinNT/2k/XP, sending VK_LCONTROL and such result in the high-level (but not low-level
  1399.     // I think) hook receiving VK_CONTROL.  So somewhere interally it's being translated (probably
  1400.     // by keybd_event itself).  In light of this, translate the keys here manually to ensure full
  1401.     // support under Win9x (which might not support this internal translation).  The scan code
  1402.     // looked up above should still be correct for left-right centric keys even under Win9x.
  1403.     // v1.0.43: Apparently, the journal playback hook also requires neutral modifier keystrokes
  1404.     // rather than left/right ones.  Otherwise, the Shift key can't capitalize letters, etc.
  1405.     if (sSendMode == SM_PLAY || g_os.IsWin9x())
  1406.     {
  1407.         // Convert any non-neutral VK's to neutral for these OSes, since apps and the OS itself
  1408.         // can't be expected to support left/right specific VKs while running under Win9x:
  1409.         switch(aVK)
  1410.         {
  1411.         case VK_LCONTROL:
  1412.         case VK_RCONTROL: aVK = VK_CONTROL; break; // But leave scan code set to a left/right specific value rather than converting it to "left" unconditionally.
  1413.         case VK_LSHIFT:
  1414.         case VK_RSHIFT: aVK = VK_SHIFT; break;
  1415.         case VK_LMENU:
  1416.         case VK_RMENU: aVK = VK_MENU; break;
  1417.         }
  1418.     }
  1419.  
  1420.     // aTargetWindow is almost always passed in as NULL by our caller, even if the overall command
  1421.     // being executed is ControlSend.  This is because of the following reasons:
  1422.     // 1) Modifiers need to be logically changed via keybd_event() when using ControlSend against
  1423.     //    a cmd-prompt, console, or possibly other types of windows.
  1424.     // 2) If a hotkey triggered the ControlSend that got us here and that hotkey is a naked modifier
  1425.     //    such as RAlt:: or modified modifier such as ^#LShift, that modifier would otherwise auto-repeat
  1426.     //    an possibly interfere with the send operation.  This auto-repeat occurs because unlike a normal
  1427.     //    send, there are no calls to keybd_event() (keybd_event() stop the auto-repeat as a side-effect).
  1428.     // One exception to this is something like "ControlSend, Edit1, {Control down}", which explicitly
  1429.     // calls us with a target window.  This exception is by design and has been bug-fixed and documented
  1430.     // in ControlSend for v1.0.21:
  1431.     if (aTargetWindow) // This block should be thread-safe because hook thread never calls it in this mode.
  1432.     {
  1433.         if (KeyToModifiersLR(aVK, aSC))
  1434.         {
  1435.             // When sending modifier keystrokes directly to a window, use the AutoIt3 SetKeyboardState()
  1436.             // technique to improve the reliability of changes to modifier states.  If this is not done,
  1437.             // sometimes the state of the SHIFT key (and perhaps other modifiers) will get out-of-sync
  1438.             // with what's intended, resulting in uppercase vs. lowercase problems (and that's probably
  1439.             // just the tip of the iceberg).  For this to be helpful, our caller must have ensured that
  1440.             // our thread is attached to aTargetWindow's (but it seems harmless to do the below even if
  1441.             // that wasn't done for any reason).  Doing this here in this function rather than at a
  1442.             // higher level probably isn't best in terms of performance (e.g. in the case where more
  1443.             // than one modifier is being changed, the multiple calls to Get/SetKeyboardState() could
  1444.             // be consolidated into one call), but it is much easier to code and maintain this way
  1445.             // since many different functions might call us to change the modifier state:
  1446.             BYTE state[256];
  1447.             GetKeyboardState((PBYTE)&state);
  1448.             if (aEventType == KEYDOWN)
  1449.                 state[aVK] |= 0x80;
  1450.             else if (aEventType == KEYUP)
  1451.                 state[aVK] &= ~0x80;
  1452.             // else KEYDOWNANDUP, in which case it seems best (for now) not to change the state at all.
  1453.             // It's rarely if ever called that way anyway.
  1454.  
  1455.             // If aVK is a left/right specific key, be sure to also update the state of the neutral key:
  1456.             switch(aVK)
  1457.             {
  1458.             case VK_LCONTROL: 
  1459.             case VK_RCONTROL:
  1460.                 if ((state[VK_LCONTROL] & 0x80) || (state[VK_RCONTROL] & 0x80))
  1461.                     state[VK_CONTROL] |= 0x80;
  1462.                 else
  1463.                     state[VK_CONTROL] &= ~0x80;
  1464.                 break;
  1465.             case VK_LSHIFT:
  1466.             case VK_RSHIFT:
  1467.                 if ((state[VK_LSHIFT] & 0x80) || (state[VK_RSHIFT] & 0x80))
  1468.                     state[VK_SHIFT] |= 0x80;
  1469.                 else
  1470.                     state[VK_SHIFT] &= ~0x80;
  1471.                 break;
  1472.             case VK_LMENU:
  1473.             case VK_RMENU:
  1474.                 if ((state[VK_LMENU] & 0x80) || (state[VK_RMENU] & 0x80))
  1475.                     state[VK_MENU] |= 0x80;
  1476.                 else
  1477.                     state[VK_MENU] &= ~0x80;
  1478.                 break;
  1479.             }
  1480.  
  1481.             SetKeyboardState((PBYTE)&state);
  1482.             // Even after doing the above, we still continue on to send the keystrokes
  1483.             // themselves to the window, for greater reliability (same as AutoIt3).
  1484.         }
  1485.  
  1486.         // lowest 16 bits: repeat count: always 1 for up events, probably 1 for down in our case.
  1487.         // highest order bits: 11000000 (0xC0) for keyup, usually 00000000 (0x00) for keydown.
  1488.         LPARAM lParam = (LPARAM)(aSC << 16);
  1489.         if (aEventType != KEYUP)  // i.e. always do it for KEYDOWNANDUP
  1490.             PostMessage(aTargetWindow, WM_KEYDOWN, aVK, lParam | 0x00000001);
  1491.         // The press-duration delay is done only when this is a down-and-up because otherwise,
  1492.         // the normal g.KeyDelay will be in effect.  In other words, it seems undesirable in
  1493.         // most cases to do both delays for only "one half" of a keystroke:
  1494.         if (aDoKeyDelay && aEventType == KEYDOWNANDUP)
  1495.             DoKeyDelay(g.PressDuration); // Since aTargetWindow!=NULL, sSendMode!=SM_PLAY, so no need for to ever use the SendPlay press-duration.
  1496.         if (aEventType != KEYDOWN)  // i.e. always do it for KEYDOWNANDUP
  1497.             PostMessage(aTargetWindow, WM_KEYUP, aVK, lParam | 0xC0000001);
  1498.     }
  1499.     else // Keystrokes are to be sent with keybd_event() or the event array rather than PostMessage().
  1500.     {
  1501.         // The following static variables are intentionally NOT thread-safe because their whole purpose
  1502.         // is to watch the combined stream of keystrokes from all our threads.  Due to our threads'
  1503.         // keystrokes getting interleaved with the user's and those of other threads, this kind of
  1504.         // monitoring is never 100% reliable.  All we can do is aim for an astronomically low chance
  1505.         // of failure.
  1506.         // Users of the below want them updated only for keybd_event() keystrokes (not PostMessage ones):
  1507.         sPrevEventType = aEventType;
  1508.         sPrevVK = aVK;
  1509.         // Turn off BlockInput momentarily to support sending of the ALT key.  This is not done for
  1510.         // Win9x because input cannot be simulated during BlockInput on that platform anyway; thus
  1511.         // it seems best (due to backward compatibility) not to turn off BlockInput then.
  1512.         // Jon Bennett noted: "As many of you are aware BlockInput was "broken" by a SP1 hotfix under
  1513.         // Windows XP so that the ALT key could not be sent. I just tried it under XP SP2 and it seems
  1514.         // to work again."  In light of this, it seems best to unconditionally and momentarily disable
  1515.         // input blocking regardless of which OS is being used (except Win9x, since no simulated input
  1516.         // is even possible for those OSes).
  1517.         // For thread safety, allow block-input modification only by the main thread.  This should avoid
  1518.         // any chance that block-input will get stuck on due to two threads simultaneously reading+changing
  1519.         // g_BlockInput (changes occur via calls to ScriptBlockInput).
  1520.         bool we_turned_blockinput_off = g_BlockInput && (aVK == VK_MENU || aVK == VK_LMENU || aVK == VK_RMENU)
  1521.             && g_os.IsWinNT4orLater() && GetCurrentThreadId() == g_MainThreadID; // Ordered for short-circuit performance.
  1522.         if (we_turned_blockinput_off)
  1523.             Line::ScriptBlockInput(false);
  1524.  
  1525.         vk_type control_vk;      // When not set somewhere below, these are left unitialized to help catch bugs.
  1526.         HKL target_keybd_layout; //
  1527.         ResultType r_mem, &target_layout_has_altgr = caller_is_keybd_hook ? r_mem : sTargetLayoutHasAltGr; // Same as above.
  1528.         bool hookable_ralt, lcontrol_was_down, do_detect_altgr;
  1529.         if (do_detect_altgr = hookable_ralt = (aVK == VK_RMENU && !put_event_into_array && g_KeybdHook)) // This is an RALT that the hook will be able to monitor. Using VK_RMENU vs. VK_MENU should be safe since this logic is only needed for the hook, which is never in effect on Win9x.
  1530.         {
  1531.             if (!caller_is_keybd_hook) // sTargetKeybdLayout is set/valid only by SendKeys().
  1532.                 target_keybd_layout = sTargetKeybdLayout;
  1533.             else
  1534.             {
  1535.                 // Below is similar to the macro "Get_active_window_keybd_layout":
  1536.                 HWND active_window;
  1537.                 target_keybd_layout = GetKeyboardLayout((active_window = GetForegroundWindow())\
  1538.                     ? GetWindowThreadProcessId(active_window, NULL) : 0); // When no foreground window, the script's own layout seems like the safest default.
  1539.                 target_layout_has_altgr = LayoutHasAltGr(target_keybd_layout); // In the case of this else's "if", target_layout_has_altgr was already set properly higher above.
  1540.             }
  1541.             if (target_layout_has_altgr != LAYOUT_UNDETERMINED) // This layout's AltGr status is already known with certainty.
  1542.                 do_detect_altgr = false; // So don't go through the detection steps here and other places later below.
  1543.             else
  1544.             {
  1545.                 control_vk = g_os.IsWin2000orLater() ? VK_LCONTROL : VK_CONTROL;
  1546.                 lcontrol_was_down = GetAsyncKeyState(control_vk) & 0x8000;
  1547.                 // Add extra detection of AltGr if hook is installed, which has been show to be useful for some
  1548.                 // scripts where the other AltGr detection methods don't occur in a timely enough fashion.
  1549.                 // The following method relies upon the fact that it's impossible for the hook to receive
  1550.                 // events from the user while it's processing our keybd_event() here.  This is because
  1551.                 // any physical keystrokes that happen to occur at the exact moment of our keybd_event()
  1552.                 // will stay queued until the main event loop routes them to the hook via GetMessage().
  1553.                 g_HookReceiptOfLControlMeansAltGr = aExtraInfo;
  1554.                 // Thread-safe: g_HookReceiptOfLControlMeansAltGr isn't thread-safe, but by its very nature it probably
  1555.                 // shouldn't be (ways to do it might introduce an unwarranted amount of complexity and performance loss
  1556.                 // given that the odds of collision might be astronimically low in this case, and the consequences too
  1557.                 // mild).  The whole point of g_HookReceiptOfLControlMeansAltGr and related altgr things below is to
  1558.                 // watch what keystrokes the hook receives in response to simulating a press of the right-alt key.
  1559.                 // Due to their global/system nature, keystrokes are never thread-safe in the sense that any process
  1560.                 // in the entire system can be sending keystrokes simultaneously with ours.
  1561.             }
  1562.         }
  1563.  
  1564.         // Calculated only once for performance (and avoided entirely if not needed):
  1565.         modLR_type key_as_modifiersLR = put_event_into_array ? KeyToModifiersLR(aVK, aSC) : 0;
  1566.  
  1567.         bool do_key_history = !caller_is_keybd_hook // If caller is hook, don't log because it does logs it.
  1568.             && sSendMode != SM_PLAY  // In playback mode, the journal hook logs so that timestamps are accurate.
  1569.             && (!g_KeybdHook || sSendMode == SM_INPUT); // In the remaining cases, log only when the hook isn't installed or won't be at the time of the event.
  1570.  
  1571.         if (aEventType != KEYUP)  // i.e. always do it for KEYDOWNANDUP
  1572.         {
  1573.             if (put_event_into_array)
  1574.                 PutKeybdEventIntoArray(key_as_modifiersLR, aVK, aSC, event_flags, aExtraInfo);
  1575.             else
  1576.             {
  1577.                 // In v1.0.35.07, g_IgnoreNextLControlDown/Up was added.
  1578.                 // The following global is used to flag as our own the keyboard driver's LControl-down keystroke
  1579.                 // that is triggered by RAlt-down (AltGr).  This prevents it from triggering hotkeys such as
  1580.                 // "*Control::".  It probably fixes other obscure side-effects and bugs also, since the
  1581.                 // event should be considered script-generated even though indirect.  Note: The problem with
  1582.                 // having the hook detect AltGr's automatic LControl-down is that the keyboard driver seems
  1583.                 // to generate the LControl-down *before* notifying the system of the RAlt-down.  That makes
  1584.                 // it impossible for the hook to flag the LControl keystroke in advance, so it would have to
  1585.                 // retroactively undo the effects.  But that is impossible because the previous keystroke might
  1586.                 // already have wrongly fired a hotkey.
  1587.                 if (hookable_ralt && target_layout_has_altgr == CONDITION_TRUE)
  1588.                     g_IgnoreNextLControlDown = aExtraInfo; // Must be set prior to keybd_event() to be effective.
  1589.                 keybd_event(aVK, aSC_lobyte // naked scan code (the 0xE0 prefix, if any, is omitted)
  1590.                     , event_flags, aExtraInfo);
  1591.                 // The following is done by us rather than by the hook to avoid problems where:
  1592.                 // 1) The hook is removed at a critical point during the operation, preventing the variable from
  1593.                 //    being reset to false.
  1594.                 // 2) For some reason this AltGr keystroke done above did not cause LControl to go down (perhaps
  1595.                 //    because the current keyboard layout doesn't have AltGr as we thought), which would be a bug
  1596.                 //    because some other Ctrl keystroke would then be wrongly ignored.
  1597.                 g_IgnoreNextLControlDown = 0; // Unconditional reset.
  1598.                 if (do_detect_altgr)
  1599.                 {
  1600.                     do_detect_altgr = false; // Indicate to the KEYUP section later below that detection has already been done.
  1601.                     if (g_HookReceiptOfLControlMeansAltGr)
  1602.                     {
  1603.                         g_HookReceiptOfLControlMeansAltGr = 0; // Must reset promptly in case key-delay below routes physical keystrokes to hook.
  1604.                         // The following line is multipurpose:
  1605.                         // 1) Retrieves an updated value of target_layout_has_altgr in case the hook just changed it.
  1606.                         // 2) If the hook didn't change it, the target keyboard layout doesn't have an AltGr key.
  1607.                         //    Only in that case will the following line set it to FALSE (because LayoutHasAltGr only
  1608.                         //    changes the value if it's currently undetermined).
  1609.                         // Finally, this also updates sTargetLayoutHasAltGr in cases where target_layout_has_altgr
  1610.                         // is an alias/reference for it.
  1611.                         target_layout_has_altgr = LayoutHasAltGr(target_keybd_layout, CONDITION_FALSE);
  1612.                     }
  1613.                     else if (!lcontrol_was_down) // i.e. if LControl was already down, this detection method isn't possible.
  1614.                         // Called this way, it updates the specified layout as long as keybd_event's call to the hook didn't already determine it to be FALSE or TRUE:
  1615.                         target_layout_has_altgr = LayoutHasAltGr(target_keybd_layout, (GetAsyncKeyState(control_vk) & 0x8000) ? CONDITION_TRUE : CONDITION_FALSE);
  1616.                         // Above also updates sTargetLayoutHasAltGr in cases where target_layout_has_altgr is an alias/reference for it.
  1617.                 }
  1618.             }
  1619.  
  1620.             if (aVK == VK_NUMLOCK && g_os.IsWin9x()) // Under Win9x, Numlock needs special treatment.
  1621.                 ToggleNumlockWin9x();
  1622.  
  1623.             if (do_key_history)
  1624.                 UpdateKeyEventHistory(false, aVK, aSC); // Should be thread-safe since if no hook means only one thread ever sends keystrokes (with possible exception of mouse hook, but that seems too rare).
  1625.         }
  1626.         // The press-duration delay is done only when this is a down-and-up because otherwise,
  1627.         // the normal g.KeyDelay will be in effect.  In other words, it seems undesirable in
  1628.         // most cases to do both delays for only "one half" of a keystroke:
  1629.         if (aDoKeyDelay && aEventType == KEYDOWNANDUP) // Hook should never specify a delay, so no need to check if caller is hook.
  1630.             DoKeyDelay(sSendMode == SM_PLAY ? g.PressDurationPlay : g.PressDuration); // DoKeyDelay() is not thread safe but since the hook thread should never pass true for aKeyDelay, it shouldn't be an issue.
  1631.         if (aEventType != KEYDOWN)  // i.e. always do it for KEYDOWNANDUP
  1632.         {
  1633.             event_flags |= KEYEVENTF_KEYUP;
  1634.             if (put_event_into_array)
  1635.                 PutKeybdEventIntoArray(key_as_modifiersLR, aVK, aSC, event_flags, aExtraInfo);
  1636.             else
  1637.             {
  1638.                 if (hookable_ralt && target_layout_has_altgr == CONDITION_TRUE) // See comments in similar section above for details.
  1639.                     g_IgnoreNextLControlUp = aExtraInfo; // Must be set prior to keybd_event() to be effective.
  1640.                 keybd_event(aVK, aSC_lobyte, event_flags, aExtraInfo);
  1641.                 g_IgnoreNextLControlUp = 0; // Unconditional reset (see similar section above).
  1642.                 if (do_detect_altgr) // This should be true only when aEventType==KEYUP because otherwise the KEYDOWN event above would have set it to false.
  1643.                 {
  1644.                     if (g_HookReceiptOfLControlMeansAltGr)
  1645.                     {
  1646.                         g_HookReceiptOfLControlMeansAltGr = 0; // Must reset promptly in case key-delay below routes physical keystrokes to hook.
  1647.                         target_layout_has_altgr = LayoutHasAltGr(target_keybd_layout, CONDITION_FALSE); // See similar section above for comments.
  1648.                     }
  1649.                     else if (lcontrol_was_down) // i.e. if LControl was already up, this detection method isn't possible.
  1650.                         // See similar section above for comments:
  1651.                         target_layout_has_altgr = LayoutHasAltGr(target_keybd_layout, (GetAsyncKeyState(control_vk) & 0x8000) ? CONDITION_FALSE : CONDITION_TRUE);
  1652.                 }
  1653.             }
  1654.             if (do_key_history)
  1655.                 UpdateKeyEventHistory(true, aVK, aSC);
  1656.         }
  1657.  
  1658.         if (we_turned_blockinput_off)  // Already made thread-safe by action higher above.
  1659.             Line::ScriptBlockInput(true);  // Turn BlockInput back on.
  1660.     }
  1661.  
  1662.     if (aDoKeyDelay) // SM_PLAY also uses DoKeyDelay(): it stores the delay item in the event array.
  1663.         DoKeyDelay(); // Thread-safe because only called by main thread in this mode.  See notes above.
  1664. }
  1665.  
  1666.  
  1667. ///////////////////
  1668. // Mouse related //
  1669. ///////////////////
  1670.  
  1671. ResultType PerformClick(char *aOptions)
  1672. {
  1673.     int x, y;
  1674.     vk_type vk;
  1675.     KeyEventTypes event_type;
  1676.     int repeat_count;
  1677.     bool move_offset;
  1678.  
  1679.     ParseClickOptions(aOptions, x, y, vk, event_type, repeat_count, move_offset);
  1680.     PerformMouseCommon(repeat_count < 1 ? ACT_MOUSEMOVE : ACT_MOUSECLICK // Treat repeat-count<1 as a move (like {click}).
  1681.         , vk, x, y, 0, 0, repeat_count, event_type, g.DefaultMouseSpeed, move_offset);
  1682.  
  1683.     return OK; // For caller convenience.
  1684. }
  1685.  
  1686.  
  1687.  
  1688. void ParseClickOptions(char *aOptions, int &aX, int &aY, vk_type &aVK, KeyEventTypes &aEventType
  1689.     , int &aRepeatCount, bool &aMoveOffset)
  1690. // Caller has trimmed leading whitespace from aOptions, but not necessarily the trailing whitespace.
  1691. // aOptions must be a modifiable string because this function temporarily alters it.
  1692. {
  1693.     // Set defaults for all output parameters for caller.
  1694.     aX = COORD_UNSPECIFIED;
  1695.     aY = COORD_UNSPECIFIED;
  1696.     aVK = VK_LBUTTON_LOGICAL; // v1.0.43: Logical vs. physical for {Click} and Click-cmd, in case user has buttons swapped via control panel.
  1697.     aEventType = KEYDOWNANDUP;
  1698.     aRepeatCount = 1;
  1699.     aMoveOffset = false;
  1700.  
  1701.     char *next_option, *option_end, orig_char;
  1702.     vk_type temp_vk;
  1703.  
  1704.     for (next_option = aOptions; *next_option; next_option = omit_leading_whitespace(option_end))
  1705.     {
  1706.         // Allow optional commas to make scripts more readable.  Don't support g_delimiter because StrChrAny
  1707.         // below doesn't.
  1708.         while (*next_option == ',') // Ignore all commas.
  1709.             if (!*(next_option = omit_leading_whitespace(next_option + 1)))
  1710.                 goto break_both; // Entire option string ends in a comma.
  1711.         // Find the end of this option item:
  1712.         if (   !(option_end = StrChrAny(next_option, " \t,"))   )  // Space, tab, comma.
  1713.             option_end = next_option + strlen(next_option); // Set to position of zero terminator instead.
  1714.  
  1715.         // Temp termination for IsPureNumeric(), ConvertMouseButton(), and peace-of-mind.
  1716.         orig_char = *option_end;
  1717.         *option_end = '\0';
  1718.  
  1719.         // Parameters can occur in almost any order to enhance usability (at the cost of
  1720.         // slightly diminishing the ability unambiguously add more parameters in the future).
  1721.         // Seems okay to support floats because ATOI() will just omit the decimal portion.
  1722.         if (IsPureNumeric(next_option, true, false, true))
  1723.         {
  1724.             // Any numbers present must appear in the order: X, Y, RepeatCount
  1725.             // (optionally with other options between them).
  1726.             if (aX == COORD_UNSPECIFIED) // This will be converted into repeat-count if it is later discovered there's no Y coordinate.
  1727.                 aX = ATOI(next_option);
  1728.             else if (aY == COORD_UNSPECIFIED)
  1729.                 aY = ATOI(next_option);
  1730.             else // Third number is the repeat-count (but if there's only one number total, that's repeat count too, see further below).
  1731.                 aRepeatCount = ATOI(next_option); // If negative or zero, caller knows to handle it as a MouseMove vs. Click.
  1732.         }
  1733.         else // Mouse button/name and/or Down/Up/Repeat-count is present.
  1734.         {
  1735.             if (temp_vk = Line::ConvertMouseButton(next_option, true, true))
  1736.                 aVK = temp_vk;
  1737.             else
  1738.             {
  1739.                 switch (toupper(*next_option))
  1740.                 {
  1741.                 case 'D': aEventType = KEYDOWN; break;
  1742.                 case 'U': aEventType = KEYUP; break;
  1743.                 case 'R': aMoveOffset = true; break; // Since it wasn't recognized as the right mouse button, it must have other letters after it, e.g. Rel/Relative.
  1744.                 // default: Ignore anything else to reserve them for future use.
  1745.                 }
  1746.             }
  1747.         }
  1748.  
  1749.         // If the item was not handled by the above, ignore it because it is unknown.
  1750.  
  1751.         *option_end = orig_char; // Undo the temporary termination because the caller needs aOptions to be unaltered.
  1752.     } // for() each item in option list
  1753.  
  1754. break_both:
  1755.     if (aX != COORD_UNSPECIFIED && aY == COORD_UNSPECIFIED)
  1756.     {
  1757.         // When only one number is present (e.g. {Click 2}, it's assumed to be the repeat count.
  1758.         aRepeatCount = aX;
  1759.         aX = COORD_UNSPECIFIED;
  1760.     }
  1761. }
  1762.  
  1763.  
  1764.  
  1765. ResultType PerformMouse(ActionTypeType aActionType, char *aButton, char *aX1, char *aY1, char *aX2, char *aY2
  1766.     , char *aSpeed, char *aOffsetMode, char *aRepeatCount, char *aDownUp)
  1767. {
  1768.     vk_type vk;
  1769.     if (aActionType == ACT_MOUSEMOVE)
  1770.         vk = 0;
  1771.     else
  1772.         // ConvertMouseButton() treats blank as "Left":
  1773.         if (   !(vk = Line::ConvertMouseButton(aButton, aActionType == ACT_MOUSECLICK))   )
  1774.             vk = VK_LBUTTON; // See below.
  1775.             // v1.0.43: Seems harmless (due to rarity) to treat invalid button names as "Left" (keeping in
  1776.             // mind that due to loadtime validation, invalid buttons are possible only when the button name is
  1777.             // contained in a variable, e.g. MouseClick %ButtonName%.
  1778.  
  1779.     KeyEventTypes event_type = KEYDOWNANDUP;  // Set defaults.
  1780.     int repeat_count = 1;                     //
  1781.  
  1782.     if (aActionType == ACT_MOUSECLICK)
  1783.     {
  1784.         if (*aRepeatCount)
  1785.             repeat_count = ATOI(aRepeatCount);
  1786.         switch(*aDownUp)
  1787.         {
  1788.         case 'u':
  1789.         case 'U':
  1790.             event_type = KEYUP;
  1791.             break;
  1792.         case 'd':
  1793.         case 'D':
  1794.             event_type = KEYDOWN;
  1795.             break;
  1796.         // Otherwise, leave it set to the default.
  1797.         }
  1798.     }
  1799.  
  1800.     PerformMouseCommon(aActionType, vk
  1801.         , *aX1 ? ATOI(aX1) : COORD_UNSPECIFIED  // If no starting coords are specified, mark it as "use the
  1802.         , *aY1 ? ATOI(aY1) : COORD_UNSPECIFIED  // current mouse position":
  1803.         , *aX2 ? ATOI(aX2) : COORD_UNSPECIFIED  // These two are blank except for dragging.
  1804.         , *aY2 ? ATOI(aY2) : COORD_UNSPECIFIED  //
  1805.         , repeat_count, event_type
  1806.         , *aSpeed ? ATOI(aSpeed) : g.DefaultMouseSpeed
  1807.         , toupper(*aOffsetMode) == 'R'); // aMoveOffset.
  1808.  
  1809.     return OK; // For caller convenience.
  1810. }
  1811.  
  1812.  
  1813.  
  1814. void PerformMouseCommon(ActionTypeType aActionType, vk_type aVK, int aX1, int aY1, int aX2, int aY2
  1815.     , int aRepeatCount, KeyEventTypes aEventType, int aSpeed, bool aMoveOffset)
  1816. {
  1817.     // The maximum number of events, which in this case would be from a MouseClickDrag.  To be conservative
  1818.     // (even though INPUT is a much larger struct than PlaybackEvent and SendInput doesn't use mouse-delays),
  1819.     // include room for the maximum number of mouse delays too.
  1820.     // Drag consists of at most:
  1821.     // 1) Move; 2) Delay; 3) Down; 4) Delay; 5) Move; 6) Delay; 7) Delay (dupe); 8) Up; 9) Delay.
  1822.     #define MAX_PERFORM_MOUSE_EVENTS 10
  1823.     INPUT event_array[MAX_PERFORM_MOUSE_EVENTS]; // Use type INPUT vs. PlaybackEvent since the former is larger (i.e. enough to hold either one).
  1824.  
  1825.     sSendMode = g.SendMode;
  1826.     if (sSendMode == SM_INPUT || sSendMode == SM_INPUT_FALLBACK_TO_PLAY)
  1827.     {
  1828.         if (!sMySendInput || SystemHasAnotherMouseHook()) // See similar section in SendKeys() for details.
  1829.             sSendMode = (sSendMode == SM_INPUT) ? SM_EVENT : SM_PLAY;
  1830.         else
  1831.             sSendMode = SM_INPUT; // Resolve early so that other sections don't have to consider SM_INPUT_FALLBACK_TO_PLAY a valid value.
  1832.     }
  1833.     if (sSendMode) // We're also responsible for setting sSendMode to SM_EVENT prior to returning.
  1834.         InitEventArray(event_array, MAX_PERFORM_MOUSE_EVENTS, 0);
  1835.  
  1836.     // Turn it on unconditionally even if it was on, since Ctrl-Alt-Del might have disabled it.
  1837.     // Turn it back off only if it wasn't ON before we started.
  1838.     bool blockinput_prev = g_BlockInput;
  1839.     bool do_selective_blockinput = (g_BlockInputMode == TOGGLE_MOUSE || g_BlockInputMode == TOGGLE_SENDANDMOUSE)
  1840.         && !sSendMode && g_os.IsWinNT4orLater();
  1841.     if (do_selective_blockinput) // It seems best NOT to use g_BlockMouseMove for this, since often times the user would want keyboard input to be disabled too, until after the mouse event is done.
  1842.         Line::ScriptBlockInput(true); // Turn it on unconditionally even if it was on, since Ctrl-Alt-Del might have disabled it.
  1843.  
  1844.     switch (aActionType)
  1845.     {
  1846.     case ACT_MOUSEMOVE:
  1847.         DWORD unused;
  1848.         MouseMove(aX1, aY1, unused, aSpeed, aMoveOffset); // Does nothing if coords are invalid.
  1849.         break;
  1850.     case ACT_MOUSECLICK:
  1851.         MouseClick(aVK, aX1, aY1, aRepeatCount, aSpeed, aEventType, aMoveOffset); // Does nothing if coords are invalid.
  1852.         break;
  1853.     case ACT_MOUSECLICKDRAG:
  1854.         MouseClickDrag(aVK, aX1, aY1, aX2, aY2, aSpeed, aMoveOffset); // Does nothing if coords are invalid.
  1855.         break;
  1856.     } // switch()
  1857.  
  1858.     if (sSendMode)
  1859.     {
  1860.         int final_key_delay = -1; // Set default.
  1861.         if (!sAbortArraySend && sEventCount > 0)
  1862.             SendEventArray(final_key_delay, 0); // Last parameter is ignored because keybd hook isn't removed for a pure-mouse SendInput.
  1863.         CleanupEventArray(final_key_delay);
  1864.     }
  1865.  
  1866.     if (do_selective_blockinput && !blockinput_prev)  // Turn it back off only if it was off before we started.
  1867.         Line::ScriptBlockInput(false);
  1868. }
  1869.  
  1870.  
  1871.  
  1872. void MouseClickDrag(vk_type aVK, int aX1, int aY1, int aX2, int aY2, int aSpeed, bool aMoveOffset)
  1873. {
  1874.     // Check if one of the coordinates is missing, which can happen in cases where this was called from
  1875.     // a source that didn't already validate it. Can't call Line::ValidateMouseCoords() because that accepts strings.
  1876.     if (   (aX1 == COORD_UNSPECIFIED && aY1 != COORD_UNSPECIFIED) || (aX1 != COORD_UNSPECIFIED && aY1 == COORD_UNSPECIFIED)
  1877.         || (aX2 == COORD_UNSPECIFIED && aY2 != COORD_UNSPECIFIED) || (aX2 != COORD_UNSPECIFIED && aY2 == COORD_UNSPECIFIED)   )
  1878.         return;
  1879.  
  1880.     // I asked Jon, "Have you discovered that insta-drags almost always fail?" and he said
  1881.     // "Yeah, it was weird, absolute lack of drag... Don't know if it was my config or what."
  1882.     // However, testing reveals "insta-drags" work ok, at least on my system, so leaving them enabled.
  1883.     // User can easily increase the speed if there's any problem:
  1884.     //if (aSpeed < 2)
  1885.     //    aSpeed = 2;
  1886.  
  1887.     // v1.0.43: Translate logical buttons into physical ones.  Which physical button it becomes depends
  1888.     // on whether the mouse buttons are swapped via the Control Panel.  Note that journal playback doesn't
  1889.     // need the swap because every aspect of it is "logical".
  1890.     if (aVK == VK_LBUTTON_LOGICAL)
  1891.         aVK = sSendMode != SM_PLAY && GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON;
  1892.     else if (aVK == VK_RBUTTON_LOGICAL)
  1893.         aVK = sSendMode != SM_PLAY && GetSystemMetrics(SM_SWAPBUTTON) ? VK_LBUTTON : VK_RBUTTON;
  1894.  
  1895.     // MSDN: If [event_flags] is not MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, or MOUSEEVENTF_XUP, then [event_data]
  1896.     // should be zero. 
  1897.     DWORD event_down, event_up, event_flags = 0, event_data = 0; // Set defaults for some.
  1898.     switch (aVK)
  1899.     {
  1900.     case VK_LBUTTON:
  1901.         event_down = MOUSEEVENTF_LEFTDOWN;
  1902.         event_up = MOUSEEVENTF_LEFTUP;
  1903.         break;
  1904.     case VK_RBUTTON:
  1905.         event_down = MOUSEEVENTF_RIGHTDOWN;
  1906.         event_up = MOUSEEVENTF_RIGHTUP;
  1907.         break;
  1908.     case VK_MBUTTON:
  1909.         event_down = MOUSEEVENTF_MIDDLEDOWN;
  1910.         event_up = MOUSEEVENTF_MIDDLEUP;
  1911.         break;
  1912.     case VK_XBUTTON1:
  1913.     case VK_XBUTTON2:
  1914.         event_down = MOUSEEVENTF_XDOWN;
  1915.         event_up = MOUSEEVENTF_XUP;
  1916.         event_data = (aVK == VK_XBUTTON1) ? XBUTTON1 : XBUTTON2;
  1917.         break;
  1918.     }
  1919.  
  1920.     // If the drag isn't starting at the mouse's current position, move the mouse to the specified position:
  1921.     if (aX1 != COORD_UNSPECIFIED && aY1 != COORD_UNSPECIFIED)
  1922.     {
  1923.         // The movement must be a separate event from the click, otherwise it's completely unreliable with
  1924.         // SendInput() and probably keybd_event() too.  SendPlay is unknown, but it seems best for
  1925.         // compatibility and peace-of-mind to do it for that too.  For example, some apps may be designed
  1926.         // to expect mouse movement prior to a click at a *new* position, which is not unreasonable given
  1927.         // that this would be the case 99.999% of the time if the user were moving the mouse physically.
  1928.         MouseMove(aX1, aY1, event_flags, aSpeed, aMoveOffset); // It calls DoMouseDelay() and also converts aX1 and aY1 to MOUSEEVENTF_ABSOLUTE coordinates.
  1929.         // v1.0.43: event_flags was added to improve reliability.  Explanation: Since the mouse was just moved to an
  1930.         // explicitly specified set of coordinates, use those coordinates with subsequent clicks.  This has been
  1931.         // shown to signficantly improve reliability in cases where the user is moving the mouse during the
  1932.         // MouseClick/Drag commands.
  1933.     }
  1934.     MouseEvent(event_flags | event_down, event_data, aX1, aY1); // It ignores aX and aY when MOUSEEVENTF_MOVE is absent.
  1935.     DoMouseDelay(); // Inserts delay for all modes except SendInput, for which it does nothing.
  1936.     // Now that the mouse button has been pushed down, move the mouse to perform the drag:
  1937.     MouseMove(aX2, aY2, event_flags, aSpeed, aMoveOffset); // It calls DoMouseDelay() and also converts aX2 and aY2 to MOUSEEVENTF_ABSOLUTE coordinates.
  1938.     DoMouseDelay(); // Duplicate, see below.
  1939.     // Above is a *duplicate* delay because MouseMove() already did one. But it seems best to keep it because:
  1940.     // 1) MouseClickDrag can be a CPU intensive operation for the target window depending on what it does
  1941.     //    during the drag (selecting objects, etc.)  Thus, and extra delay might help a lot of things.
  1942.     // 2) It would probably break some existing scripts to remove the delay, due to timing issues.
  1943.     // 3) Dragging is pretty rarely used, so the added performance of removing the delay wouldn't be
  1944.     //    a big benefit.
  1945.     MouseEvent(event_flags | event_up, event_data, aX2, aY2); // It ignores aX and aY when MOUSEEVENTF_MOVE is absent.
  1946.     DoMouseDelay();
  1947.     // Above line: It seems best to always do this delay too in case the script line that
  1948.     // caused us to be called here is followed immediately by another script line which
  1949.     // is either another mouse click or something that relies upon this mouse drag
  1950.     // having been completed:
  1951. }
  1952.  
  1953.  
  1954.  
  1955. void MouseClick(vk_type aVK, int aX, int aY, int aRepeatCount, int aSpeed, KeyEventTypes aEventType
  1956.     , bool aMoveOffset)
  1957. {
  1958.     // Check if one of the coordinates is missing, which can happen in cases where this was called from
  1959.     // a source that didn't already validate it (such as MouseClick, %x%, %BlankVar%).
  1960.     // Allow aRepeatCount<1 to simply "do nothing", because it increases flexibility in the case where
  1961.     // the number of clicks is a dereferenced script variable that may sometimes (by intent) resolve to
  1962.     // zero or negative.  For backward compatibility, a RepeatCount <1 does not move the mouse (unlike
  1963.     // the Click command and Send {Click}).
  1964.     if (   (aX == COORD_UNSPECIFIED && aY != COORD_UNSPECIFIED) || (aX != COORD_UNSPECIFIED && aY == COORD_UNSPECIFIED)
  1965.         || (aRepeatCount < 1)   )
  1966.         return;
  1967.  
  1968.     DWORD event_flags = 0; // Set default.
  1969.  
  1970.     if (!(aX == COORD_UNSPECIFIED || aY == COORD_UNSPECIFIED)) // Both coordinates were specified.
  1971.     {
  1972.         // The movement must be a separate event from the click, otherwise it's completely unreliable with
  1973.         // SendInput() and probably keybd_event() too.  SendPlay is unknown, but it seems best for
  1974.         // compatibility and peace-of-mind to do it for that too.  For example, some apps may be designed
  1975.         // to expect mouse movement prior to a click at a *new* position, which is not unreasonable given
  1976.         // that this would be the case 99.999% of the time if the user were moving the mouse physically.
  1977.         MouseMove(aX, aY, event_flags, aSpeed, aMoveOffset); // It calls DoMouseDelay() and also converts aX and aY to MOUSEEVENTF_ABSOLUTE coordinates.
  1978.         // v1.0.43: event_flags was added to improve reliability.  Explanation: Since the mouse was just moved to an
  1979.         // explicitly specified set of coordinates, use those coordinates with subsequent clicks.  This has been
  1980.         // shown to signficantly improve reliability in cases where the user is moving the mouse during the
  1981.         // MouseClick/Drag commands.
  1982.     }
  1983.     // Above must be done prior to below because initial mouse-move is supported even for wheel turning.
  1984.  
  1985.     // For wheel turning, if the user activated this command via a hotkey, and that hotkey
  1986.     // has a modifier such as CTRL, the user is probably still holding down the CTRL key
  1987.     // at this point.  Therefore, there's some merit to the fact that we should release
  1988.     // those modifier keys prior to turning the mouse wheel (since some apps disable the
  1989.     // wheel or give it different behavior when the CTRL key is down -- for example, MSIE
  1990.     // changes the font size when you use the wheel while CTRL is down).  However, if that
  1991.     // were to be done, there would be no way to ever hold down the CTRL key explicitly
  1992.     // (via Send, {CtrlDown}) unless the hook were installed.  The same argument could probably
  1993.     // be made for mouse button clicks: modifier keys can often affect their behavior.  But
  1994.     // changing this function to adjust modifiers for all types of events would probably break
  1995.     // some existing scripts.  Maybe it can be a script option in the future.  In the meantime,
  1996.     // it seems best not to adjust the modifiers for any mouse events and just document that
  1997.     // behavior in the MouseClick command.
  1998.     if (aVK == VK_WHEEL_UP)
  1999.     {
  2000.         MouseEvent(event_flags | MOUSEEVENTF_WHEEL, aRepeatCount * WHEEL_DELTA, aX, aY);  // It ignores aX and aY when MOUSEEVENTF_MOVE is absent.
  2001.         return;
  2002.     }
  2003.     else if (aVK == VK_WHEEL_DOWN)
  2004.     {
  2005.         MouseEvent(event_flags | MOUSEEVENTF_WHEEL, -(aRepeatCount * WHEEL_DELTA), aX, aY);
  2006.         return;
  2007.     }
  2008.     // Otherwise:
  2009.  
  2010.     // Although not thread-safe, the following static vars seem okay because:
  2011.     // 1) This function is currently only called by the main thread.
  2012.     // 2) Even if that isn't true, the serialized nature of simulated mouse clicks makes it likely that
  2013.     //    the statics will produce the correct behavior anyway.
  2014.     // 3) Even if that isn't true, the consequences of incorrect behavior seem minimal in this case.
  2015.     static vk_type sWorkaroundVK = 0;
  2016.     static LRESULT sWorkaroundHitTest; // Not initialized because the above will be the sole signal of whether the workaround is in progress.
  2017.     DWORD event_down, event_up, event_data = 0; // Set default.
  2018.     // MSDN: If [event_flags] is not MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, or MOUSEEVENTF_XUP, then [event_data]
  2019.     // should be zero. 
  2020.  
  2021.     // v1.0.43: Translate logical buttons into physical ones.  Which physical button it becomes depends
  2022.     // on whether the mouse buttons are swapped via the Control Panel.
  2023.     if (aVK == VK_LBUTTON_LOGICAL)
  2024.         aVK = sSendMode != SM_PLAY && GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON;
  2025.     else if (aVK == VK_RBUTTON_LOGICAL)
  2026.         aVK = sSendMode != SM_PLAY && GetSystemMetrics(SM_SWAPBUTTON) ? VK_LBUTTON : VK_RBUTTON;
  2027.  
  2028.     switch (aVK)
  2029.     {
  2030.     case VK_LBUTTON:
  2031.     case VK_RBUTTON:
  2032.         // v1.0.43 The first line below means: We're not in SendInput/Play mode or we are but this
  2033.         // will be the first event inside the array.  The latter case also implies that no initial
  2034.         // mouse-move was done above (otherwise there would already be a MouseMove event in the array,
  2035.         // and thus the click here wouldn't be the first item).  It doesn't seem necessary to support
  2036.         // the MouseMove case above because the workaround generally isn't needed in such situations
  2037.         // (see detailed comments below).  Furthermore, if the MouseMove were supported in array-mode,
  2038.         // it would require that GetCursorPos() below be conditionally replaced with something like
  2039.         // the following (since when in array-mode, the cursor hasn't actually moved *yet*):
  2040.         //        if (!(g.CoordMode & COORD_MODE_MOUSE))  // Moving mouse relative to the active window.
  2041.         //            WindowToScreen(aX_orig, aY_orig);
  2042.         // Known limitation: the work-around described below isn't as complete for SendPlay as it is
  2043.         // for the other modes: because dragging the title bar of one of this thread's windows with a
  2044.         // remap such as F1::LButton doesn't work if that remap uses SendPlay internally (the window
  2045.         // gets stuck to the mouse cursor).
  2046.         if (   (!sSendMode || !sEventCount) // See above.
  2047.             && (aEventType == KEYDOWN || (aEventType == KEYUP && sWorkaroundVK))   ) // i.e. this is a down-only event or up-only event.
  2048.         {
  2049.             // v1.0.40.01: The following section corrects misbehavior caused by a thread sending
  2050.             // simulated mouse clicks to one of its own windows.  A script consisting only of the
  2051.             // following two lines can reproduce this issue:
  2052.             // F1::LButton
  2053.             // F2::RButton
  2054.             // The problems came about from the following sequence of events:
  2055.             // 1) Script simulates a left-click-down in the title bar's close, minimize, or maximize button.
  2056.             // 2) WM_NCLBUTTONDOWN is sent to the window's window proc, which then passes it on to
  2057.             //    DefWindowProc or DefDlgProc, which then apparently enters a loop in which no messages
  2058.             //    (or a very limited subset) are pumped.
  2059.             // 3) Thus, if the user presses a hotkey while the thread is in this state, that hotkey is
  2060.             //    queued/buffered until DefWindowProc/DefDlgProc exits its loop.
  2061.             // 4) But the buffered hotkey is the very thing that's supposed to exit the loop via sending a
  2062.             //    simulated left-click-up event.
  2063.             // 5) Thus, a deadlock occurs.
  2064.             // 6) A similar situation arises when a right-click-down is sent to the title bar or sys-menu-icon.
  2065.             //
  2066.             // The following workaround operates by suppressing qualified click-down events until the
  2067.             // corresponding click-up occurs, at which time the click-up is transformed into a down+up if the
  2068.             // click-up is still in the same cursor position as the down. It seems preferable to fix this here
  2069.             // rather than changing each window proc. to always respond to click-down rather vs. click-up
  2070.             // because that would make all of the script's windows behave in a non-standard way, possibly
  2071.             // producing side-effects and defeating other programs' attempts to interact with them.
  2072.             // (Thanks to Shimanov for this solution.)
  2073.             //
  2074.             // Remaining known limitations:
  2075.             // 1) Title bar buttons are not visibly in a pressed down state when a simulated click-down is sent
  2076.             //    to them.
  2077.             // 2) A window that should not be activated, such as AlwaysOnTop+Disabled, is activated anyway
  2078.             //    by SetForegroundWindowEx().  Not yet fixed due to its rarity and minimal consequences.
  2079.             // 3) A related problem for which no solution has been discovered (and perhaps it's too obscure
  2080.             //    an issue to justify any added code size): If a remapping such as "F1::LButton" is in effect,
  2081.             //    pressing and releasing F1 while the cursor is over a script window's title bar will cause the
  2082.             //    window to move slightly the next time the mouse is moved.
  2083.             // 4) Clicking one of the script's window's title bar with a key/button that has been remapped to
  2084.             //    become the left mouse button sometimes causes the button to get stuck down from the window's
  2085.             //    point of view.  The reasons are related to those in #1 above.  In both #1 and #2, the workaround
  2086.             //    is not at fault because it's not in effect then.  Instead, the issue is that DefWindowProc enters
  2087.             //    a non-msg-pumping loop while it waits for the user to drag-move the window.  If instead the user
  2088.             //    releases the button without dragging, the loop exits on its own after a 500ms delay or so.
  2089.             // 5) Obscure behavior caused by keyboard's auto-repeat feature: Use a key that's been remapped to
  2090.             //    become the left mouse button to click and hold the minimize button of one of the script's windows.
  2091.             //    Drag to the left.  The window starts moving.  This is caused by the fact that the down-click is
  2092.             //    suppressed, thus the remap's hotkey subroutine thinks the mouse button is down, thus its
  2093.             //    auto-repeat suppression doesn't work and it sends another click.
  2094.             POINT point;
  2095.             GetCursorPos(&point); // Assuming success seems harmless.
  2096.             // Despite what MSDN says, WindowFromPoint() appears to fetch a non-NULL value even when the
  2097.             // mouse is hovering over a disabled control (at least on XP).
  2098.             HWND child_under_cursor, parent_under_cursor;
  2099.             if (   (child_under_cursor = WindowFromPoint(point))
  2100.                 && (parent_under_cursor = GetNonChildParent(child_under_cursor)) // WM_NCHITTEST below probably requires parent vs. child.
  2101.                 && GetWindowThreadProcessId(parent_under_cursor, NULL) == g_MainThreadID   ) // It's one of our thread's windows.
  2102.             {
  2103.                 LRESULT hit_test = SendMessage(parent_under_cursor, WM_NCHITTEST, 0, MAKELPARAM(point.x, point.y));
  2104.                 if (   aVK == VK_LBUTTON && (hit_test == HTCLOSE || hit_test == HTMAXBUTTON // Title bar buttons: Close, Maximize.
  2105.                         || hit_test == HTMINBUTTON || hit_test == HTHELP) // Title bar buttons: Minimize, Help.
  2106.                     || aVK == VK_RBUTTON && (hit_test == HTCAPTION || hit_test == HTSYSMENU)   )
  2107.                 {
  2108.                     if (aEventType == KEYDOWN)
  2109.                     {
  2110.                         // Ignore this event and substitute for it: Activate the window when one
  2111.                         // of its title bar buttons is down-clicked.
  2112.                         sWorkaroundVK = aVK;
  2113.                         sWorkaroundHitTest = hit_test;
  2114.                         SetForegroundWindowEx(parent_under_cursor); // Try to reproduce customary behavior.
  2115.                         // For simplicity, aRepeatCount>1 is ignored and DoMouseDelay() is not done.
  2116.                         return;
  2117.                     }
  2118.                     else // KEYUP
  2119.                     {
  2120.                         if (sWorkaroundHitTest == hit_test) // To weed out cases where user clicked down on a button then released somewhere other than the button.
  2121.                             aEventType = KEYDOWNANDUP; // Translate this click-up into down+up to make up for the fact that the down was previously suppressed.
  2122.                         //else let the click-up occur in case it does something or user wants it.
  2123.                     }
  2124.                 }
  2125.             } // Work-around for sending mouse clicks to one of our thread's own windows.
  2126.         }
  2127.         // sWorkaroundVK is reset later below.
  2128.  
  2129.         // Since above didn't return, the work-around isn't in effect and normal click(s) will be sent:
  2130.         if (aVK == VK_LBUTTON)
  2131.         {
  2132.             event_down = MOUSEEVENTF_LEFTDOWN;
  2133.             event_up = MOUSEEVENTF_LEFTUP;
  2134.         }
  2135.         else // aVK == VK_RBUTTON
  2136.         {
  2137.             event_down = MOUSEEVENTF_RIGHTDOWN;
  2138.             event_up = MOUSEEVENTF_RIGHTUP;
  2139.         }
  2140.         break;
  2141.  
  2142.     case VK_MBUTTON:
  2143.         event_down = MOUSEEVENTF_MIDDLEDOWN;
  2144.         event_up = MOUSEEVENTF_MIDDLEUP;
  2145.         break;
  2146.  
  2147.     case VK_XBUTTON1:
  2148.     case VK_XBUTTON2:
  2149.         event_down = MOUSEEVENTF_XDOWN;
  2150.         event_up = MOUSEEVENTF_XUP;
  2151.         event_data = (aVK == VK_XBUTTON1) ? XBUTTON1 : XBUTTON2;
  2152.         break;
  2153.     } // switch()
  2154.  
  2155.     // For simplicity and possibly backward compatibility, LONG_OPERATION_INIT/UPDATE isn't done.
  2156.     // In addition, some callers might do it for themselves, at least when aRepeatCount==1.
  2157.     for (int i = 0; i < aRepeatCount; ++i)
  2158.     {
  2159.         if (aEventType != KEYUP) // It's either KEYDOWN or KEYDOWNANDUP.
  2160.         {
  2161.             // v1.0.43: Reliability is significantly improved by specifying the coordinates with the event (if
  2162.             // caller gave us coordinates).  This is mostly because of SetMouseDelay: In previously versions,
  2163.             // the delay between a MouseClick's move and its click allowed time for the user to move the mouse
  2164.             // away from the target position before the click was sent.
  2165.             MouseEvent(event_flags | event_down, event_data, aX, aY); // It ignores aX and aY when MOUSEEVENTF_MOVE is absent.
  2166.             // It seems best to always Sleep a certain minimum time between events
  2167.             // because the click-down event may cause the target app to do something which
  2168.             // changes the context or nature of the click-up event.  AutoIt3 has also been
  2169.             // revised to do this. v1.0.40.02: Avoid doing the Sleep between the down and up
  2170.             // events when the workaround is in effect because any MouseDelay greater than 10
  2171.             // would cause DoMouseDelay() to pump messages, which would defeat the workaround:
  2172.             if (!sWorkaroundVK)
  2173.                 DoMouseDelay(); // Inserts delay for all modes except SendInput, for which it does nothing.
  2174.         }
  2175.         if (aEventType != KEYDOWN) // It's either KEYUP or KEYDOWNANDUP.
  2176.         {
  2177.             MouseEvent(event_flags | event_up, event_data, aX, aY); // It ignores aX and aY when MOUSEEVENTF_MOVE is absent.
  2178.             // It seems best to always do this one too in case the script line that caused
  2179.             // us to be called here is followed immediately by another script line which
  2180.             // is either another mouse click or something that relies upon the mouse click
  2181.             // having been completed:
  2182.             DoMouseDelay(); // Inserts delay for all modes except SendInput, for which it does nothing.
  2183.         }
  2184.     } // for()
  2185.  
  2186.     sWorkaroundVK = 0; // Reset this indicator in all cases except those for which above already returned.
  2187. }
  2188.  
  2189.  
  2190.  
  2191. void MouseMove(int &aX, int &aY, DWORD &aEventFlags, int aSpeed, bool aMoveOffset)
  2192. // This function also does DoMouseDelay() for the caller.
  2193. // This function converts aX and aY for the caller into MOUSEEVENTF_ABSOLUTE coordinates.
  2194. // The exception is when the playback mode is in effect, in which case such a conversion would be undesirable
  2195. // both here and by the caller.
  2196. // It also puts appropriate bit-flags into aEventFlags.
  2197. {
  2198.     // Most callers have already validated this, but some haven't.  Since it doesn't take too long to check,
  2199.     // do it here rather than requiring all callers to do (helps maintainability).
  2200.     if (aX == COORD_UNSPECIFIED || aY == COORD_UNSPECIFIED)
  2201.         return;
  2202.  
  2203.     if (sSendMode == SM_PLAY) // Journal playback mode.
  2204.     {
  2205.         // Mouse speed (aSpeed) is ignored for SendInput/Play mode: the mouse always moves instantaneously
  2206.         // (though in the case of playback-mode, MouseDelay still applies between each movmement and click).
  2207.         // Playback-mode ignores mouse speed because the cases where the user would want to move the mouse more
  2208.         // slowly (such as a demo) seem too rare to justify the code size and complexity, especially since the
  2209.         // incremental-move code would have to be implemented in the hook itself to ensure reliability.  This is
  2210.         // because calling GetCursorPos() before playback begins could cause the mouse to wind up at the wrong
  2211.         // destination, especially if our thread is preempted while building the array (which would give the user
  2212.         // a chance to physically move the mouse before uninterruptibility begins).
  2213.         // For creating demonstrations that user slower mouse movement, the older MouseMove command can be used
  2214.         // in conjunction with BlockInput. This also applies to SendInput because it's conceivable that mouse
  2215.         // speed could be supported there (though it seems useless both visually and to improve reliability
  2216.         // because no mouse delays are possible within SendInput).
  2217.         //
  2218.         // MSG_OFFSET_MOUSE_MOVE is used to have the playback hook apply the offset (rather than doing it here
  2219.         // like is done for SendInput mode).  This adds flexibility in cases where a new window becomes active
  2220.         // during playback, or the active window changes position -- if that were to happen, the offset would
  2221.         // otherwise be wrong while CoordMode is Relative because the changes can only be observed and
  2222.         // compensated for during playback.
  2223.         PutMouseEventIntoArray(MOUSEEVENTF_MOVE | (aMoveOffset ? MSG_OFFSET_MOUSE_MOVE : 0)
  2224.             , 0, aX, aY); // The playback hook uses normal vs. MOUSEEVENTF_ABSOLUTE coordinates.
  2225.         DoMouseDelay();
  2226.         if (aMoveOffset)
  2227.         {
  2228.             // Now that we're done using the old values of aX and aY above, reset them to COORD_UNSPECIFIED
  2229.             // for the caller so that any subsequent clicks it does will be marked as "at current coordinates".
  2230.             aX = COORD_UNSPECIFIED;
  2231.             aY = COORD_UNSPECIFIED;
  2232.         }
  2233.         return; // Other parts below rely on this returning early to avoid converting aX/aY into MOUSEEVENTF_ABSOLUTE.
  2234.     }
  2235.  
  2236.     // The playback mode returned from above doesn't need these flags added because they're ignored for clicks:
  2237.     aEventFlags |= MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; // Done here for caller, for easier maintenance.
  2238.  
  2239.     POINT cursor_pos;
  2240.     if (aMoveOffset)  // We're moving the mouse cursor relative to its current position.
  2241.     {
  2242.         if (sSendMode == SM_INPUT)
  2243.         {
  2244.             // Since GetCursorPos() can't be called to find out a future cursor position, use the position
  2245.             // tracked for SendInput (facilitates MouseClickDrag's R-option as well as Send{Click}'s).
  2246.             if (sSendInputCursorPos.x == COORD_UNSPECIFIED) // Initial/starting value hasn't yet been set.
  2247.                 GetCursorPos(&sSendInputCursorPos); // Start it off where the cursor is now.
  2248.             aX += sSendInputCursorPos.x;
  2249.             aY += sSendInputCursorPos.y;
  2250.         }
  2251.         else
  2252.         {
  2253.             GetCursorPos(&cursor_pos); // None of this is done for playback mode since that mode already returned higher above.
  2254.             aX += cursor_pos.x;
  2255.             aY += cursor_pos.y;
  2256.         }
  2257.     }
  2258.     else if (!(g.CoordMode & COORD_MODE_MOUSE))  // Moving mouse relative to the active window (rather than screen).
  2259.         WindowToScreen(aX, aY);  // None of this is done for playback mode since that mode already returned higher above.
  2260.  
  2261.     if (sSendMode == SM_INPUT) // Track predicted cursor position for use by subsequent events put into the array.
  2262.     {
  2263.         sSendInputCursorPos.x = aX; // Always stores normal coords (non-MOUSEEVENTF_ABSOLUTE).
  2264.         sSendInputCursorPos.y = aY; // 
  2265.     }
  2266.  
  2267.     // Find dimensions of primary monitor.
  2268.     // Without the MOUSEEVENTF_VIRTUALDESK flag (supported only by SendInput, and then only on
  2269.     // Windows 2000/XP or later), MOUSEEVENTF_ABSOLUTE coordinates are relative to the primary monitor.
  2270.     int screen_width = GetSystemMetrics(SM_CXSCREEN);
  2271.     int screen_height = GetSystemMetrics(SM_CYSCREEN);
  2272.  
  2273.     // Convert the specified screen coordinates to mouse event coordinates (MOUSEEVENTF_ABSOLUTE).
  2274.     // MSDN: "In a multimonitor system, [MOUSEEVENTF_ABSOLUTE] coordinates map to the primary monitor."
  2275.     // The above implies that values greater than 65535 or less than 0 are appropriate, but only on
  2276.     // multi-monitor systems.  For simplicity, performance, and backward compatibility, no check for
  2277.     // multi-monitor is done here. Instead, the system's default handling for out-of-bounds coordinates
  2278.     // is used; for example, mouse_event() stops the cursor at the edge of the screen.
  2279.     // UPDATE: In v1.0.43, the following formula was fixed (actually broken, see below) to always yield an
  2280.     // in-range value. The previous formula had a +1 at the end:
  2281.     // aX|Y = ((65535 * aX|Y) / (screen_width|height - 1)) + 1;
  2282.     // The extra +1 would produce 65536 (an out-of-range value for a single-monitor system) if the maximum
  2283.     // X or Y coordinate was input (e.g. x-position 1023 on a 1024x768 screen).  Although this correction
  2284.     // seems inconsequential on single-monitor systems, it may fix certain misbehaviors that have been reported
  2285.     // on multi-monitor systems. Update: according to someone I asked to test it, it didn't fix anything on
  2286.     // multimonitor systems, at least those whose monitors vary in size to each other.  In such cases, he said
  2287.     // that only SendPlay or DllCall("SetCursorPos") make mouse movement work properly.
  2288.     // FIX for v1.0.44: Although there's no explanation yet, the v1.0.43 formula is wrong and the one prior
  2289.     // to it was correct; i.e. unless +1 is present below, a mouse movement to coords near the upper-left corner of
  2290.     // the screen is typically off by one pixel (only the y-coordinate is affected in 1024x768 resolution, but
  2291.     // in other resolutions both might be affected).
  2292.     // v1.0.44.07: The following old formula has been replaced:
  2293.     // (((65535 * coord) / (width_or_height - 1)) + 1)
  2294.     // ... with the new one below.  This is based on numEric's research, which indicates that mouse_event()
  2295.     // uses the following inverse formula internally:
  2296.     // x_or_y_coord = (x_or_y_abs_coord * screen_width_or_height) / 65536
  2297.     #define MOUSE_COORD_TO_ABS(coord, width_or_height) (((65536 * coord) / width_or_height) + 1)
  2298.     aX = MOUSE_COORD_TO_ABS(aX, screen_width);
  2299.     aY = MOUSE_COORD_TO_ABS(aY, screen_height);
  2300.     // aX and aY MUST BE SET UNCONDITIONALLY because the output parameters must be updated for caller.
  2301.     // The incremental-move section further below also needs it.
  2302.  
  2303.     if (aSpeed < 0)  // This can happen during script's runtime due to something like: MouseMove, X, Y, %VarContainingNegative%
  2304.         aSpeed = 0;  // 0 is the fastest.
  2305.     else
  2306.         if (aSpeed > MAX_MOUSE_SPEED)
  2307.             aSpeed = MAX_MOUSE_SPEED;
  2308.     if (aSpeed == 0 || sSendMode == SM_INPUT) // Instantanous move to destination coordinates with no incremental positions in between.
  2309.     {
  2310.         // See the comments in the playback-mode section at the top of this function for why SM_INPUT ignores aSpeed.
  2311.         MouseEvent(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, 0, aX, aY);
  2312.         DoMouseDelay(); // Inserts delay for all modes except SendInput, for which it does nothing.
  2313.         return;
  2314.     }
  2315.  
  2316.     // Since above didn't return, use the incremental mouse move to gradually move the cursor until
  2317.     // it arrives at the destination coordinates.
  2318.     // Convert the cursor's current position to mouse event coordinates (MOUSEEVENTF_ABSOLUTE).
  2319.     GetCursorPos(&cursor_pos);
  2320.     DoIncrementalMouseMove(
  2321.           MOUSE_COORD_TO_ABS(cursor_pos.x, screen_width)  // Source/starting coords.
  2322.         , MOUSE_COORD_TO_ABS(cursor_pos.y, screen_height) //
  2323.         , aX, aY, aSpeed);                                // Destination/ending coords.
  2324. }
  2325.  
  2326.  
  2327.  
  2328. void MouseEvent(DWORD aEventFlags, DWORD aData, DWORD aX, DWORD aY)
  2329. // Having this part outsourced to a function helps remember to use KEY_IGNORE so that our own mouse
  2330. // events won't be falsely detected as hotkeys by the hooks (if they are installed).
  2331. {
  2332.     if (sSendMode)
  2333.         PutMouseEventIntoArray(aEventFlags, aData, aX, aY);
  2334.     else
  2335.         mouse_event(aEventFlags
  2336.             , aX == COORD_UNSPECIFIED ? 0 : aX // v1.0.43.01: Must be zero if no change in position is desired
  2337.             , aY == COORD_UNSPECIFIED ? 0 : aY // (fixes compatibility with certain apps/games).
  2338.             , aData, KEY_IGNORE);
  2339. }
  2340.  
  2341.  
  2342. ///////////////////////
  2343. // SUPPORT FUNCTIONS //
  2344. ///////////////////////
  2345.  
  2346. void PutKeybdEventIntoArray(modLR_type aKeyAsModifiersLR, vk_type aVK, sc_type aSC, DWORD aEventFlags, DWORD aExtraInfo)
  2347. // This function is designed to be called from only one thread (the main thread) since it's not thread-safe.
  2348. // Playback hook only supports sending neutral modifiers.  Caller must ensure that any left/right modfiiers
  2349. // such as VK_RCONTROL are translated into neutral (e.g. VK_CONTROL).
  2350. {
  2351.     bool key_up = aEventFlags & KEYEVENTF_KEYUP;
  2352.     // To make the SendPlay method identical in output to the other keystroke methods, have it generate
  2353.     // a leading down/up LControl event immediately prior to each RAlt event (with no key-delay).
  2354.     // This avoids having to add special handling to places like SetModifierLRState() to do AltGr things
  2355.     // differently when sending via playback vs. other methods.  The event order recorded by the journal
  2356.     // record hook is a little different than what the low-level keyboard hook sees, but I don't think
  2357.     // the order should matter in this case:
  2358.     //   sc  vk key     msg
  2359.     //   138 12 Alt     syskeydown (right vs. left scan code)
  2360.     //   01d 11 Ctrl keydown (left scan code) <-- In keyboard hook, normally this precedes Alt, not follows it. Seems inconsequential (testing confirms).
  2361.     //   01d 11 Ctrl keyup    (left scan code)
  2362.     //   138 12 Alt     syskeyup (right vs. left scan code)
  2363.     // Check for VK_MENU not VK_RMENU because caller should have translated it to neutral:
  2364.     if (aVK == VK_MENU && aSC == SC_RALT && sTargetLayoutHasAltGr == CONDITION_TRUE && sSendMode == SM_PLAY)
  2365.         // Must pass VK_CONTROL rather than VK_LCONTROL because playback hook requires neutral modifiers.
  2366.         PutKeybdEventIntoArray(MOD_LCONTROL, VK_CONTROL, SC_LCONTROL, aEventFlags, aExtraInfo); // Recursive call to self.
  2367.  
  2368.     // Above must be done prior to the capacity check below because above might add a new array item.
  2369.     if (sEventCount == sMaxEvents) // Array's capacity needs expanding.
  2370.         if (!ExpandEventArray())
  2371.             return;
  2372.  
  2373.     // Keep track of the predicted modifier state for use in other places:
  2374.     if (key_up)
  2375.         sEventModifiersLR &= ~aKeyAsModifiersLR;
  2376.     else
  2377.         sEventModifiersLR |= aKeyAsModifiersLR;
  2378.  
  2379.     if (sSendMode == SM_INPUT)
  2380.     {
  2381.         INPUT &this_event = sEventSI[sEventCount]; // For performance and convenience.
  2382.         this_event.type = INPUT_KEYBOARD;
  2383.         this_event.ki.wVk = aVK;
  2384.         this_event.ki.wScan = LOBYTE(aSC);
  2385.         this_event.ki.dwFlags = aEventFlags;
  2386.         this_event.ki.dwExtraInfo = aExtraInfo; // Although our hook won't be installed (or won't detect, in the case of playback), that of other scripts might be, so set this for them.
  2387.         this_event.ki.time = 0; // Let the system provide its own timestamp, which might be more accurate for individual events if this will be a very long SendInput.
  2388.         sHooksToRemoveDuringSendInput |= HOOK_KEYBD; // Presence of keyboard hook defeats uninterruptibility of keystrokes.
  2389.     }
  2390.     else // Playback hook.
  2391.     {
  2392.         PlaybackEvent &this_event = sEventPB[sEventCount]; // For performance and convenience.
  2393.         if (!(aVK || aSC)) // Caller is signaling that aExtraInfo contains a delay/sleep event.
  2394.         {
  2395.             // Although delays at the tail end of the playback array can't be implemented by the playback
  2396.             // itself, caller wants them put in too.
  2397.             this_event.message = 0; // Message number zero flags it as a delay rather than an actual event.
  2398.             this_event.time_to_wait = aExtraInfo;
  2399.         }
  2400.         else // A normal (non-delay) event for playback.
  2401.         {
  2402.             // By monitoring incoming events in a message/event loop, the following key combinations were
  2403.             // confirmed to be WM_SYSKEYDOWN vs. WM_KEYDOWN (up events weren't tested, so are assumed to
  2404.             // be the same as down-events):
  2405.             // Alt+Win
  2406.             // Alt+Shift
  2407.             // Alt+Capslock/Numlock/Scrolllock
  2408.             // Alt+AppsKey
  2409.             // Alt+F2/Delete/Home/End/Arrow/BS
  2410.             // Alt+Space/Enter
  2411.             // Alt+Numpad (tested all digits & most other keys, with/without Numlock ON)
  2412.             // F10 (by itself) / Win+F10 / Alt+F10 / Shift+F10 (but not Ctrl+F10)
  2413.             // By contrast, the following are not SYS: Alt+Ctrl, Alt+Esc, Alt+Tab (the latter two
  2414.             // are never received by msg/event loop probably because the system intercepts them).
  2415.             // So the rule appears to be: It's a normal (non-sys) key if Alt isn't down and the key
  2416.             // isn't F10, or if Ctrl is down. Though a press of the Alt key itself is a syskey unless Ctrl is down.
  2417.             // Update: The release of ALT is WM_KEYUP vs. WM_SYSKEYUP when it modified at least one key while it was down.
  2418.             if (sEventModifiersLR & (MOD_LCONTROL | MOD_RCONTROL) // Control is down...
  2419.                 || !(sEventModifiersLR & (MOD_LALT | MOD_RALT))   // ... or: Alt isn't down and this key isn't Alt or F10...
  2420.                     && aVK != VK_F10 && !(aKeyAsModifiersLR & (MOD_LALT | MOD_RALT))
  2421.                 || (sEventModifiersLR & (MOD_LALT | MOD_RALT)) && key_up) // ... or this is the release of Alt (for simplicity, assume that Alt modified something while it was down).
  2422.                 this_event.message = key_up ? WM_KEYUP : WM_KEYDOWN;
  2423.             else
  2424.                 this_event.message = key_up ? WM_SYSKEYUP : WM_SYSKEYDOWN;
  2425.             this_event.vk = aVK;
  2426.             this_event.sc = aSC; // Don't omit the extended-key-bit because it is used later on.
  2427.         }
  2428.     }
  2429.     ++sEventCount;
  2430. }
  2431.  
  2432.  
  2433.  
  2434. void PutMouseEventIntoArray(DWORD aEventFlags, DWORD aData, DWORD aX, DWORD aY)
  2435. // This function is designed to be called from only one thread (the main thread) since it's not thread-safe.
  2436. // If the array-type is journal playback, caller should include MOUSEEVENTF_ABSOLUTE in aEventFlags if the
  2437. // the mouse coordinates aX and aY are relative to the screen rather than the active window.
  2438. {
  2439.     if (sEventCount == sMaxEvents) // Array's capacity needs expanding.
  2440.         if (!ExpandEventArray())
  2441.             return;
  2442.  
  2443.     if (sSendMode == SM_INPUT)
  2444.     {
  2445.         INPUT &this_event = sEventSI[sEventCount]; // For performance and convenience.
  2446.         this_event.type = INPUT_MOUSE;
  2447.         this_event.mi.dx = (aX == COORD_UNSPECIFIED) ? 0 : aX; // v1.0.43.01: Must be zero if no change in position is
  2448.         this_event.mi.dy = (aY == COORD_UNSPECIFIED) ? 0 : aY; // desired (fixes compatibility with certain apps/games).
  2449.         this_event.mi.dwFlags = aEventFlags;
  2450.         this_event.mi.mouseData = aData;
  2451.         this_event.mi.dwExtraInfo = KEY_IGNORE; // Although our hook won't be installed (or won't detect, in the case of playback), that of other scripts might be, so set this for them.
  2452.         this_event.mi.time = 0; // Let the system provide its own timestamp, which might be more accurate for individual events if this will be a very long SendInput.
  2453.         sHooksToRemoveDuringSendInput |= HOOK_MOUSE; // Presence of mouse hook defeats uninterruptibility of mouse clicks/moves.
  2454.     }
  2455.     else // Playback hook.
  2456.     {
  2457.         // Note: Delay events (sleeps), which are supported in playback mode but not SendInput, are always inserted
  2458.         // via PutKeybdEventIntoArray() rather than this function.
  2459.         PlaybackEvent &this_event = sEventPB[sEventCount]; // For performance and convenience.
  2460.         // Determine the type of event specified by caller, but also omit MOUSEEVENTF_MOVE so that the
  2461.         // follow variations can be differentiated:
  2462.         // 1) MOUSEEVENTF_MOVE by itself.
  2463.         // 2) MOUSEEVENTF_MOVE with a click event or wheel turn (in this case MOUSEEVENTF_MOVE is permitted but
  2464.         //    not required, since all mouse events in playback mode must have explicit coordinates at the
  2465.         //    time they're playbed back).
  2466.         // 3) A click event or wheel turn by itself (same remark as above).
  2467.         // Bits are isolated in what should be a future-proof way (also omits MSG_OFFSET_MOUSE_MOVE bit).
  2468.         switch (aEventFlags & (0xFFF & ~MOUSEEVENTF_MOVE))
  2469.         {
  2470.         case 0:                      this_event.message = WM_MOUSEMOVE; break; // It's a movement without a click.
  2471.         // In cases other than the above, it's a click or wheel turn with optional WM_MOUSEMOVE too.
  2472.         case MOUSEEVENTF_LEFTDOWN:   this_event.message = WM_LBUTTONDOWN; break;
  2473.         case MOUSEEVENTF_LEFTUP:     this_event.message = WM_LBUTTONUP; break;
  2474.         case MOUSEEVENTF_RIGHTDOWN:  this_event.message = WM_RBUTTONDOWN; break;
  2475.         case MOUSEEVENTF_RIGHTUP:    this_event.message = WM_RBUTTONUP; break;
  2476.         case MOUSEEVENTF_MIDDLEDOWN: this_event.message = WM_MBUTTONDOWN; break;
  2477.         case MOUSEEVENTF_MIDDLEUP:   this_event.message = WM_MBUTTONUP; break;
  2478.         case MOUSEEVENTF_XDOWN:      this_event.message = WM_XBUTTONDOWN; break;
  2479.         case MOUSEEVENTF_XUP:        this_event.message = WM_XBUTTONUP; break;
  2480.         case MOUSEEVENTF_WHEEL:      this_event.message = WM_MOUSEWHEEL; break;
  2481.         // WHEEL: No info comes into journal-record about which direction the wheel was turned (nor by how many
  2482.         // notches).  In addition, it appears impossible to specify such info when playing back the event.
  2483.         // Therefore, playback usually produces downward wheel movement (but upward in some apps like
  2484.         // Visual Studio).
  2485.         }
  2486.         // COORD_UNSPECIFIED_SHORT is used so that the very first event can be a click with unspecified
  2487.         // coordinates: it seems best to have the cursor's position fetched during playback rather than
  2488.         // here because if done here, there might be time for the cursor to move physically before
  2489.         // playback begins (especially if our thread is preempted while building the array).
  2490.         this_event.x = (aX == COORD_UNSPECIFIED) ? COORD_UNSPECIFIED_SHORT : (WORD)aX;
  2491.         this_event.y = (aY == COORD_UNSPECIFIED) ? COORD_UNSPECIFIED_SHORT : (WORD)aY;
  2492.         if (aEventFlags & MSG_OFFSET_MOUSE_MOVE) // Caller wants this event marked as a movement relative to cursor's current position.
  2493.             this_event.message |= MSG_OFFSET_MOUSE_MOVE;
  2494.     }
  2495.     ++sEventCount;
  2496. }
  2497.  
  2498.  
  2499.  
  2500. ResultType ExpandEventArray()
  2501. // Returns OK or FAIL.
  2502. {
  2503.     #define EVENT_EXPANSION_MULTIPLIER 2  // Should be very rare for array to need to expand more than a few times.
  2504.     size_t event_size = (sSendMode == SM_INPUT) ? sizeof(INPUT) : sizeof(PlaybackEvent);
  2505.     void *new_mem;
  2506.     // SendInput() appears to be limited to 5000 chars (10000 events in array), at least on XP.  This is
  2507.     // either an undocumented SendInput limit or perhaps it's due to the system setting that determines
  2508.     // how many messages can get backlogged in each thread's msg queue before some start to get dropped.
  2509.     // Note that SendInput()'s return value always seems to indicate that all the characters were sent
  2510.     // even when the ones beyond the limit were clearly never received by the target window.
  2511.     // In any case, it seems best not to restrict to 5000 here in case the limit can vary for any reason.
  2512.     // The 5000 limit is documented in the help file.
  2513.     if (   !(new_mem = malloc(EVENT_EXPANSION_MULTIPLIER * sMaxEvents * event_size))   )
  2514.         sAbortArraySend = true; // Usually better to send nothing rather than partial.
  2515.         // And continue on below to free the old block, if appropriate.
  2516.     else // Copy old array into new memory area (note that sEventSI and sEventPB are different views of the same variable).
  2517.         memcpy(new_mem, sEventSI, sEventCount * event_size);
  2518.     if (sMaxEvents > (sSendMode == SM_INPUT ? MAX_INITIAL_EVENTS_SI : MAX_INITIAL_EVENTS_PB))
  2519.         free(sEventSI); // Previous block was malloc'd vs. _alloc'd, so free it.
  2520.     if (sAbortArraySend)
  2521.         return FAIL;
  2522.     sEventSI = (LPINPUT)new_mem; // Note that sEventSI and sEventPB are different views of the same variable.
  2523.     sMaxEvents *= EVENT_EXPANSION_MULTIPLIER;
  2524.     return OK;
  2525. }
  2526.  
  2527.  
  2528.  
  2529. void InitEventArray(void *aMem, UINT aMaxEvents, modLR_type aModifiersLR)
  2530. {
  2531.     sEventPB = (PlaybackEvent *)aMem; // Sets sEventSI too, since both are the same.
  2532.     sMaxEvents = aMaxEvents;
  2533.     sEventModifiersLR = aModifiersLR;
  2534.     sSendInputCursorPos.x = COORD_UNSPECIFIED;
  2535.     sSendInputCursorPos.y = COORD_UNSPECIFIED;
  2536.     sHooksToRemoveDuringSendInput = 0;
  2537.     sEventCount = 0;
  2538.     sAbortArraySend = false; // If KeyEvent() ever sets it to true, that allows us to send nothing at all rather than a partial send.
  2539.     sFirstCallForThisEvent = true;
  2540.     // The above isn't a local static inside PlaybackProc because PlaybackProc might get aborted in the
  2541.     // middle of a NEXT/SKIP pair by user pressing Ctrl-Esc, etc, which would make it unreliable.
  2542. }
  2543.  
  2544.  
  2545.  
  2546. void SendEventArray(int &aFinalKeyDelay, modLR_type aModsDuringSend)
  2547. // Caller must avoid calling this function if sMySendInput is NULL.
  2548. // aFinalKeyDelay (which the caller should have initialized to -1 prior to calling) may be changed here
  2549. // to the desired/final delay.  Caller must not act upon it until changing sTypeOfHookToBuild to something
  2550. // that will allow DoKeyDelay() to do a real delay.
  2551. {
  2552.     if (sSendMode == SM_INPUT)
  2553.     {
  2554.         // Remove hook(s) temporarily because the presence of low-level (LL) keybd hook completely disables
  2555.         // the uninterruptibility of SendInput's keystrokes (but the mouse hook doesn't affect them).
  2556.         // The converse is also true.  This was tested via:
  2557.         //    #space::
  2558.         //    SendInput {Click 400, 400, 100}
  2559.         //    MsgBox
  2560.         //    ExitApp
  2561.         // ... and also with BurnK6 running, a CPU maxing utility.  The mouse clicks were sent directly to the
  2562.         // BurnK6 window, and were pretty slow, and also I could physically move the mouse cursor a little
  2563.         // between each of sendinput's mouse clicks.  But removing the mouse-hook during SendInputs solves all that.
  2564.         // Rather than removing both hooks unconditionally, it's better to
  2565.         // remove only those that actually have corresponding events in the array.  This avoids temporarily
  2566.         // losing visibility of physical key states (especially when the keyboard hook is removed).
  2567.         HookType active_hooks;
  2568.         if (active_hooks = GetActiveHooks())
  2569.             AddRemoveHooks(active_hooks & ~sHooksToRemoveDuringSendInput, true);
  2570.  
  2571.         // Caller has ensured that sMySendInput isn't NULL.
  2572.         sMySendInput(sEventCount, sEventSI, sizeof(INPUT)); // Must call dynamically-resolved version for Win95/NT compatibility.
  2573.         // The return value is ignored because it never seems to be anything other than sEventCount, even if
  2574.         // the Send seems to partially fail (e.g. due to hitting 5000 event maximum).
  2575.         // Typical speed of SendInput: 10ms or less for short sends (under 100 events).
  2576.         // Typically 30ms for 500 events; and typically no more than 200ms for 5000 events (which is
  2577.         // the apparent max).
  2578.         // Testing shows that when SendInput returns to its caller, all of its key states are in effect
  2579.         // even if the target window hasn't yet had time to receive them all.  For example, the
  2580.         // following reports that LShift is down:
  2581.         //   SendInput {a 4900}{LShift down}
  2582.         //   MsgBox % GetKeyState("LShift")
  2583.         // Furthermore, if the user manages to physically press or release a key during the call to
  2584.         // SendInput, testing shows that such events are in effect immediately when SendInput returns
  2585.         // to its caller, perhaps because SendInput clears out any backlog of physical keystrokes prior to
  2586.         // returning, or perhaps because the part of the OS that updates key states is a very high priority.
  2587.  
  2588.         if (active_hooks)
  2589.         {
  2590.             if (active_hooks & sHooksToRemoveDuringSendInput & HOOK_KEYBD) // Keyboard hook was actually removed during SendInput.
  2591.             {
  2592.                 // The above call to SendInput() has not only sent its own events, it has also emptied
  2593.                 // the buffer of any events generated outside but during the SendInput.  Since such
  2594.                 // events are almost always physical events rather than simulated ones, it seems to do
  2595.                 // more good than harm on average to consider any such changes to be physical.
  2596.                 // The g_PhysicalKeyState array is also updated by GetModifierLRState(true), but only
  2597.                 // for the modifier keys, not for all keys on the keyboard.  Even if adjust all keys
  2598.                 // is possible, it seems overly complex and it might impact performance more than it's
  2599.                 // worth given the rarity of the user changing physical key states during a SendInput
  2600.                 // and then wanting to explicitly retrieve that state via GetKeyState(Key, "P").
  2601.                 modLR_type mods_current = GetModifierLRState(true); // This also serves to correct the hook's logical modifiers, since hook was absent during the SendInput.
  2602.                 modLR_type mods_changed_physically_during_send = aModsDuringSend ^ mods_current;
  2603.                 g_modifiersLR_physical &= ~(mods_changed_physically_during_send & aModsDuringSend); // Remove those that changed from down to up.
  2604.                 g_modifiersLR_physical |= mods_changed_physically_during_send & mods_current; // Add those that changed from up to down.
  2605.                 g_HShwnd = GetForegroundWindow(); // An item done by ResetHook() that seems worthwhile here.
  2606.                 // Most other things done by ResetHook() seem like they would do more harm than good to reset here
  2607.                 // because of the the time the hook is typically missing is very short, usually under 30ms.
  2608.             }
  2609.             AddRemoveHooks(active_hooks, true); // Restore the hooks that were active before the SendInput.
  2610.         }
  2611.         return;
  2612.     }
  2613.  
  2614.     // Since above didn't return, sSendMode == SM_PLAY.
  2615.     // It seems best not to call IsWindowHung() here because:
  2616.     // 1) It might improve script reliability to allow playback to a hung window because even though
  2617.     //    the entire system would appear frozen, if the window becomes unhung, the keystrokes would
  2618.     //    eventually get sent to it as intended (and the script may be designed to rely on this).
  2619.     //    Furthermore, the user can press Ctrl-Alt-Del or Ctrl-Esc to unfreeze the system.
  2620.     // 2) It might hurt performance.
  2621.     //
  2622.     // During journal playback, it appears that LL hook receives events in realtime; its just that
  2623.     // keystrokes the hook passes through (or generates itself) don't actually hit the active window
  2624.     // until after the playback is done.  Preliminary testing shows that the hook's disguise of Alt/Win
  2625.     // still function properly for Win/Alt hotkeys that use the playback method.
  2626.     sCurrentEvent = 0; // Reset for use by the hook below.  Should be done BEFORE the hook is installed in the next line.
  2627. #ifdef JOURNAL_RECORD_MODE
  2628. // To record and analyze events via the above:
  2629. // - Uncomment the line that defines this in the header file.
  2630. // - Put breakpoint after the hook removes itself (a few lines below).  Don't try to put breakpoint in RECORD hook
  2631. //   itself because it tends to freeze keyboard input (must press Ctrl-Alt-Del or Ctrl-Esc to unfreeze).
  2632. // - Have the script send a keystroke (best to use non-character keystroke such as SendPlay {Shift}).
  2633. // - It is now recording, so press the desired keys.
  2634. // - Press Ctrl+Break, Ctrl-Esc, or Ctrl-Alt-Del to stop recording (which should then hit breakpoint below).
  2635. // - Study contents of the sEventPB array, which contains the keystrokes just recorded.
  2636.     sEventCount = 0; // Used by RecordProc().
  2637.     if (   !(g_PlaybackHook = SetWindowsHookEx(WH_JOURNALRECORD, RecordProc, g_hInstance, 0))   )
  2638.         return;
  2639. #else
  2640.     if (   !(g_PlaybackHook = SetWindowsHookEx(WH_JOURNALPLAYBACK, PlaybackProc, g_hInstance, 0))   )
  2641.         return;
  2642.     // During playback, have the keybd hook (if it's installed) block presses of the Windows key.
  2643.     // This is done because the Windows key is about the only key (other than Ctrl-Esc or Ctrl-Alt-Del)
  2644.     // that takes effect immediately rather than getting buffered/postponed until after the playback.
  2645.     // It should be okay to set this after the playback hook is installed because playback shouldn't
  2646.     // actually begin until we have our thread do its first MsgSleep later below.
  2647.     g_BlockWinKeys = true;
  2648. #endif
  2649.  
  2650.     // Otherwise, hook is installed, so:
  2651.     // Wait for the hook to remove itself because the script should not be allowed to continue
  2652.     // until the Send finishes.
  2653.     // GetMessage(single_msg_filter) can't be used because then our thread couldn't playback
  2654.     // keystrokes to one of its own windows.  In addition, testing shows that it wouldn't
  2655.     // measurably improve performance anyway.
  2656.     // Note: User can't activate tray icon with mouse (because mouse is blocked), so there's
  2657.     // no need to call our main event loop merely to have the tray menu responsive.
  2658.     // Sleeping for 0 performs at least 15% worse than INTERVAL_UNSPECIFIED. I think this is
  2659.     // because the journal playback hook can operate only when this thread is in a message-pumping
  2660.     // state, and message pumping is far more efficient with GetMessage than PeekMessage.
  2661.     // Also note that both registered and hook hotkeys are noticed/caught during journal playback
  2662.     // (confirmed through testing).  However, they are kept buffered until the Send finishes
  2663.     // because ACT_SEND and such are designed to be uninterruptible by other script threads;
  2664.     // also, it would be undesirable in almost any conceivable case.
  2665.     //
  2666.     // Use a loop rather than a single call to MsgSleep(WAIT_FOR_MESSAGES) because
  2667.     // WAIT_FOR_MESSAGES is designed only for use by WinMain().  The loop doesn't measurably
  2668.     // affect performance because there used to be the following here in place of the loop,
  2669.     // and it didn't perform any better:
  2670.     // GetMessage(&msg, NULL, WM_CANCELJOURNAL, WM_CANCELJOURNAL);
  2671.     while (g_PlaybackHook)
  2672.         SLEEP_WITHOUT_INTERRUPTION(INTERVAL_UNSPECIFIED); // For maintainability, macro is used rather than optimizing/splitting the code it contains.
  2673.     g_BlockWinKeys = false;
  2674.     // Either the hook unhooked itself or the OS did due to Ctrl-Esc or Ctrl-Alt-Del.
  2675.     // MSDN: When an application sees a [system-generated] WM_CANCELJOURNAL message, it can assume
  2676.     // two things: the user has intentionally cancelled the journal record or playback mode,
  2677.     // and the system has already unhooked any journal record or playback hook procedures.
  2678.     if (!sEventPB[sEventCount - 1].message) // Playback hook can't do the final delay, so we do it here.
  2679.         // Don't do delay right here because the delay would be put into the array instead.
  2680.         aFinalKeyDelay = sEventPB[sEventCount - 1].time_to_wait;
  2681.     // GetModifierLRState(true) is not done because keystrokes generated by the playback hook
  2682.     // aren't really keystrokes in the sense that they affect global key state or modifier state.
  2683.     // They affect only the keystate retrieved when the target thread calls GetKeyState()
  2684.     // (GetAsyncKeyState can never see such changes, even if called from the target thread).
  2685.     // Furthermore, the hook (if present) continues to operate during journal playback, so it
  2686.     // will keep its own modifiers up-to-date if any physical or simulate keystrokes happen to
  2687.     // come in during playback (such keystrokes arrive in the hook in real time, but they don't
  2688.     // actually hit the active window until the playback finishes.
  2689. }
  2690.  
  2691.  
  2692.  
  2693. void CleanupEventArray(int aFinalKeyDelay)
  2694. {
  2695.     if (sMaxEvents > (sSendMode == SM_INPUT ? MAX_INITIAL_EVENTS_SI : MAX_INITIAL_EVENTS_PB))
  2696.         free(sEventSI); // Previous block was malloc'd vs. _alloc'd, so free it.  Note that sEventSI and sEventPB are different views of the same variable.
  2697.     // The following must be done only after functions called above are done using it.  But it must also be done
  2698.     // prior to our caller toggling capslock back on , to avoid the capslock keystroke from going into the array.
  2699.     sSendMode = SM_EVENT;
  2700.     DoKeyDelay(aFinalKeyDelay); // Do this only after resetting sSendMode above.  Should be okay for mouse events too.
  2701. }
  2702.  
  2703.  
  2704.  
  2705. /////////////////////////////////
  2706.  
  2707.  
  2708. void DoKeyDelay(int aDelay)
  2709. // Doesn't need to be thread safe because it should only ever be called from main thread.
  2710. {
  2711.     if (aDelay < 0) // To support user-specified KeyDelay of -1 (fastest send rate).
  2712.         return;
  2713.     if (sSendMode)
  2714.     {
  2715.         if (sSendMode == SM_PLAY && aDelay > 0) // Zero itself isn't supported by playback hook, so no point in inserting such delays into the array.
  2716.             PutKeybdEventIntoArray(0, 0, 0, 0, aDelay); // Passing zero for vk and sc signals it that aExtraInfo contains the delay.
  2717.         //else for other types of arrays, never insert a delay or do one now.
  2718.         return;
  2719.     }
  2720.     if (g_os.IsWin9x())
  2721.     {
  2722.         // Do a true sleep on Win9x because the MsgSleep() method is very inaccurate on Win9x
  2723.         // for some reason (a MsgSleep(1) causes a sleep between 10 and 55ms, for example):
  2724.         Sleep(aDelay);
  2725.         return;
  2726.     }
  2727.     SLEEP_WITHOUT_INTERRUPTION(aDelay);
  2728. }
  2729.  
  2730.  
  2731.  
  2732. void DoMouseDelay() // Helper function for the mouse functions below.
  2733. {
  2734.     int mouse_delay = sSendMode == SM_PLAY ? g.MouseDelayPlay : g.MouseDelay;
  2735.     if (mouse_delay < 0) // To support user-specified KeyDelay of -1 (fastest send rate).
  2736.         return;
  2737.     if (sSendMode)
  2738.     {
  2739.         if (sSendMode == SM_PLAY && mouse_delay > 0) // Zero itself isn't supported by playback hook, so no point in inserting such delays into the array.
  2740.             PutKeybdEventIntoArray(0, 0, 0, 0, mouse_delay); // Passing zero for vk and sc signals it that aExtraInfo contains the delay.
  2741.         //else for other types of arrays, never insert a delay or do one now (caller should have already
  2742.         // checked that, so it's written this way here only for maintainability).
  2743.         return;
  2744.     }
  2745.     // I believe the varying sleep methods below were put in place to avoid issues when simulating
  2746.     // clicks on the script's own windows.  There are extensive comments in MouseClick() and the
  2747.     // hook about these issues.  Also, Sleep() is more accurate on Win9x than MsgSleep, which is
  2748.     // why it's used in that case.  Here are more details from an older comment:
  2749.     // Always sleep a certain minimum amount of time between events to improve reliability,
  2750.     // but allow the user to specify a higher time if desired.  Note that for Win9x,
  2751.     // a true Sleep() is done because it is much more accurate than the MsgSleep() method,
  2752.     // at least on Win98SE when short sleeps are done.  UPDATE: A true sleep is now done
  2753.     // unconditionally if the delay period is small.  This fixes a small issue where if
  2754.     // LButton is a hotkey that includes "MouseClick left" somewhere in its subroutine,
  2755.     // the script's own main window's title bar buttons for min/max/close would not
  2756.     // properly respond to left-clicks.  By contrast, the following is no longer an issue
  2757.     // due to the dedicated thread in v1.0.39 (or more likely, due to an older change that
  2758.     // causes the tray menu to upon upon RButton-up rather than down):
  2759.     // RButton is a hotkey that includes "MouseClick right" somewhere in its subroutine,
  2760.     // the user would not be able to correctly open the script's own tray menu via
  2761.     // right-click (note that this issue affected only the one script itself, not others).
  2762.     if (mouse_delay < 11 || (mouse_delay < 25 && g_os.IsWin9x()))
  2763.         Sleep(mouse_delay);
  2764.     else
  2765.         SLEEP_WITHOUT_INTERRUPTION(mouse_delay)
  2766. }
  2767.  
  2768.  
  2769.  
  2770. void UpdateKeyEventHistory(bool aKeyUp, vk_type aVK, sc_type aSC)
  2771. {
  2772.     if (!g_KeyHistory) // Don't access the array if it doesn't exist (i.e. key history is disabled).
  2773.         return;
  2774.     g_KeyHistory[g_KeyHistoryNext].key_up = aKeyUp;
  2775.     g_KeyHistory[g_KeyHistoryNext].vk = aVK;
  2776.     g_KeyHistory[g_KeyHistoryNext].sc = aSC;
  2777.     g_KeyHistory[g_KeyHistoryNext].event_type = 'i'; // Callers all want this.
  2778.     g_HistoryTickNow = GetTickCount();
  2779.     g_KeyHistory[g_KeyHistoryNext].elapsed_time = (g_HistoryTickNow - g_HistoryTickPrev) / (float)1000;
  2780.     g_HistoryTickPrev = g_HistoryTickNow;
  2781.     HWND fore_win = GetForegroundWindow();
  2782.     if (fore_win)
  2783.     {
  2784.         if (fore_win != g_HistoryHwndPrev)
  2785.             GetWindowText(fore_win, g_KeyHistory[g_KeyHistoryNext].target_window, sizeof(g_KeyHistory[g_KeyHistoryNext].target_window));
  2786.         else // i.e. avoid the call to GetWindowText() if possible.
  2787.             *g_KeyHistory[g_KeyHistoryNext].target_window = '\0';
  2788.     }
  2789.     else
  2790.         strcpy(g_KeyHistory[g_KeyHistoryNext].target_window, "N/A");
  2791.     g_HistoryHwndPrev = fore_win; // Update unconditionally in case it's NULL.
  2792.     if (++g_KeyHistoryNext >= g_MaxHistoryKeys)
  2793.         g_KeyHistoryNext = 0;
  2794. }
  2795.  
  2796.  
  2797.  
  2798. ToggleValueType ToggleKeyState(vk_type aVK, ToggleValueType aToggleValue)
  2799. // Toggle the given aVK into another state.  For performance, it is the caller's responsibility to
  2800. // ensure that aVK is a toggleable key such as capslock, numlock, or scrolllock.
  2801. // Returns the state the key was in before it was changed (but it's only a best-guess under Win9x).
  2802. {
  2803.     // Can't use GetAsyncKeyState() because it doesn't have this info:
  2804.     ToggleValueType starting_state = IsKeyToggledOn(aVK) ? TOGGLED_ON : TOGGLED_OFF;
  2805.     if (aToggleValue != TOGGLED_ON && aToggleValue != TOGGLED_OFF) // Shouldn't be called this way.
  2806.         return starting_state;
  2807.     if (starting_state == aToggleValue) // It's already in the desired state, so just return the state.
  2808.         return starting_state;
  2809.     if (aVK == VK_NUMLOCK)
  2810.     {
  2811.         if (g_os.IsWin9x())
  2812.         {
  2813.             // For Win9x, we want to set the state unconditionally to be sure it's right.  This is because
  2814.             // the retrieval of the Capslock state, for example, is unreliable, at least under Win98se
  2815.             // (probably due to lack of an AttachThreadInput() having been done).  Although the
  2816.             // SetKeyboardState() method used by ToggleNumlockWin9x is not required for caps & scroll lock keys,
  2817.             // it is required for Numlock:
  2818.             ToggleNumlockWin9x();
  2819.             return starting_state;  // Best guess, but might be wrong.
  2820.         }
  2821.         // Otherwise, NT/2k/XP:
  2822.         // Sending an extra up-event first seems to prevent the problem where the Numlock
  2823.         // key's indicator light doesn't change to reflect its true state (and maybe its
  2824.         // true state doesn't change either).  This problem tends to happen when the key
  2825.         // is pressed while the hook is forcing it to be either ON or OFF (or it suppresses
  2826.         // it because it's a hotkey).  Needs more testing on diff. keyboards & OSes:
  2827.         KeyEvent(KEYUP, aVK);
  2828.     }
  2829.     // Since it's not already in the desired state, toggle it:
  2830.     KeyEvent(KEYDOWNANDUP, aVK);
  2831.     // Fix for v1.0.40: IsKeyToggledOn()'s call to GetKeyState() relies on our thread having
  2832.     // processed messages.  Confirmed necessary 100% of the time if our thread owns the active window.
  2833.     // v1.0.43: Extended the above fix to include all toggleable keys (not just Capslock) and to apply
  2834.     // to both directions (ON and OFF) since it seems likely to be needed for them all.
  2835.     bool our_thread_is_foreground;
  2836.     if (our_thread_is_foreground = (GetWindowThreadProcessId(GetForegroundWindow(), NULL) == g_MainThreadID)) // GetWindowThreadProcessId() tolerates a NULL hwnd.
  2837.         SLEEP_WITHOUT_INTERRUPTION(-1);
  2838.     if (aVK == VK_CAPITAL && aToggleValue == TOGGLED_OFF && IsKeyToggledOn(aVK))
  2839.     {
  2840.         // Fix for v1.0.36.06: Since it's Capslock and it didn't turn off as attempted, it's probably because
  2841.         // the OS is configured to turn Capslock off only in response to pressing the SHIFT key (via Ctrl Panel's
  2842.         // Regional settings).  So send shift to do it instead:
  2843.          KeyEvent(KEYDOWNANDUP, VK_SHIFT);
  2844.         if (our_thread_is_foreground) // v1.0.43: Added to try to achieve 100% reliability in all situations.
  2845.             SLEEP_WITHOUT_INTERRUPTION(-1); // Check msg queue to put SHIFT's turning off of Capslock into effect from our thread's POV.
  2846.     }
  2847.     return starting_state;
  2848. }
  2849.  
  2850.  
  2851.  
  2852. void ToggleNumlockWin9x()
  2853. // Numlock requires a special method to toggle the state and its indicator light under Win9x.
  2854. // Capslock and Scrolllock do not need this method, since keybd_event() works for them.
  2855. {
  2856.     BYTE state[256];
  2857.     GetKeyboardState((PBYTE)&state);
  2858.     state[VK_NUMLOCK] ^= 0x01;  // Toggle the low-order bit to the opposite state.
  2859.     SetKeyboardState((PBYTE)&state);
  2860. }
  2861.  
  2862.  
  2863.  
  2864. //void CapslockOffWin9x()
  2865. //{
  2866. //    BYTE state[256];
  2867. //    GetKeyboardState((PBYTE)&state);
  2868. //    state[VK_CAPITAL] &= ~0x01;
  2869. //    SetKeyboardState((PBYTE)&state);
  2870. //}
  2871.  
  2872.  
  2873.  
  2874. /*
  2875. void SetKeyState (vk_type vk, int aKeyUp)
  2876. // Later need to adapt this to support Win9x by using SetKeyboardState for those OSs.
  2877. {
  2878.     if (!vk) return;
  2879.     int key_already_up = !(GetKeyState(vk) & 0x8000);
  2880.     if ((key_already_up && aKeyUp) || (!key_already_up && !aKeyUp))
  2881.         return;
  2882.     KeyEvent(aKeyUp, vk);
  2883. }
  2884. */
  2885.  
  2886.  
  2887.  
  2888. void SetModifierLRState(modLR_type aModifiersLRnew, modLR_type aModifiersLRnow, HWND aTargetWindow
  2889.     , bool aDisguiseDownWinAlt, bool aDisguiseUpWinAlt, DWORD aExtraInfo)
  2890. // This function is designed to be called from only the main thread; it's probably not thread-safe.
  2891. // Puts modifiers into the specified state, releasing or pressing down keys as needed.
  2892. // The modifiers are released and pressed down in a very delicate order due to their interactions with
  2893. // each other and their ability to show the Start Menu, activate the menu bar, or trigger the OS's language
  2894. // bar hotkeys.  Side-effects like these would occur if a more simple approach were used, such as releasing
  2895. // all modifiers that are going up prior to pushing down the ones that are going down.
  2896. // When the target layout has an altgr key, it is tempting to try to simplify things by removing MOD_LCONTROL
  2897. // from aModifiersLRnew whenever aModifiersLRnew contains MOD_RALT.  However, this a careful review how that
  2898. // would impact various places below where sTargetLayoutHasAltGr is checked indicates that it wouldn't help.
  2899. // Note that by design and as documented for ControlSend, aTargetWindow is not used as the target for the
  2900. // various calls to KeyEvent() here.  It is only used as a workaround for the GUI window issue described
  2901. // at the bottom.
  2902. {
  2903.     if (aModifiersLRnow == aModifiersLRnew) // They're already in the right state, so avoid doing all the checks.
  2904.         return; // Especially avoids the aTargetWindow check at the bottom.
  2905.  
  2906.     // Notes about modifier key behavior on Windows XP (these probably apply to NT/2k also, and has also
  2907.     // been tested to be true on Win98): The WIN and ALT keys are the problem keys, because if either is
  2908.     // released without having modified something (even another modifier), the WIN key will cause the
  2909.     // Start Menu to appear, and the ALT key will activate the menu bar of the active window (if it has one).
  2910.     // For example, a hook hotkey such as "$#c::Send text" (text must start with a lowercase letter
  2911.     // to reproduce the issue, because otherwise WIN would be auto-disguised as a side effect of the SHIFT
  2912.     // keystroke) would cause the Start Menu to appear if the disguise method below weren't used.
  2913.     //
  2914.     // Here are more comments formerly in SetModifierLRStateSpecific(), which has since been eliminated
  2915.     // because this function is sufficient:
  2916.     // To prevent it from activating the menu bar, the release of the ALT key should be disguised
  2917.     // unless a CTRL key is currently down.  This is because CTRL always seems to avoid the
  2918.     // activation of the menu bar (unlike SHIFT, which sometimes allows the menu to be activated,
  2919.     // though this is hard to reproduce on XP).  Another reason not to use SHIFT is that the OS
  2920.     // uses LAlt+Shift as a hotkey to switch languages.  Such a hotkey would be triggered if SHIFT
  2921.     // were pressed down to disguise the release of LALT.
  2922.     //
  2923.     // Alt-down events are also disguised whenever they won't be accompanied by a Ctrl-down.
  2924.     // This is necessary whenever our caller does not plan to disguise the key itself.  For example,
  2925.     // if "!a::Send Test" is a registered hotkey, two things must be done to avoid complications:
  2926.     // 1) Prior to sending the word test, ALT must be released in a way that does not activate the
  2927.     //    menu bar.  This is done by sandwiching it between a CTRL-down and a CTRL-up.
  2928.     // 2) After the send is complete, SendKeys() will restore the ALT key to the down position if
  2929.     //    the user is still physically holding ALT down (this is done to make the logical state of
  2930.     //    the key match its physical state, which allows the same hotkey to be fired twice in a row
  2931.     //    without the user having to release and press down the ALT key physically).
  2932.     // The #2 case above is the one handled below by ctrl_wont_be_down.  It is especially necessary
  2933.     // when the user releases the ALT key prior to releasing the hotkey suffix, which would otherwise
  2934.     // cause the menu bar (if any) of the active window to be activated.
  2935.     //
  2936.     // Some of the same comments above for ALT key apply to the WIN key.  More about this issue:
  2937.     // Although the disguise of the down-event is usually not needed, it is needed in the rare case
  2938.     // where the user releases the WIN or ALT key prior to releasing the hotkey's suffix.
  2939.     // Although the hook could be told to disguise the physical release of ALT or WIN in these
  2940.     // cases, it's best not to rely on the hook since it is not always installed.
  2941.     //
  2942.     // Registered WIN and ALT hotkeys that don't use the Send command work okay except ALT hotkeys,
  2943.     // which if the user releases ALT prior the hotkey's suffix key, cause the menu bar to be activated.
  2944.     // Since it is unusual for users to do this and because it is standard behavior for  ALT hotkeys
  2945.     // registered in the OS, fixing it via the hook seems like a low priority, and perhaps isn't worth
  2946.     // the added code complexity/size.  But if there is ever a need to do so, the following note applies:
  2947.     // If the hook is installed, could tell it to disguise any need-to-be-disguised Alt-up that occurs
  2948.     // after receipt of the registered ALT hotkey.  But what if that hotkey uses the send command:
  2949.     // there might be intereference?  Doesn't seem so, because the hook only disguises non-ignored events.
  2950.  
  2951.     // Set up some conditions so that the keystrokes that disguise the release of Win or Alt
  2952.     // are only sent when necessary (which helps avoid complications caused by keystroke interaction,
  2953.     // while improving performance):
  2954.     modLR_type aModifiersLRunion = aModifiersLRnow | aModifiersLRnew; // The set of keys that were or will be down.
  2955.     bool ctrl_not_down = !(aModifiersLRnow & (MOD_LCONTROL | MOD_RCONTROL)); // Neither CTRL key is down now.
  2956.     bool ctrl_will_not_be_down = !(aModifiersLRnew & (MOD_LCONTROL | MOD_RCONTROL)) // Nor will it be.
  2957.         && !(sTargetLayoutHasAltGr == CONDITION_TRUE && (aModifiersLRnew & MOD_RALT)); // Nor will it be pushed down indirectly due to AltGr.
  2958.  
  2959.     bool ctrl_nor_shift_nor_alt_down = ctrl_not_down                             // Neither CTRL key is down now.
  2960.         && !(aModifiersLRnow & (MOD_LSHIFT | MOD_RSHIFT | MOD_LALT | MOD_RALT)); // Nor is any SHIFT/ALT key.
  2961.  
  2962.     bool ctrl_or_shift_or_alt_will_be_down = !ctrl_will_not_be_down             // CTRL will be down.
  2963.         || (aModifiersLRnew & (MOD_LSHIFT | MOD_RSHIFT | MOD_LALT | MOD_RALT)); // or SHIFT or ALT will be.
  2964.  
  2965.     // If the required disguise keys aren't down now but will be, defer the release of Win and/or Alt
  2966.     // until after the disguise keys are in place (since in that case, the caller wanted them down
  2967.     // as part of the normal operation here):
  2968.     bool defer_win_release = ctrl_nor_shift_nor_alt_down && ctrl_or_shift_or_alt_will_be_down;
  2969.     bool defer_alt_release = ctrl_not_down && !ctrl_will_not_be_down;  // i.e. Ctrl not down but it will be.
  2970.     bool release_shift_before_alt_ctrl = defer_alt_release // i.e. Control is moving into the down position or...
  2971.         || !(aModifiersLRnow & (MOD_LALT | MOD_RALT)) && (aModifiersLRnew & (MOD_LALT | MOD_RALT)); // ...Alt is moving into the down position.
  2972.     // Concerning "release_shift_before_alt_ctrl" above: Its purpose is to prevent unwanted firing of the OS's
  2973.     // language bar hotkey.  See the bottom of this function for more explanation.
  2974.  
  2975.     // ALT:
  2976.     bool disguise_alt_down = aDisguiseDownWinAlt && ctrl_not_down && ctrl_will_not_be_down; // Since this applies to both Left and Right Alt, don't take sTargetLayoutHasAltGr into account here. That is done later below.
  2977.  
  2978.     // WIN: The WIN key is successfully disguised under a greater number of conditions than ALT.
  2979.     // Since SendPlay can't display Start Menu, there's no need to send the disguise-keystrokes (such
  2980.     // keystrokes might cause unwanted effects in certain games):
  2981.     bool disguise_win_down = aDisguiseDownWinAlt && sSendMode != SM_PLAY
  2982.         && ctrl_not_down && ctrl_will_not_be_down
  2983.         && !(aModifiersLRunion & (MOD_LSHIFT | MOD_RSHIFT)) // And neither SHIFT key is down, nor will it be.
  2984.         && !(aModifiersLRunion & (MOD_LALT | MOD_RALT));    // And neither ALT key is down, nor will it be.
  2985.  
  2986.     bool release_lwin = (aModifiersLRnow & MOD_LWIN) && !(aModifiersLRnew & MOD_LWIN);
  2987.     bool release_rwin = (aModifiersLRnow & MOD_RWIN) && !(aModifiersLRnew & MOD_RWIN);
  2988.     bool release_lalt = (aModifiersLRnow & MOD_LALT) && !(aModifiersLRnew & MOD_LALT);
  2989.     bool release_ralt = (aModifiersLRnow & MOD_RALT) && !(aModifiersLRnew & MOD_RALT);
  2990.     bool release_lshift = (aModifiersLRnow & MOD_LSHIFT) && !(aModifiersLRnew & MOD_LSHIFT);
  2991.     bool release_rshift = (aModifiersLRnow & MOD_RSHIFT) && !(aModifiersLRnew & MOD_RSHIFT);
  2992.  
  2993.     // Handle ALT and WIN prior to the other modifiers because the "disguise" methods below are
  2994.     // only needed upon release of ALT or WIN.  This is because such releases tend to have a better
  2995.     // chance of being "disguised" if SHIFT or CTRL is down at the time of the release.  Thus, the
  2996.     // release of SHIFT or CTRL (if called for) is deferred until afterward.
  2997.  
  2998.     // ** WIN
  2999.     // Must be done before ALT in case it is relying on ALT being down to disguise the release WIN.
  3000.     // If ALT is going to be pushed down further below, defer_win_release should be true, which will make sure
  3001.     // the WIN key isn't released until after the ALT key is pushed down here at the top.
  3002.     // Also, WIN is a little more troublesome than ALT, so it is done first in case the ALT key
  3003.     // is down but will be going up, since the ALT key being down might help the WIN key.
  3004.     // For example, if you hold down CTRL, then hold down LWIN long enough for it to auto-repeat,
  3005.     // then release CTRL before releasing LWIN, the Start Menu would appear, at least on XP.
  3006.     // But it does not appear if CTRL is released after LWIN.
  3007.     // Also note that the ALT key can disguise the WIN key, but not vice versa.
  3008.     if (release_lwin)
  3009.     {
  3010.         if (!defer_win_release)
  3011.         {
  3012.             // Fixed for v1.0.25: To avoid triggering the system's LAlt+Shift language hotkey, the
  3013.             // Control key is now used to suppress LWIN/RWIN (preventing the Start Menu from appearing)
  3014.             // rather than the Shift key.  This is definitely needed for ALT, but is done here for
  3015.             // WIN also in case ALT is down, which might cause the use of SHIFT as the disguise key
  3016.             // to trigger the language switch.
  3017.             if (ctrl_nor_shift_nor_alt_down && aDisguiseUpWinAlt // Nor will they be pushed down later below, otherwise defer_win_release would have been true and we couldn't get to this point.
  3018.                 && sSendMode != SM_PLAY) // SendPlay can't display Start Menu, so disguise not needed (also, disguise might mess up some games).
  3019.                 KeyEvent(KEYDOWNANDUP, VK_CONTROL, 0, NULL, false, aExtraInfo); // Disguise key release to suppress Start Menu.
  3020.                 // The above event is safe because if we're here, it means VK_CONTROL will not be
  3021.                 // pressed down further below.  In other words, we're not defeating the job
  3022.                 // of this function by sending these disguise keystrokes.
  3023.             KeyEvent(KEYUP, VK_LWIN, 0, NULL, false, aExtraInfo);
  3024.         }
  3025.         // else release it only after the normal operation of the function pushes down the disguise keys.
  3026.     }
  3027.     else if (!(aModifiersLRnow & MOD_LWIN) && (aModifiersLRnew & MOD_LWIN)) // Press down LWin.
  3028.     {
  3029.         if (disguise_win_down)
  3030.             KeyEvent(KEYDOWN, VK_CONTROL, 0, NULL, false, aExtraInfo); // Ensures that the Start Menu does not appear.
  3031.         KeyEvent(KEYDOWN, VK_LWIN, 0, NULL, false, aExtraInfo);
  3032.         if (disguise_win_down)
  3033.             KeyEvent(KEYUP, VK_CONTROL, 0, NULL, false, aExtraInfo); // Ensures that the Start Menu does not appear.
  3034.     }
  3035.  
  3036.     if (release_rwin)
  3037.     {
  3038.         if (!defer_win_release)
  3039.         {
  3040.             if (ctrl_nor_shift_nor_alt_down && MOD_RWIN && sSendMode != SM_PLAY)
  3041.                 KeyEvent(KEYDOWNANDUP, VK_CONTROL, 0, NULL, false, aExtraInfo); // Disguise key release to suppress Start Menu.
  3042.             KeyEvent(KEYUP, VK_RWIN, 0, NULL, false, aExtraInfo);
  3043.         }
  3044.         // else release it only after the normal operation of the function pushes down the disguise keys.
  3045.     }
  3046.     else if (!(aModifiersLRnow & MOD_RWIN) && (aModifiersLRnew & MOD_RWIN)) // Press down RWin.
  3047.     {
  3048.         if (disguise_win_down)
  3049.             KeyEvent(KEYDOWN, VK_CONTROL, 0, NULL, false, aExtraInfo); // Ensures that the Start Menu does not appear.
  3050.         KeyEvent(KEYDOWN, VK_RWIN, 0, NULL, false, aExtraInfo);
  3051.         if (disguise_win_down)
  3052.             KeyEvent(KEYUP, VK_CONTROL, 0, NULL, false, aExtraInfo); // Ensures that the Start Menu does not appear.
  3053.     }
  3054.  
  3055.     // ** SHIFT (PART 1 OF 2)
  3056.     if (release_shift_before_alt_ctrl)
  3057.     {
  3058.         if (release_lshift)
  3059.             KeyEvent(KEYUP, VK_LSHIFT, 0, NULL, false, aExtraInfo);
  3060.         if (release_rshift)
  3061.             KeyEvent(KEYUP, VK_RSHIFT, 0, NULL, false, aExtraInfo);
  3062.     }
  3063.  
  3064.     // ** ALT
  3065.     if (release_lalt)
  3066.     {
  3067.         if (!defer_alt_release)
  3068.         {
  3069.             if (ctrl_not_down && aDisguiseUpWinAlt)
  3070.                 KeyEvent(KEYDOWNANDUP, VK_CONTROL, 0, NULL, false, aExtraInfo); // Disguise key release to suppress menu activation.
  3071.             KeyEvent(KEYUP, VK_LMENU, 0, NULL, false, aExtraInfo);
  3072.         }
  3073.     }
  3074.     else if (!(aModifiersLRnow & MOD_LALT) && (aModifiersLRnew & MOD_LALT))
  3075.     {
  3076.         if (disguise_alt_down)
  3077.             KeyEvent(KEYDOWN, VK_CONTROL, 0, NULL, false, aExtraInfo); // Ensures that menu bar is not activated.
  3078.         KeyEvent(KEYDOWN, VK_LMENU, 0, NULL, false, aExtraInfo);
  3079.         if (disguise_alt_down)
  3080.             KeyEvent(KEYUP, VK_CONTROL, 0, NULL, false, aExtraInfo);
  3081.     }
  3082.  
  3083.     if (release_ralt)
  3084.     {
  3085.         if (!defer_alt_release || sTargetLayoutHasAltGr == CONDITION_TRUE) // No need to defer if RAlt==AltGr. But don't change the value of defer_alt_release because LAlt uses it too.
  3086.         {
  3087.             if (sTargetLayoutHasAltGr == CONDITION_TRUE)
  3088.             {
  3089.                 // Indicate that control is up now, since the release of AltGr will cause that indirectly.
  3090.                 // Fix for v1.0.43: Unlike the pressing down of AltGr in a later section, which callers want
  3091.                 // to automatically press down LControl too (by the very nature of AltGr), callers do not want
  3092.                 // the release of AltGr to release LControl unless they specifically asked for LControl to be
  3093.                 // released too.  This is because the caller may need LControl down to manifest something
  3094.                 // like ^c. So don't do: aModifiersLRnew &= ~MOD_LCONTROL.
  3095.                 // Without this fix, a hotkey like <^>!m::Send ^c would send "c" vs. "^c" on the German layout.
  3096.                 // See similar section below for more details.
  3097.                 aModifiersLRnow &= ~MOD_LCONTROL; // To reflect what KeyEvent(KEYUP, VK_RMENU) below will do.
  3098.             }
  3099.             else // No AltGr, so check if disguise is necessary (AltGr itself never needs disguise).
  3100.                 if (ctrl_not_down && aDisguiseUpWinAlt)
  3101.                     KeyEvent(KEYDOWNANDUP, VK_CONTROL, 0, NULL, false, aExtraInfo); // Disguise key release to suppress menu activation.
  3102.             KeyEvent(KEYUP, VK_RMENU, 0, NULL, false, aExtraInfo);
  3103.         }
  3104.     }
  3105.     else if (!(aModifiersLRnow & MOD_RALT) && (aModifiersLRnew & MOD_RALT)) // Press down RALT.
  3106.     {
  3107.         // For the below: There should never be a need to disguise AltGr.  Doing so would likely cause unwanted
  3108.         // side-effects. Also, disguise_alt_key does not take sTargetLayoutHasAltGr into account because
  3109.         // disguise_alt_key also applies to the left alt key.
  3110.         if (disguise_alt_down && sTargetLayoutHasAltGr != CONDITION_TRUE)
  3111.         {
  3112.             KeyEvent(KEYDOWN, VK_CONTROL, 0, NULL, false, aExtraInfo); // Ensures that menu bar is not activated.
  3113.             KeyEvent(KEYDOWN, VK_RMENU, 0, NULL, false, aExtraInfo);
  3114.             KeyEvent(KEYUP, VK_CONTROL, 0, NULL, false, aExtraInfo);
  3115.         }
  3116.         else // No disguise needed.
  3117.         {
  3118.             // v1.0.43: The following check was added to complement the other .43 fix higher above.
  3119.             // It may also fix other things independently of that other fix.
  3120.             // The following two lines release LControl before pushing down AltGr because otherwise,
  3121.             // the next time RAlt is released (such as by the user), some quirk of the OS or driver
  3122.             // prevents it from automatically releasing LControl like it normally does (perhaps
  3123.             // because the OS is designed to leave LControl down if it was down before AltGr went down).
  3124.             // This would cause LControl to get stuck down for hotkeys in German layout such as:
  3125.             //   <^>!a::SendRaw, {
  3126.             //   <^>!m::Send ^c
  3127.             if (sTargetLayoutHasAltGr == CONDITION_TRUE && (aModifiersLRnow & MOD_LCONTROL))
  3128.                 KeyEvent(KEYUP, VK_LCONTROL, 0, NULL, false, aExtraInfo);
  3129.             KeyEvent(KEYDOWN, VK_RMENU, 0, NULL, false, aExtraInfo);
  3130.             if (sTargetLayoutHasAltGr == CONDITION_TRUE) // Note that KeyEvent() might have just changed the value of sTargetLayoutHasAltGr.
  3131.             {
  3132.                 // Indicate that control is both down and required down so that the section after this one won't
  3133.                 // release it.  Without this fix, a hotkey that sends an AltGr char such as "^Σ:: SendRaw, {"
  3134.                 // would fail to work under German layout because left-alt would be released after right-alt
  3135.                 // goes down.
  3136.                 aModifiersLRnow |= MOD_LCONTROL; // To reflect what KeyEvent() did above.
  3137.                 aModifiersLRnew |= MOD_LCONTROL; // All callers want LControl to be down if they wanted AltGr to be down.
  3138.             }
  3139.         }
  3140.     }
  3141.  
  3142.     // CONTROL and SHIFT are done only after the above because the above might rely on them
  3143.     // being down before for certain early operations.
  3144.  
  3145.     // ** CONTROL
  3146.     if (   (aModifiersLRnow & MOD_LCONTROL) && !(aModifiersLRnew & MOD_LCONTROL) // Release LControl.
  3147.         // v1.0.41.01: The following line was added to fix the fact that callers do not want LControl
  3148.         // released when the new modifier state includes AltGr.  This solves a hotkey such as the following and
  3149.         // probably several other circumstances:
  3150.         // <^>!a::send \  ; Backslash is solved by this fix; it's manifest via AltGr+Dash on German layout.
  3151.         && !((aModifiersLRnew & MOD_RALT) && sTargetLayoutHasAltGr == CONDITION_TRUE)   )
  3152.         KeyEvent(KEYUP, VK_LCONTROL, 0, NULL, false, aExtraInfo);
  3153.     else if (!(aModifiersLRnow & MOD_LCONTROL) && (aModifiersLRnew & MOD_LCONTROL)) // Press down LControl.
  3154.         KeyEvent(KEYDOWN, VK_LCONTROL, 0, NULL, false, aExtraInfo);
  3155.     if ((aModifiersLRnow & MOD_RCONTROL) && !(aModifiersLRnew & MOD_RCONTROL)) // Release RControl
  3156.         KeyEvent(KEYUP, VK_RCONTROL, 0, NULL, false, aExtraInfo);
  3157.     else if (!(aModifiersLRnow & MOD_RCONTROL) && (aModifiersLRnew & MOD_RCONTROL)) // Press down RControl.
  3158.         KeyEvent(KEYDOWN, VK_RCONTROL, 0, NULL, false, aExtraInfo);
  3159.     
  3160.     // ** SHIFT (PART 2 OF 2)
  3161.     // Must follow CTRL and ALT because a release of SHIFT while ALT/CTRL is down-but-soon-to-be-up
  3162.     // would switch languages via the OS hotkey.  It's okay if defer_alt_release==true because in that case,
  3163.     // CTRL just went down above (by definition of defer_alt_release), which will prevent the language hotkey
  3164.     // from firing.
  3165.     if (release_lshift && !release_shift_before_alt_ctrl) // Release LShift.
  3166.         KeyEvent(KEYUP, VK_LSHIFT, 0, NULL, false, aExtraInfo);
  3167.     else if (!(aModifiersLRnow & MOD_LSHIFT) && (aModifiersLRnew & MOD_LSHIFT)) // Press down LShift.
  3168.         KeyEvent(KEYDOWN, VK_LSHIFT, 0, NULL, false, aExtraInfo);
  3169.     if (release_rshift && !release_shift_before_alt_ctrl) // Release RShift.
  3170.         KeyEvent(KEYUP, VK_RSHIFT, 0, NULL, false, aExtraInfo);
  3171.     else if (!(aModifiersLRnow & MOD_RSHIFT) && (aModifiersLRnew & MOD_RSHIFT)) // Press down RShift.
  3172.         KeyEvent(KEYDOWN, VK_RSHIFT, 0, NULL, false, aExtraInfo);
  3173.  
  3174.     // ** KEYS DEFERRED FROM EARLIER
  3175.     if (defer_win_release) // Must be done before ALT because it might rely on ALT being down to disguise release of WIN key.
  3176.     {
  3177.         if (release_lwin)
  3178.             KeyEvent(KEYUP, VK_LWIN, 0, NULL, false, aExtraInfo);
  3179.         if (release_rwin)
  3180.             KeyEvent(KEYUP, VK_RWIN, 0, NULL, false, aExtraInfo);
  3181.     }
  3182.     if (defer_alt_release)
  3183.     {
  3184.         if (release_lalt)
  3185.             KeyEvent(KEYUP, VK_LMENU, 0, NULL, false, aExtraInfo);
  3186.         if (release_ralt && sTargetLayoutHasAltGr != CONDITION_TRUE) // If AltGr is present, RAlt would already have been released earlier since defer_alt_release would have been ignored for it.
  3187.             KeyEvent(KEYUP, VK_RMENU, 0, NULL, false, aExtraInfo);
  3188.     }
  3189.  
  3190.     // When calling KeyEvent(), probably best not to specify a scan code unless
  3191.     // absolutely necessary, since some keyboards may have non-standard scan codes
  3192.     // which KeyEvent() will resolve into the proper vk tranlations for us.
  3193.     // Decided not to Sleep() between keystrokes, even zero, out of concern that this
  3194.     // would result in a significant delay (perhaps more than 10ms) while the system
  3195.     // is under load.
  3196.  
  3197.     // Since the above didn't return early, keybd_event() has been used to change the state
  3198.     // of at least one modifier.  As a result, if the caller gave a non-NULL aTargetWindow,
  3199.     // it wants us to check if that window belongs to our thread.  If it does, we should do
  3200.     // a short msg queue check to prevent an apparent synchronization problem when using
  3201.     // ControlSend against the script's own GUI or other windows.  Here is an example of a
  3202.     // line whose modifier would not be in effect in time for its keystroke to be modified
  3203.     // by it:
  3204.     // ControlSend, Edit1, ^{end}, Test Window
  3205.     // Update: Another bug-fix for v1.0.21, as was the above: If the keyboard hook is installed,
  3206.     // the modifier keystrokes must have a way to get routed through the hook BEFORE the
  3207.     // keystrokes get sent via PostMessage().  If not, the correct modifier state will usually
  3208.     // not be in effect (or at least not be in sync) for the keys sent via PostMessage() afterward.
  3209.     // Notes about the macro below:
  3210.     // aTargetWindow!=NULL means ControlSend mode is in effect.
  3211.     // The g_KeybdHook check must come first (it should take precedence if both conditions are true).
  3212.     // -1 has been verified to be insufficient, at least for the very first letter sent if it is
  3213.     // supposed to be capitalized.
  3214.     // g_MainThreadID is the only thread of our process that owns any windows.
  3215.  
  3216.     int press_duration = (sSendMode == SM_PLAY) ? g.PressDurationPlay : g.PressDuration;
  3217.     if (press_duration > -1) // SM_PLAY does use DoKeyDelay() to store a delay item in the event array.
  3218.         // Since modifiers were changed by the above, do a key-delay if the special intra-keystroke
  3219.         // delay is in effect.
  3220.         // Since there normally isn't a delay between a change in modifiers and the first keystroke,
  3221.         // if a PressDuration is in effect, also do it here to improve reliability (I have observed
  3222.         // cases where modifiers need to be left alone for a short time in order for the keystrokes
  3223.         // that follow to be be modified by the intended set of modifiers).
  3224.         DoKeyDelay(press_duration); // It knows not to do the delay for SM_INPUT.
  3225.     else // Since no key-delay was done, check if a a delay is needed for any other reason.
  3226.     {
  3227.         // IMPORTANT UPDATE for v1.0.39: Now that the hooks are in a separate thread from the part
  3228.         // of the program that sends keystrokes for the script, you might think synchronization of
  3229.         // keystrokes would become problematic or at least change.  However, this is apparently not
  3230.         // the case.  MSDN doesn't spell this out, but testing shows that what happens with a low-level
  3231.         // hook is that the moment a keystroke comes into a thread (either physical or simulated), the OS
  3232.         // immediately calls something similar to SendMessage() from that thread to notify the hook
  3233.         // thread that a keystroke has arrived.  However, if the hook thread's priority is lower than
  3234.         // some other thread next in line for a timeslice, it might take some time for the hook thread
  3235.         // to get a timeslice (that's why the hook thread is given a high priority).
  3236.         // The SendMessage() call doesn't return until its timeout expires (as set in the registry for
  3237.         // hooks) or the hook thread processes the keystroke (which requires that it call something like
  3238.         // GetMessage/PeekMessage followed by a HookProc "return").  This is good news because it serializes
  3239.         // keyboard and mouse input to make the presence of the hook transparent to other threads (unless
  3240.         // the hook does something to reveal itself, such as suppressing keystrokes). Serialization avoids
  3241.         // any chance of synchronization problems such as a program that changes the state of a key then
  3242.         // immediately checks the state of that same key via GetAsyncKeyState().  Another way to look at
  3243.         // all of this is that in essense, a single-threaded hook program that simulates keystrokes or
  3244.         // mouse clicks should behave the same when the hook is moved into a separate thread because from
  3245.         // the program's point-of-view, keystrokes & mouse clicks result in a calling the hook almost
  3246.         // exactly as if the hook were in the same thread.
  3247.         if (aTargetWindow)
  3248.         {
  3249.             if (g_KeybdHook)
  3250.                 SLEEP_WITHOUT_INTERRUPTION(0) // Don't use ternary operator to combine this with next due to "else if".
  3251.             else if (GetWindowThreadProcessId(aTargetWindow, NULL) == g_MainThreadID)
  3252.                 SLEEP_WITHOUT_INTERRUPTION(-1)
  3253.         }
  3254.     }
  3255.  
  3256.     // Commented out because a return value is no longer needed by callers (since we do the key-delay here,
  3257.     // if appropriate).
  3258.     //return aModifiersLRnow ^ aModifiersLRnew; // Calculate the set of modifiers that changed (currently excludes AltGr's change of LControl's state).
  3259.  
  3260.  
  3261.     // NOTES about "release_shift_before_alt_ctrl":
  3262.     // If going down on alt or control (but not both, though it might not matter), and shift is to be released:
  3263.     //    Release shift first.
  3264.     // If going down on shift, and control or alt (but not both) is to be released:
  3265.     //    Release ctrl/alt first (this is already the case so nothing needs to be done).
  3266.     //
  3267.     // Release both shifts before going down on lalt/ralt or lctrl/rctrl (but not necessary if going down on
  3268.     // *both* alt+ctrl?
  3269.     // Release alt and both controls before going down on lshift/rshift.
  3270.     // Rather than the below, do the above (for the reason below).
  3271.     // But if do this, don't want to prevent a legit/intentional language switch such as:
  3272.     //    Send {LAlt down}{Shift}{LAlt up}.
  3273.     // If both Alt and Shift are down, Win or Ctrl (or any other key for that matter) must be pressed before either
  3274.     // is released.
  3275.     // If both Ctrl and Shift are down, Win or Alt (or any other key) must be pressed before either is released.
  3276.     // remind: Despite what the Regional Settings window says, RAlt+Shift (and Shift+RAlt) is also a language hotkey (i.e. not just LAlt), at least when RAlt isn't AltGr!
  3277.     // remind: Control being down suppresses language switch only once.  After that, control being down doesn't help if lalt is re-pressed prior to re-pressing shift.
  3278.     //
  3279.     // Language switch occurs when:
  3280.     // alt+shift (upon release of shift)
  3281.     // shift+alt (upon release of lalt)
  3282.     // ctrl+shift (upon release of shift)
  3283.     // shift+ctrl (upon release of ctrl)
  3284.     // Because language hotkey only takes effect upon release of Shift, it can be disguised via a Control keystroke if that is ever needed.
  3285.  
  3286.     // NOTES: More details about disguising ALT and WIN:
  3287.     // Registered Alt hotkeys don't quite work if the Alt key is released prior to the suffix.
  3288.     // Key history for Alt-B hotkey released this way, which undesirably activates the menu bar:
  3289.     // A4  038         d    0.03    Alt                
  3290.     // 42  030         d    0.03    B                  
  3291.     // A4  038         u    0.24    Alt                
  3292.     // 42  030         u    0.19    B                  
  3293.     // Testing shows that the above does not happen for a normal (non-hotkey) alt keystroke such as Alt-8,
  3294.     // so the above behavior is probably caused by the fact that B-down is suppressed by the OS's hotkey
  3295.     // routine, but not B-up.
  3296.     // The above also happens with registered WIN hotkeys, but only if the Send cmd resulted in the WIN
  3297.     // modifier being pushed back down afterward to match the fact that the user is still holding it down.
  3298.     // This behavior applies to ALT hotkeys also.
  3299.     // One solution: if the hook is installed, have it keep track of when the start menu or menu bar
  3300.     // *would* be activated.  These tracking vars can be consulted by the Send command, and the hook
  3301.     // can also be told when to use them after a registered hotkey has been pressed, so that the Alt-up
  3302.     // or Win-up keystroke that belongs to it can be disguised.
  3303.  
  3304.     // The following are important ways in which other methods of disguise might not be sufficient:
  3305.     // Sequence: shift-down win-down shift-up win-up: invokes Start Menu when WIN is held down long enough
  3306.     // to auto-repeat.  Same when Ctrl or Alt is used in lieu of Shift.
  3307.     // Sequence: shift-down alt-down alt-up shift-up: invokes menu bar.  However, as long as another key,
  3308.     // even Shift, is pressed down *after* alt is pressed down, menu bar is not activated, e.g. alt-down
  3309.     // shift-down shift-up alt-up.  In addition, CTRL always prevents ALT from activating the menu bar,
  3310.     // even with the following sequences:
  3311.     // ctrl-down alt-down alt-up ctrl-up
  3312.     // alt-down ctrl-down ctrl-up alt-up
  3313.     // (also seems true for all other permutations of Ctrl/Alt)
  3314. }
  3315.  
  3316.  
  3317.  
  3318. modLR_type GetModifierLRState(bool aExplicitlyGet)
  3319. // Try to report a more reliable state of the modifier keys than GetKeyboardState alone could.
  3320. // Fix for v1.0.42.01: On Windows 2000/XP or later, GetAsyncKeyState() should be called rather than
  3321. // GetKeyState().  This is because our callers always want the current state of the modifier keys
  3322. // rather than their state at the time of the currently-in-process message was posted.  For example,
  3323. // if the control key wasn't down at the time our thread's current message was posted, but it's logically
  3324. // down according to the system, we would want to release that control key before sending non-control
  3325. // keystrokes, even if one of our thread's own windows has keyboard focus (because if it does, the
  3326. // control-up keystroke should wind up getting processed after our thread realizes control is down).
  3327. // This applies even when the keyboard/mouse hook call use because keystrokes routed to the hook via
  3328. // the hook's message pump aren't messages per se, and thus GetKeyState and GetAsyncKeyState probably
  3329. // return the exact same thing whenever there are no messages in the hook's thread-queue (which is almost
  3330. // always the case).
  3331. {
  3332.     // If the hook is active, rely only on its tracked value rather than calling Get():
  3333.     if (g_KeybdHook && !aExplicitlyGet)
  3334.         return g_modifiersLR_logical;
  3335.  
  3336.     // Very old comment:
  3337.     // Use GetKeyState() rather than GetKeyboardState() because it's the only way to get
  3338.     // accurate key state when a console window is active, it seems.  I've also seen other
  3339.     // cases where GetKeyboardState() is incorrect (at least under WinXP) when GetKeyState(),
  3340.     // in its place, yields the correct info.  Very strange.
  3341.  
  3342.     modLR_type modifiersLR = 0;  // Allows all to default to up/off to simplify the below.
  3343.     if (g_os.IsWin9x() || g_os.IsWinNT4())
  3344.     {
  3345.         // Assume it's the left key since there's no way to tell which of the pair it
  3346.         // is? (unless the hook is installed, in which case it's value would have already
  3347.         // been returned, above).
  3348.         if (IsKeyDown9xNT(VK_SHIFT))   modifiersLR |= MOD_LSHIFT;
  3349.         if (IsKeyDown9xNT(VK_CONTROL)) modifiersLR |= MOD_LCONTROL;
  3350.         if (IsKeyDown9xNT(VK_MENU))    modifiersLR |= MOD_LALT;
  3351.         if (IsKeyDown9xNT(VK_LWIN))    modifiersLR |= MOD_LWIN;
  3352.         if (IsKeyDown9xNT(VK_RWIN))    modifiersLR |= MOD_RWIN;
  3353.     }
  3354.     else
  3355.     {
  3356.         if (IsKeyDownAsync(VK_LSHIFT))   modifiersLR |= MOD_LSHIFT;
  3357.         if (IsKeyDownAsync(VK_RSHIFT))   modifiersLR |= MOD_RSHIFT;
  3358.         if (IsKeyDownAsync(VK_LCONTROL)) modifiersLR |= MOD_LCONTROL;
  3359.         if (IsKeyDownAsync(VK_RCONTROL)) modifiersLR |= MOD_RCONTROL;
  3360.         if (IsKeyDownAsync(VK_LMENU))    modifiersLR |= MOD_LALT;
  3361.         if (IsKeyDownAsync(VK_RMENU))    modifiersLR |= MOD_RALT;
  3362.         if (IsKeyDownAsync(VK_LWIN))     modifiersLR |= MOD_LWIN;
  3363.         if (IsKeyDownAsync(VK_RWIN))     modifiersLR |= MOD_RWIN;
  3364.     }
  3365.  
  3366.     // Thread-safe: The following section isn't thread-safe because either the hook thread
  3367.     // or the main thread can be calling it.  However, given that anything dealing with
  3368.     // keystrokes isn't thread-safe in the sense that keystrokes can be coming in simultaneously
  3369.     // from multiple sources, it seems acceptable to keep it this way (especially since
  3370.     // the consequences of a thread collision seem very mild in this case).
  3371.     if (g_KeybdHook)
  3372.     {
  3373.         // Since hook is installed, fix any modifiers that it incorrectly thinks are down.
  3374.         // Though rare, this situation does arise during periods when the hook cannot track
  3375.         // the user's keystrokes, such as when the OS is doing something with the hardware,
  3376.         // e.g. switching to TV-out or changing video resolutions.  There are probably other
  3377.         // situations where this happens -- never fully explored and identified -- so it
  3378.         // seems best to do this, at least when the caller specified aExplicitlyGet = true.
  3379.         // To limit the scope of this workaround, only change the state of the hook modifiers
  3380.         // to be "up" for those keys the hook thinks are logically down but which the OS thinks
  3381.         // are logically up.  Note that it IS possible for a key to be physically down without
  3382.         // being logically down (i.e. during a Send command where the user is phyiscally holding
  3383.         // down a modifier, but the Send command needs to put it up temporarily), so do not
  3384.         // change the hook's physical state for such keys in that case.
  3385.         // UPDATE: The following adjustment is now also relied upon by the SendInput method
  3386.         // to correct physical modifier state during periods when the hook was temporarily removed
  3387.         // to allow a SendInput to be uninterruptible.
  3388.         modLR_type modifiers_wrongly_down = g_modifiersLR_logical & ~modifiersLR;
  3389.         if (modifiers_wrongly_down)
  3390.         {
  3391.             // Adjust the physical and logical hook state to release the keys that are wrongly down.
  3392.             // If a key is wrongly logically down, it seems best to release it both physically and
  3393.             // logically, since the hook's failure to see the up-event probably makes its physical
  3394.             // state wrong in most such cases.
  3395.             g_modifiersLR_physical &= ~modifiers_wrongly_down;
  3396.             g_modifiersLR_logical &= ~modifiers_wrongly_down;
  3397.             g_modifiersLR_logical_non_ignored &= ~modifiers_wrongly_down;
  3398.             // Also adjust physical state so that the GetKeyState command will retrieve the correct values:
  3399.             AdjustKeyState(g_PhysicalKeyState, g_modifiersLR_physical);
  3400.         }
  3401.     }
  3402.  
  3403.     return modifiersLR;
  3404.  
  3405.     // Only consider a modifier key to be really down if both the hook's tracking of it
  3406.     // and GetKeyboardState() agree that it should be down.  The should minimize the impact
  3407.     // of the inherent unreliability present in each method (and each method is unreliable in
  3408.     // ways different from the other).  I have verified through testing that this eliminates
  3409.     // many misfires of hotkeys.  UPDATE: Both methods are fairly reliable now due to starting
  3410.     // to send scan codes with keybd_event(), using MapVirtualKey to resolve zero-value scan
  3411.     // codes in the keyboardproc(), and using GetKeyState() rather than GetKeyboardState().
  3412.     // There are still a few cases when they don't agree, so return the bitwise-and of both
  3413.     // if the keyboard hook is active.  Bitwise and is used because generally it's safer
  3414.     // to assume a modifier key is up, when in doubt (e.g. to avoid firing unwanted hotkeys):
  3415. //    return g_KeybdHook ? (g_modifiersLR_logical & g_modifiersLR_get) : g_modifiersLR_get;
  3416. }
  3417.  
  3418.  
  3419.  
  3420. void AdjustKeyState(BYTE aKeyState[], modLR_type aModifiersLR)
  3421. // Caller has ensured that aKeyState is a 256-BYTE array of key states, in the same format used
  3422. // by GetKeyboardState() and ToAsciiEx().
  3423. {
  3424.     aKeyState[VK_LSHIFT] = (aModifiersLR & MOD_LSHIFT) ? STATE_DOWN : 0;
  3425.     aKeyState[VK_RSHIFT] = (aModifiersLR & MOD_RSHIFT) ? STATE_DOWN : 0;
  3426.     aKeyState[VK_LCONTROL] = (aModifiersLR & MOD_LCONTROL) ? STATE_DOWN : 0;
  3427.     aKeyState[VK_RCONTROL] = (aModifiersLR & MOD_RCONTROL) ? STATE_DOWN : 0;
  3428.     aKeyState[VK_LMENU] = (aModifiersLR & MOD_LALT) ? STATE_DOWN : 0;
  3429.     aKeyState[VK_RMENU] = (aModifiersLR & MOD_RALT) ? STATE_DOWN : 0;
  3430.     aKeyState[VK_LWIN] = (aModifiersLR & MOD_LWIN) ? STATE_DOWN : 0;
  3431.     aKeyState[VK_RWIN] = (aModifiersLR & MOD_RWIN) ? STATE_DOWN : 0;
  3432.     // Update the state of neutral keys only after the above, in case both keys of the pair were wrongly down:
  3433.     aKeyState[VK_SHIFT] = (aKeyState[VK_LSHIFT] || aKeyState[VK_RSHIFT]) ? STATE_DOWN : 0;
  3434.     aKeyState[VK_CONTROL] = (aKeyState[VK_LCONTROL] || aKeyState[VK_RCONTROL]) ? STATE_DOWN : 0;
  3435.     aKeyState[VK_MENU] = (aKeyState[VK_LMENU] || aKeyState[VK_RMENU]) ? STATE_DOWN : 0;
  3436. }
  3437.  
  3438.  
  3439.  
  3440. modLR_type KeyToModifiersLR(vk_type aVK, sc_type aSC, bool *pIsNeutral)
  3441. // Convert the given virtual key / scan code to its equivalent bitwise modLR value.
  3442. // Callers rely upon the fact that we convert a neutral key such as VK_SHIFT into MOD_LSHIFT,
  3443. // not the bitwise combo of MOD_LSHIFT|MOD_RSHIFT.
  3444. // v1.0.43: VK_SHIFT should yield MOD_RSHIFT if the caller explicitly passed the right vs. left scan code.
  3445. // The SendPlay method relies on this to properly release AltGr, such as after "SendPlay @" in German.
  3446. // Other things may also rely on it because it is more correct.
  3447. {
  3448.     bool placeholder;
  3449.     bool &is_neutral = pIsNeutral ? *pIsNeutral : placeholder; // Simplifies other things below.
  3450.     is_neutral = false; // Set default for output parameter for caller.
  3451.  
  3452.     if (!(aVK || aSC))
  3453.         return 0;
  3454.  
  3455.     if (aVK) // Have vk take precedence over any non-zero sc.
  3456.         switch(aVK)
  3457.         {
  3458.         case VK_SHIFT:
  3459.             if (aSC == SC_RSHIFT)
  3460.                 return MOD_RSHIFT;
  3461.             //else aSC is omitted (0) or SC_LSHIFT.  Either way, most callers would probably want that considered "neutral".
  3462.             is_neutral = true;
  3463.             return MOD_LSHIFT;
  3464.         case VK_LSHIFT: return MOD_LSHIFT;
  3465.         case VK_RSHIFT:    return MOD_RSHIFT;
  3466.  
  3467.         case VK_CONTROL:
  3468.             if (aSC == SC_RCONTROL)
  3469.                 return MOD_RCONTROL;
  3470.             //else aSC is omitted (0) or SC_LCONTROL.  Either way, most callers would probably want that considered "neutral".
  3471.             is_neutral = true;
  3472.             return MOD_LCONTROL;
  3473.         case VK_LCONTROL: return MOD_LCONTROL;
  3474.         case VK_RCONTROL: return MOD_RCONTROL;
  3475.  
  3476.         case VK_MENU:
  3477.             if (aSC == SC_RALT)
  3478.                 return MOD_RALT;
  3479.             //else aSC is omitted (0) or SC_LALT.  Either way, most callers would probably want that considered "neutral".
  3480.             is_neutral = true;
  3481.             return MOD_LALT;
  3482.         case VK_LMENU: return MOD_LALT;
  3483.         case VK_RMENU: return MOD_RALT;
  3484.  
  3485.         case VK_LWIN: return MOD_LWIN;
  3486.         case VK_RWIN: return MOD_RWIN;
  3487.  
  3488.         default:
  3489.             return 0;
  3490.         }
  3491.  
  3492.     // If above didn't return, rely on the scan code instead, which is now known to be non-zero.
  3493.     switch(aSC)
  3494.     {
  3495.     case SC_LSHIFT: return MOD_LSHIFT;
  3496.     case SC_RSHIFT:    return MOD_RSHIFT;
  3497.     case SC_LCONTROL: return MOD_LCONTROL;
  3498.     case SC_RCONTROL: return MOD_RCONTROL;
  3499.     case SC_LALT: return MOD_LALT;
  3500.     case SC_RALT: return MOD_RALT;
  3501.     case SC_LWIN: return MOD_LWIN;
  3502.     case SC_RWIN: return MOD_RWIN;
  3503.     }
  3504.     return 0;
  3505. }
  3506.  
  3507.  
  3508.  
  3509. modLR_type ConvertModifiers(mod_type aModifiers)
  3510. // Convert the input param to a modifiersLR value and return it.
  3511. {
  3512.     modLR_type modifiersLR = 0;
  3513.     if (aModifiers & MOD_WIN) modifiersLR |= (MOD_LWIN | MOD_RWIN);
  3514.     if (aModifiers & MOD_ALT) modifiersLR |= (MOD_LALT | MOD_RALT);
  3515.     if (aModifiers & MOD_CONTROL) modifiersLR |= (MOD_LCONTROL | MOD_RCONTROL);
  3516.     if (aModifiers & MOD_SHIFT) modifiersLR |= (MOD_LSHIFT | MOD_RSHIFT);
  3517.     return modifiersLR;
  3518. }
  3519.  
  3520.  
  3521.  
  3522. mod_type ConvertModifiersLR(modLR_type aModifiersLR)
  3523. // Convert the input param to a normal modifiers value and return it.
  3524. {
  3525.     mod_type modifiers = 0;
  3526.     if (aModifiersLR & (MOD_LWIN | MOD_RWIN)) modifiers |= MOD_WIN;
  3527.     if (aModifiersLR & (MOD_LALT | MOD_RALT)) modifiers |= MOD_ALT;
  3528.     if (aModifiersLR & (MOD_LSHIFT | MOD_RSHIFT)) modifiers |= MOD_SHIFT;
  3529.     if (aModifiersLR & (MOD_LCONTROL | MOD_RCONTROL)) modifiers |= MOD_CONTROL;
  3530.     return modifiers;
  3531. }
  3532.  
  3533.  
  3534.  
  3535. char *ModifiersLRToText(modLR_type aModifiersLR, char *aBuf)
  3536. // Caller has ensured that aBuf is not NULL.
  3537. {
  3538.     *aBuf = '\0';
  3539.     if (aModifiersLR & MOD_LWIN) strcat(aBuf, "LWin ");
  3540.     if (aModifiersLR & MOD_RWIN) strcat(aBuf, "RWin ");
  3541.     if (aModifiersLR & MOD_LSHIFT) strcat(aBuf, "LShift ");
  3542.     if (aModifiersLR & MOD_RSHIFT) strcat(aBuf, "RShift ");
  3543.     if (aModifiersLR & MOD_LCONTROL) strcat(aBuf, "LCtrl ");
  3544.     if (aModifiersLR & MOD_RCONTROL) strcat(aBuf, "RCtrl ");
  3545.     if (aModifiersLR & MOD_LALT) strcat(aBuf, "LAlt ");
  3546.     if (aModifiersLR & MOD_RALT) strcat(aBuf, "RAlt ");
  3547.     return aBuf;
  3548. }
  3549.  
  3550.  
  3551.  
  3552. bool ActiveWindowLayoutHasAltGr()
  3553. // Thread-safety: See comments in LayoutHasAltGr() below.
  3554. {
  3555.     Get_active_window_keybd_layout // Defines the variable active_window_keybd_layout for use below.
  3556.     return LayoutHasAltGr(active_window_keybd_layout) == CONDITION_TRUE; // i.e caller wants both CONDITION_FALSE and LAYOUT_UNDETERMINED to be considered non-AltGr.
  3557. }
  3558.  
  3559.  
  3560.  
  3561. ResultType LayoutHasAltGr(HKL aLayout, ResultType aHasAltGr)
  3562. // Thread-safety: While not thoroughly thread-safe, due to the extreme simplicity of the cache array, even if
  3563. // a collision occurs it should be inconsequential.
  3564. // Caller must ensure that aLayout is a valid layout (special values like 0 aren't supported here).
  3565. // If aHasAltGr is not at its default of LAYOUT_UNDETERMINED, the specified layout's has_altgr property is
  3566. // updated to the new value, but only if it is currently undetermined (callers can rely on this).
  3567. {
  3568.     // Layouts are cached for performance (to avoid the discovery loop later below).
  3569.     int i;
  3570.     for (i = 0; i < MAX_CACHED_LAYOUTS && sCachedLayout[i].hkl; ++i)
  3571.         if (sCachedLayout[i].hkl == aLayout) // Match Found.
  3572.         {
  3573.             if (aHasAltGr != LAYOUT_UNDETERMINED && sCachedLayout[i].has_altgr == LAYOUT_UNDETERMINED) // Caller relies on this.
  3574.                 sCachedLayout[i].has_altgr = aHasAltGr;
  3575.             return sCachedLayout[i].has_altgr;
  3576.         }
  3577.  
  3578.     // Since above didn't return, this layout isn't cached yet.  So create a new cache entry for it and
  3579.     // determine whether this layout has an AltGr key.  If i<MAX_CACHED_LAYOUTS (which it almost always will be),
  3580.     // there's room in the array for a new cache entry.  In the very unlikely event that there isn't room,
  3581.     // overwrite an arbitrary item in the array.  An LRU/MRU algorithm (timestamp) isn't used because running out
  3582.     // of slots seems too unlikely, and the consequences of running out are merely a slight degradation in performance.
  3583.     CachedLayoutType &cl = sCachedLayout[(i < MAX_CACHED_LAYOUTS) ? i : MAX_CACHED_LAYOUTS-1];
  3584.     if (aHasAltGr != LAYOUT_UNDETERMINED) // Caller determined it for us.  See top of function for explanation.
  3585.     {
  3586.         cl.hkl = aLayout;
  3587.         return cl.has_altgr = aHasAltGr;
  3588.     }
  3589.  
  3590.     // Otherwise, do AltGr detection on this newly cached layout so that we can return the AltGr state to caller.
  3591.     // This detection is probably not 100% reliable because there may be some layouts (especially custom ones)
  3592.     // that have an AltGr key yet none of its characters actually require AltGr to manifest.  A more reliable
  3593.     // way to detect AltGr would be to simulate an RALT keystroke (maybe only an up event, not a down) and have
  3594.     // a keyboard hook catch and block it.  If the layout has altgr, the hook would see a driver-generated LCtrl
  3595.     // keystroke immediately prior to RAlt.
  3596.     // Performance: This loop is quite fast. Doing this section 1000 times only takes about 160ms
  3597.     // on a 2gHz system (0.16ms per call).
  3598.     SHORT s; // Also, an int is used for "i" vs. char to avoid overflow on final character.
  3599.     for (cl.has_altgr = LAYOUT_UNDETERMINED, i = 32; i < 256; ++i) // Include Spacebar up through final ANSI character (i.e. include 255 but not 256).
  3600.     {
  3601.         s = VkKeyScanEx((char)i, aLayout);
  3602.         // Check for presence of Ctrl+Alt but allow other modifiers like Shift to be present because
  3603.         // I believe there are some layouts that manifest characters via Shift+AltGr.
  3604.         if (s != -1 && (s & 0x600) == 0x600) // In this context, Ctrl+Alt means AltGr.
  3605.         {
  3606.             cl.has_altgr = CONDITION_TRUE;
  3607.             break;
  3608.         }
  3609.     }
  3610.     // If loop didn't break, leave cl.has_altgr as LAYOUT_UNDETERMINED because we can't be sure whether AltGr is
  3611.     // present (see other comments for details).
  3612.     cl.hkl = aLayout; // This is done here (immediately after has_altgr was set in the loop above) rather than earlier to minimize the consequences of not being fully thread-safe.
  3613.     return cl.has_altgr;
  3614. }
  3615.  
  3616.  
  3617.  
  3618. char *SCtoKeyName(sc_type aSC, char *aBuf, int aBufSize)
  3619. // aBufSize is an int so that any negative values passed in from caller are not lost.
  3620. // Always produces a non-empty string.
  3621. {
  3622.     for (int i = 0; i < g_key_to_sc_count; ++i)
  3623.     {
  3624.         if (g_key_to_sc[i].sc == aSC)
  3625.         {
  3626.             strlcpy(aBuf, g_key_to_sc[i].key_name, aBufSize);
  3627.             return aBuf;
  3628.         }
  3629.     }
  3630.     // Since above didn't return, no match was found.  Use the default format for an unknown scan code:
  3631.     snprintf(aBuf, aBufSize, "SC%03x", aSC);
  3632.     return aBuf;
  3633. }
  3634.  
  3635.  
  3636.  
  3637. char *VKtoKeyName(vk_type aVK, sc_type aSC, char *aBuf, int aBufSize)
  3638. // aBufSize is an int so that any negative values passed in from caller are not lost.
  3639. // Caller may omit aSC and it will be derived if needed.
  3640. {
  3641.     for (int i = 0; i < g_key_to_vk_count; ++i)
  3642.     {
  3643.         if (g_key_to_vk[i].vk == aVK)
  3644.         {
  3645.             strlcpy(aBuf, g_key_to_vk[i].key_name, aBufSize);
  3646.             return aBuf;
  3647.         }
  3648.     }
  3649.     // Since above didn't return, no match was found.  Ask the OS for the name instead (it's probably
  3650.     // a letter key such as A through Z, but could be anything for which we don't have a listing):
  3651.     return GetKeyName(aVK, aSC, aBuf, aBufSize);
  3652. }
  3653.  
  3654.  
  3655.  
  3656. sc_type TextToSC(char *aText)
  3657. {
  3658.     if (!*aText) return 0;
  3659.     for (int i = 0; i < g_key_to_sc_count; ++i)
  3660.         if (!stricmp(g_key_to_sc[i].key_name, aText))
  3661.             return g_key_to_sc[i].sc;
  3662.     // Do this only after the above, in case any valid key names ever start with SC:
  3663.     if (toupper(*aText) == 'S' && toupper(*(aText + 1)) == 'C')
  3664.         return (sc_type)strtol(aText + 2, NULL, 16);  // Convert from hex.
  3665.     return 0; // Indicate "not found".
  3666. }
  3667.  
  3668.  
  3669.  
  3670. vk_type TextToVK(char *aText, modLR_type *pModifiersLR, bool aExcludeThoseHandledByScanCode, bool aAllowExplicitVK
  3671.     , HKL aKeybdLayout)
  3672. // If modifiers_p is non-NULL, place the modifiers that are needed to realize the key in there.
  3673. // e.g. M is really +m (shift-m), # is really shift-3.
  3674. // HOWEVER, this function does not completely overwrite the contents of pModifiersLR; instead, it just
  3675. // adds the required modifiers into whatever is already there.
  3676. {
  3677.     if (!*aText) return 0;
  3678.  
  3679.     // Don't trim() aText or modify it because that will mess up the caller who expects it to be unchanged.
  3680.     // Instead, for now, just check it as-is.  The only extra whitespace that should exist, due to trimming
  3681.     // of text during load, is that on either side of the COMPOSITE_DELIMITER (e.g. " then ").
  3682.  
  3683.     if (strlen(aText) == 1)
  3684.         return CharToVKAndModifiers(*aText, pModifiersLR, aKeybdLayout); // Making this a function simplifies things because it can do early return, etc.
  3685.  
  3686.     if (aAllowExplicitVK && toupper(aText[0]) == 'V' && toupper(aText[1]) == 'K')
  3687.         return (vk_type)strtol(aText + 2, NULL, 16);  // Convert from hex.
  3688.  
  3689.     for (int i = 0; i < g_key_to_vk_count; ++i)
  3690.         if (!stricmp(g_key_to_vk[i].key_name, aText))
  3691.             return g_key_to_vk[i].vk;
  3692.  
  3693.     if (aExcludeThoseHandledByScanCode)
  3694.         return 0; // Zero is not a valid virtual key, so it should be a safe failure indicator.
  3695.  
  3696.     // Otherwise check if aText is the name of a key handled by scan code and if so, map that
  3697.     // scan code to its corresponding virtual key:
  3698.     sc_type sc = TextToSC(aText);
  3699.     return sc ? sc_to_vk(sc) : 0;
  3700. }
  3701.  
  3702.  
  3703.  
  3704. vk_type CharToVKAndModifiers(char aChar, modLR_type *pModifiersLR, HKL aKeybdLayout)
  3705. // If non-NULL, pModifiersLR contains the initial set of modifiers provided by the caller, to which
  3706. // we add any extra modifiers required to realize aChar.
  3707. {
  3708.     // For v1.0.25.12, it seems best to avoid the many recent problems with linefeed (`n) being sent
  3709.     // as Ctrl+Enter by changing it to always send a plain Enter, just like carriage return (`r).
  3710.     if (aChar == '\n')
  3711.         return VK_RETURN;
  3712.  
  3713.     // Otherwise:
  3714.     SHORT mod_plus_vk = VkKeyScanEx(aChar, aKeybdLayout); // v1.0.44.03: Benchmark shows that VkKeyScanEx() is the same speed as VkKeyScan() when the layout has been pre-fetched.
  3715.     vk_type vk = LOBYTE(mod_plus_vk);
  3716.     char keyscan_modifiers = HIBYTE(mod_plus_vk);
  3717.     if (keyscan_modifiers == -1 && vk == (UCHAR)-1) // No translation could be made.
  3718.         return 0;
  3719.  
  3720.     // For v1.0.35, pModifiersLR was changed to modLR vs. mod so that AltGr keys such as backslash and
  3721.     // '{' are supported on layouts such as German when sending to apps such as Putty that are fussy about
  3722.     // which ALT key is held down to produce the character.  The following section detects AltGr by the
  3723.     // assuming that any character that requires both CTRL and ALT (with optional SHIFT) to be held
  3724.     // down is in fact an AltGr key (I don't think there are any that aren't AltGr in this case, but
  3725.     // confirmation would be nice).  Also, this is not done for Win9x because the distinction between
  3726.     // right and left-alt is not well-supported and it might do more harm than good (testing is
  3727.     // needed on fussy apps like Putty on Win9x).  UPDATE: Windows NT4 is now excluded from this
  3728.     // change because apparently it wants the left Alt key's virtual key and not the right's (though
  3729.     // perhaps it would prefer the right scan code vs. the left in apps such as Putty, but until that
  3730.     // is proven, the complexity is not added here).  Otherwise, on French and other layouts on NT4,
  3731.     // AltGr-produced characters such as backslash do not get sent properly.  In hindsight, this is
  3732.     // not suprising because the keyboard hook also receives neutral modifier keys on NT4 rather than
  3733.     // a more specific left/right key.
  3734.  
  3735.     // The win docs for VkKeyScan() are a bit confusing, referring to flag "bits" when it should really
  3736.     // say flag "values".  In addition, it seems that these flag values are incompatible with
  3737.     // MOD_ALT, MOD_SHIFT, and MOD_CONTROL, so they must be translated:
  3738.     if (pModifiersLR) // The caller wants this info added to the output param.
  3739.     {
  3740.         // Best not to reset this value because some callers want to retain what was in it before,
  3741.         // merely merging these new values into it:
  3742.         //*pModifiers = 0;
  3743.         if ((keyscan_modifiers & 0x06) == 0x06 && g_os.IsWin2000orLater()) // 0x06 means "requires/includes AltGr".
  3744.         {
  3745.             // v1.0.35: The critical difference below is right vs. left ALT.  Must not include MOD_LCONTROL
  3746.             // because simulating the RAlt keystroke on these keyboard layouts will automatically
  3747.             // press LControl down.
  3748.             *pModifiersLR |= MOD_RALT;
  3749.         }
  3750.         else // Do normal/default translation.
  3751.         {
  3752.             // v1.0.40: If caller-supplied modifiers already include the right-side key, no need to
  3753.             // add the left-side key (avoids unnecessary keystrokes).
  3754.             if (   (keyscan_modifiers & 0x02) && !(*pModifiersLR & (MOD_LCONTROL|MOD_RCONTROL))   )
  3755.                 *pModifiersLR |= MOD_LCONTROL; // Must not be done if requires_altgr==true, see above.
  3756.             if (   (keyscan_modifiers & 0x04) && !(*pModifiersLR & (MOD_LALT|MOD_RALT))   )
  3757.                 *pModifiersLR |= MOD_LALT;
  3758.         }
  3759.         // v1.0.36.06: Done unconditionally because presence of AltGr should not preclude the presence of Shift.
  3760.         // v1.0.40: If caller-supplied modifiers already contains MOD_RSHIFT, no need to add LSHIFT (avoids
  3761.         // unnecessary keystrokes).
  3762.         if (   (keyscan_modifiers & 0x01) && !(*pModifiersLR & (MOD_LSHIFT|MOD_RSHIFT))   )
  3763.             *pModifiersLR |= MOD_LSHIFT;
  3764.     }
  3765.     return vk;
  3766. }
  3767.  
  3768.  
  3769.  
  3770. vk_type TextToSpecial(char *aText, UINT aTextLength, KeyEventTypes &aEventType, modLR_type &aModifiersLR
  3771.     , bool aUpdatePersistent)
  3772. // Returns vk for key-down, negative vk for key-up, or zero if no translation.
  3773. // We also update whatever's in *pModifiers and *pModifiersLR to reflect the type of key-action
  3774. // specified in <aText>.  This makes it so that {altdown}{esc}{altup} behaves the same as !{esc}.
  3775. // Note that things like LShiftDown are not supported because: 1) they are rarely needed; and 2)
  3776. // they can be down via "lshift down".
  3777. {
  3778.     if (!strlicmp(aText, "ALTDOWN", aTextLength))
  3779.     {
  3780.         if (aUpdatePersistent)
  3781.             if (!(aModifiersLR & (MOD_LALT | MOD_RALT))) // i.e. do nothing if either left or right is already present.
  3782.                 aModifiersLR |= MOD_LALT; // If neither is down, use the left one because it's more compatible.
  3783.         aEventType = KEYDOWN;
  3784.         return VK_MENU;
  3785.     }
  3786.     if (!strlicmp(aText, "ALTUP", aTextLength))
  3787.     {
  3788.         // Unlike for Lwin/Rwin, it seems best to have these neutral keys (e.g. ALT vs. LALT or RALT)
  3789.         // restore either or both of the ALT keys into the up position.  The user can use {LAlt Up}
  3790.         // to be more specific and avoid this behavior:
  3791.         if (aUpdatePersistent)
  3792.             aModifiersLR &= ~(MOD_LALT | MOD_RALT);
  3793.         aEventType = KEYUP;
  3794.         return VK_MENU;
  3795.     }
  3796.     if (!strlicmp(aText, "SHIFTDOWN", aTextLength))
  3797.     {
  3798.         if (aUpdatePersistent)
  3799.             if (!(aModifiersLR & (MOD_LSHIFT | MOD_RSHIFT))) // i.e. do nothing if either left or right is already present.
  3800.                 aModifiersLR |= MOD_LSHIFT; // If neither is down, use the left one because it's more compatible.
  3801.         aEventType = KEYDOWN;
  3802.         return VK_SHIFT;
  3803.     }
  3804.     if (!strlicmp(aText, "SHIFTUP", aTextLength))
  3805.     {
  3806.         if (aUpdatePersistent)
  3807.             aModifiersLR &= ~(MOD_LSHIFT | MOD_RSHIFT); // See "ALTUP" for explanation.
  3808.         aEventType = KEYUP;
  3809.         return VK_SHIFT;
  3810.     }
  3811.     if (!strlicmp(aText, "CTRLDOWN", aTextLength) || !strlicmp(aText, "CONTROLDOWN", aTextLength))
  3812.     {
  3813.         if (aUpdatePersistent)
  3814.             if (!(aModifiersLR & (MOD_LCONTROL | MOD_RCONTROL))) // i.e. do nothing if either left or right is already present.
  3815.                 aModifiersLR |= MOD_LCONTROL; // If neither is down, use the left one because it's more compatible.
  3816.         aEventType = KEYDOWN;
  3817.         return VK_CONTROL;
  3818.     }
  3819.     if (!strlicmp(aText, "CTRLUP", aTextLength) || !strlicmp(aText, "CONTROLUP", aTextLength))
  3820.     {
  3821.         if (aUpdatePersistent)
  3822.             aModifiersLR &= ~(MOD_LCONTROL | MOD_RCONTROL); // See "ALTUP" for explanation.
  3823.         aEventType = KEYUP;
  3824.         return VK_CONTROL;
  3825.     }
  3826.     if (!strlicmp(aText, "LWINDOWN", aTextLength))
  3827.     {
  3828.         if (aUpdatePersistent)
  3829.             aModifiersLR |= MOD_LWIN;
  3830.         aEventType = KEYDOWN;
  3831.         return VK_LWIN;
  3832.     }
  3833.     if (!strlicmp(aText, "LWINUP", aTextLength))
  3834.     {
  3835.         if (aUpdatePersistent)
  3836.             aModifiersLR &= ~MOD_LWIN;
  3837.         aEventType = KEYUP;
  3838.         return VK_LWIN;
  3839.     }
  3840.     if (!strlicmp(aText, "RWINDOWN", aTextLength))
  3841.     {
  3842.         if (aUpdatePersistent)
  3843.             aModifiersLR |= MOD_RWIN;
  3844.         aEventType = KEYDOWN;
  3845.         return VK_RWIN;
  3846.     }
  3847.     if (!strlicmp(aText, "RWINUP", aTextLength))
  3848.     {
  3849.         if (aUpdatePersistent)
  3850.             aModifiersLR &= ~MOD_RWIN;
  3851.         aEventType = KEYUP;
  3852.         return VK_RWIN;
  3853.     }
  3854.     // Otherwise, leave aEventType unchanged and return zero to indicate failure:
  3855.     return 0;
  3856. }
  3857.  
  3858.  
  3859.  
  3860. #ifdef ENABLE_KEY_HISTORY_FILE
  3861. ResultType KeyHistoryToFile(char *aFilespec, char aType, bool aKeyUp, vk_type aVK, sc_type aSC)
  3862. {
  3863.     static char sTargetFilespec[MAX_PATH] = "";
  3864.     static FILE *fp = NULL;
  3865.     static HWND last_foreground_window = NULL;
  3866.     static DWORD last_tickcount = GetTickCount();
  3867.  
  3868.     if (!g_KeyHistory) // Since key history is disabled, keys are not being tracked by the hook, so there's nothing to log.
  3869.         return OK;     // Files should not need to be closed since they would never have been opened in the first place.
  3870.  
  3871.     if (!aFilespec && !aVK && !aSC) // Caller is signaling to close the file if it's open.
  3872.     {
  3873.         if (fp)
  3874.         {
  3875.             fclose(fp);
  3876.             fp = NULL;
  3877.         }
  3878.         return OK;
  3879.     }
  3880.  
  3881.     if (aFilespec && *aFilespec && lstrcmpi(aFilespec, sTargetFilespec)) // Target filename has changed.
  3882.     {
  3883.         if (fp)
  3884.         {
  3885.             fclose(fp);
  3886.             fp = NULL;  // To indicate to future calls to this function that it's closed.
  3887.         }
  3888.         strlcpy(sTargetFilespec, aFilespec, sizeof(sTargetFilespec));
  3889.     }
  3890.  
  3891.     if (!aVK && !aSC) // Caller didn't want us to log anything this time.
  3892.         return OK;
  3893.     if (!*sTargetFilespec)
  3894.         return OK; // No target filename has ever been specified, so don't even attempt to open the file.
  3895.  
  3896.     if (!aVK)
  3897.         aVK = sc_to_vk(aSC);
  3898.     else
  3899.         if (!aSC)
  3900.             aSC = vk_to_sc(aVK);
  3901.  
  3902.     char buf[2048] = "", win_title[1024] = "<Init>", key_name[128] = "";
  3903.     HWND curr_foreground_window = GetForegroundWindow();
  3904.     DWORD curr_tickcount = GetTickCount();
  3905.     bool log_changed_window = (curr_foreground_window != last_foreground_window);
  3906.     if (log_changed_window)
  3907.     {
  3908.         if (curr_foreground_window)
  3909.             GetWindowText(curr_foreground_window, win_title, sizeof(win_title));
  3910.         else
  3911.             strlcpy(win_title, "<None>", sizeof(win_title));
  3912.         last_foreground_window = curr_foreground_window;
  3913.     }
  3914.  
  3915.     snprintf(buf, sizeof(buf), "%02X" "\t%03X" "\t%0.2f" "\t%c" "\t%c" "\t%s" "%s%s\n"
  3916.         , aVK, aSC
  3917.         , (float)(curr_tickcount - last_tickcount) / (float)1000
  3918.         , aType
  3919.         , aKeyUp ? 'u' : 'd'
  3920.         , GetKeyName(aVK, aSC, key_name, sizeof(key_name))
  3921.         , log_changed_window ? "\t" : ""
  3922.         , log_changed_window ? win_title : ""
  3923.         );
  3924.     last_tickcount = curr_tickcount;
  3925.     if (!fp)
  3926.         if (   !(fp = fopen(sTargetFilespec, "a"))   )
  3927.             return OK;
  3928.     fputs(buf, fp);
  3929.     return OK;
  3930. }
  3931. #endif
  3932.  
  3933.  
  3934.  
  3935. char *GetKeyName(vk_type aVK, sc_type aSC, char *aBuf, int aBufSize)
  3936. // aBufSize is an int so that any negative values passed in from caller are not lost.
  3937. // Caller has ensured that aBuf isn't NULL.
  3938. {
  3939.     if (aBufSize < 3)
  3940.         return aBuf;
  3941.  
  3942.     *aBuf = '\0'; // Set default.
  3943.     if (!aVK && !aSC)
  3944.         return aBuf;
  3945.  
  3946.     if (!aVK)
  3947.         aVK = sc_to_vk(aSC);
  3948.     else
  3949.         if (!aSC)
  3950.             aSC = vk_to_sc(aVK);
  3951.  
  3952.     // Use 0x02000000 to tell it that we want it to give left/right specific info, lctrl/rctrl etc.
  3953.     // Relies on short-circuit boolean order.  v1.0.43: WheelDown/Up store the notch/turn count in SC,
  3954.     // so don't consider that to be a valid SC:
  3955.     if (!aSC || aVK == VK_WHEEL_DOWN || aVK == VK_WHEEL_UP || !GetKeyNameText((long)(aSC) << 16, aBuf, (int)(aBufSize/sizeof(TCHAR))))
  3956.     {
  3957.         int j;
  3958.         for (j = 0; j < g_key_to_vk_count; ++j)
  3959.             if (g_key_to_vk[j].vk == aVK)
  3960.                 break;
  3961.         if (j < g_key_to_vk_count) // Match found.
  3962.             strlcpy(aBuf, g_key_to_vk[j].key_name, aBufSize);
  3963.         else
  3964.         {
  3965.             if (isprint(aVK))
  3966.             {
  3967.                 aBuf[0] = aVK;
  3968.                 aBuf[1] = '\0';
  3969.             }
  3970.             else
  3971.                 strlcpy(aBuf, "not found", aBufSize);
  3972.         }
  3973.     }
  3974.     return aBuf;
  3975. }
  3976.  
  3977.  
  3978.  
  3979. sc_type vk_to_sc(vk_type aVK, bool aReturnSecondary)
  3980. // For v1.0.37.03, vk_to_sc() was converted into a function rather than being an array because if the
  3981. // script's keyboard layout changes while it's running, the array would get out-of-date.
  3982. // If caller passes true for aReturnSecondary, the non-primary scan code will be returned for
  3983. // virtual keys that two scan codes (if there's only one scan code, callers rely on zero being returned).
  3984. {
  3985.     // Try to minimize the number mappings done manually because MapVirtualKey is a more reliable
  3986.     // way to get the mapping if user has non-standard or custom keyboard layout.
  3987.  
  3988.     sc_type sc = 0;
  3989.  
  3990.     switch (aVK)
  3991.     {
  3992.     // Yield a manually translation for virtual keys that MapVirtualKey() doesn't support or for which it
  3993.     // doesn't yield consistent result (such as Win9x supporting only SHIFT rather than VK_LSHIFT/VK_RSHIFT).
  3994.     case VK_LSHIFT:   sc = SC_LSHIFT; break; // Modifiers are listed first for performance.
  3995.     case VK_RSHIFT:   sc = SC_RSHIFT; break;
  3996.     case VK_LCONTROL: sc = SC_LCONTROL; break;
  3997.     case VK_RCONTROL: sc = SC_RCONTROL; break;
  3998.     case VK_LMENU:    sc = SC_LALT; break;
  3999.     case VK_RMENU:    sc = SC_RALT; break;
  4000.     case VK_LWIN:     sc = SC_LWIN; break; // Earliest versions of Win95/NT might not support these, so map them manually.
  4001.     case VK_RWIN:     sc = SC_RWIN; break; //
  4002.  
  4003.     // According to http://support.microsoft.com/default.aspx?scid=kb;en-us;72583
  4004.     // most or all numeric keypad keys cannot be mapped reliably under any OS. The article is
  4005.     // a little unclear about which direction, if any, that MapVirtualKey() does work in for
  4006.     // the numpad keys, so for peace-of-mind map them all manually for now:
  4007.     case VK_NUMPAD0:  sc = SC_NUMPAD0; break;
  4008.     case VK_NUMPAD1:  sc = SC_NUMPAD1; break;
  4009.     case VK_NUMPAD2:  sc = SC_NUMPAD2; break;
  4010.     case VK_NUMPAD3:  sc = SC_NUMPAD3; break;
  4011.     case VK_NUMPAD4:  sc = SC_NUMPAD4; break;
  4012.     case VK_NUMPAD5:  sc = SC_NUMPAD5; break;
  4013.     case VK_NUMPAD6:  sc = SC_NUMPAD6; break;
  4014.     case VK_NUMPAD7:  sc = SC_NUMPAD7; break;
  4015.     case VK_NUMPAD8:  sc = SC_NUMPAD8; break;
  4016.     case VK_NUMPAD9:  sc = SC_NUMPAD9; break;
  4017.     case VK_DECIMAL:  sc = SC_NUMPADDOT; break;
  4018.     case VK_NUMLOCK:  sc = SC_NUMLOCK; break;
  4019.     case VK_DIVIDE:   sc = SC_NUMPADDIV; break;
  4020.     case VK_MULTIPLY: sc = SC_NUMPADMULT; break;
  4021.     case VK_SUBTRACT: sc = SC_NUMPADSUB; break;
  4022.     case VK_ADD:      sc = SC_NUMPADADD; break;
  4023.     }
  4024.  
  4025.     if (sc) // Above found a match.
  4026.         return aReturnSecondary ? 0 : sc; // Callers rely on zero being returned for VKs that don't have secondary SCs.
  4027.  
  4028.     // Use the OS API's MapVirtualKey() to resolve any not manually done above:
  4029.     if (   !(sc = MapVirtualKey(aVK, 0))   )
  4030.         return 0; // Indicate "no mapping".
  4031.  
  4032.     // Turn on the extended flag for those that need it.
  4033.     // Because MapVirtualKey can only accept (and return) naked scan codes (the low-order byte),
  4034.     // handle extended scan codes that have a non-extended counterpart manually.
  4035.     // Older comment: MapVirtualKey() should include 0xE0 in HIBYTE if key is extended, BUT IT DOESN'T.
  4036.     // There doesn't appear to be any built-in function to determine whether a vk's scan code
  4037.     // is extended or not.  See MSDN topic "keyboard input" for the below list.
  4038.     // Note: NumpadEnter is probably the only extended key that doesn't have a unique VK of its own.
  4039.     // So in that case, probably safest not to set the extended flag.  To send a true NumpadEnter,
  4040.     // as well as a true NumPadDown and any other key that shares the same VK with another, the
  4041.     // caller should specify the sc param to circumvent the need for KeyEvent() to use the below:
  4042.     switch (aVK)
  4043.     {
  4044.     case VK_APPS:     // Application key on keyboards with LWIN/RWIN/Apps.  Not listed in MSDN as "extended"?
  4045.     case VK_CANCEL:   // Ctrl-break
  4046.     case VK_SNAPSHOT: // PrintScreen
  4047.     case VK_DIVIDE:   // NumpadDivide (slash)
  4048.     case VK_NUMLOCK:
  4049.     // Below are extended but were already handled and returned from higher above:
  4050.     //case VK_LWIN:
  4051.     //case VK_RWIN:
  4052.     //case VK_RMENU:
  4053.     //case VK_RCONTROL:
  4054.     //case VK_RSHIFT: // WinXP needs this to be extended for keybd_event() to work properly.
  4055.         sc |= 0x0100;
  4056.         break;
  4057.  
  4058.     // The following virtual keys have more than one physical key, and thus more than one scan code.
  4059.     // If the caller passed true for aReturnSecondary, the extended version of the scan code will be
  4060.     // returned (all of the following VKs have two SCs):
  4061.     case VK_RETURN:
  4062.     case VK_INSERT:
  4063.     case VK_DELETE:
  4064.     case VK_PRIOR: // PgUp
  4065.     case VK_NEXT:  // PgDn
  4066.     case VK_HOME:
  4067.     case VK_END:
  4068.     case VK_UP:
  4069.     case VK_DOWN:
  4070.     case VK_LEFT:
  4071.     case VK_RIGHT:
  4072.         return aReturnSecondary ? (sc | 0x0100) : sc; // Below relies on the fact that these cases return early.
  4073.     }
  4074.  
  4075.     // Since above didn't return, if aReturnSecondary==true, return 0 to indicate "no secondary SC for this VK".
  4076.     return aReturnSecondary ? 0 : sc; // Callers rely on zero being returned for VKs that don't have secondary SCs.
  4077. }
  4078.  
  4079.  
  4080.  
  4081. vk_type sc_to_vk(sc_type aSC)
  4082. {
  4083.     // These are mapped manually because MapVirtualKey() doesn't support them correctly, at least
  4084.     // on some -- if not all -- OSs.  The main app also relies upon the values assigned below to
  4085.     // determine which keys should be handled by scan code rather than vk:
  4086.     switch (aSC)
  4087.     {
  4088.     // Even though neither of the SHIFT keys are extended -- and thus could be mapped with MapVirtualKey()
  4089.     // -- it seems better to define them explicitly because under Win9x (maybe just Win95).
  4090.     // I'm pretty sure MapVirtualKey() would return VK_SHIFT instead of the left/right VK.
  4091.     case SC_LSHIFT:      return VK_LSHIFT; // Modifiers are listed first for performance.
  4092.     case SC_RSHIFT:      return VK_RSHIFT;
  4093.     case SC_LCONTROL:    return VK_LCONTROL;
  4094.     case SC_RCONTROL:    return VK_RCONTROL;
  4095.     case SC_LALT:        return VK_LMENU;
  4096.     case SC_RALT:        return VK_RMENU;
  4097.  
  4098.     // Numpad keys require explicit mapping because MapVirtualKey() doesn't support them on all OSes.
  4099.     // See comments in vk_to_sc() for details.
  4100.     case SC_NUMLOCK:     return VK_NUMLOCK;
  4101.     case SC_NUMPADDIV:   return VK_DIVIDE;
  4102.     case SC_NUMPADMULT:  return VK_MULTIPLY;
  4103.     case SC_NUMPADSUB:   return VK_SUBTRACT;
  4104.     case SC_NUMPADADD:   return VK_ADD;
  4105.     case SC_NUMPADENTER: return VK_RETURN;
  4106.  
  4107.     // The following are ambiguous because each maps to more than one VK.  But be careful
  4108.     // changing the value to the other choice because some callers rely upon the values
  4109.     // assigned below to determine which keys should be handled by scan code rather than vk:
  4110.     case SC_NUMPADDEL:   return VK_DELETE;
  4111.     case SC_NUMPADCLEAR: return VK_CLEAR;
  4112.     case SC_NUMPADINS:   return VK_INSERT;
  4113.     case SC_NUMPADUP:    return VK_UP;
  4114.     case SC_NUMPADDOWN:  return VK_DOWN;
  4115.     case SC_NUMPADLEFT:  return VK_LEFT;
  4116.     case SC_NUMPADRIGHT: return VK_RIGHT;
  4117.     case SC_NUMPADHOME:  return VK_HOME;
  4118.     case SC_NUMPADEND:   return VK_END;
  4119.     case SC_NUMPADPGUP:  return VK_PRIOR;
  4120.     case SC_NUMPADPGDN:  return VK_NEXT;
  4121.  
  4122.     // No callers currently need the following alternate virtual key mappings.  If it is ever needed,
  4123.     // could have a new aReturnSecondary parameter that if true, causes these to be returned rather
  4124.     // than the above:
  4125.     //case SC_NUMPADDEL:   return VK_DECIMAL;
  4126.     //case SC_NUMPADCLEAR: return VK_NUMPAD5; // Same key as Numpad5 on most keyboards?
  4127.     //case SC_NUMPADINS:   return VK_NUMPAD0;
  4128.     //case SC_NUMPADUP:    return VK_NUMPAD8;
  4129.     //case SC_NUMPADDOWN:  return VK_NUMPAD2;
  4130.     //case SC_NUMPADLEFT:  return VK_NUMPAD4;
  4131.     //case SC_NUMPADRIGHT: return VK_NUMPAD6;
  4132.     //case SC_NUMPADHOME:  return VK_NUMPAD7;
  4133.     //case SC_NUMPADEND:   return VK_NUMPAD1;
  4134.     //case SC_NUMPADPGUP:  return VK_NUMPAD9;
  4135.     //case SC_NUMPADPGDN:  return VK_NUMPAD3;    
  4136.     }
  4137.  
  4138.     // Use the OS API call to resolve any not manually set above.  This should correctly
  4139.     // resolve even elements such as SC_INSERT, which is an extended scan code, because
  4140.     // it passes in only the low-order byte which is SC_NUMPADINS.  In the case of SC_INSERT
  4141.     // and similar ones, MapVirtualKey() will return the same vk for both, which is correct.
  4142.     // Only pass the LOBYTE because I think it fails to work properly otherwise.
  4143.     // Also, DO NOT pass 3 for the 2nd param of MapVirtualKey() because apparently
  4144.     // that is not compatible with Win9x so it winds up returning zero for keys
  4145.     // such as UP, LEFT, HOME, and PGUP (maybe other sorts of keys too).  This
  4146.     // should be okay even on XP because the left/right specific keys have already
  4147.     // been resolved above so don't need to be looked up here (LWIN and RWIN
  4148.     // each have their own VK's so shouldn't be problem for the below call to resolve):
  4149.     return MapVirtualKey((BYTE)aSC, 1);
  4150. }
  4151.