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

Intercepting Events

Started by Selim, 19 November 2015 - 10:25 PM
Selim #1
Posted 19 November 2015 - 11:25 PM
Is it possible to intercept an event before it can be caught and change its parameters before re-queueing it?

For example, catching every "key" event and changing any time that the "tab" key is pressed to queue as pressing the "enter" key?
KingofGamesYami #2
Posted 20 November 2015 - 12:15 AM
Sure, just overwrite coroutine.yeild.
H4X0RZ #3
Posted 20 November 2015 - 12:29 AM
Also, I made a utility for that.

http://www.computercraft.info/forums2/index.php?/topic/23974-h4x0rz-stuff-newest-randomutils/
CoderPuppy #4
Posted 20 November 2015 - 12:34 AM
Sure, just overwrite coroutine.yeild.

That would break any program that uses coroutines and doesn't just pass events through.
KingofGamesYami #5
Posted 20 November 2015 - 12:36 AM
Umm… no it wouldn't.

Every program uses coroutines.
Edited on 19 November 2015 - 11:36 PM
TheOddByte #6
Posted 20 November 2015 - 12:53 AM
That would break any program that uses coroutines and doesn't just pass events through.
As KingOfGamesYami stated, every program uses coroutines, that's because the event system uses coroutine.yield.
The os.pullEventRaw function looks something like this I believe

os.pullEventRaw = function( ... )
	return coroutine.yield( ... )
end
So that's why it wouldn't break anything

Edit: But still, I'd recommend to modify os.pullEventRaw or os.pullEvent instead, and incercept the events there

os.pullEventRaw = function( ... )
    local e = { coroutine.yield( ... ) } --# Call coroutine.yield, which is what os.pullEventRaw usually is using( so no need to backup the function )

    --# Handle the events here
    if e[1] == "key" then
        if e[2] == keys.enter then
            print( "The enter key was pressed" )
        elseif e[2] == keys.tab then --# The tab key was pressed
            e[2] = keys.enter --# Change it to the enter key instead
        end
    end

    return unpack( e ) --# Return the event
end
Edited on 20 November 2015 - 12:07 AM
CoderPuppy #7
Posted 20 November 2015 - 01:14 AM
and doesn't just pass events through.


function test()
  local co = coroutine.create(function()
    print(coroutine.yield('world'))
  end)
  local ok, res = coroutine.resume(co)
  local ok = coroutine.resume(co, 'hello ' .. res)
end

--# try it before the override
test()
--# says 'hello world'

local oldYield = coroutine.yield
function coroutine.yield(...)
  local res = {oldYield(...)}
  if res[1] == 'hello world' then
    return 'broken'
  else
    return unpack(res)
  end
end

--# try it after the override
test()
--# says 'broken'
Bomb Bloke #8
Posted 20 November 2015 - 01:47 AM
That appears to be the desired behaviour.
CoderPuppy #9
Posted 20 November 2015 - 01:55 AM
No, you only want to change the events (the 'hello world' isn't an event).
Thus that program is broken by the modification.
KingofGamesYami #10
Posted 20 November 2015 - 02:20 AM
'hello world' is an event

An event is just data given to coroutine.resume
Edited on 20 November 2015 - 01:24 AM
CoderPuppy #11
Posted 20 November 2015 - 02:27 AM
Not in that case.

Here's another example.

function test()
  local co = coroutine.create(function()
    print(coroutine.yield())
  end)
  local ok, res = coroutine.resume(co)
  local ok = coroutine.resume(co, io.read('*l'))
end
--# type in 'key'
--# it says 'key'
test()
local oldYield = coroutine.yield
function coroutine.yield(...)
  local res = {oldYield(...)}
  if res[1] == 'key' then
    return 'broken'
  else
    return unpack(res)
  end
end
--# type in 'key'
--# it says 'broken'
test()
KingofGamesYami #12
Posted 20 November 2015 - 02:31 AM
Again, the definition of an event is data passed to coroutine.yield.

In addition, unless he overwrites the 'key' event to return 'broken' specifically (as you did), it won't break anything. And if he does overwrite it like that, obviously it was his intention to break it.
CoderPuppy #13
Posted 20 November 2015 - 02:44 AM
No, the definition of an event is an arg-list of event_name,event_data…
You can resume coroutines with stuff other than events, it's just the environment that programs run in in CraftOS is being resumed with events.
Coroutines are also helpful for parsers if you don't have all the input for it available they can yield and wait for more input.
Edited on 20 November 2015 - 01:44 AM
Bomb Bloke #14
Posted 20 November 2015 - 02:57 AM
Again, the definition of an event is data passed to coroutine.yield.

Well, really that's an "all mammals are dolphins" type-statement - only the reverse is true, in that all events come from coroutine.yield! Really you can pass whatever sort of data you like back and forth between coroutines. ComputerCraft primarily has us sending event data, but that's because of the manner in which Dan designed CraftOS, the framework within which all our scripts run.

But, CoderPuppy, the entire point is to carry out the sort of translation your demonstrations are performing. Eg:

local oldYield = coroutine.yield
function coroutine.yield(...)
  local res = {oldYield(...)}
  if res[1] == "key" and res[2] == keys.tab then
    return "key", keys.enter
  else
    return unpack(res)
  end
end

Odds of another script using that specific set of values for "res" for something other than keyboard input? Slim. To say the least.

Yes, this would act as a system-wide translation, and that could be potentially unwanted… but who knows, as Selim hasn't said.
CoderPuppy #15
Posted 20 November 2015 - 03:01 AM
snip

No the whole point is to change the events, not anything using coroutines.
So basically wrap it in a coroutine (and modify the events before resuming it) or override os.pullRawEvent (or os.pullEvent).
Bomb Bloke #16
Posted 20 November 2015 - 05:33 AM
I get what you're saying, but to say that the suggested override will "break" anything is pushing it.

Odds are a custom coroutine manager would indeed be the "neatest" way to handle things (possibly with a TLCO in front of it, depending on whether you're going for a system-wide translation or not). By all means provide Selim with an example, if you like.
Selim #17
Posted 20 November 2015 - 01:09 PM
Thanks, somehow I didn't think of just overriding os.pullEventRaw().