title: What is the best way to get keyboard events (input without press 'enter') in a Ruby console application?
body: <p>I've been looking for this answer in the internet for a while and have found other people asking the same thing, even here. So this post will be a presentation of my case and a response to the "solutions" that I have found.</p>
  
  <p>I am such new in Ruby, but for learning purposes I decided to create a gem, <a href="https://github.com/fschuindt/camelog" rel="nofollow">here</a>.
  I am trying to implement a keyboard navigation to this program, that will allow the user use short-cuts to select what kind of request he want to see. And in the future, arrow navigations, etc.</p>
  
  <p>My problem: I can't find a consistent way to get the keyboard events from the user's console with Ruby.</p>
  
  <p>Solutions that I have tried:</p>
  
  <ol>
  <li>Highline gem: Seems do not support this feature anymore. Anyway it uses the STDIN, keep reading.</li>
  <li>STDIN.getch: I need to run it in a parallel loop, because at the same time that the user can use a short-cut, more data can be created and the program needs to show it. And well, I display formated text in the console, (Rails log). When this loop is running, my text lost the all the format.</li>
  <li>Curses: Cool but I need to set position(x,y) to display my text every time? It will get confusing.</li>
  </ol>
  
  <p><a href="https://gist.github.com/fschuindt/5567063#file-camelog-rb-L43" rel="nofollow">Here</a> is where I am trying to do it.
  You may note that I am using "stty -raw echo" (turns raw off) before show my text and "stty raw -echo" (turns raw on) after. That keeps my text formated.</p>
  
  <p>But my key listener loop is not working. I mean, It works in sometimes but is not consistent. If a press a key twice it don't work anymore and sometimes it stops alone too.</p>
  
  <p>Let me put one part of the code here: </p>
  
  <pre><code>    def run
      # Two loops run in parallel using Threads.
      # stream_log loops like a normal stream in the file, but it also parser the text.
      # break it into requests and store in @requests_queue.
      # stream_parsed_log stream inside the @requests_queue and shows it in the screen.
      @requests_queue = Queue.new
      @all_requests = Array.new
      # It's not working yet.
      Thread.new { listen_keyboard }
      Thread.new { stream_log }
      stream_parsed_log
    end
  
    def listen_keyboard
      # not finished
      loop do
        char = STDIN.getch
        case char
        when 'q'
          puts "Exiting."
          exit
        when 'a'
          @types_to_show = ['GET', 'POST', 'PUT', 'DELETE', 'ASSET']
          requests_to_show = filter_to_show(@all_requests)
          command = true
        when 'p'
          @types_to_show = ['POST']
          requests_to_show = filter_to_show(@all_requests)
          command = true
        end
        clear_screen if command
        @requests_queue += requests_to_show if command
        command = false
      end
    end
  </code></pre>
  
  <p>I need a light in my path, what should I do? </p>