"Fossies" - the Fresh Open Source Software Archive

Member "AutoHotkey_L-" (8 May 2021, 19437 Bytes) of package /windows/misc/AutoHotkey_L-

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

    1 /*
    2 AutoHotkey
    4 Copyright 2003-2009 Chris Mallett (support@autohotkey.com)
    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.
   11 This program is distributed in the hope that it will be useful,
   12 but WITHOUT ANY WARRANTY; without even the implied warranty of
   14 GNU General Public License for more details.
   15 */
   17 #ifndef hook_h
   18 #define hook_h
   20 #include "hotkey.h" // Use here and also by hook.cpp for ChangeHookState(), which reads from static Hotkey class vars.
   22 // WM_USER is the lowest number that can be a user-defined message.  Anything above that is also valid.
   23 // NOTE: Any msg about WM_USER will be kept buffered (unreplied-to) whenever the script is uninterruptible.
   24 // If this is a problem, try making the msg have an ID less than WM_USER via a technique such as that used
   25 // for AHK_USER_MENU (perhaps WM_COMMNOTIFY can be "overloaded" to contain more than one type of msg).
   26 // Also, it has been announced in OnMessage() that message numbers between WM_USER and 0x1000 are earmarked
   27 // for possible future use by the program, so don't use a message above 0x1000 without good reason.
   30     // Allow some room here in between for more "exit" type msgs to be added in the future (see below comment).
   31     , AHK_GUI_ACTION = WM_USER+20 // Avoid WM_USER+100/101 and vicinity.  See below comment.
   32     // v1.0.43.05: On second thought, it seems better to stay close to WM_USER because the OnMessage page
   33     // documents, "it is best to choose a number greater than 4096 (0x1000) to the extent you have a choice.
   34     // This reduces the chance of interfering with messages used internally by current and future versions..."
   35     // v1.0.43.03: Changed above msg number because Micha reports that previous number (WM_USER+100) conflicts
   36     // with msgs sent by HTML control (AHK_CLIPBOARD_CHANGE) and possibly others (I think WM_USER+100 may be the
   37     // start of a range used by other common controls too).  So trying a higher number that's (hopefully) very
   38     // unlikely to be used by OS features.
   40     , AHK_HOT_IF_EVAL   // HotCriterionAllowsFiring uses this to ensure expressions are evaluated only on the main thread.
   41     , AHK_HOOK_SYNC // For WaitHookIdle().
   43 };
   44 // NOTE: TRY NEVER TO CHANGE the specific numbers of the above messages, since some users might be
   45 // using the Post/SendMessage commands to automate AutoHotkey itself.  Here is the original order
   46 // that should be maintained:
   49 // UPDATE to the below comment: After a careful review, it seems best to buffer a user's selection of
   50 // a custom menu item if the current quasi-thread is uninterruptible.  This is exactly the same way
   51 // hotkeys are buffered.  By making a thread truly uninterruptible, behavior is more consistent with
   52 // what most users would want, though it should be noted that this also makes it impossible for the
   53 // OnExit subroutine to be interrupted by a custom menu item, even one that is designed to simply
   54 // exit the script (by means of aborting the on-exit subroutine).  Another reason to buffer the
   55 // selection of a custom menu item is that we don't want to interrupt the current thread if is
   56 // right in the middle of executing a single line, e.g. doing something with the deref buffer
   57 // (during which time an interruption might destroy the buffer's contents) or trying to open the
   58 // clipboard or save data to it.  This particular weakness may be resolved when/if a dedicated
   59 // thread is created to maintain the hook(s), thus allowing critical operations such as opening
   60 // the clipboard to use a true Sleep() rather than MsgSleep().
   61 // Since WM_COMMNOTIFY is never generated by the Win32 API, and since we want AHK_USER_MENU to be
   62 // an ID less than WM_HOTKEY so that it doesn't get filtered out when the script is uninterruptible,
   63 // the following trick is used to map our user-defined messages onto WM_COMMNOTIFY by sacrificing the
   64 // wParam part of the message (using it as an indicator of what the message really is).
   65 // Another reserved msg that might be fairly safe is WM_MDIICONARRANGE, but it's far less preferable:
   66 #define TRANSLATE_AHK_MSG(msg, wparam) \
   67     if (msg == WM_COMMNOTIFY)\
   68     {\
   69         msg = (UINT)wparam;\
   70         wparam = 0;\
   71     } // In the above, wparam is made zero to help catch bugs.
   73 // And these macros are kept here so that all this trickery is centrally located and thus more maintainable:
   74 #define ASK_INSTANCE_TO_CLOSE(hwnd, reason) PostMessage(hwnd, WM_COMMNOTIFY, reason, 0);
   76 // POST_AHK_USER_MENU: A gui_hwnd value != 0 is passed with the message if it came from a GUI's menu bar.
   77 // This is done because it's good way to pass the info, but also so that its value will be in sync with the
   78 // timestamp of the message (in case the message is stuck in the queue for a long time).  No pointer is
   79 // passed in this case since they might become invalid between the time the msg is posted vs. processed.
   80 #define POST_AHK_USER_MENU(hwnd, menu, gui_hwnd) PostMessage(hwnd, AHK_USER_MENU, gui_hwnd, menu);
   81 #define POST_AHK_GUI_ACTION(hwnd, control_index, gui_event, event_info) PostMessage(hwnd, AHK_GUI_ACTION \
   82     , (WPARAM)(((control_index) << 16) | (gui_event)), (LPARAM)(event_info)); // Caller must ensure that gui_event is less than 0xFFFF.
   84 // Post a special msg that will attempt to force it to the foreground after it has been displayed,
   85 // since the dialog often will flash in the task bar instead of becoming foreground.
   86 // It's enough just to queue up a single message that dialog's message pump will forward to our
   87 // main window proc once the dialog window has been displayed.  This avoids the overhead of creating
   88 // and destroying the timer (although the timer may be needed anyway if any timed subroutines are
   89 // enabled).  My only concern about this is that on some OS's, or on slower CPUs, the message may be
   90 // received too soon (before the dialog window actually exists) resulting in our window proc not
   91 // being able to ensure that it's the foreground window.  That seems unlikely, however, since
   92 // MessageBox() and the other dialog invocating API calls (for FileSelectFile/Folder) likely
   93 // ensures its window really exists before dispatching messages.
   94 #define POST_AHK_DIALOG(timeout) PostMessage(g_hWnd, WM_COMMNOTIFY, AHK_DIALOG, (LPARAM)timeout);
   96 // Some reasoning behind the below data structures: Could build a new array for [sc][sc] and [vk][vk]
   97 // (since only two keys are allowed in a ModifierVK/SC combination, only 2 dimensions are needed).
   98 // But this would be a 512x512 array of shorts just for the SC part, which is 512K.  Instead, what we
   99 // do is check whenever a key comes in: if it's a suffix and if a non-standard modifier key of any kind
  100 // is currently down: consider action.  Most of the time, an action be found because the user isn't
  101 // likely to be holding down a ModifierVK/SC, while pressing another key, unless it's modifying that key.
  102 // Nor is he likely to have more than one ModifierVK/SC held down at a time.  It's still somewhat
  103 // inefficient because have to look up the right prefix in a loop.  But most suffixes probably won't
  104 // have more than one ModifierVK/SC anyway, so the lookup will usually find a match on the first
  105 // iteration.
  106 struct vk_hotkey
  107 {
  108     vk_type vk;
  109     HotkeyIDType id_with_flags;
  110 };
  111 struct sc_hotkey
  112 {
  113     sc_type sc;
  114     HotkeyIDType id_with_flags;
  115 };
  117 // Style reminder: Any POD structs (those without any methods) don't use the "m" prefix
  118 // for member variables because there's no need: the variables are always prefixed by
  119 // the struct that owns them, so there's never any ambiguity:
  120 struct key_type
  121 {
  122     ToggleValueType *pForceToggle;  // Pointer to a global variable for toggleable keys only.  NULL for others.
  123     // Keep sub-32-bit members contiguous to save memory without having to sacrifice performance of
  124     // 32-bit alignment:
  125     HotkeyIDType hotkey_to_fire_upon_release; // A up-event hotkey queued by a prior down-event.
  126     HotkeyIDType first_hotkey; // The first hotkey using this key as a suffix.
  127     modLR_type as_modifiersLR; // If this key is a modifier, this will have the corresponding bit(s) for that key.
  128     #define PREFIX_ACTUAL 1 // Values for used_as_prefix below, for places that need to distinguish between type of prefix.
  129     #define PREFIX_FORCED 2 // v1.0.44: Added so that a neutral hotkey like Control can be forced to fire on key-up even though it isn't actually a prefix key.
  130     UCHAR used_as_prefix; // Whether a given virtual key or scan code is even used by a hotkey.
  131     bool used_as_suffix;  //
  132     bool used_as_key_up;  // Whether this suffix also has an enabled key-up hotkey.
  133     UCHAR no_suppress; // Contains bitwise flags such as NO_SUPPRESS_PREFIX.
  134     bool is_down; // this key is currently down.
  135     bool it_put_alt_down;  // this key resulted in ALT being pushed down (due to alt-tab).
  136     bool it_put_shift_down;  // this key resulted in SHIFT being pushed down (due to shift-alt-tab).
  137     bool down_performed_action; // the last key-down resulted in an action (modifiers matched those of a valid hotkey)
  138     bool hotkey_down_was_suppressed; // Whether the down-event for a key was suppressed (thus its up-event should be too).
  139     // The values for "was_just_used" (zero is the initialized default, meaning it wasn't just used):
  140     char was_just_used; // a non-modifier key of any kind was pressed while this prefix key was down.
  141     // And these are the values for the above (besides 0):
  142     #define AS_PREFIX 1
  143     #define AS_PREFIX_FOR_HOTKEY 2
  144     bool sc_takes_precedence; // used only by the scan code array: this scan code should take precedence over vk.
  145 }; // Keep the macro below in sync with the above.
  147 // Fix for v1.0.43.01: Caller wants item.no_suppress initialized to remove all flags except NO_SUPPRESS_STATES.
  148 // Otherwise, a hotkey that removes the mouse hook will cause a non-suppressed key-up to become suppressed,
  149 // causing the key to get stuck down.  The following two-line script can reproduce this:
  150 //   ~LCtrl::Hotkey, RButton, Off
  151 //   RButton::return
  152 #define RESET_KEYTYPE_ATTRIB(item) \
  153 {\
  154     item.first_hotkey = HOTKEY_ID_INVALID;\
  155     item.used_as_prefix = 0;\
  156     item.used_as_suffix = false;\
  157     item.used_as_key_up = false;\
  158     item.no_suppress &= NO_SUPPRESS_STATES;\
  159     item.sc_takes_precedence = false;\
  160 }
  162 // Since index zero is a placeholder for the invalid virtual key or scan code, add one to each MAX value
  163 // to compute the number of elements actually needed to accommodate 0 up to and including VK_MAX or SC_MAX:
  164 #define VK_ARRAY_COUNT (VK_MAX + 1)
  165 #define SC_ARRAY_COUNT (SC_MAX + 1)
  167 #define INPUT_BUFFER_SIZE 16384 // Default buffer size for Input.  Used to be the absolute max.
  168 #define INPUTHOOK_BUFFER_SIZE 1024 // Default buffer size for InputHook.
  173 // Bitwise flags for the Key arrays:
  174 #define END_KEY_WITH_SHIFT 0x01
  175 #define END_KEY_WITHOUT_SHIFT 0x02
  177 #define INPUT_KEY_SUPPRESS 0x04
  178 #define INPUT_KEY_VISIBLE 0x08
  180 #define INPUT_KEY_IGNORE_TEXT 0x10
  181 #define INPUT_KEY_NOTIFY 0x20
  182 #define INPUT_KEY_OPTION_MASK 0x3F
  183 #define INPUT_KEY_IS_TEXT 0x40
  184 #define INPUT_KEY_DOWN_SUPPRESSED 0x80
  186 class InputObject;
  187 struct input_type
  188 {
  189     InputStatusType Status;
  190     input_type *Prev;
  191     InputObject *ScriptObject;
  192     LPTSTR Buffer; // Stores the user's actual input.
  193     int BufferLength; // The current length of what the user entered.
  194     int BufferLengthMax; // The maximum allowed length of the input.
  195     TCHAR *EndChars; // A string of characters that should terminate the input.
  196     UINT EndCharsMax; // Current size of EndChars buffer.
  197     LPTSTR *match; // Array of strings, each string is a match-phrase which if entered, terminates the input.
  198     UINT MatchCount; // The number of strings currently in the array.
  199     UINT MatchCountMax; // The maximum number of strings that the match array can contain.
  200     #define INPUT_ARRAY_BLOCK_SIZE 1024  // The increment by which the above array expands.
  201     LPTSTR MatchBuf; // The is the buffer whose contents are pointed to by the match array.
  202     UINT MatchBufSize; // The capacity of the above buffer.
  203     int Timeout;
  204     DWORD TimeoutAt;
  205     SendLevelType MinSendLevel; // The minimum SendLevel that can be captured by this input (0 allows all).
  206     bool BackspaceIsUndo;
  207     bool CaseSensitive;
  208     bool TranscribeModifiedKeys; // Whether the input command will attempt to transcribe modified keys such as ^c.
  209     bool VisibleText, VisibleNonText;
  210     bool NotifyNonText;
  211     bool FindAnywhere;
  212     bool EndCharMode;
  213     vk_type EndingVK; // The hook puts the terminating key into one of these if that's how it was terminated.
  214     sc_type EndingSC;
  215     TCHAR EndingChar;
  216     bool EndingBySC; // Whether the Ending key was one handled by VK or SC.
  217     bool EndingRequiredShift; // Whether the key that terminated the input was one that needed the SHIFT key.
  218     modLR_type EndingMods;
  219     UINT EndingMatchIndex;
  220     UCHAR KeyVK[VK_ARRAY_COUNT]; // A sparse array of key flags by VK.
  221     UCHAR KeySC[SC_ARRAY_COUNT]; // A sparse array of key flags by SC.
  222     input_type::input_type() // A simple constructor to initialize the fields that need it.
  223         : Status(INPUT_OFF), Prev(NULL), ScriptObject(NULL)
  224         , Buffer(NULL), match(NULL), MatchBuf(NULL), MatchBufSize(0)
  225         , EndChars(NULL), EndCharsMax(0), KeyVK(), KeySC(), BufferLength(0)
  226         , EndingMods(0)
  227         // Default options:
  228         , MinSendLevel(0), BackspaceIsUndo(true), CaseSensitive(false), TranscribeModifiedKeys(false)
  229         , VisibleText(false), VisibleNonText(true), NotifyNonText(false), FindAnywhere(false), EndCharMode(false)
  230         , BufferLengthMax(INPUTHOOK_BUFFER_SIZE - 1), Timeout(0)
  231     {
  232     }
  233     ~input_type()
  234     {
  235         free(Buffer);
  236         free(match);
  237         free(MatchBuf);
  238         if (EndCharsMax) // If zero, EndChars may point to static memory.
  239             free(EndChars);
  240     }
  241     inline bool InProgress() { return Status == INPUT_IN_PROGRESS; }
  242     bool IsInteresting(KBDLLHOOKSTRUCT &aEvent);
  243     ResultType Setup(LPTSTR aOptions, LPTSTR aEndKeys, LPTSTR aMatchList, size_t aMatchList_length);
  244     void ParseOptions(LPTSTR aOptions);
  245     void SetTimeoutTimer();
  246     ResultType SetKeyFlags(LPTSTR aKeys, bool aEndKeyMode = true, UCHAR aFlagsRemove = 0, UCHAR aFlagsAdd = END_KEY_ENABLED);
  247     ResultType SetMatchList(LPTSTR aMatchList, size_t aMatchList_length);
  248     void Start();
  249     void EndByMatch(UINT aMatchIndex);
  250     void EndByKey(vk_type aVK, sc_type aSC, bool aBySC, bool aRequiredShift);
  251     void EndByChar(TCHAR aChar);
  252     void EndByTimeout() { EndByReason(INPUT_TIMED_OUT); }
  253     void EndByLimit() { EndByReason(INPUT_LIMIT_REACHED); }
  254     void EndByNewInput() { EndByReason(INPUT_INTERRUPTED); }
  255     void Stop() { EndByReason(INPUT_OFF); }
  256     void CollectChar(TCHAR *ch, int char_count);
  257     LPTSTR GetEndReason(LPTSTR aKeyBuf, int aKeyBufSize, bool aCombined = true);
  258 private:
  259     void EndByReason(InputStatusType aReason);
  260 };
  262 #include "input_object.h"
  264 ResultType InputStart(input_type &input, Var *output_var = NULL);
  265 ResultType InputWait(Var *output_var, input_type &input);
  266 input_type *InputRelease(input_type *aInput);
  267 input_type *InputFind(InputObject *object);
  270 //-------------------------------------------
  272 struct KeyHistoryItem
  273 {
  274     vk_type vk;
  275     sc_type sc;
  276     TCHAR event_type; // space=none, i=ignored, s=suppressed, h=hotkey, etc.
  277     bool key_up;
  278     float elapsed_time;  // Time since prior key or mouse button, in seconds.
  279     // It seems better to store the foreground window's title rather than its HWND since keystrokes
  280     // might result in a window closing (being destroyed), in which case the displayed key history
  281     // would not be able to display the title at the time the history is displayed, which would
  282     // be undesirable.
  283     // To save mem, could point this into a shared buffer instead, but if that buffer were to run
  284     // out of space (perhaps due to the target window changing frequently), window logging would
  285     // no longer be possible without adding complexity to the logging function.  Seems best
  286     // to keep it simple:
  288     TCHAR target_window[KEY_HISTORY_WINDOW_TITLE_SIZE];
  289 };
  292 //-------------------------------------------
  295 LRESULT CALLBACK LowLevelKeybdProc(int aCode, WPARAM wParam, LPARAM lParam);
  296 LRESULT CALLBACK LowLevelMouseProc(int aCode, WPARAM wParam, LPARAM lParam);
  297 LRESULT LowLevelCommon(const HHOOK aHook, int aCode, WPARAM wParam, LPARAM lParam, const vk_type aVK
  298     , sc_type aSC, bool aKeyUp, ULONG_PTR aExtraInfo, DWORD aEventFlags);
  300 #define HOTSTRING_INDEX_INVALID INT_MAX  // Use a signed maximum rather than unsigned, in case indexes ever become signed.
  301 #define SuppressThisKey SuppressThisKeyFunc(aHook, lParam, aVK, aSC, aKeyUp, aExtraInfo, pKeyHistoryCurr, hotkey_id_to_post)
  302 LRESULT SuppressThisKeyFunc(const HHOOK aHook, LPARAM lParam, const vk_type aVK, const sc_type aSC
  303     , bool aKeyUp, ULONG_PTR aExtraInfo, KeyHistoryItem *pKeyHistoryCurr, WPARAM aHotkeyIDToPost
  304     , WPARAM aHSwParamToPost = HOTSTRING_INDEX_INVALID, LPARAM aHSlParamToPost = 0);
  306 #define AllowKeyToGoToSystem AllowIt(aHook, aCode, wParam, lParam, aVK, aSC, aKeyUp, aExtraInfo, pKeyHistoryCurr, hotkey_id_to_post)
  307 LRESULT AllowIt(const HHOOK aHook, int aCode, WPARAM wParam, LPARAM lParam, const vk_type aVK, const sc_type aSC
  308     , bool aKeyUp, ULONG_PTR aExtraInfo, KeyHistoryItem *pKeyHistoryCurr, WPARAM aHotkeyIDToPost);
  310 bool CollectInput(KBDLLHOOKSTRUCT &aEvent, const vk_type aVK, const sc_type aSC, bool aKeyUp, bool aIsIgnored
  311     , KeyHistoryItem *pKeyHistoryCurr, WPARAM &aHotstringWparamToPost, LPARAM &aHotstringLparamToPost);
  312 bool CollectHotstring(KBDLLHOOKSTRUCT &aEvent, TCHAR aChar[], int aCharCount, HWND aActiveWindow
  313     , KeyHistoryItem *pKeyHistoryCurr, WPARAM &aHotstringWparamToPost, LPARAM &aHotstringLparamToPost);
  314 bool CollectInputHook(KBDLLHOOKSTRUCT &aEvent, const vk_type aVK, const sc_type aSC, TCHAR aChar[], int aCharCount, bool aIsIgnored);
  315 bool IsHotstringWordChar(TCHAR aChar);
  316 void UpdateKeybdState(KBDLLHOOKSTRUCT &aEvent, const vk_type aVK, const sc_type aSC, bool aKeyUp, bool aIsSuppressed);
  317 bool KeybdEventIsPhysical(DWORD aEventFlags, const vk_type aVK, bool aKeyUp);
  319 void ChangeHookState(Hotkey *aHK[], int aHK_count, HookType aWhichHook, HookType aWhichHookAlways);
  320 void AddRemoveHooks(HookType aHooksToBeActive, bool aChangeIsTemporary = false);
  321 bool HookAdjustMaxHotkeys(Hotkey **&aHK, int &aCurrentMax, int aNewMax);
  322 bool SystemHasAnotherKeybdHook();
  323 bool SystemHasAnotherMouseHook();
  324 DWORD WINAPI HookThreadProc(LPVOID aUnused);
  326 void LinkKeysForCustomCombo(vk_type aNeutral, vk_type aLeft, vk_type aRight);
  328 void ResetHook(bool aAllModifiersUp = false, HookType aWhichHook = (HOOK_KEYBD | HOOK_MOUSE)
  329     , bool aResetKVKandKSC = false);
  330 HookType GetActiveHooks();
  331 void FreeHookMem();
  332 void ResetKeyTypeState(key_type &key);
  333 void GetHookStatus(LPTSTR aBuf, int aBufSize);
  335 void WaitHookIdle();
  337 #endif