Захват событий со стрелками в сценарии Ruby - PullRequest
3 голосов
/ 02 января 2012

Я пишу небольшой скрипт на Ruby, который читает ввод из командной строки.

Я бы хотел поймать сигнал стрелки вверх, вниз, влево, вправо. Я хочу сделать что-то вроде в терминале. (когда вы нажимаете стрелку вверх, у вас есть предыдущая команда ...) Как я могу это сделать?

Ответы [ 2 ]

2 голосов
/ 02 января 2012

Чтобы сделать небуферизованный ввод, вы можете использовать что-то вроде termios. Однако вам придется интерпретировать последовательности клавиш со стрелками вручную.

Если вы можете жить со средним слоем для завершения истории, я предлагаю использовать GNU readline , как упоминалось ранее, или библиотеку RawLine от H3RALD:

http://www.h3rald.com/rawline/
http://www.h3rald.com/articles/real-world-rawline-usage/

Пример небуферизованного ввода с termios:

require 'rubygems'
require 'termios'

def with_unbuffered_input
  old_attrs = Termios.tcgetattr(STDOUT)

  new_attrs = old_attrs.dup

  new_attrs.lflag &= ~Termios::ECHO
  new_attrs.lflag &= ~Termios::ICANON

  Termios::tcsetattr(STDOUT, Termios::TCSANOW, new_attrs)

  yield
ensure
  Termios::tcsetattr(STDOUT, Termios::TCSANOW, old_attrs)
end

with_unbuffered_input do
  10.times {
    c = STDIN.getc
    puts "Got #{c}"
  }
end
0 голосов
/ 02 мая 2015

Начиная с ruby ​​1.9.3, io/console поставляется с ruby. Можно использовать его #raw для получения небуферизованного ввода:

http://ruby -doc.org / STDLIB-2.2.2 / libdoc / IO / консоль / RDoc / IO.html # метод-я-сырец

Однако клавиши со стрелками представлены последовательностью символов, а не одним символом. Эта последовательность всегда начинается с "\e", но, к сожалению, маркера конца последовательности нет.

Нечто подобное можно использовать для чтения клавиш со стрелками:

require 'io/console'
require 'timeout'

def readkey
  c = ''
  result = ''
  $stdin.raw do |stdin|
    c = stdin.getc
    result << c
    if c == "\e"
      begin
        while (c = Timeout::timeout(0.0001) { stdin.getc })
          result << c
        end
      rescue Timeout::Error
        # no action required
      end
    end
  end
  result
end

puts readkey.inspect #=> outputs "\e[D" if left arrow is pressed
...