This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Marcono1234's profile picture

Having a timer while read() is waiting for input?

Started by Marcono1234, 03 September 2014 - 06:03 PM
Marcono1234 #1
Posted 03 September 2014 - 08:03 PM
Hello, I have a question,
is there a way of having a timer and the "read()" input so, for example the read() gets stopped when you press no key for 7 seconds? (I am using TekkitLite -> ComputerCraft 1.5)

I read something about events but I don't really understand how to do this :/
It would be very nice if you could also explain then a little bit what each command does :)/>
flaghacker #2
Posted 03 September 2014 - 08:58 PM
Take a look at the parallel api: http://computercraft.info/wiki/Parallel_(API) .

Create a function that calls read, one that waits, and run them using parallel.waitForAny. That way it will stop both functions when one of them ends.
KingofGamesYami #3
Posted 03 September 2014 - 09:11 PM
I'm just going to leave this here, to add to flaghackers suggestion.

os.queueEvent( 'key', 28 ) --#simulates the user pressing "ENTER"
Marcono1234 #4
Posted 03 September 2014 - 09:24 PM
Thank you flaghacker :)/>
And how could I then set the countdown every time the user enters something back to 7 seconds?

KingofGamesYami, could you please explain me, what that does and how to use for my situation :)/> ?

I changed it now to this (could be very wrong, I am a beginner, keep in mind please :)/> ):

-- abcdef4
local start
local startupExists
local readTimeOut = 7 -- time in seconds until read() stops
local readTimeOutActive
function copyStartup()
fs.copy("disk/startup.file","startup")
end
function readInput(inputVariable, readType)
inputVariable = read(readType)
return
end
function readTimer()
readTimeOutActive = true
while readTimeOutActive do
  readTimeOutActive = false
  sleep(readTimeOut)
end
return
end
function pressKey()
local sEvent, param = os.pullEvent("key")
if(sEvent == "key") then
  readTimeOutActive = true
end
end
parallel.waitForAny(readInput("startupExists",""), readTime(), pressKey())
but now, everytime I try to enter something here, the letters are invisible and also it gives me the error "startup:38:attempt to call nil"
Edited on 03 September 2014 - 08:01 PM
flaghacker #5
Posted 03 September 2014 - 10:07 PM
Make your wait function something like this:

function wait ()
  local id = os.startTimer (7)
  while true do
    event = {os.pullEvent ()}
    if event [1] == "timer" and event [2] == id then
      os.queEvent ("key",  28)
      break
    elseid event [1] == "char" then
      id = os.startTimer (7)
    end
  end
end

I used his suggestion here, it basically fakes an enter press, so the read function can stop and return its string when the timer stops. If you don't want that just remove the line with os.queEvent in my code.

EDIT: Coding on mobile is a pain.
Edited on 03 September 2014 - 08:08 PM
flaghacker #6
Posted 03 September 2014 - 10:12 PM
Ninja'd.

I can debug your code tomorrow, when I have access to my laptop. Maybe try with the code I posted, else we'll see tomorrow.
Marcono1234 #7
Posted 03 September 2014 - 10:24 PM
Thank you very much :)/> Sorry for creating you aggravations :/ (hope that makes sense, English is not my mother language)

But now I have multiple questions:
  1. what does this part exactly mean " if event [1] == "timer" and event [2] == id then" I don't really understand this completely, would be nice if you could explain that to me :)/>
  2. what does this " elseid event [1] == "char" then" mean, and are you missing a space there, can you also add a condition with else and does the "char" means just any letter and even backspace
  3. And to get this running, could you just have something like this:
  4. 
    	function wait ()
    	  local id = os.startTimer (7)
    	  while true do
    	    event = {os.pullEvent ()}
    	    if event [1] == "timer" and event [2] == id then
    		  os.queEvent ("key",  28)
    		  break
    	    elseid event [1] == "char" then
    		  id = os.startTimer (7)
    	    end
    	  end
    	end
    	function readInput(inputVariable, readType)
    	  inputVariable = read(readType)
    	  return
    	end
    	parallel.waitForAny(readInput("startupExists",""), wait())
    	
  5. And don't you have to end the function just with "return" or can you also use "break" like you did, and does this even work better?
Thank you already for your help and until tomorrow ;)/>
KingofGamesYami #8
Posted 03 September 2014 - 10:38 PM
  1. what does this part exactly mean " if event [1] == "timer" and event [2] == id then" I don't really understand this completely, would be nice if you could explain that to me :)/>
Event is a table, the first one being the type of event. The timer event returns the id of the timer. "and" simply links checks together, in one statement. if both are true, then it will continue. Otherwise, it will not.

