[v2.1] #Warn SendInputRevert

Propose new features and changes
Descolada
Posts: 1193
Joined: 23 Dec 2021, 02:30

[v2.1] #Warn SendInputRevert

28 Aug 2023, 06:47

Currently SendInput will silently revert to either SendEvent or SendPlay (if SendMode "InputThenPlay" is in effect) if a script other than the one executing SendInput has a low-level keyboard hook installed. This behavior is easy to forget when writing multiple scripts and a keyboard hook might be automatically installed in multiple, not always obvious, situations (eg a normal hotkey might not install it, but $ prefix does).

I propose adding a #Warn SendInputRevert directive that will cause a warning to be emitted whenever SendInput reverts to Event or Play.

Also, it might be of use to have a way to check whether a KeybdHook or MouseHook is installed by currently running and/or any other script. My current way has the unfortunate(?) side-effect of removing the hook from the running script if any other script has a hook installed...

Code: Select all

IsKeybdHookInstalled() {
   if CheckKeybdMutex() {
      InstallKeybdHook(0, 1)
      if CheckKeybdMutex()
         return 2 ; Some other script has hook
      InstallKeybdHook(1)
      return 1 ; This script has hook
   }
   return 0 ; No hook
   CheckKeybdMutex() {
      if hMutex := DllCall("OpenMutex", "int", 0x00100000, "int", 0, "str", "AHK Keybd", "ptr")
         DllCall("CloseHandle", "ptr", hMutex)
      return hMutex != 0
   }
}
Edit: created PR #326 as one possible implementation for checking Keybd/MouseHook status.
lexikos
Posts: 9688
Joined: 30 Sep 2013, 04:07
Contact:

Re: [v2.1] #Warn SendInputRevert

31 Aug 2023, 22:26

I am not sure that the default warning method (dialog) is appropriate when the script is attempting to send keystrokes to the active window.

