Forum: Ruby Keyboard key input

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
5ca81a4f5c56f18eb8b1cedefe06520c?d=identicon&s=25 Clément Caillat (clment_c)
on 2017-01-05 01:24
Attachment: Star10_OS.rb (852 Bytes)
Hey, everybody. I'm new to this forum, and to Ruby in general. I started
making an operating system program in Ruby, but I am already stuck, as I
am still learning. What I need help with is keyboard key input. What I
mean by that is that I want to know what code I should write if I want
the person to press Enter and then the program responds to the user who
pressed Enter, not because he wrote it and send it. I have googled this
for a while but I have not been able to find a satisfactory or
understandable answer.
Could anybody help?
PS: I have attached my code to this post if you want to take a look at
it.
0fa73332c8e4a3b06ea439fd3f034322?d=identicon&s=25 Ronald Fischer (rovf)
on 2017-01-05 09:11
If I understand your question correctly, you want to get a single
character from the keyboard, as soon as it is pressed.

Ruby doesn't have the concept of a "keyboard", and a correct solution
depends on the operating system where your application is running.

There is some discussion on this issue here:
http://www.alecjacobson.com/weblog/?p=75
B078cb4f4fb473c7a54d1fc36d10c70e?d=identicon&s=25 Regis d'Aubarede (raubarede)
on 2017-01-05 14:57
for windows:
 https://gist.github.com/acook/4190379

STDIN.echo = false
STDIN.raw!
p STDIN.getc
5ca81a4f5c56f18eb8b1cedefe06520c?d=identicon&s=25 Clément Caillat (clment_c)
on 2017-01-05 18:32
Ronald Fischer wrote in post #1185433:
> If I understand your question correctly, you want to get a single
> character from the keyboard, as soon as it is pressed.
>
> Ruby doesn't have the concept of a "keyboard", and a correct solution
> depends on the operating system where your application is running.
>
> There is some discussion on this issue here:
> http://www.alecjacobson.com/weblog/?p=75

This is could work, but how do I integrate this into my code? Also, what
are the main lines used to detect that a keyboard key has been pressed?
I kind of understand how to integrate this into my code, however I will
probably have to rewrite it to fit my purpose. Thank you though. It is
quite helpful and I think I can use it. I will tell you if I get it to
work.
5ca81a4f5c56f18eb8b1cedefe06520c?d=identicon&s=25 Clément Caillat (clment_c)
on 2017-01-05 18:35
Regis d'Aubarede wrote in post #1185437:
> for windows:
>  https://gist.github.com/acook/4190379
>
> STDIN.echo = false
> STDIN.raw!
> p STDIN.getc

Sorry, I forgot to tell you. I'm programming in Ruby with Kubuntu 15.10,
not Windows. Thanks though. I think I may have an idea of how to solve
this. I'll reply if I figure it out.
0fa73332c8e4a3b06ea439fd3f034322?d=identicon&s=25 Ronald Fischer (rovf)
on 2017-01-06 09:31
Clément Caillat wrote in post #1185439:
> This is could work, but how do I integrate this into my code?

Well, I don't know your code, so I can answer this; but the solution
given in this blog article for reading a key is pretty self-contained.

> Also, what
> are the main lines used to detect that a keyboard key has been pressed?

THIS is a completely different issue, which you had not mentioned
before. There is one thing to read the next character (i.e. wait for the
next character to be pressed), and checking *whether* a character has
been pressed.

In this case, you could use a non-blocking read. See for instance

http://stackoverflow.com/questions/946738/detect-k...

but this doesn't make it unbuffered reading. You could try to combine
the two approaches, but I don't know whether it will work.

In the Stackoverflow article, there is a suggestion to use the courses
library, which brings another point: In what environment is your
application running? Just from the command line? Or wouldn't it make
more sense to run an X application in its own Window? Since you want to
intercept events (here: key press events), the latter would maybe the
better approach.
5ca81a4f5c56f18eb8b1cedefe06520c?d=identicon&s=25 Clément Caillat (clment_c)
on 2017-01-06 19:59
Attachment: Star10_OS.rb (2 KB)
Here is my code. I'm trying to make it detect ENTER being pressed when I
need it then disable the show_single_key method using a variable called
login, but it is not working. Is it the best way to do what I want by
using a variable or would there be a better way to control the method? I
have also read the forum post of your latest post but I do not
understand it as well as the first one.
PS: I would indeed like if I could have my ruby script as a standalone
application, however I do not know how to do that.
0fa73332c8e4a3b06ea439fd3f034322?d=identicon&s=25 Ronald Fischer (rovf)
on 2017-01-09 12:35
What exactly is not working? You don't get any key back without pressing
ENTER?
5ca81a4f5c56f18eb8b1cedefe06520c?d=identicon&s=25 Clément Caillat (clment_c)
on 2017-01-09 22:48
I don't really understand what you mean by that. The method in the code
to detect a keyboard key and print text works, but I'm trying to find a
way to activate and disable this method when I need it.
0fa73332c8e4a3b06ea439fd3f034322?d=identicon&s=25 Ronald Fischer (rovf)
on 2017-01-10 07:03
Now it's my turn to not really understand what you mean  ;-)

