3

Seems that Ruby IO#getc wait until receiving a \n before returning the chars.

If you try running this script:

STDOUT.sync = true
STDIN.sync = true
while data = STDIN.getc
  STDOUT.puts "Char arrived"
end

It will return one "Char arrived" per char sent to stdin, but only after a \n has been sent.

Seems that all char are buffered even if I write STDIN.sync = true.

Does anyone knows how to make the script print "Char arrived" right after a char has been sent to STDIN ?

Martinos
  • 2,116
  • 1
  • 21
  • 28
  • 1
    Possible duplicate of [Get Single Char from Console Immediately](http://stackoverflow.com/questions/8072623/get-single-char-from-console-immediately) or [How to Get a Single Character in Ruby without Pressing Enter](http://stackoverflow.com/questions/174933/how-to-get-a-single-character-in-ruby-without-pressing-enter) (which have several good answers on how to solve this). – Phrogz Nov 15 '11 at 21:03

4 Answers4

8

There was an answer from Matz :)

UPDATE

Also, you can use gem entitled highline, because using above example may be linked with strange screen effects:

require "highline/system_extensions"
include HighLine::SystemExtensions

while k = get_character
  print k.chr
end
WarHog
  • 8,622
  • 2
  • 29
  • 23
  • +1 for citing a post from over 11.5 years ago. :) See the question I linked to for more answers that you can compile into yours. – Phrogz Nov 15 '11 at 21:03
  • Yeah, that post is ancient, but as you can see it's still actual :D – WarHog Nov 15 '11 at 21:06
  • Thanks for your quick answer. This makes my day. It explains some strange behaviour I had with other programs. – Martinos Nov 15 '11 at 21:13
2

Adapted from from another answered question.

def get_char
  begin
    system("stty raw -echo")
    str = STDIN.getc
  ensure
    system("stty -raw echo")
  end
  str.chr
end

p get_char # => "q"
Community
  • 1
  • 1
Sean Vikoren
  • 1,084
  • 1
  • 13
  • 24
0

https://stackoverflow.com/a/27021816/203673 and its comments are the best answer in the ruby 2+ world. This will block to read a single character and exit when ctrl + c is pressed:

require 'io/console'

STDIN.getch.tap { |char| exit(1) if char == "\u0003" }
drewish
  • 9,042
  • 9
  • 38
  • 51
0

From https://flylib.com/books/en/2.44.1/getting_input_one_character_at_a_time.html

def getch
  state = `stty -g`
  begin
    `stty raw -echo cbreak`
    $stdin.getc
  ensure
    `stty #{state}`
  end
end

while (k = getch)
  print k.chr.inspect
  sleep 0.2
end
Amir
  • 9,091
  • 5
  • 34
  • 46