cls
do
keyed$=inkey$
loop until keyed$<>""
print"the hello world"
end
so in this program as you have seen until a press a key in the statement "keyed$=inkey$" the program wont display the hello world. so i want such a statement or program which will exit the loop in certain time. so the program will wait for 4 second and if users press the key before than that it will go to next line and even if the user wont press any key then program will move to next line in 4 second. please help me!!!
You can use the SLEEP statement:
PRINT "Press a key within 4 seconds to win!"
' Wait 4 seconds or until a key is pressed.
SLEEP 4
' Collect the key pressed, if any.
keyed$ = INKEY$
IF keyed$ <> "" THEN
PRINT "You WON by typing: "; keyed$
ELSE
PRINT "You LOST!"
END IF
Note that certain keys such as the arrow keys are considered "extended" keys. The first character of keyed$ will be equal to CHR$(0) to tell you that an extended key was detected, and the second character will allow you to determine which key it was. You can find more information on the QB64 wiki about those "two byte codes" if you need to handle them. For such keys, the code above won't work so well, as shown below when I press the Up arrow key (CHR$(0) + CHR$(&H48)):
Press a key within 4 seconds to win!
You WON by typing: H
^note the extra space for CHR$(0)
Edit
You can use this instead of a loop to do what you want:
' Wait 4 seconds for a key to be pressed.
SLEEP 4
' If a key was not pressed in 4 seconds, keyed$ = "".
keyed$ = INKEY$
IF keyed$ = "" THEN PRINT "Timeout (no key pressed)"
PRINT "the hello world"
In other words, no loop is needed to detect whether a key was pressed if you use the SLEEP statement and immediately use the INKEY$ function afterward.
If you still prefer a timer-based solution with a loop, then you can use a few extra variables, an additional loop condition, and the TIMER function, which returns the number of seconds elapsed since midnight. The following does the same thing as the SLEEP method above:
maxWait = 4
startTime = TIMER
DO
' Detect a key press.
keyed$ = INKEY$
' Fix the start time if the loop started before midnight
' and the current time is after midnight.
IF startTime > TIMER THEN startTime = startTime - 86400
' Loop until a key is pressed or maxWait seconds have elapsed.
LOOP UNTIL keyed$ <> "" OR startTime + maxWait < TIMER
' If a key was not pressed in 4 seconds, keyed$ = "".
IF keyed$ = "" THEN PRINT "Timeout (no key pressed)"
PRINT "the hello world"
The advantage to this more complex option is the fact that you can do other things in the loop while waiting for a key press. Of course, there is a slight problem. If you're doing too much, the key press will be detected late because INKEY$ won't be called right when the key is pressed. For example:
maxWait = 4
startTime = TIMER
DO
' Do some work.
x = 0
FOR i = 1 TO 1000000
x = x + 1
NEXT i
' Detect a key press and exit the loop if one is detected.
keyed$ = INKEY$
' Fix the start time if the loop started before midnight
' and the current time is after midnight.
IF startTime > TIMER THEN startTime = startTime - 86400
' Loop until a key is pressed or maxWait seconds have elapsed.
LOOP UNTIL keyed$ <> "" OR startTime + maxWait < TIMER
It's tricky to avoid the issue. One option is ON TIMER(n) as suggested by #MatthewWhited, except you can only use one timer event. This means you would need it to exit the loop after maxWait seconds rather than detect a key press, even if there is work occurring. Meanwhile, your key presses will still be detected noticeably later than desired. QB64 allows for the usage of multiple timers, allowing you to handle both. It also allows you to specify n with millisecond precision, unlike QBasic that only allows for 1-second precision at minimum. See ON TIMER(n) on the QB64 Wiki for more information about QB64's improvements to ON TIMER(n).
Since I don't know your usage case, I can't recommend one solution or another, based on the code you've provided.
Related
I have been reading a text file a object and create a list with the contents.
textfile:
Activity Time Location
Football 8-9 Pitch
Basketball 9-10 Gym
Lunch 11-12 Home
Read 13-14 Library
Swim 14-15 Pool
openTime = 6
closeTime = 15
come = int(input('When do you want to come?'))
leave = int(input('When do you want to leave?'))
# endtime_of_activity and startTimeofactivity is equal to the startingtime
# of each activity and the end time of each activity in the textfile
# (taken from a list that I have been splitting).
for i in range(len(my_list)):
item = my_list[i]
if (i == 1):
continue
if closeTime <= come <= endtime_of_activity and startTimeofactivity < leave <= closeTime:
print(item.activities)
My question: As you can read in the textfile there are some activities appering on different times. For example football between 8 and 9. With the code I want to be able to skip the second element (basketball) as the code is doing, however, I want the if statement under "continue" to work. If i type that im coming 8 and leaving at 12 I want all the activities (excluding the second one) to show. This works for me when I'm doing a regular for-loop without skiping the second activity, like when im just writing: for i in my_list, then adding on the condition, but when Im doing the code above it shows me all the activites (except basketball) independeltly of when I chose to come and leave. What have I missed? How could I write the code better?
If you want to skip a certain activity, simply test if the activitiy to be printed is the same and skip it if it is:
with open("f.txt","w") as f:
f.write(("Activity Time Location\nFootball 8-9 "
"Pitch\nBasketball 9-10 Gym\nLunch 11-12"
" Home\nRead 13-14 Library\nSwim 14-15"))
data = []
with open("f.txt") as f:
for line in f:
act, time, what = (line.strip().split(" ") + ["","",""])[:3]
if data:
try:
time=list(map(int, time.split("-")))
except ValueError:
continue # invalid time: skip row
data.append([act,time,what])
header,*data = data
openTime = 6
closeTime = 15
come = 9
leave = 12
skip=set(["Basketball"])
fmt = "{:<15}"*len(header)
print(fmt.format(*header))
for act,(start,stop),what in data:
if act in skip:
continue
if start >= come and stop <= leave and openTime <= come and closeTime >= leave:
print(fmt.format(act, f"{start}-{stop}", what))
Output:
Activity Time Location
Football 8-9 Pitch
Lunch 11-12 Home
My code:
Func myFunc()
$lag = 1300
while (1)
MouseMove(870, 189)
sleep(10)
LC(870, 189)
sleep(1200 + $lag)
LC(1010,333)
sleep(100)
RC(826,115)
sleep(50)
LC(870,212)
sleep(50)
send("{ESC}")
sleep(150)
$x = 0
$y = 0
For $i = 0 To 27 Step 1
sleep(11)
MouseClick("left", 1158 + $x ,260 + $y)
$x+=42
if ($x = 168) Then
$x = 0
$y+=36
EndIf
Next
WEnd
EndFunc
The only delay within the for loop is the sleep(11) but it takes about .5 seconds (500ms) for each iteration rather than 11ms + whatever small delay. Also, completely removing the sleep(11) part of the loop still results in an approximately 500ms delay.
Incase anyone was wondering, it's a video game macro; the first part of the while loop opens an interface and sets something up while the second part (the for loop) is suppose to click through the inventory very quickly.
The mouse cursor takes time to move. Set the speed parameter to 0 to make it move instantly
MouseClick("left", 1158 + $x ,260 + $y,1,0)
Alright so the question is hard to word. I've googled this several times, but usually it turns out I'm not googling the right phrases, and the answer is readily available. I do work as a medical biller for a doctors office, and I have to include diagnosis codes for the office visits. In the Electronic Medical Record program, there's a diagnosis list. The first line is the doctors description, I don't care about that. The second line is an ICD-9 code. Those are old, I don't care about those either. The third line (every third line) contains the ICD-10 code. That's what I need. What I'd like to be able to do is grab the whole list, dump it into an array delimited by new lines, and get rid of every element that doesn't contain a specific string. Then, dump all the kept elements into another array (or the same one, but not separated by 3 like they would be after the removals) and remove that prefixed string that I kept elements based on. After that, I need to click a specific spot (I know how to do this), add exactly four of the arrays elements as text (can't figure this out), hit enter, and keep adding and hitting enter until I've entered all of the array. I will post what I've tried cobble together from google searches if anyone wants to see that mess. But a general explanation on how to do this would also be appreciated. Thanks.
first of all, the stuff I'd be copying would look like this (actual example)
Lumbar stenosis - Primary
ICD-9-CM: 724.02
ICD-10-CM: M48.06
Spondylolisthesis of lumbar region
ICD-9-CM: 738.4
ICD-10-CM: M43.16
Lumbar degenerative disc disease
ICD-9-CM: 722.52
ICD-10-CM: M51.36
Chronic bilateral low back pain with bilateral sciatica
ICD-9-CM: 724.2, 724.3, 338.29
ICD-10-CM: M54.42, M54.41, G89.29
Naturally the list would be much longer.
The string I'd look for to keep the lines would be "ICD-10-CM: ", just so you guys know. I DID try using it as a delimiter, in quotes, but got some really quite weird results. It would have made this problem slightly easier to solve had that worked as the delimiter.
Arrays:={}
RealArray:={}
^j::
sendinput, ^c
sleep 20
bigone:=ClipBoard
sleep 2000
;StringReplace, bigone, newbigone, `n, "DLMTR", All
;Arrays:= StrSplit(newbigone, "DLMTR")
StringSplit, Arrays, bigone, `n
k=4
j=1
loop
{
if (k<Arrays.Max_Index)
{
RealArray%j%=Arrays%k%
j++
k++
k++
k++
}
else
return
}
return
^L::
a=0
loop
{
if (a<RealArray.Max_Index)
{
send RealArray%a%
a++
sendinput, {Space}
if(mod(a,5)==0)
sendinput, {enter}
}
else
return
}
Program
^j collects codes containing "ICD-10", ^k pastes the codes formatted 5 per line
^j::copyit()
^l::pasteit()
copyit()
{
sendinput, ^c
sleep 20
bigone := ClipBoard
sleep 100
global matches
matches := []
numMatches := 0
Loop parse, bigone, `n
Loop parse, A_LoopField, `,
if InStr(A_LoopField, "ICD-10")
matches[++numMatches] := trim( substr(A_LoopField, InStr(A_LoopField, ":") + 1), " `t`n`r")
}
pasteit()
{
global matches
for index, element in matches
{
Send %element%{SPACE}
if mod(index,5) == 0
Send {ENTER}
}
}
Input:
Recurrent major depressive disorder, in partial remission
ICD-9-CM: 296.35
ICD-10-CM: F33.1
ICD-10-CM: F33.2
ICD-9-CM: 296.35
ICD-10-CM: F33.3
ICD-10-CM: F33.4
ICD-9-CM: 296.35
ICD-10-CM: F33.5, ICD-10-CM: X432.6, ICD-10-CM: Y232.6
ICD-10-CM: F33.6
ICD-9-CM: 296.35
Output:
F33.1 F33.2 F33.3 F33.4 F33.5
X432.6 Y232.6 F33.6
Without knowing how the underlying program that you are automating works, I can't tell you when to sleep or send extra ENTERs.
Maybe you can query the state of the screen to determine what to do next (e.g., send codes, extra ENTERs, wait).
I identify the screen state by searching for a small image that uniquely identifies the state the program is in. I make the images using Alt+PrintScrn to capture the entire screen and then use pbrush.exe to crop out small a unique identifying image.
; Search screen for image stored in "images/name.png"
; return true if found, false otherwise
find( name )
{
fname := "images\" . name . ".png"
ImageSearch x, y, 0,0,A_ScreenWidth, A_ScreenHeight, *32 %fname%
return ( ErrorLevel = 0 and x >= 0 and y >= 0 )
}
; Wait for image stored in "images/name.png" to appear on the screen
wait_for( name )
{
tooltip Waiting for %name%, 100,0,1
while !find(name)
sleep 100
}
; business/domain logic bot
automate_screen()
{
if ( find( "logon" ))
do_stuff_to_logon()
else if ( find( "payroll_history" ))
do_some_other_stuff()
else if ( find( "payroll_screen1" ))
{
sendplay Type this on screen1{enter}01{enter}
wait_for( "payroll_screen2" )
sendplay Type this on screen2{enter}
}
}
main()
{
loop
{
automate_screen()
sleep 250
}
}
I want to receive a string from an array using a variables' integer as the array index. But it is not working.
Attempt 1
; Suspended | 0 = No, 1 = Yes
global Suspended := 0
global SuspendedMsg := ["The script has been paused.","The script has been re-activated."]
Pause::
Suspend
if suspended = 0 ; If script is not suspended
{
TrayTip, Paused, SuspendedMsg[Suspended], 3
Suspended++
} else ; If it is suspended
{
TrayTip, Activated, SuspendedMsg[Suspended], 3
Suspended--
}
return
Attempt #1 will just display the string "SuspendedMsg[Suspended]" because I don't know where to set the variable indicator %. Even if I set it to SuspendedMsg[%Suspended%] it will either display [1] or [0].
Attempt 2
; Suspended | 0 = No, 1 = Yes
global Suspended := 0
global SuspendedMsg := ["The script has been paused.","The script has been re-activated."]
global SendSuspendMsg := SuspendedMsg[Suspended]
Pause::
Suspend
if suspended = 0 ; If script is not suspended
{
TrayTip, Paused, %SendSuspendMsg%, 3
Suspended++
} else ; If it is suspended
{
TrayTip, Activated, %SendSuspendMsg%, 3
Suspended--
}
return
Attempt #2 won't do as well, it doesn't even display any message. I tried fiddling arround with % inside the global SendSuspendMsg := SuspendedMsg[Suspended] variable but it won't do no good. Anyone care to help me out?
#Blauhim missed an important point, although his answer is mostly correct. First the Index in an Array when created like you did, always starts at 1, then proceeds to 2 etc, etc... So your code was flawed when you tried to use your Boolean variable to call to an index as a 0 Index does not exist (not to mention that you didn't force and Expression on that TrayTip Command).
; Set our variable to 1 why? Because we are going to use a Logical switch below.
Suspended := 1
; This was correct format and I left it, although I removed Global's as they are not needed
SuspendedMsg := ["The script has been paused.","The script has been re-activated."]
Pause::
; Suspend toggles each time it's called
Suspend
; Here we are toggling the value of our variable using !
; We started with a 1 so that it would be correctly
;Changed to a 0 for the code below.
suspended := !suspended
; Nothing changed here
if suspended = 0 ; If script is not suspended
{
; In order to pass an Array or Object or Expression to a Command you Force it
; using the a Percent Sign with a space on either side.
; Also note you were trying to use your Logical True/False 0 or 1 variable to
; itterate. This didn't work because Array's always start with an Index of 1.
; Below I've accounted for this by simply added a 1 to your suspended so it correctly
; points to the Index in our Array.
TrayTip, Paused, % SuspendedMsg[suspended + 1], 3
} else ; If it is suspended
{
TrayTip, Activated, % SuspendedMsg[suspended + 1], 3
}
return
Instead of TrayTip, Paused, SuspendedMsg[Suspended], 3 or TrayTip, Paused, SuspendedMsg[%Suspended%], 3, try
TrayTip, Paused, % SuspendedMsg[Suspended], 3
. TrayTip asks you for a
specify the message to display
which means as much as a String. So, variables names aren't handled as variables here, but as strings instead (as most of the times in commands). It would make sense to state TrayTip, Paused, %SuspendedMsg[%Suspended%]%, 3
, but you cannot nest variable's percent signs. So, we'll have to use the percent sign to force an expression:
Force an expression: An expression can be used in a parameter that does not directly support it (except OutputVar parameters) by preceding the expression with a percent sign and a space or tab. In [v1.1.21+], this prefix can be used in the InputVar parameters of all commands except the traditional IF commands (use If (expression) instead). This technique is often used to access arrays.
Concerning your second problem: I don't think Arrays can be declared like that, can they..? (but I'm not sure). Also see this short article. So I guess the problem lies within the 3rd line of your code, because the rest of it looks good to me
Question
Basically, the title says it all! How do I stop execution of my hotkey via a hotkey?
How do I do so without closing the script?
How do I explicitly set a hotkey to take priority over a specific loop?
Explanation
I have a loop that executes several hundred times (code attached), and I would like to create a kill switch. I don't want to have to re-open the script if I stop it running, and I need to have lengthy sleeps, so I can fool with the mouse, as it is.
I'm looking at various pages, such as tutorial and break.
What I've tried
For example, should I name my loop somehow? Because Break takes no parameters, I'm thinking: there's no way to specify what to break.
Another example: should I add a hotkey into my loop to break? If so, how do I do that? Just throw ^!p:: into a nest under each hotkey? Or is there another way to add a hotkey to a hotkey (for example, with GetKeyState)?
Answer format
If possible, please show don't tell your answers, using the following code:
^!i::
{
Loop 1300
{
Send ^+{PrintScreen}
Sleep 1500
MouseClickDrag, left, 0, 100, 600, 400
Sleep 1000
Send 1
Sleep 500
}
Return
}
^!o::
{
Loop 1323
{
Send ^+{PrintScreen}
Sleep 1500
MouseClickDrag, left, 0, 200, 600, 400
Sleep 1000
Send 1
}
Return
}
If you want a controlled stop, i.e. at a certain point in the script, then you could use a hotkey to set a variable and test that variable in the script. When the variable has been set and the IF statement is true, you reset that variable and exit the loop. Otherwise, you could kill the script at a random point through the reload command. This way the script is closed, but immediately reopened.
^!i::
MyStopVariable:=0 ; Set the variable to 0
Loop 1300
{
If MyStopVariable
Exit ; Or Break if you want to finish something of after the loop
Send ^+{PrintScreen}
Sleep 1500
MouseClickDrag, left, 0, 200, 600, 400
Sleep 1000
If MyStopVariable
Exit ; Or Break if you want to finish something of after the loop
Sleep 500
}
Return
^!o::
MyStopVariable:=0 ; Set the variable to 0
Loop 1323
{
If MyStopVariable
Exit ; Or Break if you want to finish something of after the loop
Send ^+{PrintScreen}
Sleep 1500
MouseClickDrag, left, 0, 200, 600, 400
Sleep 1000
If MyStopVariable
Exit ; Or Break if you want to finish something of after the loop
Send 1
}
Return
^!s:: ; Ctrl+Alt+s = stop
MyStopVariable:=1
Return
Alternatively, you could use your original code and add a reload.
^!s:: ; Ctrl+Alt+s = stop
Reload
Return