class

Termisu::Event::Source::Input

Inherits Termisu::Event::Source < Reference < Object

Terminal input event source.

Wraps Reader and Input::Parser to produce Key and Mouse events via a dedicated polling fiber.

Usage

reader = Termisu::Reader.new(terminal.infd)
parser = Termisu::Input::Parser.new(reader)
input = Termisu::Event::Source::Input.new(reader, parser)

loop = Termisu::Event::Loop.new
loop.add_source(input)
loop.start

while event = loop.output.receive?
  case event
  when Termisu::Event::Key
    break if event.key.escape?
  when Termisu::Event::Mouse
    puts "Click at #{event.x},#{event.y}"
  end
end

Thread Safety

Uses Atomic(Bool) for the running state. Safe to call start/stop from different fibers.

Constants

IDLE_SLEEP = 4.milliseconds

Idle sleep when no input is available.

Keeps CPU usage low without introducing long blocking waits that can starve high-frequency timers.

4ms is a measured stopgap for the idle busy-poll: it cuts idle select(2) calls from ~978/s to ~244/s at the cost of up to 4ms of added input latency when idle. The proper fix (deferred) is evented IO on the input fd — cooperative IO::FileDescriptor wakeup on data, ~20 wakeups/s with lower latency than any fixed sleep.

Log = Termisu::Logs::Event
MAX_DRAIN_PER_CYCLE = 64

Maximum events drained per loop iteration.

Prevents a continuous input stream from monopolizing the scheduler while still allowing bursty input to be processed quickly.

Constructors

new(reader : Termisu::Reader, parser : Termisu::Input::Parser)

Creates a new input source.

  • reader - Reader instance for raw input
  • parser - Parser instance for escape sequence parsing
Source

Instance methods

name

Returns the source name for identification.

Source
prepare_raw_handoff

Prepares the stopped source to hand its reader to a raw-input consumer.

Callers must stop the source first. A parsed event blocked on backpressure and bytes retained by an in-progress parser probe both remain event-owned; handing the reader to a raw consumer in either state would reorder or split the input stream.

Source
running?

Returns true if the input source is currently running.

Source
start(output : Channel(Event::Any)) : Nil

Starts polling for input events and sending them to the output channel.

Spawns a fiber that drains available input events without blocking and sends them to the channel.

Serializes lifecycle changes so a previous polling fiber is fully stopped before another can start.

Source
stop

Stops polling for input events.

Signals the polling fiber and waits for it to finish. When this method returns, the parser no longer touches the reader, so ownership can be handed to a raw-input caller without splitting an input sequence.

Source