Skip to content

Commit

Permalink
Merge branch 'InputLevel' of git://github.com/russelldavis/AutoHotkey_L
Browse files Browse the repository at this point in the history
  • Loading branch information
Lexikos committed Jan 14, 2012
2 parents c52d085 + 8d086e2 commit f85a680
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 25 deletions.
2 changes: 2 additions & 0 deletions source/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,7 @@ bool MsgSleep(int aSleepDuration, MessageMode aMode)

case AHK_HOTSTRING:
g.hWndLastUsed = criterion_found_hwnd; // v1.0.42. Even if the window is invalid for some reason, IsWindow() and such are called whenever the script accesses it (GetValidLastUsedWindow()).
g.SendLevel = hs->mInputLevel;
hs->PerformInNewThreadMadeByCaller();
break;

Expand All @@ -1290,6 +1291,7 @@ bool MsgSleep(int aSleepDuration, MessageMode aMode)
g.EventInfo = (DWORD)msg.lParam; // v1.0.43.03: Override the thread default of 0 with the number of notches by which the wheel was turned.
// Above also works for RunAgainAfterFinished since that feature reuses the same thread attributes set above.
g.hWndLastUsed = criterion_found_hwnd; // v1.0.42. Even if the window is invalid for some reason, IsWindow() and such are called whenever the script accesses it (GetValidLastUsedWindow()).
g.SendLevel = variant->mInputLevel;
hk->PerformInNewThreadMadeByCaller(*variant);
}

