質問

I'm writing a roguelike in Scala. I need to be able to see when the user presses an arrow key for example. All of the solutions I have found require the player to press enter.

Is there any way to detect keypresses in a console app in a similar manner to getch() in C?

役に立ちましたか?

解決

Scala includes jline in its distribution (with slightly modified packaging), since it uses it in the REPL. It's not normally loaded, but if you know where your Scala lib directory is, you can add it to the classpath. If you add it to the classpath, then this will work:

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

(note that this method will give ^P ^N ^B ^F for up, down, left, and right, respectively, matching the standard control keys). But this will also override the standard behavior of System.in.read(), so you can pass it arrays of length 1 to get the next waiting byte (and test for waiting bytes with System.in.available, which should be more than 1 for arrow keys).

他のヒント

The problem with Enter is that terminal buffers input, so you need to turn it to raw mode. Note that it is a platform-specific issue, so it is not very portable.

Look at answers to this question: How to read a single char from the console in Java (as the user types it)?

Short answer for UNIX systems:

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)
}

I must be missing something:

System.in.read

Works for me.

Scala sits on top of the JVM, so the answer for Scala is exactly the same as the answer for Java.

Unfortunately, I don't think you're going to like it - see this other answer for details.

I used the version 3 of jline. It doesn't work inside the IntelliJ IDE, but perfectly in SBT in the terminal of my Macbook.

build.sbt

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

This is an example app, which will stop on pressing the key 'enter'.

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()

That should work.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top