1

I have a Console-Java game. The score from the game will be saved in a JSON file if Ctrl+C is pressed. The process to save the score in a JSON file works. But I don't know, how to detect Ctrl+C from the console and if this happens, I will save the score (just a method call). With KeyListener it doesn't work on the console (only with JFrame as far as I know).

I couldn't find a solution to my problem on the internet.

Do I have to do it with Runtime? I have tried it, but it didn't work...

Runtime.getRuntime().addShutdownHook(new Thread()
{
    public void run()
    {
        Test.mainThread.interrupt();
    }
});

There are similar questions on Stackoverflow, but not for use on the console Catching Ctrl+C in Java

SwissCodeMen
  • 4,222
  • 8
  • 24
  • 34
  • 1
    Maybe this answer will help you: https://stackoverflow.com/questions/18037576/how-do-i-check-if-the-user-is-pressing-a-key – Krzysztof Cichocki May 15 '20 at 14:39
  • _I have tried it, but it didn't work_ More specific details, please. Did your shutdown hook not run? Did it run but threw an exception? Did it run without exception but did not do what you wanted it to? – Abra May 15 '20 at 14:49
  • Nothing works, not even a message. But I also have no idea how to do that... But I will look at the link from @KrzysztofCichocki – SwissCodeMen May 15 '20 at 15:12

2 Answers2

0

Adding a shutdown hook is the right way to do it, but Test.mainThread.interrupt(); probably will not work. The JVM is already shutting down. Your mainThread is unlikely to have time to respond to an interrupt; once all shutdown hooks finish, Java terminates.

Just have your shutdown hook explicitly perform whatever actions you need taken:

Runtime.getRuntime().addShutdownHook(new Thread()
{
    @Override
    public void run()
    {
        try
        {
            Test.saveScore();
        }
        catch (IOException e)
        {
            System.err.println("Couldn't save score before terminating.");
            e.printStackTrace();
        }
    }
});
VGR
  • 40,506
  • 4
  • 48
  • 63
  • 1
    Here is an excerpt from the _javadoc_ of method `addShutdownHook()` in class `java.lang.Runtime`: _In rare circumstances the virtual machine may abort, that is, stop running without shutting down cleanly. This occurs when the virtual machine is terminated externally, for example with the SIGKILL signal on Unix or the TerminateProcess call on Microsoft Windows. ... If the virtual machine aborts then no guarantee can be made about whether or not any shutdown hooks will be run._ Doesn't `Ctrl+C` call `TerminateProcess` on Windows? If it does, then the shutdown hook will most likely not run. – Abra May 16 '20 at 13:34
  • 1
    @Abra [This Microsoft page](https://learn.microsoft.com/en-us/windows/console/ctrl-c-and-ctrl-break-signals) and [this Java technical documentation](https://docs.oracle.com/en/java/javase/14/troubleshoot/handle-signals-and-exceptions.html#GUID-43732853-4FDD-4FED-99A0-56B79B44B3AD) seem to suggest that Ctrl-C can be intercepted and handled. – VGR May 16 '20 at 19:08
  • @VGR what is meen with `Test.mainThread.saveScore();` ? `Test` is the class, and in this class I must throw an exception that called `mainThread`? – SwissCodeMen May 20 '20 at 06:27
  • @SwissCodeMen `saveScore()` is an example. Whatever effect you intended `Test.mainThread.interrupt();` to have, must be moved to a separate method in `Test` (or some other class), so you can call it explicitly. Interrupting a thread is not likely to be effective. – VGR May 20 '20 at 11:24
  • So in this try-catch block, I just call the method that saves the game... But i become following error-message in the console: `Exception in thread "main" java.util.NoSuchElementException: No line found` @VGR – SwissCodeMen May 20 '20 at 12:07
  • @SwissCodeMen That sounds like an entirely different problem. You should create a new question for that. Be sure to include the code that generated the NoSuchElementException, and the full stack trace of the NoSuchElementException. – VGR May 20 '20 at 15:22
0

We know that CTRL-C closes the application and shuts down the JVM. And since it is a normal shutdown, it runs the shutdown hooks. So creating a shutdown hook is a correct approach:

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    // Do something to save the score 
}));

Note that we're passing a Runnable here as the shutdown task. So we can pass an object that has the required functionality:

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    gameScores.save(); // assuming we have a gameScores object in this scope
}));

Your initial attempt by interrupting the thread can be viewed as a variant of this approach. Instead of passing the business object - gameScores - we can pass the thread to interrupt it later. But it's better to operate on the business level.

isaolmez
  • 1,015
  • 11
  • 14