Buffer keyboard input

Get help with using AutoHotkey and its commands and hotkeys
User avatar
Micromegas
Posts: 219
Joined: 28 Apr 2015, 23:02
Location: Germany

Buffer keyboard input

26 Nov 2019, 07:18

Is there a way to hold off keyboard input until a thread is done? In other words, I'm looking for the opposite of KeyWait – make the key wait for the script.

Sometimes (e.g. here) it is recommended to “use the Critical command to buffer keyboard input”. However, the doc page only speaks of “other threads”, and indeed, after running the following code

Code: Select all

q::
	Critical On
	Sleep 1000	; in reality, the script does something useful here
	Send X		; in reality, this is the result of the previous computations
	return
quickly entering the word “quickly” results in “uickXly”.
Last edited by Micromegas on 26 Nov 2019, 09:36, edited 1 time in total.
rommmcek
Posts: 1007
Joined: 15 Aug 2014, 15:18

Re: Buffer keyboard input

26 Nov 2019, 08:39

Try:

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

q::
    SetTimer, CatchKeys, -0
    Sleep, 100
    Send X
return

catchKeys:
    While !GetKeyState("VK20", "P") ; wait until Space is pressed
        Sleep, 50
Return

^esc::ExitApp
User avatar
Micromegas
Posts: 219
Joined: 28 Apr 2015, 23:02
Location: Germany

Re: Buffer keyboard input

26 Nov 2019, 09:33

Hmm, that doesn't seem to solve my problem:
  1. I don't want the script to sleep; I only put Sleep in the above code to simulate the time the script takes for its task. (Sorry about the confusion; I edited my original post to make that clear.)
  2. Why specifically wait for Space? The user can enter all kinds of stuff after running the script.
rommmcek
Posts: 1007
Joined: 15 Aug 2014, 15:18

Re: Buffer keyboard input

26 Nov 2019, 11:46

Maybe like this:

Code: Select all

q::
    SetTimer, CatchKeys, -0
    Sleep, 100
    Send % X
return

catchKeys:
    s:= A_TickCount
    While A_TickCount-s < 5000 { ; wait 5 sec
        X:= A_Index  ; put here the code to do something useful
        Sleep, 50 ; just to slow down the loop a bit 
    }
Return

^esc::ExitApp
User avatar
Micromegas
Posts: 219
Joined: 28 Apr 2015, 23:02
Location: Germany

Re: Buffer keyboard input

26 Nov 2019, 12:54

:eh: Did you try that yourself? :?: This is no better than the original. The subroutine named “catchKeys” doesn't catch any keys – just as in the original code example, they are simply passed on while the thread is running. (In fact, I could squeeze in many more characters before the output – but that of course depends on the timing choice). But even if it caught all keys, it would be very cumbersome: I would have to chop up my actual computation code into many small steps, one for each iteration of the loop.

But I do have one understanding question. What do you achieve by setting the Period for SetTimer to -0? -0 is undocumented. One would expect that to evaluate to 0. Unfortunately, the documentation isn't explicit about 0, either. If that counts as a positive number, then it would infinitely repeat. That doesn't happen, though (regardless of the sign I put before “0”). Rather, it appears execution just jumps to the label, as if it were a Gosub command. So what am I missing?
Last edited by Micromegas on 26 Nov 2019, 13:01, edited 2 times in total.
rommmcek
Posts: 1007
Joined: 15 Aug 2014, 15:18

Re: Buffer keyboard input

26 Nov 2019, 12:56

To catch input you must enter the appropriate code. Maybe this:

Code: Select all

hwnd:= ""
q::
    if !hwnd {
        Gui +hwndhwnd
        Gui add, Text,, Enter a number:
        gui add, Edit, w150 vEditCtrl
        gui show
    } else GuiControl,, EditCtrl
    
    SetTimer, CatchKeys, -0
    Sleep, 100
	;Send % X
    GuiControl,, EditCtrl, % X " * " CtrlContent " = " X * CtrlContent
return

catchKeys:
    s:= A_TickCount
    While A_TickCount-s < 5000 { ; wait 5000 sec
        X:= A_Index  ; put here the code to do something useful
        Sleep, 50 ; just to slow down the loop a bit 
    }
    GuiControlGet, CtrlContent,, EditCtrl
Return

;GuiClose:
^esc::ExitApp
Edit: If you have in the script #Warn then it you get the Warning. Code updated!
Last edited by rommmcek on 26 Nov 2019, 13:52, edited 1 time in total.
User avatar
Micromegas
Posts: 219
Joined: 28 Apr 2015, 23:02
Location: Germany

Re: Buffer keyboard input

26 Nov 2019, 13:12

Please, don't just post random complications to the code without trying it out yourself. The new code still has the same problem; except that it now writes the keyboard input, just like the output of the computation, into the text box of the otherwise completely useless unmotivated GUI. (It also creates a warning, which I prevented by setting hwnd to an arbitrary number.)

Edit: In addition to the problems we already have, we now get an error when we hit “q” again any time later.

I replaced the words “otherwise completely useless” with “unmotivated”. Arguably, one can use the GUI as a keyboard buffer. But that's very awkward and user unfriendly; it's throwing out the baby with the bath water. Now, instead of remembering not to type too quickly, the user has to react to an unmotivated GUI. Even if we further amend the code to close it automatically, it will still remain a distraction and not something that makes keyboard entry any easier.
rommmcek
Posts: 1007
Joined: 15 Aug 2014, 15:18

Re: Buffer keyboard input