what does this " elseid event [1] == "char" then" mean, and are you missing a space there, can you also add a condition with else and does the "char" means just any letter and even backspace
He means:

elseif event[ 1 ] == "char" then
Which checks if the user pressed an alphanumeric key. (which would be something that read() accepts)

       function wait ()
          local id = os.startTimer (7)
          while true do
            event = {os.pullEvent ()}
            if event [1] == "timer" and event [2] == id then
                  os.queEvent ("key",  28)
                  break
            elseid event [1] == "char" then
                  id = os.startTimer (7)
            end
          end
        end
        function readInput(inputVariable, readType)
          inputVariable = read(readType)
          return
        end
        parallel.waitForAny(readInput("startupExists",""), wait())get this running, could you just have something like this:
No. When using parallel, you cannot use parentheses. If you do that, you pass the return of the function rather than the actual function itself.

And don't you have to end the function just with "return" or can you also use "break" like you did, and does this even work better?
either way works, since after "break" the function ends anyway. Actually, you don't even need break because after queuing the "enter" event, the read() function returns and terminates both.
Edited on 03 September 2014 - 08:40 PM
Marcono1234 #9
Posted 04 September 2014 - 08:35 PM
And can maybe also someone help me with this:

while coordinatesInputDir ~= ("north" or "east" or "south" or "west" or "x" or "-x" or "z" or "-z") do
I don't really understand why it only accepts "north", but the rest no, or do I have do write everytime "coordinatesInputDir ~= east"…?
flaghacker #10
Posted 04 September 2014 - 08:49 PM
Yes, but you could do it with a for loop:

function check (value, list)
  for _, j in pairs (list) do
    if j == value then
      return true
    end
  end
  return false
end

local v = "east"
local directions = {
  "north",
  "east",
  "west,
}

if check(v, directions) then
  print ("Yaay")
end

It loops through the table, checking if the value matches. If it does, return true. If nothing matched return false.
KingofGamesYami #11
Posted 04 September 2014 - 09:03 PM

print( "hello" or "goodbye" )

The easiest way to do this is:

local acceptable_inputs = {
  "north" = true,
  "east" = true,
  "south" = true,
  "west" = true,
  "x" = true,
}
while acceptable_inputs[ coordinatesInputDir ] do
end
Marcono1234 #12
Posted 04 September 2014 - 10:36 PM
Thank you :)/>
And back to my old post, how can I now do this with the read() and the timer, because I also want to detect if the player presses for example backspace and I don't know if this counts as char…
KingofGamesYami #13
Posted 04 September 2014 - 11:39 PM
Thank you :)/>
And back to my old post, how can I now do this with the read() and the timer, because I also want to detect if the player presses for example backspace and I don't know if this counts as char…
If you want to detect backspace, etc. Use "key" instead of "char."
Marcono1234 #14
Posted 05 September 2014 - 07:40 PM
Thank you, but guys please could you please also answer my other question:
  1. How can I do that now, I asked this now two times but you didn't really response, what is the second function I have to run that I can do the read() ?
  2. Could it be, that tables are really bugged in 1.5, I mean I can't set numbers as keys, and also not "-x", because then it doesn't recognize the table and I can't put "" quotation marks around the key…
  3. Why does this not work
  4. 
    		while coordinatesInputDir ~= ("north" or "east" or "south" or "west" or "x" or "-x" or "z" or "-z") do
    		
    I want that while loop to run until the input is one of the values, but when I do it like this, only "north" is accepted, also when I do this
    
    		while coordinatesInputDir ~= "north" or "east" or "south" or "west" or "x" or "-x" or "z" or "-z" do
    		
    And when I do this
    
    		while coordinatesInputDir == not ("north" or "east" or "south" or "west" or "x" or "-x" or "z" or "-z") do
    		
    it wont even start the loop…
Edited on 05 September 2014 - 05:40 PM
Lyqyd #15
Posted 05 September 2014 - 07:47 PM
1. I'm not sure what you're asking.

2. No, tables work fine in that version. Show us the code you're having trouble with specifically, please.

3. You need to explicitly make each comparison. And, or and not keywords are used to combine the results of individual comparisons, not to expand a single comparison.
KingofGamesYami #16
Posted 05 September 2014 - 08:43 PM
Here's a brief idea of how to define stuff in tables:

tbl = {
  ["-x"] = true,
  x = true,
  [1] = true, --#note: without the brackets the key becomes "1" (the string instead of the number)
}
tbl[ "-x" ] = true
tbl.x = true
tbl[ 1 ] = true

These should all work
Marcono1234 #17
Posted 05 September 2014 - 08:45 PM
1. Is how do I then run the second function which includes the "read()", or what does it have to contain (I want to have read() input which stops when the user presses for 7 seconds no key)
2. These all are not working:

local test = {
53 = "HI"
}

local test = {
"53" = "HI"
}

local test2 = {
"x" = true
}

local test2 = {
"-x" = true
}

local test2 = {
-x = true
}
3. These are also not working

while (coordinatesInputDir ~= "north" or coordinatesInputDir ~= "east" or coordinatesInputDir ~= "south" or coordinatesInputDir ~= "west" or coordinatesInputDir ~= "-z" or coordinatesInputDir ~= "x" or coordinatesInputDir ~= "z" or coordinatesInputDir ~= "-x") do

while coordinatesInputDir ~= "north" or coordinatesInputDir ~= "east" or coordinatesInputDir ~= "south" or coordinatesInputDir ~= "west" or coordinatesInputDir ~= "-z" or coordinatesInputDir ~= "x" or coordinatesInputDir ~= "z" or coordinatesInputDir ~= "-x" do

Whole code:

while (coordinatesInputDir ~= "north" or coordinatesInputDir ~= "east" or coordinatesInputDir ~= "south" or coordinatesInputDir ~= "west" or coordinatesInputDir ~= "-z" or coordinatesInputDir ~= "x" or coordinatesInputDir ~= "z" or coordinatesInputDir ~= "-x") do
  term.clear()
  term.setCursorPos(1,1)
  print("Please enter the direction and the coordinates of the turtle: ")
  print("Tips:")
  print("* You can see the your direction and coordinates when you press the F3 key")
  print("* When you type in 0, the turtle uses it as realitve coordinates")
  print("* Instead of north, east, south and west you can also enter -z, x, z and -x")
  print("")
  print("X: " .. coordinatesInputX)
  print("Y: " .. coordinatesInputY)
  print("Z: " ..coordinatesInputZ)
  write("Direction: ")
  coordinatesInputDir = read()
end
Edited on 05 September 2014 - 06:47 PM
Lyqyd #18
Posted 05 September 2014 - 10:48 PM
1. You'd need to run the read() call in a separate coroutine. A parallel call is probably the simplest implementation. Someone can provide an example for you.

2. The keys should be written thus:


[53]
["53"]
x (or ["x"], either way is the string "x" as the key; use [x] for the value contained in variable x)
["-x"]
[-x]

3. while not (x ~= "n" and x ~= "s") and not (y ~= "-x" and y ~= "-z") do

You inverted the statement such that while your variables were not all possible values simultaneously, the loop would continue.
Marcono1234 #19
Posted 07 September 2014 - 03:36 PM
This was exactly would I wanted to do, so the loop would continue until the user enters one of the possibilities, but somehow it doesn't work like it should, do you have a clue why it is like this?
Marcono1234 #20
Posted 27 September 2014 - 01:41 PM
Could you please help me :(/> ?
1. Is how do I then run the second function which includes the "read()", or what does it have to contain (I want to have read() input which stops when the user presses for 7 seconds no key)
Bomb Bloke #21
Posted 27 September 2014 - 04:36 PM
One example:

local input

local function getInput()
  input = read()
end

local function wait()
  sleep(7)
end

parallel.waitForAny(getInput, wait)

if input then
  print("User typed "..input)
else
  print("Timer ended before user finished typing")
end
Marcono1234 #22
Posted 27 September 2014 - 08:15 PM
One example:

local input

local function getInput()
  input = read()
end

local function wait()
  sleep(7)
end

parallel.waitForAny(getInput, wait)

if input then
  print("User typed "..input)
else
  print("Timer ended before user finished typing")
end
That is pretty friendly from you, but this doesn't solve my problem completely, because I need also something that sets the time again to 7 seconds when the player presses any key :)/>
Can you please help me again?
MKlegoman357 #23
Posted 27 September 2014 - 08:40 PM
Well, you could expand the 'wait' function a little:


local function wait ()
  local event, id

  repeat
    local timer = os.startTimer(7) --// Start the timer

    repeat
      event, id = os.pullEvent() --// Continually pull events
    until event == "timer" or event == "key" --// until there's either a 'timer' event or a 'key' event
  until event == "timer" and timer == id --// If the event was not a 'timer' event or it's another timer, restart the countdown
end
Marcono1234 #24
Posted 27 September 2014 - 10:05 PM
Well, you could expand the 'wait' function a little:


local function wait ()
  local event, id

  repeat
	local timer = os.startTimer(7) --// Start the timer

	repeat
	  event, id = os.pullEvent() --// Continually pull events
	until event == "timer" or event == "key" --// until there's either a 'timer' event or a 'key' event
  until event == "timer" and timer == id --// If the event was not a 'timer' event or it's another timer, restart the countdown
end
Alright, I will test this, thank you very much :)/>