While in theory you *can* redefine a method at runtime (which would, in
some sense, disable it), I see no gain from this. When you need this
method, you call it. When you need a different method, you call a
different one. Where exactly is the problem?
5ca81a4f5c56f18eb8b1cedefe06520c?d=identicon&s=25 Clément Caillat (clment_c)
on 2017-01-10 19:07
Attachment: Star10_OS.rb (2 KB)
Ronald Fischer wrote in post #1185453:
> Now it's my turn to not really understand what you mean  ;-)
>
> While in theory you *can* redefine a method at runtime (which would, in
> some sense, disable it), I see no gain from this. When you need this
> method, you call it. When you need a different method, you call a
> different one. Where exactly is the problem?

Thank you for your post! I followed your advice and called my own method
to do what I wanted, and it finally works! If you want to check it out,
it is attached to my reply. Also thank you to Ronald Fischer for the
keyboard reading method to which he posted a link to it which helped me
start to solve this problem. Problem solved, but I think this forum
topic should be referenced because it could help a lot of other people
with the same problem.
PS: I'm not sure whether or not you can see my code when I attach it. So
here it is below:

puts "..."
sleep 3

puts "BIOS sleep mode activated. Entering boot mode."
sleep 1

puts "Boot mode entered. Preparing to boot."
sleep 0.5

puts "Booting..."
sleep 5

puts "Starting core..."
sleep 2
puts "Started."
sleep 1
puts "Starting kernel..."
sleep 2
puts "Started."
sleep 1
puts "Starting Star10 'GUI'..."
sleep 1
puts "Started."
sleep 0.5
puts "Starting Holographic (filesystem)..."
sleep 1
puts "Started."
sleep 0.5
puts "Starting Star Store (softwarecenter)..."
sleep 1
puts "Started."
sleep 0.5
puts "Starting Galaxy Explorer (webbrowser)..."
sleep 1
puts "Started."
sleep 0.5
puts "Finishing booting..."
sleep 10
puts "Operating system booted."
sleep 1
puts ""
puts "                              Star 10 : A terminal-based operating
sytem made in Ruby."
puts "                                                  Press ENTER to
login."
puts ""

# read a character without pressing enter and without printing to the
screen
def read_char
  begin
    # save previous state of stty
    old_state = `stty -g`
    # disable echoing and enable raw (not having to press enter)
    system "stty raw -echo"
    c = STDIN.getc.chr
    # gather next two characters of special keys
    if(c=="\e")
      extra_thread = Thread.new{
        c = c + STDIN.getc.chr
        c = c + STDIN.getc.chr
      }
      # wait just long enough for special keys to get swallowed
      extra_thread.join(0.00001)
      # kill thread so not-so-long special keys don't wait on getc
      extra_thread.kill
    end
  rescue => ex
    puts "#{ex.class}: #{ex.message}"
    puts ex.backtrace
  ensure
    # restore previous state of stty
    system "stty #{old_state}"
  end
  return c
end

# takes a single character command
#def show_single_key
    #c = read_char
  #case c
  #when " "
   # puts "SPACE"
  #when "\t"
   # puts "TAB"
  #when "\r"
   # puts "RETURN"
  #when "\n"
   # puts "LINE FEED"
  #when "\e"
   # puts "ESCAPE"
  #when "\e[A"
   # puts "UP ARROW"
  #when "\e[B"
   # puts "DOWN ARROW"
  #when "\e[C"
   # puts "RIGHT ARROW"
  #when "\e[D"
   # puts "LEFT ARROW"
  #when "\177"
   # puts "BACKSPACE"
  #when "\004"
   # puts "DELETE"
  #when /^.$/
   # puts "SINGLE CHAR HIT: #{c.inspect}"
  #else
   # puts "SOMETHING ELSE: #{c.inspect}"
  #end
#end

#show_single_key while(true)

# detects pressing ENTER for login
def detect_enter_login
    c = read_char
    case c
    when "\r"
        puts "Login"
    end
end
detect_enter_login
This topic is locked and can not be replied to.