 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
jballi
Joined: 01 Oct 2005 Posts: 313 Location: Texas, USA
|
Posted: Mon Sep 10, 2007 12:58 pm Post subject: SetTimer not working correctly if context menu used |
|
|
In a nutshell, if a SetTimer timer is running when a context menu is displayed/fired, subsequent SetTimer commands do not wait the requested period before running. In these conditions, the SetTimer command acts like a gosub statement instead of a SetTimer statement.
I've created a short script to illustrate the problem:
| Code: | menu cm,Add,Run it!,RunIt
gui Add,Checkbox,vOff x100 y50 Checked,Off
gui Add,Checkbox,vRunning y+10,Running
gui show,w300 h150,Test
return
guiContextMenu:
menu cm,Show,%A_GuiX%,%A_GuiY%
return
runit:
settimer runit_timer,off
guicontrol,,Off,0
guicontrol,,Running,1
settimer runit_timer,3000
return
runit_timer:
settimer runit_timer,off
guicontrol,,Off,1
guicontrol,,Running,0
return
guiescape:
guiclose:
exitapp
|
In this example, a context menu routine is used to change the value of two objects and a timer is used to return the objects back to their original values after 3 seconds.
To see how the example is supposed to work, run the GUI, open the context menu and select the "Run it" item. The routine will change the value of the checkboxes ("Off" set to unchecked and "Running" set to checked) and after 3 seconds, will change them back.
To illustrate the problem, run the same test except that before the 3 seconds have elapsed, open the context menu again. Keep the context menu open longer than the SetTimer period (at least 4 seconds) [the bug only occurs if the timeout period has expired] and then select the "Run It" item. Note that after the "Run It" item is selected, the value of the checkboxes are immediate set to their original state.
The workaround is to set the SetTimer period to a negative value (-3000). Give it a try. It does resolve the problem that occurs in this example.
Thank you for your consideration. Let me know if you need any additional information. |
|
| Back to top |
|
 |
Superfraggle
Joined: 02 Nov 2004 Posts: 770 Location: London, UK
|
Posted: Mon Sep 10, 2007 1:31 pm Post subject: |
|
|
It looks like the one time timer has a higher threap priority than a normal timer.
When you click the menu you are interupting the timer thread and it starts resets to running. However the interupted timer kicks in after this and sets them back to its original state.
When you specify a one time timer. It appears as though the system sees this as a more critical timer, and doesn't allow it to be interupted. Looking at the recently exucuted lines you can see the difference in execution.
Seeing as in this case the Timer must run, Make its line critical and the problem goes away. _________________ Steve F AKA Superfraggle
http://r.yuwie.com/superfraggle |
|
| Back to top |
|
 |
jballi
Joined: 01 Oct 2005 Posts: 313 Location: Texas, USA
|
Posted: Mon Sep 10, 2007 2:27 pm Post subject: |
|
|
| Superfraggle wrote: | | Seeing as in this case the Timer must run, Make its line critical and the problem goes away. |
I tried it and it didn't work for me. Making the SetTimer line "critical" doesn't make any sense to me because the thread ends immediately after that line with the "return" statement. Perhaps you can show me in the code exactly what you did to make it work.
Thanks. |
|
| Back to top |
|
 |
Superfraggle
Joined: 02 Nov 2004 Posts: 770 Location: London, UK
|
Posted: Mon Sep 10, 2007 3:08 pm Post subject: |
|
|
| Code: | menu cm,Add,Run it!,RunIt
gui Add,Checkbox,vOff x100 y50 Checked,Off
gui Add,Checkbox,vRunning y+10,Running
gui show,w300 h150,Test
return
guiContextMenu:
menu cm,Show,%A_GuiX%,%A_GuiY%
return
runit:
settimer runit_timer,off
guicontrol,,Off,0
guicontrol,,Running,1
settimer runit_timer,3000
return
runit_timer:
critical
settimer runit_timer,off
guicontrol,,Off,1
guicontrol,,Running,0
return
guiescape:
guiclose:
exitapp |
This works for me _________________ Steve F AKA Superfraggle
http://r.yuwie.com/superfraggle |
|
| Back to top |
|
 |