26 Nov 2019, 13:34

Oh, you are picky! Hope you take no offense! The concept is there, you just have to adapt it to your needs:

Code: Select all

q::
    SetTimer, CatchKeys, -100
    Input, InputedValue, V T5 L4 C
    Sleep, 100
    Send % ": " X " * " InputedValue " = " X * InputedValue
return

catchKeys:
    s:= A_TickCount
    While A_TickCount-s < 5000 { ; wait 5000 sec
        X:= A_Index  ; put here the code to do something useful
        Sleep, 50 ; just to slow down the loop a bit 
    }
Return

^esc::ExitApp
Edit: Removed remnant code.
Edit2: Updated the Gui example above to prevent Warning.
Last edited by rommmcek on 26 Nov 2019, 13:55, edited 1 time in total.
User avatar
Micromegas
Posts: 219
Joined: 28 Apr 2015, 23:02
Location: Germany

Re: Buffer keyboard input

26 Nov 2019, 13:55

No, it's not that I'm picky. I have a very straightforward requirement; it's all in my first post: I don't need any GUI or Input, just a second of time for the script to do something before any further keys get displayed.
rommmcek
Posts: 1007
Joined: 15 Aug 2014, 15:18

Re: Buffer keyboard input

26 Nov 2019, 13:57

O.k.: I posted code with Input (no Gui) above.
User avatar
Micromegas
Posts: 219
Joined: 28 Apr 2015, 23:02
Location: Germany

Re: Buffer keyboard input

26 Nov 2019, 14:17

I saw that. That is why I wrote “GUI or Input”. To be clear, the point is that this needs to make things easier for the user. KISS. So, no InputBox, either. Nothing that would only make it worse for the user.
Image
rommmcek
Posts: 1007
Joined: 15 Aug 2014, 15:18

Re: Buffer keyboard input

26 Nov 2019, 14:41

I think I posted such code here.

Edit: Oh, critical humour! I deciphered the "Nerrenbeschwerung"! I except it! I read very fast, code very fast and post very fast, but all that in hope to help and learn as quick as possible.
rommmcek
Posts: 1007
Joined: 15 Aug 2014, 15:18

Re: Buffer keyboard input

26 Nov 2019, 15:56

Sorry for truble! I really misunderstood your need. This should solve your problem:

Code: Select all

q::
    SetTimer, CatchKeys, -0
    BlockInput, On
    Sleep, 100
    Send % X
return

catchKeys:
    s:= A_TickCount
    While A_TickCount-s < 5000 { ; wait 5 sec
        X:= A_Index  ; put here the code to do something useful
        Sleep, 50 ; just to slow down the loop a bit 
    }
    BlockInput, Off
Return

^esc::ExitApp
NOTE: Be carful with this code! If it happens that you can't interact with your computer any more, the solution is Win + L (#L) or Ctrl + Alt + Del. Such key combination usually cannot be blocked!

I think I get it now: Topic name is: "Buffer keyboard input", but later have you changed the text to "hold off keyboard input" and said sorry below, but I looked just in the updated code comments, without reading your edited text again...
rommmcek
Posts: 1007
Joined: 15 Aug 2014, 15:18

Re: Buffer keyboard input

27 Nov 2019, 16:20

Thanks for clarification on PM!
This works for me:

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
 #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
;https://www.autohotkey.com/boards/viewtopic.php?f=76&t=70193&p=303001#p303001

;ensure runnig script as admin
if not A_IsAdmin
{
   Run *RunAs "%A_ScriptFullPath%"  ; Requires v1.0.92.01+
   ExitApp
}
X:= ""

q::
    SetTimer, CatchKeys, -100
    Send, % "Enter a number: "
    BlockInput, On
    Input, InputedValue, V T5 L10 C ; T5 means 5 sec
    Sleep, 100
    Send % InputedValue " * X = " X * InputedValue
return

catchKeys:
    s:= A_TickCount
    While A_TickCount-s < 5000 { ; wait 5 sec and do some calculations
        X:= A_Index  ; put here the code to do something useful
        Sleep, 50 ; just to slow down the loop a bit 
    }
    BlockInput, Off
Return

^esc::ExitApp
Here is a string example:

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
 #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
;https://www.autohotkey.com/boards/viewtopic.php?f=76&t=70193&p=303001#p303001

;ensure runnig script as admin
if not A_IsAdmin
{
   Run *RunAs "%A_ScriptFullPath%"  ; Requires v1.0.92.01+
   ExitApp
}
X:= "", hk:= ""

$q::
    if !hk {
        Send, % "Enter a string ""quickly"": "
        hk:=1
        Return
    }
    SetTimer, CatchKeys, -100
    BlockInput, On
    Input, InputedValue, V T5 L10 C ; T5 means 5 sec
    Sleep, 100
	Send % X InputedValue
    hk:= ""
return

catchKeys:
    s:= A_TickCount
    While A_TickCount-s < 5000 { ; wait 5 sec and do some calcualtions
        if !X
            X:= "Q"  ; put here the code to do something useful
        Sleep, 50 ; just to slow down the loop a bit 
    }
    BlockInput, Off
Return

^esc::ExitApp
P.s.: Maybe BlockInput in previous script didn't work for you, because the script was not run as admin (fixed).

WARNING: Once again, if anything in the while loop happens to hang up the script, Input will not be unblocked, so use shortcuts mentioned in previous post!

Return to “Ask For Help”

Who is online

Users browsing this forum: boiler, ktfroy and 65 guests