Wait for keyboard input - just DON'T!

Hi

I am looking for a way to pause script execution and wait for user input. Nothing in particular, just any keystroke or click, to allow to continue execution.

Right now I am trying to write something with the help of the new on-chart GUI controls.

Would there be a simpler way to do this?

I came up with this code, but it does not work at all.

// This procedure is supposed to wait until user clicks on the button
procedure wait_for_click( idmain )
{
    local
    id, n;

    id = idmain + 10; // set to something different than idmain

    do
    {

// this loop searches the event queue
        for( n = 0; id = GuiGetEvent( n, 0 ); n++ )
        {
            if( id == idmain )
                break; // we found the id in the event queue, so exit the for loop
        }
        printf( "Waiting ...\n" );
        ThreadSleep( 500 );
    }
    while( id != idmain );

    GuiSetVisible( idmain, False );  // make the button invisible after the click
}

printf( "  Hello 1\n" );

ContinueButtonId = 100;
GuiButton( "Click to Continue", ContinueButtonId, 10, 30, 130, 30, notifyClicked );
GuiSetVisible( ContinueButtonId, true );
printf( "  Hello 2\n" );
wait_for_click( ContinueButtonId );
printf( "  Hello 3\n" );

Can somebody help me fix the above?

Maybe the problem lies to what @Tomasz has already mentioned here:

I am just too stuck on the previous line of thought.

1 Like

Instead of "waiting for a click", why not "do only if clicked"

if( clicked ) {
do something
}

By the way

1 Like

Yes, this was my alternative, and it does work:

function check_if_clicked( idmain )
{
    local
    clicked,
    id, n;

    clicked = False;

    // this loop searches the event queue
    for( n = 0; id = GuiGetEvent( n, 0 ); n++ )
    {
        if( id == idmain )
        {
            clicked = True;
            break; // we found the id in the event queue
        }
    }

    return clicked;
}

printf( "  Hello 1\n" );

ContinueButtonId = 100;
GuiButton( "Click to Continue", ContinueButtonId, 10, 30, 130, 30, notifyClicked );
GuiSetVisible( ContinueButtonId, true );
printf( "  Hello 2\n" );
printf( "GuiGetEvent( 0, 0 ) = " + NumToStr( GuiGetEvent( 0, 0 ) ) + "\n" );

if( check_if_clicked( ContinueButtonId ) )
{
    GuiSetVisible( ContinueButtonId, false );
    printf( "  CLICKED !!\n" );
}
else
    printf( "Nothing yet....\n" );

printf( "  Hello 3\n" );

However I took it as a challenge to finish the original code, in the first post.

1 Like

Try out GetAsyncKeyState. Here is the AFL for sensing right arrow key.

if (GetAsyncKeyState( 39 ) < 0) {
	ThreadSleep(80); // make key less sensitive, delay 80 milliseconds
        // do something
} 
https://www.amibroker.com/guide/afl/getasynckeystate.html

Thank you @Peter2047

First and foremost: NO formula should EVER busy wait or pause for anything.
That is a rule that must be obeyed.

Pausing prevents proper refresh of chart!
The formula MUST always execute without pausing.

If you want to act upon key stroke use GetAsyncKeyState but if key is NOT pressed, do NOT wait. Just allow formula to proceed (end) and let it check state next time it runs (you can use RequestTimedRefresh if you want it to be re-run).

So:

if (GetAsyncKeyState( 'A' ) < 0)  // key A held down
{
 // do whatever you want
 // BUT DO NOT PAUSE !
 // DO NOT CALL ThreadSleep!
}

// other stuff that needs to be done unconditionally
// optionally:
RequestTimedRefresh(0.1); //if you want it to be re-executed

1 Like

@Tomasz,
I should explain my situation for using it.
I have a sheet that display smaller charts.
chart
I used the left and right arrow keys to move the active symbol(highlighted in darker box).
Without a way to slow down, I will always miss the tile that I want to get to.

@Peter2047 and @Tomasz, everybody's needs are different.

I spent the last 2 afternoons and nights troubleshooting a script that refused to work. It had to do with processing text files, copying them, renaming etc.

I stepped again and again through the debugger and it worked perfectly. But in normal mode it would not work. I wanted to be able to examine the state of the text files at various steps of the script. So I just wanted to FREEZE the script, not from the debugger, but something like the breakpoint the debugger places.

I wanted to insert/remove those FREEZE points in the code fast. I did not want to place elaborate IF statements, redirect the code, close the files etc. That would be even more hasle.

Anyway, I did find what the problem was.

Again, you should NOT freeze or pause anything.

Instead you should implement simple state machine so you act on transitions from key "up" to "down" (or vice versa).

keydown = GetAsyncKeyState( 'A' ) < 0;
prevkeydown = StaticVarGet("keystate");
StaticVarSet("keystate", keydown );

if( keydown and NOT prevkeydown )
{
   // transition from NOT pressed to pressed, do whatever you want
}
1 Like

@Tomasz, I do understand your logic, you are right, this is how charts work and should work in AFL. And again I did learn a bit more about how AFL works. Thank you for the time you take to explain things to us.

The particular script I was trying to debug had no chart, nothing to refresh. I should have written it in C++ instead, if I was any good at it (which I am not). It was a script that did a one time scan and processing of TXT files.

Actually I needed to make sure it would run for just one cycle, otherwise I risked corrupting the TXT files I was processing, therefore I used something like the following code:

if( ParamTrigger( "Run the script", "OK" ) )
{
// Run the script once only, prevent the script from running a 2nd time.
}