Как обнаружить нажатия клавиш на консоли?

Я пишу roguelike в Scala. Мне нужно иметь возможность видеть, когда пользователь нажимает клавишу со стрелкой, например. Все решения, которые я нашел, требуют, чтобы игрок нажал ввод.

Есть ли способ обнаружить нажатия клавиш в консольном приложении аналогично getch() в C?

5 ответов

Решение

Скала включает jline в его распространении (со слегка измененной упаковкой), поскольку он использует его в REPL. Обычно он не загружается, но если вы знаете, где находится ваша директория Scala lib, вы можете добавить ее в classpath. Если вы добавите его в classpath, то это будет работать:

object Key extends App {
  val con = new tools.jline.console.ConsoleReader()
  println( con.readVirtualKey() )
}

(обратите внимание, что этот метод даст ^P ^N ^B ^F для вверх, вниз, влево и вправо, соответственно, соответствующие стандартным клавишам управления). Но это также переопределит стандартное поведение System.in.read(), так что вы можете передать ему массивы длины 1, чтобы получить следующий ожидающий байт (и проверить наличие ожидающих байтов с System.in.available, который должен быть больше 1 для клавиш со стрелками).

Проблема с Enter это терминал буферизует ввод, так что вам нужно включить его raw Режим. Обратите внимание, что это проблема конкретной платформы, поэтому она не очень переносима.

Посмотрите на ответы на этот вопрос: Как прочитать один символ с консоли в Java (как пользователь вводит его)?

Краткий ответ для систем UNIX:

import sys.process._
(Seq("sh", "-c", "stty -icanon min 1 < /dev/tty") !)
(Seq("sh", "-c", "stty -echo < /dev/tty") !)

(1 to 20).foreach { _ =>
  val c = Console.in.read
  println("Got " + c)
}

Я должен что-то упустить

System.in.read

Работает для меня.

Scala находится на вершине JVM, поэтому ответ для Scala точно такой же, как и для Java.

К сожалению, я не думаю, что вам это понравится - подробности смотрите в этом другом ответе.

Я использовал версию 3 jline, Он не работает внутри IntelliJ IDE, но прекрасно работает в SBT в терминале моего Macbook.

build.sbt

libraryDependencies += "org.jline" % "jline" % "3.1.3"

Это пример приложения, которое останавливается при нажатии клавиши "Ввод".

Main.scala

import org.jline.terminal.TerminalBuilder

object Main extends App {

  val terminal = TerminalBuilder.builder().jna(true).system(true).build()
  terminal.enterRawMode()

  val reader = terminal.reader()
  var input = -1

  while (input != 13) {
    input = reader.read

    input match {
       case 'a' =>
         println("you pressed 'a'")
       case unknown =>
         println(s"you pressed a unknown key $unknown")
    }

  }
}

terminal.close()
reader.close()

Это должно работать.

Другие вопросы по тегам