Expand Down
14 changes: 13 additions & 1 deletion source/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ enum enum_act {
, ACT_SEND, ACT_SENDRAW, ACT_SENDINPUT, ACT_SENDPLAY, ACT_SENDEVENT
, ACT_CONTROLSEND, ACT_CONTROLSENDRAW, ACT_CONTROLCLICK, ACT_CONTROLMOVE, ACT_CONTROLGETPOS, ACT_CONTROLFOCUS
, ACT_CONTROLGETFOCUS, ACT_CONTROLSETTEXT, ACT_CONTROLGETTEXT, ACT_CONTROL, ACT_CONTROLGET
, ACT_SENDMODE, ACT_COORDMODE, ACT_SETDEFAULTMOUSESPEED
, ACT_SENDMODE, ACT_SENDLEVEL, ACT_COORDMODE, ACT_SETDEFAULTMOUSESPEED
, ACT_CLICK, ACT_MOUSEMOVE, ACT_MOUSECLICK, ACT_MOUSECLICKDRAG, ACT_MOUSEGETPOS
, ACT_STATUSBARGETTEXT
, ACT_STATUSBARWAIT
Expand Down Expand Up @@ -568,6 +568,16 @@ typedef USHORT CoordModeType;

typedef UINT_PTR EventInfoType;

typedef UCHAR SendLevelType;
// Setting the max level to 100 is somewhat arbitrary. It seems that typical usage would only
// require a few levels at most. We do want to keep the max somewhat small to keep the range
// for magic values that get used in dwExtraInfo to a minimum, to avoid conflicts with other
// apps that may be using the field in other ways.
const SendLevelType SendLevelMax = 100;
// Using int as the type for level so this can be used as validation before converting to SendLevelType.
inline bool SendLevelIsValid(int level) { return level >= 0 && level <= SendLevelMax; }


// Same reason as above struct. It's best to keep this struct as small as possible
// because it's used as a local (stack) var by at least one recursive function:
// Each instance of this struct generally corresponds to a quasi-thread. The function that creates
Expand Down Expand Up @@ -641,6 +651,7 @@ struct global_struct
bool StoreCapslockMode;
bool AutoTrim;
char FormatInt;
SendLevelType SendLevel;
bool MsgBoxTimedOut; // Doesn't require initialization.
bool IsPaused; // The latter supports better toggling via "Pause" or "Pause Toggle".
bool ListLinesIsEnabled;
Expand Down Expand Up @@ -740,6 +751,7 @@ inline void global_init(global_struct &g)
g.AutoTrim = true; // AutoIt2's default, and overall the best default in most cases.
_tcscpy(g.FormatFloat, _T("%0.6f"));
g.FormatInt = 'D';
g.SendLevel = 0;
g.ListLinesIsEnabled = true;
g.Encoding = CP_ACP;
// For FormatFloat:
Expand Down
2 changes: 2 additions & 0 deletions source/globaldata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ int g_MaxThreadsTotal = MAX_THREADS_DEFAULT;
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.
int g_HotkeyThrottleInterval = 2000; // Milliseconds.
bool g_MaxThreadsBuffer = false; // This feature usually does more harm than good, so it defaults to OFF.
SendLevelType g_InputLevel = 0;
HotCriterionType g_HotCriterion = HOT_NO_CRITERION;
LPTSTR g_HotWinTitle = _T(""); // In spite of the above being the primary indicator,
LPTSTR g_HotWinText = _T(""); // these are initialized for maintainability.
Expand Down Expand Up @@ -376,6 +377,7 @@ Action g_act[] =
, {_T("ControlGet"), 2, 8, 8 H, NULL} // Output-var, Command, Value, Control, std. 4 window params

, {_T("SendMode"), 1, 1, 1, NULL}
, {_T("SendLevel"), 1, 1, 1, {1, 0}}
, {_T("CoordMode"), 1, 2, 2, NULL} // Attribute, screen|relative
, {_T("SetDefaultMouseSpeed"), 1, 1, 1, {1, 0}} // speed (numeric)
, {_T("Click"), 0, 1, 1, NULL} // Flex-list of options.
Expand Down
1 change: 1 addition & 0 deletions source/globaldata.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ extern int g_MaxThreadsTotal;
extern int g_MaxHotkeysPerInterval;
extern int g_HotkeyThrottleInterval;
extern bool g_MaxThreadsBuffer;
extern SendLevelType g_InputLevel;
extern HotCriterionType g_HotCriterion;
extern LPTSTR g_HotWinTitle;
extern LPTSTR g_HotWinText;
Expand Down
19 changes: 14 additions & 5 deletions source/hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ inline bool IsIgnored(ULONG_PTR aExtraInfo)
// such events as true physical events might cause infinite loops or other side-effects in
// the instance that generated the event. More review of this is needed if KEY_PHYS_IGNORE
// events ever need to be treated as true physical events by the instances of the hook that
// didn't originate them:
// didn't originate them. UPDATE: The foregoing can now be accomplished using SendLevel.
{
return aExtraInfo == KEY_IGNORE || aExtraInfo == KEY_PHYS_IGNORE || aExtraInfo == KEY_IGNORE_ALL_EXCEPT_MODIFIER;
}
Expand Down Expand Up @@ -1389,7 +1389,7 @@ LRESULT LowLevelCommon(const HHOOK aHook, int aCode, WPARAM wParam, LPARAM lPara
// v1.0.41:
if (hotkey_id_temp < Hotkey::sHotkeyCount) // Don't call the below for Alt-tab hotkeys and similar.
if ( !(firing_is_certain = Hotkey::CriterionFiringIsCertain(hotkey_id_with_flags
, aKeyUp, this_key.no_suppress, fire_with_no_suppress, &pKeyHistoryCurr->event_type)) )
, aKeyUp, aExtraInfo, this_key.no_suppress, fire_with_no_suppress, &pKeyHistoryCurr->event_type)) )
return AllowKeyToGoToSystem; // This should handle pForceToggle for us, suppressing if necessary.
else // The naked hotkey ID may have changed, so update it (flags currently don't matter in this case).
hotkey_id_temp = hotkey_id_with_flags & HOTKEY_ID_MASK; // Update in case CriterionFiringIsCertain() changed it.
Expand Down Expand Up @@ -1649,6 +1649,7 @@ LRESULT LowLevelCommon(const HHOOK aHook, int aCode, WPARAM wParam, LPARAM lPara
// releases the key, but there doesn't seem any way around that.
Hotkey::CriterionFiringIsCertain(this_key.hotkey_to_fire_upon_release // firing_is_certain==false under these conditions, so no need to check it.
, true // Always a key-up since it's will fire upon release.
, 0 // Not applicable here, only affects aSingleChar and return value
, this_key.no_suppress // Unused and won't be altered because above is "true".
, fire_with_no_suppress, NULL); // fire_with_no_suppress is the value we really need to get back from it.
return fire_with_no_suppress ? AllowKeyToGoToSystem : SuppressThisKey;
Expand All @@ -1675,7 +1676,7 @@ LRESULT LowLevelCommon(const HHOOK aHook, int aCode, WPARAM wParam, LPARAM lPara
hotkey_id_temp = hotkey_id_with_flags & HOTKEY_ID_MASK;
if (hotkey_id_temp < Hotkey::sHotkeyCount // i.e. don't call the below for Alt-tab hotkeys and similar.
&& !firing_is_certain // i.e. CriterionFiringIsCertain() wasn't already called earlier.
&& !(firing_is_certain = Hotkey::CriterionFiringIsCertain(hotkey_id_with_flags, aKeyUp, this_key.no_suppress, fire_with_no_suppress, &pKeyHistoryCurr->event_type)))
&& !(firing_is_certain = Hotkey::CriterionFiringIsCertain(hotkey_id_with_flags, aKeyUp, aExtraInfo, this_key.no_suppress, fire_with_no_suppress, &pKeyHistoryCurr->event_type)))
return AllowKeyToGoToSystem;
hotkey_id_temp = hotkey_id_with_flags & HOTKEY_ID_MASK; // Update in case CriterionFiringIsCertain() changed the naked/raw ID.

Expand Down Expand Up @@ -2295,7 +2296,7 @@ LRESULT AllowIt(const HHOOK aHook, int aCode, WPARAM wParam, LPARAM lParam, cons
// This is done unconditionally so that even if a qualified Input is not in progress, the
// variable will be correctly reset anyway:
if ((Hotstring::mAtLeastOneEnabled && !is_ignored) || (g_input.status == INPUT_IN_PROGRESS && !(g_input.IgnoreAHKInput && is_ignored)))
if (!CollectInput(event, aVK, aSC, aKeyUp, is_ignored, hs_wparam_to_post, hs_lparam_to_post)) // Key should be invisible (suppressed).
if (!CollectInput(event, aVK, aSC, aKeyUp, is_ignored, pKeyHistoryCurr, hs_wparam_to_post, hs_lparam_to_post)) // Key should be invisible (suppressed).
return SuppressThisKeyFunc(aHook, lParam, aVK, aSC, aKeyUp, pKeyHistoryCurr, aHotkeyIDToPost, hs_wparam_to_post, hs_lparam_to_post);

// Do these here since the above "return SuppressThisKey" will have already done it in that case.
Expand Down Expand Up @@ -2455,7 +2456,7 @@ LRESULT AllowIt(const HHOOK aHook, int aCode, WPARAM wParam, LPARAM lParam, cons


bool CollectInput(KBDLLHOOKSTRUCT &aEvent, const vk_type aVK, const sc_type aSC, bool aKeyUp, bool aIsIgnored
, WPARAM &aHotstringWparamToPost, LPARAM &aHotstringLparamToPost)
, KeyHistoryItem *pKeyHistoryCurr, WPARAM &aHotstringWparamToPost, LPARAM &aHotstringLparamToPost)
// Caller is responsible for having initialized aHotstringWparamToPost to HOTSTRING_INDEX_INVALID.
// Returns true if the caller should treat the key as visible (non-suppressed).
// Always use the parameter vk rather than event.vkCode because the caller or caller's caller
Expand Down Expand Up @@ -2814,7 +2815,15 @@ bool CollectInput(KBDLLHOOKSTRUCT &aEvent, const vk_type aVK, const sc_type aSC,
// more flexible not to do it; instead, to let the script determine (even by resorting to
// #IfWinNOTActive) what precedence hotstrings have with respect to each other.

//////////////////////////////////////////////////////////////
// MATCHING HOTSTRING WAS FOUND (since above didn't continue).
//////////////////////////////////////////////////////////////

// Now that we have a match, see if its InputLevel is allowed. If not,
// consider the key ignored (rather than continuing to search for more matches).
if (!HotInputLevelAllowsFiring(hs.mInputLevel, aEvent.dwExtraInfo, &pKeyHistoryCurr->event_type))
break;

// Since default KeyDelay is 0, and since that is expected to be typical, it seems
// best to unconditionally post a message rather than trying to handle the backspacing
// and replacing here. This is because a KeyDelay of 0 might be fairly slow at
Expand Down
2 changes: 1 addition & 1 deletion source/hook.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ LRESULT AllowIt(const HHOOK aHook, int aCode, WPARAM wParam, LPARAM lParam, cons
, bool aKeyUp, KeyHistoryItem *pKeyHistoryCurr, WPARAM aHotkeyIDToPost, bool aDisguiseWinAlt);

bool CollectInput(KBDLLHOOKSTRUCT &aEvent, const vk_type aVK, const sc_type aSC, bool aKeyUp, bool aIsIgnored
, WPARAM &aHotstringWparamToPost, LPARAM &aHotstringLparamToPost);
, KeyHistoryItem *pKeyHistoryCurr, WPARAM &aHotstringWparamToPost, LPARAM &aHotstringLparamToPost);
void UpdateKeybdState(KBDLLHOOKSTRUCT &aEvent, const vk_type aVK, const sc_type aSC, bool aKeyUp, bool aIsSuppressed);
bool KeybdEventIsPhysical(DWORD aEventFlags, const vk_type aVK, bool aKeyUp);
bool DualStateNumpadKeyIsDown();
Expand Down
50 changes: 45 additions & 5 deletions source/hotkey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,9 +586,34 @@ HotkeyVariant *Hotkey::CriterionAllowsFiring(HWND *aFoundHWND)
return vp_to_fire; // Either NULL or the variant found by the loop.
}

bool HotInputLevelAllowsFiring(SendLevelType inputLevel, ULONG_PTR aEventExtraInfo, LPTSTR aKeyHistoryChar)
{
if (aEventExtraInfo >= KEY_IGNORE_MIN && aEventExtraInfo <= KEY_IGNORE_MAX)
{
// We can safely cast here since aExtraInfo is constrained above
int eventInputLevel = (int)(KEY_IGNORE_LEVEL(0) - aEventExtraInfo);
if (eventInputLevel <= inputLevel) {
if (aKeyHistoryChar)
*aKeyHistoryChar = 'i'; // Mark as ignored in KeyHistory
return false;
}
}
return true;
}


HotkeyVariant *Hotkey::CriterionFiringIsCertain(HotkeyIDType &aHotkeyIDwithFlags, bool aKeyUp, ULONG_PTR aExtraInfo
, UCHAR &aNoSuppress, bool &aFireWithNoSuppress, LPTSTR aSingleChar)
{
HotkeyVariant *hkv = CriterionFiringIsCertainHelper(aHotkeyIDwithFlags, aKeyUp, aNoSuppress, aFireWithNoSuppress, aSingleChar);
if (!hkv)
return NULL;

return HotInputLevelAllowsFiring(hkv->mInputLevel, aExtraInfo, aSingleChar) ? hkv : NULL;
}


HotkeyVariant *Hotkey::CriterionFiringIsCertain(HotkeyIDType &aHotkeyIDwithFlags, bool aKeyUp, UCHAR &aNoSuppress
HotkeyVariant *Hotkey::CriterionFiringIsCertainHelper(HotkeyIDType &aHotkeyIDwithFlags, bool aKeyUp, UCHAR &aNoSuppress
, bool &aFireWithNoSuppress, LPTSTR aSingleChar)
// v1.0.44: Caller has ensured that aFireWithNoSuppress is true if has already been decided and false if undecided.
// Upon return, caller can assume that the value in it is now decided rather than undecided.
Expand Down Expand Up @@ -1551,11 +1576,17 @@ HotkeyVariant *Hotkey::AddVariant(Label *aJumpToLabel, bool aSuffixHasTilde)
v.mJumpToLabel = aJumpToLabel ? aJumpToLabel : g_script.mPlaceholderLabel;
v.mMaxThreads = g_MaxThreadsPerHotkey; // The values of these can vary during load-time.
v.mMaxThreadsBuffer = g_MaxThreadsBuffer; //
v.mInputLevel = g_InputLevel;
v.mHotCriterion = g_HotCriterion; // If this hotkey is an alt-tab one (mHookAction), this is stored but ignored until/unless the Hotkey command converts it into a non-alt-tab hotkey.
v.mHotWinTitle = g_HotWinTitle;
v.mHotWinText = g_HotWinText; // The value of this and other globals used above can vary during load-time.
v.mHotExprIndex = g_HotExprIndex; // L4: Added mHotExprIndex for #if (expression).
v.mEnabled = true;
if (v.mInputLevel > 0)
{
// A non-zero InputLevel only works when using the hook
mKeybdHookMandatory = true;
}
if (aSuffixHasTilde)
{
v.mNoSuppress = true; // Override the false value set by ZeroMemory above.
Expand Down Expand Up @@ -2360,10 +2391,16 @@ void Hotstring::DoReplace(LPARAM alParam)
int old_press_duration = g.PressDuration;
int old_delay_play = g.KeyDelayPlay;
int old_press_duration_play = g.PressDurationPlay;
SendLevelType old_send_level = g.SendLevel;

g.KeyDelay = mKeyDelay; // This is relatively safe since SendKeys() normally can't be interrupted by a new thread.
g.PressDuration = -1; // Always -1, since Send command can be used in body of hotstring to have a custom press duration.
g.KeyDelayPlay = -1;
g.PressDurationPlay = mKeyDelay; // Seems likely to be more useful (such as in games) to apply mKeyDelay to press duration rather than above.
// Setting the SendLevel to 0 rather than this->mInputLevel since auto-replace hotstrings are used for text replacement rather than
// key remapping, which means the user almost always won't want the generated input to trigger other hotkeys or hotstrings.
// Action hotstrings (not using auto-replace) do get their thread's SendLevel initialized to the hotstring's InputLevel.
g.SendLevel = 0;

// v1.0.43: The following section gives time for the hook to pass the final keystroke of the hotstring to the
// system. This is necessary only for modes other than the original/SendEvent mode because that one takes
Expand All @@ -2377,10 +2414,12 @@ void Hotstring::DoReplace(LPARAM alParam)

SendKeys(SendBuf, mSendRaw, mSendMode); // Send the backspaces and/or replacement.

g.KeyDelay = old_delay; // Restore original values.
g.PressDuration = old_press_duration; //
g.KeyDelayPlay = old_delay_play; //
g.PressDurationPlay = old_press_duration_play; //
// Restore original values.
g.KeyDelay = old_delay;
g.PressDuration = old_press_duration;
g.KeyDelayPlay = old_delay_play;
g.PressDurationPlay = old_press_duration_play;
g.SendLevel = old_send_level;
}


Expand Down Expand Up @@ -2444,6 +2483,7 @@ Hotstring::Hotstring(Label *aJumpToLabel, LPTSTR aOptions, LPTSTR aHotstring, LP
, mOmitEndChar(g_HSOmitEndChar), mSendRaw(aHasContinuationSection ? true : g_HSSendRaw)
, mEndCharRequired(g_HSEndCharRequired), mDetectWhenInsideWord(g_HSDetectWhenInsideWord), mDoReset(g_HSDoReset)
, mHotCriterion(g_HotCriterion)
, mInputLevel(g_InputLevel)
, mHotWinTitle(g_HotWinTitle), mHotWinText(g_HotWinText)
, mConstructedOK(false)
, mHotExprIndex(g_HotExprIndex) // L4: Added mHotExprIndex for #if (expression).
Expand Down
11 changes: 9 additions & 2 deletions source/hotkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ typedef UCHAR HotCriterionType;
// L4: Added HOT_IF_EXPR and aHotExprIndex for #if (expression).
enum HotCriterionEnum {HOT_NO_CRITERION, HOT_IF_ACTIVE, HOT_IF_NOT_ACTIVE, HOT_IF_EXIST, HOT_IF_NOT_EXIST, HOT_IF_EXPR}; // HOT_NO_CRITERION must be zero.
HWND HotCriterionAllowsFiring(HotCriterionType aHotCriterion, LPTSTR aWinTitle, LPTSTR aWinText, int aHotExprIndex, LPTSTR aHotkeyName); // Used by hotkeys and hotstrings.
bool HotInputLevelAllowsFiring(SendLevelType inputLevel, ULONG_PTR aEventExtraInfo, LPTSTR aKeyHistoryChar);
ResultType SetGlobalHotTitleText(LPTSTR aWinTitle, LPTSTR aWinText);


Expand All @@ -86,6 +87,7 @@ struct HotkeyVariant
// 4-byte alignment:
HotCriterionType mHotCriterion;
UCHAR mExistingThreads, mMaxThreads;
SendLevelType mInputLevel;
bool mNoSuppress; // v1.0.44: This became a per-variant attribute because it's more useful/flexible that way.
bool mMaxThreadsBuffer;
bool mRunAgainAfterFinished;
Expand Down Expand Up @@ -213,8 +215,8 @@ class Hotkey
static bool PrefixHasNoEnabledSuffixes(int aVKorSC, bool aIsSC);
HotkeyVariant *CriterionAllowsFiring(HWND *aFoundHWND = NULL);
static HotkeyVariant *CriterionAllowsFiring(HotkeyIDType aHotkeyID, HWND &aFoundHWND);
static HotkeyVariant *CriterionFiringIsCertain(HotkeyIDType &aHotkeyIDwithFlags, bool aKeyUp, UCHAR &aNoSuppress
, bool &aFireWithNoSuppress, LPTSTR aSingleChar);
static HotkeyVariant *CriterionFiringIsCertain(HotkeyIDType &aHotkeyIDwithFlags, bool aKeyUp, ULONG_PTR aExtraInfo
, UCHAR &aNoSuppress, bool &aFireWithNoSuppress, LPTSTR aSingleChar);
static void TriggerJoyHotkeys(int aJoystickID, DWORD aButtonsNewlyDown);
void PerformInNewThreadMadeByCaller(HotkeyVariant &aVariant);
static void ManifestAllHotkeysHotstringsHooks();
Expand Down Expand Up @@ -314,6 +316,10 @@ class Hotkey

static LPTSTR ListHotkeys(LPTSTR aBuf, int aBufSize);
LPTSTR ToText(LPTSTR aBuf, int aBufSize, bool aAppendNewline);

private:
static HotkeyVariant *CriterionFiringIsCertainHelper(HotkeyIDType &aHotkeyIDwithFlags, bool aKeyUp, UCHAR &aNoSuppress
, bool &aFireWithNoSuppress, LPTSTR aSingleChar);
};


Expand Down Expand Up @@ -343,6 +349,7 @@ class Hotstring
// Keep members that are smaller than 32-bit adjacent with each other to conserve memory (due to 4-byte alignment).
SendModes mSendMode;
HotCriterionType mHotCriterion;
SendLevelType mInputLevel;
UCHAR mStringLength;
bool mSuspended;
UCHAR mExistingThreads, mMaxThreads;
Expand Down

0 comments on commit f85a680

Please sign in to comment.