"Repeat while the mouseClick is false" makes program hang

Got a LiveCode personal license? Are you a beginner, hobbyist or educator that's new to LiveCode? This forum is the place to go for help getting started. Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller

sritcp
Posts: 431
Joined: Tue Jun 05, 2012 5:38 pm

"Repeat while the mouseClick is false" makes program hang

Post by sritcp » Sun Jul 08, 2012 4:07 am

In my app, an audio plays and then the program waits for 10 seconds for a user click. I used the following code to process the waiting for the click:

Code: Select all

......
......
put the seconds into gLastClickTime -- reset the clock
repeat while the mouseClick is false
      if the seconds - gLastClickTime > 10 then  -- if more than 10 seconds of no response
         put "waited too long" into message box -- or do something else
         exit repeat
      end if
end repeat

on mouseUp
 rewardIfCorrectButtonIsClicked
end mouseUp
On execution, when the audio plays, and I click (say, the correct button), the program hangs. It gets stuck on mouseDown (that is, the highlight of the clicked button stays). The mouseUp message never gets sent.
First things first, is my "repeat" code okay to handle waiting for the mouseClick?
If so, what is going wrong?

Thanks,
Sri.

Mark
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 5150
Joined: Thu Feb 23, 2006 9:24 pm
Contact:

Re: "Repeat while the mouseClick is false" makes program han

Post by Mark » Sun Jul 08, 2012 10:09 am

Hi Sri,

The repeat loop locks up the IDE. It is fine for really short repeat loops, but in scripts like yours, you need a "wait" statement:

repeat until the mouseClick with messages
-- more syntax here
wait 0 millisecs with messages
end repeat

This repeat loop will not lock up the IDE and will actually display the text after the put command.

The mouseClick is true only after the mouseUp occurs. LiveCode polls the state of the mouse when you call mouseClick and then flushes the mouseUp message. This makes sense, since it is the mouseUp that triggered the mouseClick message (even though this may not be very practical). Apparently, you always want to run the mouseUp handler, which means that you can put the two handlers together.

Code: Select all

on mouseDown theBtn
   put the seconds into gLastClickTime -- reset the clock
   repeat until the mouseClick with messages
         if the seconds - gLastClickTime > 10 then  -- if more than 10 seconds of no response
            put "waited too long" into message box -- or do something else
            exit repeat
         end if
         wait 0 millisecs with messages
   end repeat
   rewardIfCorrectButtonIsClicked theBtn
end mouseDown
If you want to know which button was clicked, then you can pass on the parameter accompanying the mouseDown handler to the rewardIfCorrectButtonIsClicked handler.

Kind regards,

Mark
The biggest LiveCode group on Facebook: https://www.facebook.com/groups/livecode.developers
The book "Programming LiveCode for the Real Beginner"! Get it here! http://tinyurl.com/book-livecode

sritcp
Posts: 431
Joined: Tue Jun 05, 2012 5:38 pm

Re: "Repeat while the mouseClick is false" makes program han

Post by sritcp » Sun Jul 08, 2012 1:50 pm

Hi Mark:

Thanks for the suggestions.

1. I didn't know "with messages" could be used with "repeat" control structure (especially since "repeat" uses "with" in one of its loopforms). The only place "with messages" is mentioned in the dictionary is under "wait" command. I wish the LC documentation were more comprehensive. (Your suggestion worked, by the way!)

2. Interesting point about using mouseDown and mouseUp together; your code example doesn't apply to my situation, though. I want to time the user inactivity, not how long he is holding down the mouse without letting go (as your code example does).

Thanks,
Sri.

Mark
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 5150
Joined: Thu Feb 23, 2006 9:24 pm
Contact:

Re: "Repeat while the mouseClick is false" makes program han

Post by Mark » Sun Jul 08, 2012 1:59 pm

Hi Sri,

It applies, even though my code does something slightly different from your code. The problem here is that polling the mouseClick function flushes the the mouseUp messages. You can adjust my example to circumvent this problem and still do what you want.

Kind regards,

Mark
The biggest LiveCode group on Facebook: https://www.facebook.com/groups/livecode.developers
The book "Programming LiveCode for the Real Beginner"! Get it here! http://tinyurl.com/book-livecode

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7393
Joined: Sat Apr 08, 2006 8:31 pm
Contact:

Re: "Repeat while the mouseClick is false" makes program han

Post by jacque » Sun Jul 08, 2012 6:25 pm

Better than a repeat loop would be a "send" structure. It doesn't lock up the CPU, won't require a wait, and won't block other messages.
http://www.hyperactivesw.com/polling.html

The example on that page discusses moving an object but the principle is the same here. You'd set a start time script variable on mouse down and call a handler that checks the time compared to the stored value. If the time is not yet elapsed the handler would call itself again in a second or so. If the time has elapsed the handler would present the dialog and exit. This method allows your scripts to run normally without any side effects and is far more efficient.

Another disadvantage of using "wait until the mouseclick" is that in rare cases the mouseclick will never register and your handler will go into an endless loop. Mouseclicks can occasionally be lost in tight repeat loops.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

Mark
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 5150
Joined: Thu Feb 23, 2006 9:24 pm
Contact:

Re: "Repeat while the mouseClick is false" makes program han

Post by Mark » Sun Jul 08, 2012 7:54 pm

Hi Jacque,

A send command is more complicated than a repeat loop and if it lasts only a few seconds, then I don't mind if the CPU gets a little busy. Also, if you want to know exactly when the user clicked the mouse, rather than whether the user clicked the mouse after a specified amount of time, then you'll have to send a message every 10 millisecs or so, to get any precision at all. This in itself would also take a lot of CPU power (I tested this). It seems that in terms of required CPU time, there isn't much difference between a repeat loop and the send message, if precision is a requirement.

It is true that the mouseClick may never become true, as I already explained. This isn't a very rare occasion. It is quite easy to create such a situation. In fact, this might happen in the examples above and depending on OP's requirements we might come up with a better solution.

It isn't clear to me whether the user is supposed to keep the mouse pressed until the moment when OP expects the mouseClick to be true. I wonder if a simple "until the mouse is up" would do? If not, then I would use a locally declared variable or a property to store the "state" of the button, each time when the user clicks:

Code: Select all

local lState,lTime
on mouseDown
  if lSate is not true then
    put true into lState
    put the seconds into lTime
  else
    put false into lState
    if (the seconds - lTime > 10) then
      put "waited too long"
    end if
  end if
end mouseDown
I believe this would be the best way to store the time between two clicks. It assumes that the user presses the mouse button twice, but it doesn't include either a repeat loop or a send command.

Kind regards,

Mark
The biggest LiveCode group on Facebook: https://www.facebook.com/groups/livecode.developers
The book "Programming LiveCode for the Real Beginner"! Get it here! http://tinyurl.com/book-livecode

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7393
Joined: Sat Apr 08, 2006 8:31 pm
Contact:

Re: "Repeat while the mouseClick is false" makes program han

Post by jacque » Sun Jul 08, 2012 8:19 pm

I disagree. This type of repeat loop is inefficient and blocks all (or almost all) background activity, including all non-LiveCode processes and OS activity. Using "with messages" helps somewhat, but still isn't as efficient. A loop is easy to implement, which is why it is done so often, but it isn't the best or recommended way. When you consider that mouse messages can fail, the choice is seems clear.

Ten seconds is a very long time for a CPU and doesn't require calling a handler more than every 50 or 60 milliseconds, if that. I'd be very surprised if that causes the same type of CPU activity as a non-stop loop.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

Mark
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 5150
Joined: Thu Feb 23, 2006 9:24 pm
Contact:

Re: "Repeat while the mouseClick is false" makes program han

Post by Mark » Sun Jul 08, 2012 8:25 pm

You're free to disagree, Jacque. At least, I hope that you like the, much better, solution which I gave in my previous post.

Oh, and note that a repeat loop with messages doesn't lock up the GUI at all and that your solution took as much CPU time as my first solution.

Kind regards,

Mark
The biggest LiveCode group on Facebook: https://www.facebook.com/groups/livecode.developers
The book "Programming LiveCode for the Real Beginner"! Get it here! http://tinyurl.com/book-livecode

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7393
Joined: Sat Apr 08, 2006 8:31 pm
Contact:

Re: "Repeat while the mouseClick is false" makes program han

