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

Monitor touch interrupt

Started by ExtremeRedstone, 06 December 2017 - 04:12 PM
ExtremeRedstone #1
Posted 06 December 2017 - 05:12 PM
Hi,

I am making a Big Reactors management program.
This is my problem: I want to be able to press monitor buttons (next screen, settings, etc) while frequently updating (1Hz) the monitor with new statistics.
As far as I can tell, the os.pullEvent("monitor_touch") blocks further code from executing until it has received a monitor touch event.
Is there any way I can keep updating the screen and receiving button presses?

I have thought of the following but do not know how to code them (or if they are actually possible at all):
- interrupts that execute a function when an event has happened, like the attachInterrupt(pin, function) for Arduino's and other microcontrollers
- parallel programming: a separate thread waits for an event while the main thread handles the updating stuff

Do you have any experience with this problem?
Dog #2
Posted 07 December 2017 - 12:29 AM
You don't need to filter for an event when you capture it - you can do the filtering afterward like so…

local event, data, x, y = os.pullEvent()
if event == "monitor_touch" then
  --# do monitor touch stuff - x and y are the touch coords
elseif event == "updateTriggerEvent"
  --# update values and screens, etc.
end
KingofGamesYami #3
Posted 07 December 2017 - 12:30 AM
If you call os.pullEvent without a parameter, it will return any event.

Example:


while true do
  local tEvent = {os.pullEvent()}
  print( "An event of type " .. tEvent[ 1 ] .. " has occurred" )
end

Assuming you are currently using sleep to update the monitor, it may be useful to view the actual declaration of sleep
Bomb Bloke #4
Posted 07 December 2017 - 12:57 AM
If you're using touchpoint, then you might integrate in os.startTimer() like so:

local timerDelay = 1

local myTimer = os.startTimer( timerDelay )

while true do
	local event, p1 = t:handleEvents( os.pullEvent() )
	
	if event == "button_click" then
		-- Handle button clicks here.
	
	elseif event == "timer" and p1 == myTimer then
		-- Update displays here.
		
		myTimer = os.startTimer( timerDelay )
		
	end
end
Dave-ee Jones #5
Posted 07 December 2017 - 05:17 AM
If you call os.pullEvent without a parameter, it will return any event.

Example:


while true do
  local tEvent = {os.pullEvent()}
  print( "An event of type " .. tEvent[ 1 ] .. " has occurred" )
end

Assuming you are currently using sleep to update the monitor, it may be useful to view the actual declaration of sleep

Well, isn't that frustrating?
Calling sleep() clears your events because it's going through all those events!
It would be useful if you stored those events in a table and then queued them all again after the sleep() function has completed. Might not work well for longer sleep times but I haven't tested it.
Luca_S #6
Posted 07 December 2017 - 06:15 AM
If you call os.pullEvent without a parameter, it will return any event.

Example:


while true do
  local tEvent = {os.pullEvent()}
  print( "An event of type " .. tEvent[ 1 ] .. " has occurred" )
end

Assuming you are currently using sleep to update the monitor, it may be useful to view the actual declaration of sleep

Well, isn't that frustrating?
Calling sleep() clears your events because it's going through all those events!
It would be useful if you stored those events in a table and then queued them all again after the sleep() function has completed. Might not work well for longer sleep times but I haven't tested it.

That would be a terrible idea to be honest.
Imagine a program with a GUI you can click in using sleep, if it captures the mouse_click events during the sleep a user might click randomly in the GUI to check if the program is hanging. All these clicks will then be used by the program and some strange stuff might happen.
If you really wanted to you could override the sleep function:

function sleep( nTime )
    local tEvents = {}
    if nTime ~= nil and type( nTime ) ~= "number" then
	    error( "bad argument #1 (expected number, got " .. type( nTime ) .. ")", 2 )
    end
    local timer = os.startTimer( nTime or 0 )
    local tEvent
    repeat
	   tEvent = {os.pullEvent()}
	   tEvents[#tEvents+1] = tEvent
    until tEvent[1] == "timer" and tEvent[2] == timer
    tEvents[#tEvents] = nil --Remove the last entry which is the timer event from sleep
    for _,v in ipairs(tEvents) do
	    os.queueEvent(unpack(v))
    end
end
ExtremeRedstone #7
Posted 07 December 2017 - 03:30 PM
If you really wanted to you could override the sleep function

I just found this: https://github.com/sandalle/minecraft_bigreactor_control/blob/master/lolmer_bigreactor_monitor_prog.lua#L1387-L1399
It seems a bit more simple than your suggestion Luca, but the repeat […] until seems more appropiate here so I'll replace the while loop with that, and the 'event[2] == timer' piece with >= in case it misses the exact second for whatever reason.

Thanks!
(but there really isn't a built-in interrupt function?)
Dave-ee Jones #8
Posted 08 December 2017 - 12:04 AM
That would be a terrible idea to be honest.
Imagine a program with a GUI you can click in using sleep, if it captures the mouse_click events during the sleep a user might click randomly in the GUI to check if the program is hanging. All these clicks will then be used by the program and some strange stuff might happen.
If you really wanted to you could override the sleep function:

I thought that too at first, but then realised that it would only store the event queue it had BEFORE it started pulling them, not DURING or AFTER.
Luca_S #9
Posted 08 December 2017 - 05:53 AM
I'm unsure what you mean. Every event before sleep() is send to the program and can be retrieved via os.pullEvent()
Bomb Bloke #10
Posted 08 December 2017 - 06:46 AM
I'll replace … and the 'event[2] == timer' piece with >= in case it misses the exact second for whatever reason.

Timers don't work like that - read the documentation again.