Keyboard key input

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.

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

for windows:
Read keypresses from user in terminal, including arrow keys using pure Ruby. This has since been folded into a much more robust gem called Remedy. https://rubygems.org/gems/remedy & https://github.com/acook/remedy · GitHub

STDIN.echo = false
STDIN.raw!
p STDIN.getc

Ronald F. 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:
Read a single keyboard hit (even arrows and special keys) without echoing, in Ruby « Alec's Web Log

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.

Regis d’Aubarede wrote in post #1185437:

for windows:
Read keypresses from user in terminal, including arrow keys using pure Ruby. This has since been folded into a much more robust gem called Remedy. https://rubygems.org/gems/remedy & https://github.com/acook/remedy · GitHub

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.

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

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.

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.

What exactly is not working? You don’t get any key back without pressing
ENTER?

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.

Now it’s my turn to not really understand what you mean :wink:

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?

Ronald F. wrote in post #1185453:

Now it’s my turn to not really understand what you mean :wink:

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 F. 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