Post by jacque » Sun Jul 08, 2012 8:33 pm

Do you have benchmarks?

BTW: it is't "my" solution, it was the pet peeve of the guy who wrote the engine. I decided he's probably right. He asked me to put up the web page so that he didn't have to keep correcting people on the MC list.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

Mark
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 5150
Joined: Thu Feb 23, 2006 9:24 pm
Contact:

Re: "Repeat while the mouseClick is false" makes program han

Post by Mark » Sun Jul 08, 2012 8:47 pm

Jacque,

I did a quick test with both a repeat loop with messages and "wait 10 millisecs with messages" at the end as well as a send in 10 millisecs recursive command. Both scripts caused Revolution to take more than 90% CPU time.

I'm sure the numbers get quite different, if you increase the 10 millisecs tenfold or hundredfold. Eventually, the send in time command will use much less CPU time than the repeat loop, but if precision is a requirement (e.g. 10 seconds shouldn't be 9.05 or 10.05 seconds), then you need to poll frequently.

Kind regards,

Mark
The biggest LiveCode group on Facebook: https://www.facebook.com/groups/livecode.developers
The book "Programming LiveCode for the Real Beginner"! Get it here! http://tinyurl.com/book-livecode

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7393
Joined: Sat Apr 08, 2006 8:31 pm
Contact:

Re: "Repeat while the mouseClick is false" makes program han

Post by jacque » Sun Jul 08, 2012 9:26 pm

I agree. If you poll at the same speed or less as the repeat loop takes to run, then either method will lock up the CPU at the same rate. In real world situations that's rarely necessary though. For counting something as long as ten seconds, polling every quarter or half second is usually good enough. Precise timing isn't ever possible on any computer; various system operations and messaging overhead will always skew the timing. Apple used to mention that in their developer notes. A script can get close but will never achieve exact precision.

Your second method is good, and pretty much agrees with Scott Raney. The basic idea is to set some type of flag, use natural messaging to track user actions and progress, and avoid waiting inside a repeat loop. I'd be likely to use your second script.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

Mark
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 5150
Joined: Thu Feb 23, 2006 9:24 pm
Contact:

Re: "Repeat while the mouseClick is false" makes program han

Post by Mark » Sun Jul 08, 2012 9:32 pm

Jacque,

I'm glad we agree. Whether OP is willing to allow for a margine larger then the smallest possible is up to him of course.

Yes, I also think I'd rather use the second method. I hope OP will consider using it.

Kind regards,

Mark
The biggest LiveCode group on Facebook: https://www.facebook.com/groups/livecode.developers
The book "Programming LiveCode for the Real Beginner"! Get it here! http://tinyurl.com/book-livecode

sritcp
Posts: 431
Joined: Tue Jun 05, 2012 5:38 pm

Re: "Repeat while the mouseClick is false" makes program han

Post by sritcp » Mon Jul 09, 2012 2:14 am

Wow, this issue seems to be a whole lot more complicated than I thought!

1. Mark,
The problem here is that polling the mouseClick function flushes the the mouseUp messages.
If I understand you correctly, are you saying: If a "repeat" loop polls the mouseClick, then the resultant mouseUp won't even be sent to the target of the click (which is the very purpose of the whole exercise!)
In my program, once I put in your first suggestion ("wait 0 millisecs with messages"), this happens only rarely. I take it that most of the time the mouseUp message gets sent to its target BEFORE the "repeat" loop polls and flushes it. Actually, I wonder why it doesn't happen more frequently!

2.
It isn't clear to me whether the user is supposed to keep the mouse pressed until the moment when OP expects the mouseClick to be true. I wonder if a simple "until the mouse is up" would do?
No, not at all. May be a little description of my app would help. It is to be used by children with hearing loss (most with a cochlear implant) who are learning to listen and talk. They are of toddler-preschooler age level. The app can be used with and/or without adult (parent/therapist) supervision. In one of the modules, the child is trying to discriminate among spoken sentences. Each card contains a scenario, with about 10 clickable areas (transparent buttons). The program speaks a sentence, and waits. If the child clicks within 10 seconds, it processes the click and gives feedback ("Correct", an animation, etc.). If there is no response for 10 seconds, it repeats the sentence. And, waits, again. Etc. So, the waiting is not while the mouse is kept pressed, but pure user inactivity. Does this info make any difference to any of your suggestions?

