3

TL;DR

How can I get Ruby curses to respond properly to arrow keys? The KEY_UP constant doesn't seem to match my input.

Environment and Problem Descriptions

I am running Ruby 2.1.2 with the curses 1.0.1 gem. I'm trying to enable arrow-key navigation with curses. I've enabled Curses#getch to fetch a single key without waiting for the carriage return by calling Curses#cbreak, and this is working fine for the k character. However, I really want to enable arrow key navigation, and not just HJKL for movement.

Currently, the up-arrow prints 27 within my program, which seems like the correct ordinal value my keyboard gives for the up-arow key:

"^[[A".ord
#=> 27

and which should be matched by the Curses KEY_UP constant. It isn't, and so falls through to the else statement to display the ordinal value. The up-arrow key also leaves [A as two separate characters at the command prompt when the ruby program exits, which might indicate that Curses#getch isn't capturing the key press properly.

My Ruby Code

require 'curses'
include  Curses

begin
  init_screen
  cbreak
  noecho
  keypad = true

  addstr 'Check for up arrow or letter k.'
  refresh
  ch = getch
  addch ?\n

  case ch
  when KEY_UP
    addstr "up arrow \n"
  when ?k
    addstr "up char \n"
  else
    addstr "%s\n" % ch
  end

  refresh
  sleep 1
ensure
  close_screen
end
Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199

1 Answers1

4

In the line to enable the keypad, you're actually creating a local variable called 'keypad' because that method is on the class Curses::Window. Since you're not making your own windows (apart from with init_screen), you can just refer to the standard one using the stdscr method. If I change line 8 to:

stdscr.keypad = true

then you sample code works for me.

Tim Peters
  • 4,034
  • 2
  • 21
  • 27
  • This seems to work, but I'm not sure I understand why the *keypad=* setter needs an explicit receiver when none of the other methods do, and when I don't have to qualify Curses::Key::KEY_UP. Remember, I used `include Curses`. So why does #keypad= seem to be unique in this way? – Todd A. Jacobs Aug 15 '14 at 13:17
  • Sorry, I haven't used curses for a long time (and when I did, it wasn't with ruby) so I can't answer your question :( – Tim Peters Aug 19 '14 at 00:32
  • I'm going to accept your answer because it solved my immediate problem. Hopefully someone else will help us both with the "why" somewhere down the line. Thanks for your prompt solution! – Todd A. Jacobs Aug 19 '14 at 01:31