jballi
Joined: 01 Oct 2005 Posts: 313 Location: Texas, USA
|
Posted: Tue Sep 11, 2007 1:03 am Post subject: |
|
|
If you've seen the Matrix, you've seen how the guys are able tell what is going on in the Matrix by learning how to read streaming symbols. My Matrix is the "lines most recently executed" view that is built in to AHK. The output is very easy to read if stuff happens from top to bottom but if stuff is happening in more than one place (multiple threads), it gets confusing very quickly, at least to me.
This definitely is (OK, "appears to be") a thread priority issue. Putting a Critical command as the first line (can't be the 2nd or 3rd line..., etc.) of the routine that the SetTimer command calls makes the timer thread critical and in this example, allows the runit_timer routine to run (finish) before calling the runit routine for the 2nd time. Because I'm not quite able to read the Matrix (yet), I had to use a debugger to watch what was happening in real time.
This fixes my problem. Thank you.
I have a couple of very minor issues...
I read through the SetTimer and Critical documentation and I couldn't find where putting a Critical statement as the first line of the routine that the SetTimer calls, makes the timer critical. Is this an undocumented feature or am I the only one that didn't know this?
Also, I'm glad that SetTimer "Run Once" feature works in my example but shouldn't it work the same as without the "Run Once" option? I'm not sure which way to vote for...
Finally, without the Critical statement in the runit_timer routine, the original timer will not fire until the runit routine (called from the context menu while the first timer was running) has completed, no matter what I do. Shouldn't a "sleep xxxx" command allow the original timer to complete. It appears that the runit routine is running as critical because it was initiated from a context menu.
Thank you for your feedback. |
|
| Back to top |
|
 |
Superfraggle
Joined: 02 Nov 2004 Posts: 770 Location: London, UK
|
Posted: Tue Sep 11, 2007 11:43 am Post subject: |
|
|
| jballi wrote: | | I read through the SetTimer and Critical documentation and I couldn't find where putting a Critical statement as the first line of the routine that the SetTimer calls, makes the timer critical. Is this an undocumented feature or am I the only one that didn't know this? |
Its kind of documented but not specifically. possibly a document improvement there.
| jballi wrote: | | Also, I'm glad that SetTimer "Run Once" feature works in my example but shouldn't it work the same as without the "Run Once" option? I'm not sure which way to vote for... |
I'm interested to work out whats going on here. Heres my ideas that could explain a little, I think Chris or someone would need to verify.
When running a normal timer and the timer cannot run. The timer will wait until it can run. If it cannot run, it will cancel the last run and wait for the next run therefor its thread is canceled and the other thread is run instead.
I'm assuming that a run once timer will NOT stop itself from running, no matter how long it has to run. So its thread stays in the queue.
| jballi wrote: | | Finally, without the Critical statement in the runit_timer routine, the original timer will not fire until the runit routine (called from the context menu while the first timer was running) has completed, no matter what I do. Shouldn't a "sleep xxxx" command allow the original timer to complete. It appears that the runit routine is running as critical because it was initiated from a context menu. |
All threads will run as interuptable unless specified, so because the runit timer is called whilst the timer is waiting to run it interupts the timer. It does look as though the run once timer has a higher priority.
I could be way off track here, this is only what I can see establish. _________________ Steve F AKA Superfraggle
http://r.yuwie.com/superfraggle |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10463
|
Posted: Sun Nov 11, 2007 10:30 pm Post subject: |
|
|
Sorry for the late reply. I hope the following explains it:
As documented, no threads can run while the script is displaying a menu. This raises the possibility that a timer can become overdue while a menu is visible. So when the user finally selects a menu item, the program must choose which to run first: the menu item subroutine or the overdue timer. Currently, I don't think there's any prioritization, so the choice might be somewhat random -- it might even depend subtle factors like CPU speed.
Although I'm glad you found a workaround, I haven't analyzed it or the AHK code enough to guaranty that it's 100% reliable. If you ever need another workaround, one possibility is the trick that allows threads to run during the display of a menu: www.autohotkey.com/forum/viewtopic.php?p=81572#81572 |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|