Rijul
Rijul

Reputation: 515

Press and hold key programmatically java

Alright, I've searched now for a whole day, but no result. Maybe someone can help it.

I'm trying to generate a key "press and hold" situation in my java program, programmatically. Let me explain the situation:

I listen constantly for an event. Consider 2 events 'A' and 'B'. If event A occurs, I want to press and hold down the keyboard key (X), and if event 'B' occurs, I want to release the key (X). Now the main thing is, this all has to be a side process, so even if A occurs, I can listen for event B.

I've tried making a separate thread, making an infinite loop inside it, pressing the key using 'Robot' in java, but it turned out to be the most inefficient way of achieving this, as it consumes more than 60% of CPU. I've tried achieving this with a state changed, but don't seem to find a way to restrict the key press, to change only when I want it to.

I would appreciate a solution without any infinite loop, if possible, as I am already using 1 to listen for event occurrences. (Suggestions are welcome)

Here is my code for the thread:

public class KeyPress implements Runnable {
public String command;

public void run() {
    try {
        Robot r = new Robot();

        while (true) {
            //System.out.println(command);
            if (command.equals("up")) {
                r.keyPress(KeyEvent.VK_UP);
                r.delay(20);
                r.keyRelease(KeyEvent.VK_UP);
            } else if (command.equals("finish")) {
                break;
            }
        }

    } catch (Exception e) {
        System.out.println(e);
    }
}
}

The instance of thread is created as usual, in my main class. Also, if someone can explain this - when I remove or comment out the

System.out.println(command);

statement (as you see in the code), This thread stops working. If I add this, it works. Although this problem is secondary, as it still is a non-feasible solution.

Upvotes: 1

Views: 2461

Answers (2)

Rijul
Rijul

Reputation: 515

Well, after a long and tiring attempt to solve this problem, I think I might have a solution.

Firstly, I create a thread everytime event 'A' occurs, although its the same as before. When event 'B' occurs, I interrupt the thread, which makes it to exit. Since these events 'A' and 'B' occur alternatively, this works for the CPU usage problem.

Another optimization, and possibly the answer to the problem of having to write print() statement, was I made the variable command as volatile. As explained here, the compiler optimization was most likely the problem I was facing.

Here is the code after these changes:

public class KeyPress implements Runnable {
public volatile String command;

public void run() {
    try {
        Robot r = new Robot();
        while (command.equals("up") && !Thread.currentThread().isInterrupted()) {
            r.keyPress(KeyEvent.VK_UP);
            r.delay(20);
        }
    } catch (Exception e) {
        System.out.println(e);
    }
}
}

I hope this helps someone, and someone can provide suggestions on how to improve it.

Upvotes: 1

lichengwu
lichengwu

Reputation: 4307

Observer pattern maybe a good solution.

Do not loop in the thread. Use notify and listener mode like this:

Listen to the command:

class RobotObserver implements Observer{
    private Robot  r = new Robot();
    @Override
    public void update(Observable o, Object arg) {
        String command=arg.toString();
        if (command.equals("up")) {
            r.keyPress(KeyEvent.VK_UP);
            r.delay(20);
            r.keyRelease(KeyEvent.VK_UP);
        } else if (command.equals("finish")) {
            System.out.println(command);
        }
    }
}

Notify listener:

Observable observable = new Observable();
observable.addObserver(new RobotObserver());
observable.notifyObservers("up");
observable.notifyObservers("finish");

PS: class Observer and Observable are both in package java.util.

Upvotes: 0

Related Questions