Ch4rAss Ch4rAss - 3 months ago 19
Ruby Question

EventMachine how to write keyboard handler reacting on keypress

I use EventMachine LineText2 protocol and I would like to fire

receive_line
method everytime I press a character on my keyboard and not just when I enter a new line. Is there a way to change that default behaviour?

class KeyboardHandler < EM::Connection
include EM::Protocols::LineText2

def initialize(q)
@queue = q
end

def receive_line(data)
@queue.push(data)
end
end

EM.run {
q = EM::Queue.new

callback = Proc.new do |line|
# puts on every keypress not on "\n"
puts line
q.pop(&callback)
end
q.pop(&callback)

EM.open_keyboard(KeyboardHandler, q)
}

Answer Source

If you want to receive unbuffered input from the terminal, you should turn off canonical-mode on standard input. (I also turn off echo to make the screen easier to read.) Add this before your code calls #open_keyboard or within your handler initializer:

require 'termios'
# ...
attributes = Termios.tcgetattr($stdin).dup
attributes.lflag &= ~Termios::ECHO # Optional.
attributes.lflag &= ~Termios::ICANON
Termios::tcsetattr($stdin, Termios::TCSANOW, attributes)

For example:

require 'termios'
require 'eventmachine'

module UnbufferedKeyboardHandler
  def receive_data(buffer)
    puts ">>> #{buffer}"
  end
end

EM.run do
  attributes = Termios.tcgetattr($stdin).dup
  attributes.lflag &= ~Termios::ECHO
  attributes.lflag &= ~Termios::ICANON
  Termios::tcsetattr($stdin, Termios::TCSANOW, attributes)

  EM.open_keyboard(UnbufferedKeyboardHandler)
end