3. I am not entirely sure that I understand your second method. I am not trying store the time between mouseClicks (my variable name, gLastClickTime, may have misled you). The program plays an audio, puts the time into gLastClickTime, and waits. If there is a mouseClick, it is very important that a mouseUp is sent to the target, and is not handled through the repeat loop sending a message to the object (this is because I have a single mouseUp handler at the stack level that handles it for all clickable buttons. This way, we can easily add additional cards -- i.e., exercises -- with nearly no additional coding). I am not sure how I can modify your second method to my purposes.

4. Jacque,
For counting something as long as ten seconds, polling every quarter or half second is usually good enough.
For my purposes, half a second would be too long. If a click doesn't produce a response immediately, the child (user) is likely to click another button. 100 millisec should be okay, I guess.

Regards,
Sri.

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7393
Joined: Sat Apr 08, 2006 8:31 pm
Contact:

Re: "Repeat while the mouseClick is false" makes program han

Post by jacque » Mon Jul 09, 2012 4:57 am

sritcp wrote: 4. Jacque,
For counting something as long as ten seconds, polling every quarter or half second is usually good enough.
For my purposes, half a second would be too long. If a click doesn't produce a response immediately, the child (user) is likely to click another button. 100 millisec should be okay, I guess.
I understand. There will be no delay after the initial mouseclick. The polling I was talking about is for counting down the time before initiating a second action -- in this case, repeating the question. If you are waiting ten seconds, it's usually sufficient to only check the elapsed time in half or quarter second intervals (or even full seconds, depending on the amount of precision you want.) If you were waiting a shorter amount of time, then smaller polling intervals would be necessary.

In this situation, the first mouseclick will trigger your action immediately. It's the second mouseclick we've been discussing -- the child's response that needs to occur within ten seconds. You will need to count those ten seconds (which is why you need to store the initial time of the mouseclick, so you can calculate when ten seconds have elapsed.)

In Mark's second example, two script variables are loaded. The first sets a flag that indicates whether we're waiting or not (the state; watch out for the typo in "lSate") and the second, lTime, records the time of the first mouseclick in seconds. The next time the child clicks, the state is currently "waiting" so it registers the second click as a response and resets the state to "not waiting" (false). Where the script currently puts "waited too long", you'd substitute the action you want to take when ten seconds have elapsed; i.e., you'd replay the question. BTW, with this method, you don't need the global gLastClickTime. The script local lTime holds that value.

The handler is partially incomplete, omitting any action on the first click where the child initiates the sequence. You'd need to add that. You could use "send mouseup to the target" which would trigger your mouseup handler in the stack script as long as the object itself doesn't have a mouseup handler.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

sritcp
Posts: 431
Joined: Tue Jun 05, 2012 5:38 pm

Re: "Repeat while the mouseClick is false" makes program han

Post by sritcp » Mon Jul 09, 2012 5:13 pm

Hi Jacque,
1.
There will be no delay after the initial mouseclick. The polling I was talking about is for counting down the time
I get it. I was worried about the click happening, and the loop not checking it for about 1 second, and click not taking effect until then. But what you are saying is the mouseClick will be processed (by mouseUp handler) regardless of when the waiting loop checks it. Am I right?

2. The following is a brief code combining Mark's flag and your "wait for 500 ms" suggestions. Am I on the right track?

Code: Select all

local sWaiting, sTime -- script local variables

on programStart
  playAudio -- the program initiates the sequence, not the child
  /* now the wait starts */
  put the seconds into sTime
  put "true" into sWaiting

  repeat while sWaiting
    if the seconds - sTime > 10 then
      put "false" into sWaiting -- the timer is done for this cycle
      repeatAudio -- repeat the phrase with emphasis; note that this is a different audio file
    end if
    wait for 500 millisecs with messages -- this shouldn't affect the click being processed by mouseUp handler
  end repeat
end programStart


on mouseUp
    put "false" into sWaiting -- turn the timer off
    processTheClick -- do necessary things
end mouseUp
Regards,
Sri.

Post Reply