Also, warnings tend toward conditions that are detected at load-time. The script can't respond to such conditions, because the script isn't executing (and a warning might indicate that the script won't be able to execute correctly). Since this is a runtime condition, it would probably be better to use a mechanism which allows the script to respond automatically.

Variables as in PR #326 seem more suitable. I will consider it.

Another option might be some way to disable the fallback altogether, instead throwing an error that can be handled with try/catch or OnError. I suppose the variables are more flexible and could be used to implement this behaviour anyway.
Descolada
Posts: 1193
Joined: 23 Dec 2021, 02:30

Re: [v2.1] #Warn SendInputRevert

01 Sep 2023, 07:55

@lexikos
Concept-wise, in my opinion errors are serious problems in code from which the code cannot recover from on its own nor can continue without addressing the error. Warnings on the other hand are problems which *are* recoverable, or signal that under certain conditions (which may or may not have been met) the code might fail or cause problems. The current #Warn directives cause "continuable errors", which in my opinion is an oxymoron: it shouldn't be possible to continue after an error, these are in my opinion warnings.

The default error method of dialogs seems fine, because uncaught errors disturb the flow of code and so does a pop-up dialog. However, for warnings, I think the default method should be OutputDebug, because a warning doesn't interrupt code flow and neither does OutputDebug. I also expect that users who know to enable warnings are also using software that allows for debugging, so OutputDebug seems like the best choice over StdOut or logging to a file.

The current #Warn directive is for load-time detection of problems and I agree that run-time warnings might not fit that well into that. On the other hand, why couldn't a #Warn directive be a toggle to enable or disable run-time warnings exactly one (that can't be toggled at run-time any more)? This could lend for even more possibilities than #Warn SendInputRevert. I imagine creating load-time warning levels that may be enabled during the creation and debugging phase of making a script and disabled for production releases. This could allow for code such as

Code: Select all

#Warn Runtime

F("string")
F(arg:=0) {
    #IfWarn
    if !IsInteger(arg)
        throw TypeError("arg must be integer", -1)
    #If
    OutputDebug "Other code"
}
which without the #Warn Runtime would instead be preprocessed to

Code: Select all

#Warn Runtime, Off

F("string")
F(arg:=0) {
    ;#IfWarn
    ;if !IsInteger(arg)
    ;    throw TypeError("arg must be integer", -1)
    ;#If
    OutputDebug "Other code"
}
That would make it possible to create well-debugged code without the added performance deficit by all the input validation etc in release versions.
The syntax I used here is merely an example and would need more thought as to how to handle different warnlevels, whether to use #IfWarnRuntime instead etc...

It might be useful to have a way to throw continuable errors as well, for example with throw Warning("This is continuable and creates a stack-trace like a normal error").

The variables might be useful in other cases as well in addition to being a surrogate to whether Input will revert or not, so this post isn't meant as a replacement for that.
lexikos
Posts: 9688
Joined: 30 Sep 2013, 04:07
Contact:

Re: [v2.1] #Warn SendInputRevert

01 Sep 2023, 23:38

Descolada wrote:
01 Sep 2023, 07:55
Concept-wise, in my opinion errors are serious problems in code from which the code cannot recover from on its own nor can continue without addressing the error.
If a function cannot fulfill its purpose, that is an error condition. If a function's purpose is to send keys while buffering the user's input, it cannot fulfill its purpose if another hook is present. For something like TrySendInput, it would not be an error condition; it is implied that the function's purpose is to make an attempt, and the return value would indicate whether it succeeded.

If the code relies on the function to send keys, which is likely, and the keys aren't sent because it can't use the method which was requested, would it not be generally the case that the code will need to address the problem before continuing?

How would code recover from a problem without first detecting it, such as by catching an exception? Why is it even considered a problem if it is not an error?
Warnings on the other hand are problems which *are* recoverable, or signal that under certain conditions (which may or may not have been met) the code might fail or cause problems.
Emphasis on under certain conditions (that haven't been verified prior to showing the warning) and might. All current warnings are detected through static analysis of the code before it runs. They are all conditions which may or may not indicate a mistake that may prevent the code from running correctly.
The current #Warn directives cause "continuable errors", which in my opinion is an oxymoron: it shouldn't be possible to continue after an error, these are in my opinion warnings.
They do not "cause errors". A dialog box or OutputDebug message is not an error. A warning is literally just a warning. It warns.
However, for warnings, I think the default method should be OutputDebug, because a warning doesn't interrupt code flow and neither does OutputDebug.
Why did this topic become about changing the default behaviour of warnings?
I also expect that users who know to enable warnings are also using software that allows for debugging, so OutputDebug seems like the best choice over StdOut or logging to a file.
The directive exists for users who know how to use it. The default behaviour exists for everyone. Everone, especially users who haven't learned enough to know about warnings, should be warned when they are likely to be making a mistake. It will save them time. Consider what happens if we default to StdOut and the parent process isn't catching or displaying it, or we default to OutputDebug and no debugger is running: nothing happens. The user is not warned.
#IfWarn
Something like the C preprocessor's #if has been suggested several times over the decades. Why would you limit it to a "warning" toggle? This is getting a bit far from the original topic.
It might be useful to have a way to throw continuable errors as well, for example with throw Warning("This is continuable and creates a stack-trace like a normal error").
Throw is already continuable in v2.1-alpha.3, which I am preparing for release. As with all continuable errors, it is continuable only if try/catch is not in use.

Exceptions are thrown. Throwing a warning makes no sense. A warning just warns.
The variables might be useful in other cases as well in addition to being a surrogate to whether Input will revert or not, so this post isn't meant as a replacement for that.
You've lost me again. Variables?
Descolada
Posts: 1193
Joined: 23 Dec 2021, 02:30

Re: [v2.1] #Warn SendInputRevert

02 Sep 2023, 14:29

If the code relies on the function to send keys, which is likely, and the keys aren't sent because it can't use the method which was requested, would it not be generally the case that the code will need to address the problem before continuing?
For SendInput yes, for Send perhaps not. I would say SendInputs' name is quite clear and if it couldn't perform its action of sending via SendMode Input then throwing an error might be better indeed. In this I support your final thought in your first response, that is, disabling the revert for it and throwing an error when appropriate, which could be handled by try...catch, via the return value of TrySendInput, or using variables as in PR #326.
Send could be left more flexible if it's possible to detect whether it reverted or not after the fact. PR #326 variables are one option, another would be for Send to return the method it used to send instead of returning nothing (though knowing the method beforehand would probably be more useful...), third is run-time warnings without dialogs.
Why did this topic become about changing the default behaviour of warnings?
Because I got sidetracked by your first response of:
I am not sure that the default warning method (dialog) is appropriate when the script is attempting to send keystrokes to the active window.
That is, I attempted to convey why I think the default warning method (dialog) is *not* appropriate when Send reverts, and also why the dialog method perhaps isn't suitable for other warnings/continuable errors as well. I'll try to address these thoughts further in a separate thread.
You've lost me again. Variables?
The ones mentioned in PR #326: A_KeybdHookInstalled, A_MouseHookInstalled.
lexikos
Posts: 9688
Joined: 30 Sep 2013, 04:07
Contact:

Re: [v2.1] #Warn SendInputRevert

02 Sep 2023, 19:05

For SendInput yes, for Send perhaps not.
This was in the context of "some way to disable the fallback altogether". If the mode is "InputAndOnlyInput" and that mode can't be used, it is just as much an error condition for Send as it is for SendInput.

Alternatively, the fallback could be specified as a function, which can output a warning, throw an error, whatever. You could even pass SendEvent itself or ControlSend.Bind(,,"A").
In this I support your final thought in your first response, that is, disabling the revert for it and throwing an error when appropriate
That was nothing more than a casual idea.

Return to “Wish List”

Who is online

Users browsing this forum: No registered users and 10 guests