EventMachine how to write a keyboard handler reacting to keystrokes

I am using the EventMachine LineText2 protocol and I would like to run the method receive_line

every time I press a character on my keyboard, not just when I enter a new line. Is there a way to change this default behavior?

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)
}

      

+3


source to share


3 answers


If you want to receive unbuffered input from the terminal, you must disable canonical mode on standard input. (I'll also disable echo to make the screen easier to read.) Add this before your code calls #open_keyboard

or inside 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

      

+5


source


I haven't used EventMachine before, but this page on the EventMachine wiki indicates that you shouldn't use the protocol LineText2

as it sounds like you don't want buffered lines.

They give this example:



module MyKeyboardHandler
  def receive_data(keystrokes)
    puts "I received the following data from the keyboard: #{keystrokes}"
  end
end

EM.run {
  EM.open_keyboard(MyKeyboardHandler)
}

      

Does it give you what you want?

0


source


Here's an update for Ruby 2.0+. In Ruby 2.0 we got io/console

that much easier handling the original keyboard, and it's cross-platform.

Here's a working example that reacts to raw keyboard events with io/console

:

require 'io/console'
require 'eventmachine'

module KB
  def receive_data(d)
    puts "GOT: #{d}\r"

    # CTRL-C will not work in raw mode, so we need another way to exit    
    EM::stop if d == 'q'
  end
end

begin
  EM.run {
    # Put console in raw mode (no echo, no line buffering)
    IO.console.raw!
    EM.open_keyboard(KB)
  }
ensure
  # Ensure cooked, otherwise console will be unusable after exit
  IO.console.cooked!
end

      

0


source







All Articles