home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Open Source / AutoHotKey / Source / AutoHotkey104705_source.exe / source / globaldata.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2007-06-12  |  41.7 KB  |  764 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. // These includes should probably a superset of those in globaldata.h:
  19. #include "hook.h" // For KeyHistoryItem and probably other things.
  20. #include "clipboard.h"  // For the global clipboard object
  21. #include "script.h" // For the global script object and g_ErrorLevel
  22. #include "os_version.h" // For the global OS_Version object
  23.  
  24. // Since at least some of some of these (e.g. g_modifiersLR_logical) should not
  25. // be kept in the struct since it's not correct to save and restore their
  26. // state, don't keep anything in the global_struct except those things
  27. // which are necessary to save and restore (even though it would clean
  28. // up the code and might make maintaining it easier):
  29. HINSTANCE g_hInstance = NULL; // Set by WinMain().
  30. DWORD g_MainThreadID = GetCurrentThreadId();
  31. DWORD g_HookThreadID; // Not initialized by design because 0 itself might be a valid thread ID.
  32. CRITICAL_SECTION g_CriticalRegExCache;
  33.  
  34. bool g_DestroyWindowCalled = false;
  35. HWND g_hWnd = NULL;
  36. HWND g_hWndEdit = NULL;
  37. HWND g_hWndSplash = NULL;
  38. HFONT g_hFontSplash = NULL;  // So that font can be deleted on program close.
  39. HACCEL g_hAccelTable = NULL;
  40.  
  41. typedef int (WINAPI *StrCmpLogicalW_type)(LPCWSTR, LPCWSTR);
  42. StrCmpLogicalW_type g_StrCmpLogicalW = NULL;
  43. WNDPROC g_TabClassProc = NULL;
  44.  
  45. modLR_type g_modifiersLR_logical = 0;
  46. modLR_type g_modifiersLR_logical_non_ignored = 0;
  47. modLR_type g_modifiersLR_physical = 0;
  48.  
  49. #ifdef FUTURE_USE_MOUSE_BUTTONS_LOGICAL
  50. WORD g_mouse_buttons_logical = 0;
  51. #endif
  52.  
  53. // Used by the hook to track physical state of all virtual keys, since GetAsyncKeyState() does
  54. // not retrieve the physical state of a key.  Note that this array is sometimes used in a way that
  55. // requires its format to be the same as that returned from GetKeyboardState():
  56. BYTE g_PhysicalKeyState[VK_ARRAY_COUNT] = {0};
  57. bool g_BlockWinKeys = false;
  58. DWORD g_HookReceiptOfLControlMeansAltGr = 0; // In these cases, zero is used as a false value, any others are true.
  59. DWORD g_IgnoreNextLControlDown = 0;          //
  60. DWORD g_IgnoreNextLControlUp = 0;            //
  61.  
  62. int g_HotkeyModifierTimeout = 50;  // Reduced from 100, which was a little too large for fast typists.
  63. int g_ClipboardTimeout = 1000; // v1.0.31
  64.  
  65. HHOOK g_KeybdHook = NULL;
  66. HHOOK g_MouseHook = NULL;
  67. HHOOK g_PlaybackHook = NULL;
  68. bool g_ForceLaunch = false;
  69. bool g_WinActivateForce = false;
  70. SingleInstanceType g_AllowOnlyOneInstance = ALLOW_MULTI_INSTANCE;
  71. bool g_persistent = false;  // Whether the script should stay running even after the auto-exec section finishes.
  72. bool g_NoEnv = false; // BOOL vs. bool didn't help performance in spite of the frequent accesses to it.
  73. bool g_NoTrayIcon = false;
  74. #ifdef AUTOHOTKEYSC
  75.     bool g_AllowMainWindow = false;
  76. #endif
  77. bool g_AllowSameLineComments = true;
  78. bool g_MainTimerExists = false;
  79. bool g_UninterruptibleTimerExists = false;
  80. bool g_AutoExecTimerExists = false;
  81. bool g_InputTimerExists = false;
  82. bool g_DerefTimerExists = false;
  83. bool g_SoundWasPlayed = false;
  84. bool g_IsSuspended = false;  // Make this separate from g_AllowInterruption since that is frequently turned off & on.
  85. bool g_AllowInterruption = true;
  86. bool g_DeferMessagesForUnderlyingPump = false;
  87. int g_nLayersNeedingTimer = 0;
  88. int g_nThreads = 0;
  89. int g_nPausedThreads = 0;
  90. bool g_IdleIsPaused = false;
  91. int g_MaxHistoryKeys = 40;
  92.  
  93. // g_MaxVarCapacity is used to prevent a buggy script from consuming all available system RAM. It is defined
  94. // as the maximum memory size of a variable, including the string's zero terminator.
  95. // The chosen default seems big enough to be flexible, yet small enough to not be a problem on 99% of systems:
  96. VarSizeType g_MaxVarCapacity = 64 * 1024 * 1024;
  97. UCHAR g_MaxThreadsPerHotkey = 1;
  98. int g_MaxThreadsTotal = 10;
  99. // On my system, the repeat-rate (which is probably set to XP's default) is such that between 20
  100. // and 25 keys are generated per second.  Therefore, 50 in 2000ms seems like it should allow the
  101. // key auto-repeat feature to work on most systems without triggering the warning dialog.
  102. // In any case, using auto-repeat with a hotkey is pretty rare for most people, so it's best
  103. // to keep these values conservative:
  104. int g_MaxHotkeysPerInterval = 70; // Increased to 70 because 60 was still causing the warning dialog for repeating keys sometimes.  Increased from 50 to 60 for v1.0.31.02 since 50 would be triggered by keyboard auto-repeat when it is set to its fastest.
  105. int g_HotkeyThrottleInterval = 2000; // Milliseconds.
  106. bool g_MaxThreadsBuffer = false;  // This feature usually does more harm than good, so it defaults to OFF.
  107. HotCriterionType g_HotCriterion = HOT_NO_CRITERION;
  108. char *g_HotWinTitle = ""; // In spite of the above being the primary indicator,
  109. char *g_HotWinText = "";  // these are initialized for maintainability.
  110. HotkeyCriterion *g_FirstHotCriterion = NULL, *g_LastHotCriterion = NULL;
  111.  
  112. MenuTypeType g_MenuIsVisible = MENU_TYPE_NONE;
  113. int g_nMessageBoxes = 0;
  114. int g_nInputBoxes = 0;
  115. int g_nFileDialogs = 0;
  116. int g_nFolderDialogs = 0;
  117. InputBoxType g_InputBox[MAX_INPUTBOXES];
  118. SplashType g_Progress[MAX_PROGRESS_WINDOWS] = {{0}};
  119. SplashType g_SplashImage[MAX_SPLASHIMAGE_WINDOWS] = {{0}};
  120. GuiType *g_gui[MAX_GUI_WINDOWS] = {NULL};
  121. HWND g_hWndToolTip[MAX_TOOLTIPS] = {NULL};
  122. MsgMonitorStruct *g_MsgMonitor = NULL; // An array to be allocated upon first use (if any).
  123. int g_MsgMonitorCount = 0;
  124.  
  125. // Init not needed for these:
  126. UCHAR g_SortCaseSensitive;
  127. bool g_SortNumeric;
  128. bool g_SortReverse;
  129. int g_SortColumnOffset;
  130. Func *g_SortFunc;
  131.  
  132. char g_delimiter = ',';
  133. char g_DerefChar = '%';
  134. char g_EscapeChar = '`';
  135.  
  136. // Hot-string vars (initialized when ResetHook() is first called):
  137. char g_HSBuf[HS_BUF_SIZE];
  138. int g_HSBufLength;
  139. HWND g_HShwnd;
  140.  
  141. // Hot-string global settings:
  142. int g_HSPriority = 0;  // default priority is always 0
  143. int g_HSKeyDelay = 0;  // Fast sends are much nicer for auto-replace and auto-backspace.
  144. SendModes g_HSSendMode = SM_INPUT; // v1.0.43: New default for more reliable hotstrings.
  145. bool g_HSCaseSensitive = false;
  146. bool g_HSConformToCase = true;
  147. bool g_HSDoBackspace = true;
  148. bool g_HSOmitEndChar = false;
  149. bool g_HSSendRaw = false;
  150. bool g_HSEndCharRequired = true;
  151. bool g_HSDetectWhenInsideWord = false;
  152. bool g_HSDoReset = false;
  153. bool g_HSResetUponMouseClick = true;
  154. char g_EndChars[HS_MAX_END_CHARS + 1] = "-()[]{}:;'\"/\\,.?!\n \t";  // Hotstring default end chars, including a space.
  155. // The following were considered but seemed too rare and/or too likely to result in undesirable replacements
  156. // (such as while programming or scripting, or in usernames or passwords): <>*+=_%^&|@#$|
  157. // Although dash/hyphen is used for multiple purposes, it seems to me that it is best (on average) to include it.
  158. // Jay D. Novak suggested ([{/ for things such as fl/nj or fl(nj) which might resolve to USA state names.
  159. // i.e. word(synonym) and/or word/synonym
  160.  
  161. // Global objects:
  162. Var *g_ErrorLevel = NULL; // Allows us (in addition to the user) to set this var to indicate success/failure.
  163. input_type g_input;
  164. Script g_script;
  165. // This made global for performance reasons (determining size of clipboard data then
  166. // copying contents in or out without having to close & reopen the clipboard in between):
  167. Clipboard g_clip;
  168. OS_Version g_os;  // OS version object, courtesy of AutoIt3.
  169.  
  170. // THIS MUST BE DONE AFTER the g_os object is initialized above:
  171. // These are conditional because on these OSes, only standard-palette 16-color icons are supported,
  172. // which would cause the normal icons to look mostly gray when used with in the tray.  So we use
  173. // special 16x16x16 icons, but only for the tray because these OSes display the nicer icons okay
  174. // in places other than the tray.  Also note that the red icons look okay, at least on Win98,
  175. // because they are "red enough" not to suffer the graying effect from the palette shifting done
  176. // by the OS:
  177. int g_IconTray = (g_os.IsWinXPorLater() || g_os.IsWinMeorLater()) ? IDI_MAIN : IDI_TRAY_WIN9X;
  178. int g_IconTraySuspend = (g_IconTray == IDI_MAIN) ? IDI_SUSPEND : IDI_TRAY_WIN9X_SUSPEND;
  179.  
  180. DWORD g_OriginalTimeout;
  181.  
  182. global_struct g, g_default;
  183.  
  184. // I considered maintaining this on a per-quasi-thread basis (i.e. in global_struct), but the overhead
  185. // of having to check and restore the working directory when a suspended thread is resumed (especially
  186. // when the script has many high-frequency timers), and possibly changing the working directory
  187. // whenever a new thread is launched, doesn't seem worth it.  This is because the need to change
  188. // the working directory is comparatively rare:
  189. char g_WorkingDir[MAX_PATH] = "";
  190. char *g_WorkingDirOrig = NULL;  // Assigned a value in WinMain().
  191.  
  192. bool g_ContinuationLTrim = false;
  193. bool g_ForceKeybdHook = false;
  194. ToggleValueType g_ForceNumLock = NEUTRAL;
  195. ToggleValueType g_ForceCapsLock = NEUTRAL;
  196. ToggleValueType g_ForceScrollLock = NEUTRAL;
  197.  
  198. ToggleValueType g_BlockInputMode = TOGGLE_DEFAULT;
  199. bool g_BlockInput = false;
  200. bool g_BlockMouseMove = false;
  201.  
  202. // The order of initialization here must match the order in the enum contained in script.h
  203. // It's in there rather than in globaldata.h so that the action-type constants can be referred
  204. // to without having access to the global array itself (i.e. it avoids having to include
  205. // globaldata.h in modules that only need access to the enum's constants, which in turn prevents
  206. // many mutual dependency problems between modules).  Note: Action names must not contain any
  207. // spaces or tabs because within a script, those characters can be used in lieu of a delimiter
  208. // to separate the action-type-name from the first parameter.
  209. // Note about the sub-array: Since the parent array array is global, it would be automatically
  210. // zero-filled if we didn't provide specific initialization.  But since we do, I'm not sure
  211. // what value the unused elements in the NumericParams subarray will have.  Therefore, it seems
  212. // safest to always terminate these subarrays with an explicit zero, below.
  213.  
  214. // STEPS TO ADD A NEW COMMAND:
  215. // 1) Add an entry to the command enum in script.h.
  216. // 2) Add an entry to the below array (it's position here MUST exactly match that in the enum).
  217. //    The first item is the command name, the second is the minimum number of parameters (e.g.
  218. //    if you enter 3, the first 3 args are mandatory) and the third is the maximum number of
  219. //    parameters (the user need not escape commas within the last parameter).
  220. //    The subarray should indicate the param numbers that must be numeric (first param is numbered 1,
  221. //    not zero).  That subarray should be terminated with an explicit zero to be safe and
  222. //    so that the compiler will complain if the sub-array size needs to be increased to
  223. //    accommodate all the elements in the new sub-array, including room for it's 0 terminator.
  224. //    Note: If you use a value for MinParams than is greater than zero, remember than any params
  225. //    beneath that threshold will also be required to be non-blank (i.e. user can't omit them even
  226. //    if later, non-blank params are provided).  UPDATE: For a parameter to recognize an expression
  227. //    such as x+100, it must be listed in the sub-array as a pure numeric parameter.
  228. // 3) If the new command has any params that are output or input vars, change Line::ArgIsVar().
  229. // 4) Add any desired load-time validation in Script::AddLine() in an syntax-checking section.
  230. // 5) Implement the command in Line::Perform() or Line::EvaluateCondition (if it's an IF).
  231. //    If the command waits for anything (e.g. calls MsgSleep()), be sure to make a local
  232. //    copy of any ARG values that are needed during the wait period, because if another hotkey
  233. //    subroutine suspends the current one while its waiting, it could also overwrite the ARG
  234. //    deref buffer with its own values.
  235.  
  236. // v1.0.45 The following macro sets the high-bit for those commands that require overlap-checking of their
  237. // input/output variables during runtime (commands that don't have an output variable never need this byte
  238. // set, and runtime performance is improved even for them).  Some of commands are given the high-bit even
  239. // though they might not strictly require it because rarity/performance/maintainability say its best to do
  240. // so when in doubt.  Search on "MaxParamsAu2WithHighBit" for more details.
  241. #define H |(char)0x80
  242.  
  243. Action g_act[] =
  244. {
  245.     {"", 0, 0, 0, NULL}  // ACT_INVALID.
  246.  
  247.     // ACT_ASSIGN, ACT_ADD/SUB/MULT/DIV: Give them names for display purposes.
  248.     // Note: Line::ToText() relies on the below names being the correct symbols for the operation:
  249.     // 1st param is the target, 2nd (optional) is the value:
  250.     , {"=", 1, 2, 2 H, NULL}  // Omitting the second param sets the var to be empty. "H" (high-bit) is probably needed for those cases when PerformAssign() must call ExpandArgs() or similar.
  251.     , {":=", 1, 2, 2, {2, 0}} // Same, though param #2 is flagged as numeric so that expression detection is automatic.  "H" (high-bit) doesn't appear to be needed even when ACT_ASSIGNEXPR calls AssignBinaryClip() because that AssignBinaryClip() checks for source==dest.
  252.  
  253.     // ACT_EXPRESSION, which is a stand-alone expression outside of any IF or assignment-command;
  254.     // e.g. fn1(123, fn2(y)) or x&=3
  255.     // Its name should be "" so that Line::ToText() will properly display it.
  256.     , {"", 1, 1, 1, {1, 0}}
  257.  
  258.     , {"+=", 2, 3, 3, {2, 0}}
  259.     , {"-=", 1, 3, 3, {2, 0}} // Subtraction (but not addition) allows 2nd to be blank due to 3rd param.
  260.     , {"*=", 2, 2, 2, {2, 0}}
  261.     , {"/=", 2, 2, 2, {2, 0}}
  262.  
  263.     // This command is never directly parsed, but we need to have it here as a translation
  264.     // target for the old "repeat" command.  This is because that command treats a zero
  265.     // first-param as an infinite loop.  Since that param can be a dereferenced variable,
  266.     // there's no way to reliably translate each REPEAT command into a LOOP command at
  267.     // load-time.  Thus, we support both types of loops as actual commands that are
  268.     // handled separately at runtime.
  269.     , {"Repeat", 0, 1, 1, {1, 0}}  // Iteration Count: was mandatory in AutoIt2 but doesn't seem necessary here.
  270.     , {"Else", 0, 0, 0, NULL}
  271.  
  272.     , {"between", 1, 3, 3, NULL}, {"not between", 1, 3, 3, NULL}  // Min 1 to allow #2 and #3 to be the empty string.
  273.     , {"in", 2, 2, 2, NULL}, {"not in", 2, 2, 2, NULL}
  274.     , {"contains", 2, 2, 2, NULL}, {"not contains", 2, 2, 2, NULL}  // Very similar to "in" and "not in"
  275.     , {"is", 2, 2, 2, NULL}, {"is not", 2, 2, 2, NULL}
  276.     , {"", 1, 1, 1, {1, 0}} // ACT_IFEXPR's name should be "" so that Line::ToText() will properly display it.
  277.  
  278.     // Comparison operators take 1 param (if they're being compared to blank) or 2.
  279.     // For example, it's okay (though probably useless) to compare a string to the empty
  280.     // string this way: "If var1 >=".  Note: Line::ToText() relies on the below names:
  281.     , {"=", 1, 2, 2, NULL}, {"<>", 1, 2, 2, NULL}, {">", 1, 2, 2, NULL}
  282.     , {">=", 1, 2, 2, NULL}, {"<", 1, 2, 2, NULL}, {"<=", 1, 2, 2, NULL}
  283.  
  284.     // For these, allow a minimum of zero, otherwise, the first param (WinTitle) would
  285.     // be considered mandatory-non-blank by default.  It's easier to make all the params
  286.     // optional and validate elsewhere that at least one of the four isn't blank.
  287.     // Also, All the IFs must be physically adjacent to each other in this array
  288.     // so that ACT_FIRST_IF and ACT_LAST_IF can be used to detect if a command is an IF:
  289.     , {"IfWinExist", 0, 4, 4, NULL}, {"IfWinNotExist", 0, 4, 4, NULL}  // Title, text, exclude-title, exclude-text
  290.     // Passing zero params results in activating the LastUsed window:
  291.     , {"IfWinActive", 0, 4, 4, NULL}, {"IfWinNotActive", 0, 4, 4, NULL} // same
  292.     , {"IfInString", 2, 2, 2, NULL} // String var, search string
  293.     , {"IfNotInString", 2, 2, 2, NULL} // String var, search string
  294.     , {"IfExist", 1, 1, 1, NULL} // File or directory.
  295.     , {"IfNotExist", 1, 1, 1, NULL} // File or directory.
  296.     // IfMsgBox must be physically adjacent to the other IFs in this array:
  297.     , {"IfMsgBox", 1, 1, 1, NULL} // MsgBox result (e.g. OK, YES, NO)
  298.     , {"MsgBox", 0, 4, 3, {4, 0}} // Text (if only 1 param) or: Mode-flag, Title, Text, Timeout.
  299.     , {"InputBox", 1, 11, 11 H, {5, 6, 7, 8, 10, 0}} // Output var, title, prompt, hide-text (e.g. passwords), width, height, X, Y, Font (e.g. courier:8 maybe), Timeout, Default
  300.     , {"SplashTextOn", 0, 4, 4, {1, 2, 0}} // Width, height, title, text
  301.     , {"SplashTextOff", 0, 0, 0, NULL}
  302.     , {"Progress", 0, 6, 6, NULL}  // Off|Percent|Options, SubText, MainText, Title, Font, FutureUse
  303.     , {"SplashImage", 0, 7, 7, NULL}  // Off|ImageFile, |Options, SubText, MainText, Title, Font, FutureUse
  304.     , {"ToolTip", 0, 4, 4, {2, 3, 4, 0}}  // Text, X, Y, ID.  If Text is omitted, the Tooltip is turned off.
  305.     , {"TrayTip", 0, 4, 4, {3, 4, 0}}  // Title, Text, Timeout, Options
  306.  
  307.     , {"Input", 0, 4, 4 H, NULL}  // OutputVar, Options, EndKeys, MatchList.
  308.  
  309.     , {"Transform", 2, 4, 4 H, NULL}  // output var, operation, value1, value2
  310.  
  311.     , {"StringLeft", 3, 3, 3, {3, 0}}  // output var, input var, number of chars to extract
  312.     , {"StringRight", 3, 3, 3, {3, 0}} // same
  313.     , {"StringMid", 3, 5, 5, {3, 4, 0}} // Output Variable, Input Variable, Start char, Number of chars to extract, L
  314.     , {"StringTrimLeft", 3, 3, 3, {3, 0}}  // output var, input var, number of chars to trim
  315.     , {"StringTrimRight", 3, 3, 3, {3, 0}} // same
  316.     , {"StringLower", 2, 3, 3, NULL} // output var, input var, T = Title Case
  317.     , {"StringUpper", 2, 3, 3, NULL} // output var, input var, T = Title Case
  318.     , {"StringLen", 2, 2, 2, NULL} // output var, input var
  319.     , {"StringGetPos", 3, 5, 3, {5, 0}}  // Output Variable, Input Variable, Search Text, R or Right (from right), Offset
  320.     , {"StringReplace", 3, 5, 4, NULL} // Output Variable, Input Variable, Search String, Replace String, do-all.
  321.     , {"StringSplit", 2, 5, 5, NULL} // Output Array, Input Variable, Delimiter List (optional), Omit List, Future Use
  322.     , {"SplitPath", 1, 6, 6 H, NULL} // InputFilespec, OutName, OutDir, OutExt, OutNameNoExt, OutDrive
  323.     , {"Sort", 1, 2, 2, NULL} // OutputVar (it's also the input var), Options
  324.  
  325.     , {"EnvGet", 2, 2, 2 H, NULL} // OutputVar, EnvVar
  326.     , {"EnvSet", 1, 2, 2, NULL} // EnvVar, Value
  327.     , {"EnvUpdate", 0, 0, 0, NULL}
  328.  
  329.     , {"RunAs", 0, 3, 3, NULL} // user, pass, domain (0 params can be passed to disable the feature)
  330.     , {"Run", 1, 4, 4 H, NULL}      // TargetFile, Working Dir, WinShow-Mode/UseErrorLevel, OutputVarPID
  331.     , {"RunWait", 1, 4, 4 H, NULL}  // TargetFile, Working Dir, WinShow-Mode/UseErrorLevel, OutputVarPID
  332.     , {"URLDownloadToFile", 2, 2, 2, NULL} // URL, save-as-filename
  333.  
  334.     , {"GetKeyState", 2, 3, 3 H, NULL} // OutputVar, key name, mode (optional) P = Physical, T = Toggle
  335.     , {"Send", 1, 1, 1, NULL}         // But that first param can validly be a deref that resolves to a blank param.
  336.     , {"SendRaw", 1, 1, 1, NULL}      //
  337.     , {"SendInput", 1, 1, 1, NULL}    //
  338.     , {"SendPlay", 1, 1, 1, NULL}     //
  339.     , {"SendEvent", 1, 1, 1, NULL}    // (due to rarity, there is no raw counterpart for this one)
  340.  
  341.     // For these, the "control" param can be blank.  The window's first visible control will
  342.     // be used.  For this first one, allow a minimum of zero, otherwise, the first param (control)
  343.     // would be considered mandatory-non-blank by default.  It's easier to make all the params
  344.     // optional and validate elsewhere that the 2nd one specifically isn't blank:
  345.     , {"ControlSend", 0, 6, 6, NULL} // Control, Chars-to-Send, std. 4 window params.
  346.     , {"ControlSendRaw", 0, 6, 6, NULL} // Control, Chars-to-Send, std. 4 window params.
  347.     , {"ControlClick", 0, 8, 8, {5, 0}} // Control, WinTitle, WinText, WhichButton, ClickCount, Hold/Release, ExcludeTitle, ExcludeText
  348.     , {"ControlMove", 0, 9, 9, {2, 3, 4, 5, 0}} // Control, x, y, w, h, WinTitle, WinText, ExcludeTitle, ExcludeText
  349.     , {"ControlGetPos", 0, 9, 9 H, NULL} // Four optional output vars: xpos, ypos, width, height, control, std. 4 window params.
  350.     , {"ControlFocus", 0, 5, 5, NULL}     // Control, std. 4 window params
  351.     , {"ControlGetFocus", 1, 5, 5 H, NULL}  // OutputVar, std. 4 window params
  352.     , {"ControlSetText", 0, 6, 6, NULL}   // Control, new text, std. 4 window params
  353.     , {"ControlGetText", 1, 6, 6 H, NULL}   // Output-var, Control, std. 4 window params
  354.     , {"Control", 1, 7, 7, NULL}   // Command, Value, Control, std. 4 window params
  355.     , {"ControlGet", 2, 8, 8 H, NULL}   // Output-var, Command, Value, Control, std. 4 window params
  356.  
  357.     , {"SendMode", 1, 1, 1, NULL}
  358.     , {"CoordMode", 1, 2, 2, NULL} // Attribute, screen|relative
  359.     , {"SetDefaultMouseSpeed", 1, 1, 1, {1, 0}} // speed (numeric)
  360.     , {"Click", 0, 1, 1, NULL} // Flex-list of options.
  361.     , {"MouseMove", 2, 4, 4, {1, 2, 3, 0}} // x, y, speed, option
  362.     , {"MouseClick", 0, 7, 7, {2, 3, 4, 5, 0}} // which-button, x, y, ClickCount, speed, d=hold-down/u=release, Relative
  363.     , {"MouseClickDrag", 1, 7, 7, {2, 3, 4, 5, 6, 0}} // which-button, x1, y1, x2, y2, speed, Relative
  364.     , {"MouseGetPos", 0, 5, 5 H, {5, 0}} // 4 optional output vars: xpos, ypos, WindowID, ControlName. Finally: Mode. MinParams must be 0.
  365.  
  366.     , {"StatusBarGetText", 1, 6, 6 H, {2, 0}} // Output-var, part# (numeric), std. 4 window params
  367.     , {"StatusBarWait", 0, 8, 8, {2, 3, 6, 0}} // Wait-text(blank ok),seconds,part#,title,text,interval,exclude-title,exclude-text
  368.     , {"ClipWait", 0, 2, 2, {1, 2, 0}} // Seconds-to-wait (0 = 500ms), 1|0: Wait for any format, not just text/files
  369.     , {"KeyWait", 1, 2, 2, NULL} // KeyName, Options
  370.  
  371.     , {"Sleep", 1, 1, 1, {1, 0}} // Sleep time in ms (numeric)
  372.     , {"Random", 0, 3, 3, {2, 3, 0}} // Output var, Min, Max (Note: MinParams is 1 so that param2 can be blank).
  373.  
  374.     , {"Goto", 1, 1, 1, NULL}
  375.     , {"Gosub", 1, 1, 1, NULL}   // Label (or dereference that resolves to a label).
  376.     , {"OnExit", 0, 2, 2, NULL}  // Optional label, future use (since labels are allowed to contain commas)
  377.     , {"Hotkey", 1, 3, 3, NULL}  // Mod+Keys, Label/Action (blank to avoid changing curr. label), Options
  378.     , {"SetTimer", 1, 3, 3, {3, 0}}  // Label (or dereference that resolves to a label), period (or ON/OFF), Priority
  379.     , {"Critical", 0, 1, 1, NULL}  // On|Off
  380.     , {"Thread", 1, 3, 3, {2, 3, 0}}  // Command, value1 (can be blank for interrupt), value2
  381.     , {"Return", 0, 1, 1, {1, 0}}
  382.     , {"Exit", 0, 1, 1, {1, 0}} // ExitCode
  383.     , {"Loop", 0, 4, 4, NULL} // Iteration Count or FilePattern or root key name [,subkey name], FileLoopMode, Recurse? (custom validation for these last two)
  384.     , {"Break", 0, 0, 0, NULL}, {"Continue", 0, 0, 0, NULL}
  385.     , {"{", 0, 0, 0, NULL}, {"}", 0, 0, 0, NULL}
  386.  
  387.     , {"WinActivate", 0, 4, 2, NULL} // Passing zero params results in activating the LastUsed window.
  388.     , {"WinActivateBottom", 0, 4, 4, NULL} // Min. 0 so that 1st params can be blank and later ones not blank.
  389.  
  390.     // These all use Title, Text, Timeout (in seconds not ms), Exclude-title, Exclude-text.
  391.     // See above for why zero is the minimum number of params for each:
  392.     , {"WinWait", 0, 5, 5, {3, 0}}, {"WinWaitClose", 0, 5, 5, {3, 0}}
  393.     , {"WinWaitActive", 0, 5, 5, {3, 0}}, {"WinWaitNotActive", 0, 5, 5, {3, 0}}
  394.  
  395.     , {"WinMinimize", 0, 4, 2, NULL}, {"WinMaximize", 0, 4, 2, NULL}, {"WinRestore", 0, 4, 2, NULL} // std. 4 params
  396.     , {"WinHide", 0, 4, 2, NULL}, {"WinShow", 0, 4, 2, NULL} // std. 4 params
  397.     , {"WinMinimizeAll", 0, 0, 0, NULL}, {"WinMinimizeAllUndo", 0, 0, 0, NULL}
  398.     , {"WinClose", 0, 5, 2, {3, 0}} // title, text, time-to-wait-for-close (0 = 500ms), exclude title/text
  399.     , {"WinKill", 0, 5, 2, {3, 0}} // same as WinClose.
  400.     , {"WinMove", 0, 8, 8, {1, 2, 3, 4, 5, 6, 0}} // title, text, xpos, ypos, width, height, exclude-title, exclude_text
  401.     // Note for WinMove: title/text are marked as numeric because in two-param mode, they are the X/Y params.
  402.     // This helps speed up loading expression-detection.  Also, xpos/ypos/width/height can be the string "default",
  403.     // but that is explicitly checked for, even though it is required it to be numeric in the definition here.
  404.     , {"WinMenuSelectItem", 0, 11, 11, NULL} // WinTitle, WinText, Menu name, 6 optional sub-menu names, ExcludeTitle/Text
  405.  
  406.     , {"Process", 1, 3, 3, NULL}  // Sub-cmd, PID/name, Param3 (use minimum of 1 param so that 2nd can be blank)
  407.  
  408.     , {"WinSet", 1, 6, 6, NULL} // attribute, setting, title, text, exclude-title, exclude-text
  409.     // WinSetTitle: Allow a minimum of zero params so that title isn't forced to be non-blank.
  410.     // Also, if the user passes only one param, the title of the "last used" window will be
  411.     // set to the string in the first param:
  412.     , {"WinSetTitle", 0, 5, 3, NULL} // title, text, newtitle, exclude-title, exclude-text
  413.     , {"WinGetTitle", 1, 5, 3 H, NULL} // Output-var, std. 4 window params
  414.     , {"WinGetClass", 1, 5, 5 H, NULL} // Output-var, std. 4 window params
  415.     , {"WinGet", 1, 6, 6 H, NULL} // Output-var/array, cmd (if omitted, defaults to ID), std. 4 window params
  416.     , {"WinGetPos", 0, 8, 8 H, NULL} // Four optional output vars: xpos, ypos, width, height.  Std. 4 window params.
  417.     , {"WinGetText", 1, 5, 5 H, NULL} // Output var, std 4 window params.
  418.  
  419.     , {"SysGet", 2, 4, 4 H, NULL} // Output-var/array, sub-cmd or sys-metrics-number, input-value1, future-use
  420.  
  421.     , {"PostMessage", 1, 8, 8, {1, 2, 3, 0}}  // msg, wParam, lParam, Control, WinTitle, WinText, ExcludeTitle, ExcludeText
  422.     , {"SendMessage", 1, 8, 8, {1, 2, 3, 0}}  // msg, wParam, lParam, Control, WinTitle, WinText, ExcludeTitle, ExcludeText
  423.  
  424.     , {"PixelGetColor", 3, 4, 4 H, {2, 3, 0}} // OutputVar, X-coord, Y-coord [, RGB]
  425.     , {"PixelSearch", 0, 9, 9 H, {3, 4, 5, 6, 7, 8, 0}} // OutputX, OutputY, left, top, right, bottom, Color, Variation [, RGB]
  426.     , {"ImageSearch", 0, 7, 7 H, {3, 4, 5, 6, 0}} // OutputX, OutputY, left, top, right, bottom, ImageFile
  427.     // NOTE FOR THE ABOVE: 0 min args so that the output vars can be optional.
  428.  
  429.     // See above for why minimum is 1 vs. 2:
  430.     , {"GroupAdd", 1, 6, 6, NULL} // Group name, WinTitle, WinText, Label, exclude-title/text
  431.     , {"GroupActivate", 1, 2, 2, NULL}
  432.     , {"GroupDeactivate", 1, 2, 2, NULL}
  433.     , {"GroupClose", 1, 2, 2, NULL}
  434.  
  435.     , {"DriveSpaceFree", 2, 2, 2 H, NULL} // Output-var, path (e.g. c:\)
  436.     , {"Drive", 1, 3, 3, NULL} // Sub-command, Value1 (can be blank for Eject), Value2
  437.     , {"DriveGet", 0, 3, 3 H, NULL} // Output-var (optional in at least one case), Command, Value
  438.  
  439.     , {"SoundGet", 1, 4, 4 H, {4, 0}} // OutputVar, ComponentType (default=master), ControlType (default=vol), Mixer/Device Number
  440.     , {"SoundSet", 1, 4, 4, {1, 4, 0}} // Volume percent-level (0-100), ComponentType, ControlType (default=vol), Mixer/Device Number
  441.     , {"SoundGetWaveVolume", 1, 2, 2 H, {2, 0}} // OutputVar, Mixer/Device Number
  442.     , {"SoundSetWaveVolume", 1, 2, 2, {1, 2, 0}} // Volume percent-level (0-100), Device Number (1 is the first)
  443.     , {"SoundBeep", 0, 2, 2, {1, 2, 0}} // Frequency, Duration.
  444.     , {"SoundPlay", 1, 2, 2, NULL} // Filename [, wait]
  445.  
  446.     , {"FileAppend", 0, 2, 2, NULL} // text, filename (which can be omitted in a read-file loop). Update: Text can be omitted too, to create an empty file or alter the timestamp of an existing file.
  447.     , {"FileRead", 2, 2, 2 H, NULL} // Output variable, filename
  448.     , {"FileReadLine", 3, 3, 3 H, {3, 0}} // Output variable, filename, line-number
  449.     , {"FileDelete", 1, 1, 1, NULL} // filename or pattern
  450.     , {"FileRecycle", 1, 1, 1, NULL} // filename or pattern
  451.     , {"FileRecycleEmpty", 0, 1, 1, NULL} // optional drive letter (all bins will be emptied if absent.
  452.     , {"FileInstall", 2, 3, 3, {3, 0}} // source, dest, flag (1/0, where 1=overwrite)
  453.     , {"FileCopy", 2, 3, 3, {3, 0}} // source, dest, flag
  454.     , {"FileMove", 2, 3, 3, {3, 0}} // source, dest, flag
  455.     , {"FileCopyDir", 2, 3, 3, {3, 0}} // source, dest, flag
  456.     , {"FileMoveDir", 2, 3, 3, NULL} // source, dest, flag (which can be non-numeric in this case)
  457.     , {"FileCreateDir", 1, 1, 1, NULL} // dir name
  458.     , {"FileRemoveDir", 1, 2, 1, {2, 0}} // dir name, flag
  459.  
  460.     , {"FileGetAttrib", 1, 2, 2 H, NULL} // OutputVar, Filespec (if blank, uses loop's current file)
  461.     , {"FileSetAttrib", 1, 4, 4, {3, 4, 0}} // Attribute(s), FilePattern, OperateOnFolders?, Recurse? (custom validation for these last two)
  462.     , {"FileGetTime", 1, 3, 3 H, NULL} // OutputVar, Filespec, WhichTime (modified/created/accessed)
  463.     , {"FileSetTime", 0, 5, 5, {1, 4, 5, 0}} // datetime (YYYYMMDDHH24MISS), FilePattern, WhichTime, OperateOnFolders?, Recurse?
  464.     , {"FileGetSize", 1, 3, 3 H, NULL} // OutputVar, Filespec, B|K|M (bytes, kb, or mb)
  465.     , {"FileGetVersion", 1, 2, 2 H, NULL} // OutputVar, Filespec
  466.  
  467.     , {"SetWorkingDir", 1, 1, 1, NULL} // New path
  468.     , {"FileSelectFile", 1, 5, 3 H, NULL} // output var, options, working dir, greeting, filter
  469.     , {"FileSelectFolder", 1, 4, 4 H, {3, 0}} // output var, root directory, options, greeting
  470.  
  471.     , {"FileGetShortcut", 1, 8, 8 H, NULL} // Filespec, OutTarget, OutDir, OutArg, OutDescrip, OutIcon, OutIconIndex, OutShowState.
  472.     , {"FileCreateShortcut", 2, 9, 9, {8, 9, 0}} // file, lnk [, workdir, args, desc, icon, hotkey, icon_number, run_state]
  473.  
  474.     , {"IniRead", 4, 5, 4 H, NULL}   // OutputVar, Filespec, Section, Key, Default (value to return if key not found)
  475.     , {"IniWrite", 4, 4, 4, NULL}  // Value, Filespec, Section, Key
  476.     , {"IniDelete", 2, 3, 3, NULL} // Filespec, Section, Key
  477.  
  478.     // These require so few parameters due to registry loops, which provide the missing parameter values
  479.     // automatically.  In addition, RegRead can't require more than 1 param since the 2nd param is
  480.     // an option/obsolete parameter:
  481.     , {"RegRead", 1, 5, 5 H, NULL} // output var, (ValueType [optional]), RegKey, RegSubkey, ValueName
  482.     , {"RegWrite", 0, 5, 5, NULL} // ValueType, RegKey, RegSubKey, ValueName, Value (set to blank if omitted?)
  483.     , {"RegDelete", 0, 3, 3, NULL} // RegKey, RegSubKey, ValueName
  484.  
  485.     , {"OutputDebug", 1, 1, 1, NULL}
  486.  
  487.     , {"SetKeyDelay", 0, 3, 3, {1, 2, 0}} // Delay in ms (numeric, negative allowed), PressDuration [, Play]
  488.     , {"SetMouseDelay", 1, 2, 2, {1, 0}} // Delay in ms (numeric, negative allowed) [, Play]
  489.     , {"SetWinDelay", 1, 1, 1, {1, 0}} // Delay in ms (numeric, negative allowed)
  490.     , {"SetControlDelay", 1, 1, 1, {1, 0}} // Delay in ms (numeric, negative allowed)
  491.     , {"SetBatchLines", 1, 1, 1, NULL} // Can be non-numeric, such as 15ms, or a number (to indicate line count).
  492.     , {"SetTitleMatchMode", 1, 1, 1, NULL} // Allowed values: 1, 2, slow, fast
  493.     , {"SetFormat", 1, 2, 2, NULL} // Float|Integer, FormatString (for float) or H|D (for int)
  494.     , {"FormatTime", 1, 3, 3 H, NULL} // OutputVar, YYYYMMDDHH24MISS, Format (format is last to avoid having to escape commas in it).
  495.  
  496.     , {"Suspend", 0, 1, 1, NULL} // On/Off/Toggle/Permit/Blank (blank is the same as toggle)
  497.     , {"Pause", 0, 2, 2, NULL} // On/Off/Toggle/Blank (blank is the same as toggle), AlwaysAffectUnderlying
  498.     , {"AutoTrim", 1, 1, 1, NULL} // On/Off
  499.     , {"StringCaseSense", 1, 1, 1, NULL} // On/Off/Locale
  500.     , {"DetectHiddenWindows", 1, 1, 1, NULL} // On/Off
  501.     , {"DetectHiddenText", 1, 1, 1, NULL} // On/Off
  502.     , {"BlockInput", 1, 1, 1, NULL} // On/Off
  503.  
  504.     , {"SetNumlockState", 0, 1, 1, NULL} // On/Off/AlwaysOn/AlwaysOff or blank (unspecified) to return to normal.
  505.     , {"SetScrollLockState", 0, 1, 1, NULL} // same
  506.     , {"SetCapslockState", 0, 1, 1, NULL} // same
  507.     , {"SetStoreCapslockMode", 1, 1, 1, NULL} // On/Off
  508.  
  509.     , {"KeyHistory", 0, 2, 2, NULL}, {"ListLines", 0, 0, 0, NULL}
  510.     , {"ListVars", 0, 0, 0, NULL}, {"ListHotkeys", 0, 0, 0, NULL}
  511.  
  512.     , {"Edit", 0, 0, 0, NULL}
  513.     , {"Reload", 0, 0, 0, NULL}
  514.     , {"Menu", 2, 6, 6, NULL}  // tray, add, name, label, options, future use
  515.     , {"Gui", 1, 4, 4, NULL}  // Cmd/Add, ControlType, Options, Text
  516.     , {"GuiControl", 0, 3, 3 H, NULL} // Sub-cmd (defaults to "contents"), ControlName/ID, Text
  517.     , {"GuiControlGet", 1, 4, 4, NULL} // OutputVar, Sub-cmd (defaults to "contents"), ControlName/ID (defaults to control assoc. with OutputVar), Text/FutureUse
  518.  
  519.     , {"ExitApp", 0, 1, 1, NULL}  // Optional exit-code
  520.     , {"Shutdown", 1, 1, 1, {1, 0}} // Seems best to make the first param (the flag/code) mandatory.
  521. };
  522. // Below is the most maintainable way to determine the actual count?
  523. // Due to C++ lang. restrictions, can't easily make this a const because constants
  524. // automatically get static (internal) linkage, thus such a var could never be
  525. // used outside this module:
  526. int g_ActionCount = sizeof(g_act) / sizeof(Action);
  527.  
  528.  
  529.  
  530. Action g_old_act[] =
  531. {
  532.     {"", 0, 0, 0, NULL}  // OLD_INVALID.
  533.     , {"SetEnv", 1, 2, 2, NULL}
  534.     , {"EnvAdd", 2, 3, 3, {2, 0}}, {"EnvSub", 1, 3, 3, {2, 0}} // EnvSub (but not Add) allow 2nd to be blank due to 3rd param.
  535.     , {"EnvMult", 2, 2, 2, {2, 0}}, {"EnvDiv", 2, 2, 2, {2, 0}}
  536.     , {"IfEqual", 1, 2, 2, NULL}, {"IfNotEqual", 1, 2, 2, NULL}
  537.     , {"IfGreater", 1, 2, 2, NULL}, {"IfGreaterOrEqual", 1, 2, 2, NULL}
  538.     , {"IfLess", 1, 2, 2, NULL}, {"IfLessOrEqual", 1, 2, 2, NULL}
  539.     , {"LeftClick", 2, 2, 2, {1, 2, 0}}, {"RightClick", 2, 2, 2, {1, 2, 0}}
  540.     , {"LeftClickDrag", 4, 4, 4, {1, 2, 3, 4, 0}}, {"RightClickDrag", 4, 4, 4, {1, 2, 3, 4, 0}}
  541.     , {"HideAutoItWin", 1, 1, 1, NULL}
  542.       // Allow zero params, unlike AutoIt.  These params should match those for REPEAT in the above array:
  543.     , {"Repeat", 0, 1, 1, {1, 0}}, {"EndRepeat", 0, 0, 0, NULL}
  544.     , {"WinGetActiveTitle", 1, 1, 1, NULL} // <Title Var>
  545.     , {"WinGetActiveStats", 5, 5, 5, NULL} // <Title Var>, <Width Var>, <Height Var>, <Xpos Var>, <Ypos Var>
  546. };
  547. int g_OldActionCount = sizeof(g_old_act) / sizeof(Action);
  548.  
  549.  
  550. key_to_vk_type g_key_to_vk[] =
  551. { {"Numpad0", VK_NUMPAD0}
  552. , {"Numpad1", VK_NUMPAD1}
  553. , {"Numpad2", VK_NUMPAD2}
  554. , {"Numpad3", VK_NUMPAD3}
  555. , {"Numpad4", VK_NUMPAD4}
  556. , {"Numpad5", VK_NUMPAD5}
  557. , {"Numpad6", VK_NUMPAD6}
  558. , {"Numpad7", VK_NUMPAD7}
  559. , {"Numpad8", VK_NUMPAD8}
  560. , {"Numpad9", VK_NUMPAD9}
  561. , {"NumpadMult", VK_MULTIPLY}
  562. , {"NumpadDiv", VK_DIVIDE}
  563. , {"NumpadAdd", VK_ADD}
  564. , {"NumpadSub", VK_SUBTRACT}
  565. // , {"NumpadEnter", VK_RETURN}  // Must do this one via scan code, see below for explanation.
  566. , {"NumpadDot", VK_DECIMAL}
  567. , {"Numlock", VK_NUMLOCK}
  568. , {"ScrollLock", VK_SCROLL}
  569. , {"CapsLock", VK_CAPITAL}
  570.  
  571. , {"Escape", VK_ESCAPE}  // So that VKtoKeyName() delivers consistent results, always have the preferred name first.
  572. , {"Esc", VK_ESCAPE}
  573. , {"Tab", VK_TAB}
  574. , {"Space", VK_SPACE}
  575. , {"Backspace", VK_BACK} // So that VKtoKeyName() delivers consistent results, always have the preferred name first.
  576. , {"BS", VK_BACK}
  577.  
  578. // These keys each have a counterpart on the number pad with the same VK.  Use the VK for these,
  579. // since they are probably more likely to be assigned to hotkeys (thus minimizing the use of the
  580. // keyboard hook, and use the scan code (SC) for their counterparts.  UPDATE: To support handling
  581. // these keys with the hook (i.e. the sc_takes_precedence flag in the hook), do them by scan code
  582. // instead.  This allows Numpad keys such as Numpad7 to be differentiated from NumpadHome, which
  583. // would otherwise be impossible since both of them share the same scan code (i.e. if the
  584. // sc_takes_precedence flag is set for the scan code of NumpadHome, that will effectively prevent
  585. // the hook from telling the difference between it and Numpad7 since the hook is currently set
  586. // to handle an incoming key by either vk or sc, but not both.
  587.  
  588. // Even though ENTER is probably less likely to be assigned than NumpadEnter, must have ENTER as
  589. // the primary vk because otherwise, if the user configures only naked-NumPadEnter to do something,
  590. // RegisterHotkey() would register that vk and ENTER would also be configured to do the same thing.
  591. , {"Enter", VK_RETURN}  // So that VKtoKeyName() delivers consistent results, always have the preferred name first.
  592. , {"Return", VK_RETURN}
  593.  
  594. , {"NumpadDel", VK_DELETE}
  595. , {"NumpadIns", VK_INSERT}
  596. , {"NumpadClear", VK_CLEAR}  // same physical key as Numpad5 on most keyboards?
  597. , {"NumpadUp", VK_UP}
  598. , {"NumpadDown", VK_DOWN}
  599. , {"NumpadLeft", VK_LEFT}
  600. , {"NumpadRight", VK_RIGHT}
  601. , {"NumpadHome", VK_HOME}
  602. , {"NumpadEnd", VK_END}
  603. , {"NumpadPgUp", VK_PRIOR}
  604. , {"NumpadPgDn", VK_NEXT}
  605.  
  606. , {"PrintScreen", VK_SNAPSHOT}
  607. , {"CtrlBreak", VK_CANCEL}  // Might want to verify this, and whether it has any peculiarities.
  608. , {"Pause", VK_PAUSE} // So that VKtoKeyName() delivers consistent results, always have the preferred name first.
  609. , {"Break", VK_PAUSE} // Not really meaningful, but kept for as a synonym of Pause for backward compatibility.  See CtrlBreak.
  610. , {"Help", VK_HELP}  // VK_HELP is probably not the extended HELP key.  Not sure what this one is.
  611. , {"Sleep", VK_SLEEP}
  612.  
  613. , {"AppsKey", VK_APPS}
  614.  
  615. // UPDATE: For the NT/2k/XP version, now doing these by VK since it's likely to be
  616. // more compatible with non-standard or non-English keyboards:
  617. , {"LControl", VK_LCONTROL} // So that VKtoKeyName() delivers consistent results, always have the preferred name first.
  618. , {"RControl", VK_RCONTROL} // So that VKtoKeyName() delivers consistent results, always have the preferred name first.
  619. , {"LCtrl", VK_LCONTROL} // Abbreviated versions of the above.
  620. , {"RCtrl", VK_RCONTROL} //
  621. , {"LShift", VK_LSHIFT}
  622. , {"RShift", VK_RSHIFT}
  623. , {"LAlt", VK_LMENU}
  624. , {"RAlt", VK_RMENU}
  625. // These two are always left/right centric and I think their vk's are always supported by the various
  626. // Windows API calls, unlike VK_RSHIFT, etc. (which are seldom supported):
  627. , {"LWin", VK_LWIN}
  628. , {"RWin", VK_RWIN}
  629.  
  630. // The left/right versions of these are handled elsewhere since their virtual keys aren't fully API-supported:
  631. , {"Control", VK_CONTROL} // So that VKtoKeyName() delivers consistent results, always have the preferred name first.
  632. , {"Ctrl", VK_CONTROL}  // An alternate for convenience.
  633. , {"Alt", VK_MENU}
  634. , {"Shift", VK_SHIFT}
  635. /*
  636. These were used to confirm the fact that you can't use RegisterHotkey() on VK_LSHIFT, even if the shift
  637. modifier is specified along with it:
  638. , {"LShift", VK_LSHIFT}
  639. , {"RShift", VK_RSHIFT}
  640. */
  641. , {"F1", VK_F1}
  642. , {"F2", VK_F2}
  643. , {"F3", VK_F3}
  644. , {"F4", VK_F4}
  645. , {"F5", VK_F5}
  646. , {"F6", VK_F6}
  647. , {"F7", VK_F7}
  648. , {"F8", VK_F8}
  649. , {"F9", VK_F9}
  650. , {"F10", VK_F10}
  651. , {"F11", VK_F11}
  652. , {"F12", VK_F12}
  653. , {"F13", VK_F13}
  654. , {"F14", VK_F14}
  655. , {"F15", VK_F15}
  656. , {"F16", VK_F16}
  657. , {"F17", VK_F17}
  658. , {"F18", VK_F18}
  659. , {"F19", VK_F19}
  660. , {"F20", VK_F20}
  661. , {"F21", VK_F21}
  662. , {"F22", VK_F22}
  663. , {"F23", VK_F23}
  664. , {"F24", VK_F24}
  665.  
  666. // Mouse buttons:
  667. , {"LButton", VK_LBUTTON}
  668. , {"RButton", VK_RBUTTON}
  669. , {"MButton", VK_MBUTTON}
  670. // Supported in only in Win2k and beyond:
  671. , {"XButton1", VK_XBUTTON1}
  672. , {"XButton2", VK_XBUTTON2}
  673. // Custom/fake VKs for use by the mouse hook (supported only in WinNT SP3 and beyond?):
  674. , {"WheelDown", VK_WHEEL_DOWN}
  675. , {"WheelUp", VK_WHEEL_UP}
  676.  
  677. , {"Browser_Back", VK_BROWSER_BACK}
  678. , {"Browser_Forward", VK_BROWSER_FORWARD}
  679. , {"Browser_Refresh", VK_BROWSER_REFRESH}
  680. , {"Browser_Stop", VK_BROWSER_STOP}
  681. , {"Browser_Search", VK_BROWSER_SEARCH}
  682. , {"Browser_Favorites", VK_BROWSER_FAVORITES}
  683. , {"Browser_Home", VK_BROWSER_HOME}
  684. , {"Volume_Mute", VK_VOLUME_MUTE}
  685. , {"Volume_Down", VK_VOLUME_DOWN}
  686. , {"Volume_Up", VK_VOLUME_UP}
  687. , {"Media_Next", VK_MEDIA_NEXT_TRACK}
  688. , {"Media_Prev", VK_MEDIA_PREV_TRACK}
  689. , {"Media_Stop", VK_MEDIA_STOP}
  690. , {"Media_Play_Pause", VK_MEDIA_PLAY_PAUSE}
  691. , {"Launch_Mail", VK_LAUNCH_MAIL}
  692. , {"Launch_Media", VK_LAUNCH_MEDIA_SELECT}
  693. , {"Launch_App1", VK_LAUNCH_APP1}
  694. , {"Launch_App2", VK_LAUNCH_APP2}
  695.  
  696. // Probably safest to terminate it this way, with a flag value.  (plus this makes it a little easier
  697. // to code some loops, maybe).  Can also calculate how many elements are in the array using sizeof(array)
  698. // divided by sizeof(element).  UPDATE: Decided not to do this in case ever decide to sort this array; don't
  699. // want to rely on the fact that this will wind up in the right position after the sort (even though it
  700. // should):
  701. //, {"", 0}
  702. };
  703.  
  704.  
  705.  
  706. key_to_sc_type g_key_to_sc[] =
  707. // Even though ENTER is probably less likely to be assigned than NumpadEnter, must have ENTER as
  708. // the primary vk because otherwise, if the user configures only naked-NumPadEnter to do something,
  709. // RegisterHotkey() would register that vk and ENTER would also be configured to do the same thing.
  710. { {"NumpadEnter", SC_NUMPADENTER}
  711.  
  712. , {"Delete", SC_DELETE}
  713. , {"Del", SC_DELETE}
  714. , {"Insert", SC_INSERT}
  715. , {"Ins", SC_INSERT}
  716. // , {"Clear", SC_CLEAR}  // Seems unnecessary because there is no counterpart to the Numpad5 clear key?
  717. , {"Up", SC_UP}
  718. , {"Down", SC_DOWN}
  719. , {"Left", SC_LEFT}
  720. , {"Right", SC_RIGHT}
  721. , {"Home", SC_HOME}
  722. , {"End", SC_END}
  723. , {"PgUp", SC_PGUP}
  724. , {"PgDn", SC_PGDN}
  725.  
  726. // If user specified left or right, must use scan code to distinguish *both* halves of the pair since
  727. // each half has same vk *and* since their generic counterparts (e.g. CONTROL vs. L/RCONTROL) are
  728. // already handled by vk.  Note: RWIN and LWIN don't need to be handled here because they each have
  729. // their own virtual keys.
  730. // UPDATE: For the NT/2k/XP version, now doing these by VK since it's likely to be
  731. // more compatible with non-standard or non-English keyboards:
  732. /*
  733. , {"LControl", SC_LCONTROL}
  734. , {"RControl", SC_RCONTROL}
  735. , {"LShift", SC_LSHIFT}
  736. , {"RShift", SC_RSHIFT}
  737. , {"LAlt", SC_LALT}
  738. , {"RAlt", SC_RALT}
  739. */
  740. };
  741.  
  742.  
  743. // Can calc the counts only after the arrays are initialized above:
  744. int g_key_to_vk_count = sizeof(g_key_to_vk) / sizeof(key_to_vk_type);
  745. int g_key_to_sc_count = sizeof(g_key_to_sc) / sizeof(key_to_sc_type);
  746.  
  747. KeyHistoryItem *g_KeyHistory = NULL; // Array is allocated during startup.
  748. int g_KeyHistoryNext = 0;
  749.  
  750. #ifdef ENABLE_KEY_HISTORY_FILE
  751. bool g_KeyHistoryToFile = false;
  752. #endif
  753.  
  754. // These must be global also, since both the keyboard and mouse hook functions,
  755. // in addition to KeyEvent() when it's logging keys with only the mouse hook installed,
  756. // MUST refer to the same variables.  Otherwise, the elapsed time between keyboard and
  757. // and mouse events will be wrong:
  758. DWORD g_HistoryTickNow = 0;
  759. DWORD g_HistoryTickPrev = GetTickCount();  // So that the first logged key doesn't have a huge elapsed time.
  760. HWND g_HistoryHwndPrev = NULL;
  761.  
  762. // Also hook related:
  763. DWORD g_TimeLastInputPhysical = GetTickCount();
  764.