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

Getting a Key without Interrupting Program Flow

Started by CastleMan2000, 21 April 2014 - 12:45 AM
CastleMan2000 #1
Posted 21 April 2014 - 02:45 AM
To put it simply, how do I use OS.pullEvent without pausing the program? I need to check if the user has pressed a key at any time, while also updating information.
Grim Reaper #2
Posted 21 April 2014 - 04:40 AM
I believe that events queue when they aren't being actively looked for by os.pullEvent, so, in theory, you could just catch events at any time even if they were triggered before the time that you were checking. This would allow you to mimic catching events continuously since your update code will probably run pretty quickly.

However, you can also make the time allowed to check for key presses very short which may look like continuous checking if the rest of your program updates quickly enough.

For example, you could do something like this:

local YIELD_TIME = 0.05 -- The amount of time we yield to wait for key presses. Real short to look like its continuous.

local function updateStuff()
    while isThereStuffToDo() do
        doStuff()
        coroutine.yield()
    end
end

local function handleEventData (eventData)
    handleTheStuff (unpack (eventData))
end

local updateThread = coroutine.create (updateStuff)

while coroutine.status (updateThread) ~= "dead" do
    local timer     = os.startTimer (YIELD_TIME)
    local eventData = { os.pullEvent() }

    -- Handle the event data if we didn't catch our yield timer.
    -- NOTE: The timer might get caught by the 'handleTheStuff' function if it pulls an event fast enough.
    if not (eventData[1] == "timer" and eventData[2] == timer) then
        handleEventData (eventData)
    end

    -- Update our information now that events have been handled.
    updateStuff()
end
adencraft2000 #3
Posted 21 April 2014 - 04:43 AM
You could use the parallel API

http://computercraft.info/wiki/Parallel_(API)
Edited on 21 April 2014 - 02:44 AM
apemanzilla #4
Posted 21 April 2014 - 11:32 AM
Two choices. Parallel API (see wiki) and using timer events to set a "timeout" for the pullEvent.

Take a look at os.startTimer on the wiki.
CastleMan2000 #5
Posted 21 April 2014 - 04:17 PM
Alright, I'll see what I can do with that. On an unrelated note, is there a tutorial for all this fancy new rednet stuff? I'm really behind the times.
electrodude512 #6
Posted 21 April 2014 - 11:15 PM
For example, you could do something like this:

local YIELD_TIME = 0.05 -- The amount of time we yield to wait for key presses. Real short to look like its continuous.

local function updateStuff()
	while isThereStuffToDo() do
		doStuff()
		coroutine.yield()
	end
end

local function handleEventData (eventData)
	handleTheStuff (unpack (eventData))
end

local updateThread = coroutine.create (updateStuff)

while coroutine.status (updateThread) ~= "dead" do
	local timer	 = os.startTimer (YIELD_TIME)
	local eventData = { os.pullEvent() }

	-- Handle the event data if we didn't catch our yield timer.
	-- NOTE: The timer might get caught by the 'handleTheStuff' function if it pulls an event fast enough.
	if not (eventData[1] == "timer" and eventData[2] == timer) then
		handleEventData (eventData)
	end

	-- Update our information now that events have been handled.
	updateStuff()
end
That's a bad idea. You should only queue a new timer event when you get the old one, or you'll have a huge pileup of timer events, with the pile getting one timer bigger every non-dummy-timer event.

local YIELD_TIME = 0.05 -- The amount of time we yield to wait for key presses. Real short to look like its continuous.

local function updateStuff()
    while isThereStuffToDo() do
        doStuff()
        coroutine.yield()
    end
end

local function handleEventData (eventData)
    handleTheStuff (unpack (eventData))
end

local updateThread = coroutine.create (updateStuff)
local timer = os.startTimer (YIELD_TIME)

while coroutine.status (updateThread) ~= "dead" do
    local eventData = { os.pullEvent() }

    -- Handle the event data if we didn't catch our yield timer.
    -- NOTE: The timer might get caught by the 'handleTheStuff' function if it pulls an event fast enough.
    if eventData[1] == "timer" and eventData[2] == timer then
        timer = os.startTimer (YIELD_TIME)
    else
        handleEventData (eventData)
    end

    -- Update our information now that events have been handled.
    updateStuff()
end
Edited on 21 April 2014 - 09:18 PM
Grim Reaper #7
Posted 22 April 2014 - 01:24 AM
Spoiler
For example, you could do something like this:

local YIELD_TIME = 0.05 -- The amount of time we yield to wait for key presses. Real short to look like its continuous.

local function updateStuff()
	while isThereStuffToDo() do
		doStuff()
		coroutine.yield()
	end
end

local function handleEventData (eventData)
	handleTheStuff (unpack (eventData))
end

local updateThread = coroutine.create (updateStuff)

while coroutine.status (updateThread) ~= "dead" do
	local timer	 = os.startTimer (YIELD_TIME)
	local eventData = { os.pullEvent() }

	-- Handle the event data if we didn't catch our yield timer.
	-- NOTE: The timer might get caught by the 'handleTheStuff' function if it pulls an event fast enough.
	if not (eventData[1] == "timer" and eventData[2] == timer) then
		handleEventData (eventData)
	end

	-- Update our information now that events have been handled.
	updateStuff()
end
That's a bad idea. You should only queue a new timer event when you get the old one, or you'll have a huge pileup of timer events, with the pile getting one timer bigger every non-dummy-timer event.

local YIELD_TIME = 0.05 -- The amount of time we yield to wait for key presses. Real short to look like its continuous.

local function updateStuff()
	while isThereStuffToDo() do
		doStuff()
		coroutine.yield()
	end
end

local function handleEventData (eventData)
	handleTheStuff (unpack (eventData))
end

local updateThread = coroutine.create (updateStuff)
local timer = os.startTimer (YIELD_TIME)

while coroutine.status (updateThread) ~= "dead" do
	local eventData = { os.pullEvent() }

	-- Handle the event data if we didn't catch our yield timer.
	-- NOTE: The timer might get caught by the 'handleTheStuff' function if it pulls an event fast enough.
	if eventData[1] == "timer" and eventData[2] == timer then
		timer = os.startTimer (YIELD_TIME)
	else
		handleEventData (eventData)
	end

	-- Update our information now that events have been handled.
	updateStuff()
end

Nice catch, thanks.
Edited on 21 April 2014 - 11:25 PM