-1

So I made a javafx application that store texts and you can choose which text you want the program to type in (using for a game to set the binds)

I have this:

public class AutoClicker {

private Robot robot;

public AutoClicker() {
    try {
        robot = new Robot();
    } catch (AWTException ex) {
        System.out.println("Problem in AutoClicker constructor: " + ex);
    }
}

public void click(int button) {
    robot.keyPress(button);
    robot.delay(10);
    robot.keyRelease(button);
}

public void oneModifier(int pressing, int button) {
    robot.keyPress(pressing);
    robot.delay(10);
    robot.keyPress(button);
    robot.delay(10);
    robot.keyRelease(button);
    robot.delay(10);
    robot.keyRelease(pressing);
    robot.delay(10);

}

public void twoModifier(int pressing1, int pressing2, int button) {
    robot.keyPress(pressing1);
    robot.delay(10);
    robot.keyPress(pressing2);
    robot.delay(10);
    robot.keyPress(button);
    robot.delay(10);
    robot.keyRelease(button);
    robot.delay(10);
    robot.keyRelease(pressing2);
    robot.delay(10);
    robot.keyRelease(pressing1);
    robot.delay(10);

}

public void clickingENG(String tmp) {

    int length = tmp.length();
    int[] text = new int[length];

    for (int i = 0; i < length; i++) {
        text[i] = tmp.charAt(i);
    }

    for (int i = 0; i < text.length; i++) {
        switch (text[i]) {
            case ' ':
                click(KeyEvent.VK_SPACE);
                break;
            case '.':
                click(KeyEvent.VK_PERIOD);
                break;
            case '"':
                oneModifier(KeyEvent.VK_SHIFT, KeyEvent.VK_QUOTE);
                break;
            case '/':
                click(KeyEvent.VK_SLASH);
                break;
            case '\\':
                click(KeyEvent.VK_BACK_SLASH);
                break;
            case '+':
                oneModifier(KeyEvent.VK_SHIFT, KeyEvent.VK_EQUALS);
                break;
            case '!':
                oneModifier(KeyEvent.VK_SHIFT, KeyEvent.VK_1);
                break;
            case '0':
                click(KeyEvent.VK_0);
                break;
            case '1':
                click(KeyEvent.VK_1);
                break;
            case '2':
                click(KeyEvent.VK_2);
                break;
            case '3':
                click(KeyEvent.VK_3);
                break;
            case '4':
                click(KeyEvent.VK_4);
                break;
            case '5':
                click(KeyEvent.VK_5);
                break;
            case '6':
                click(KeyEvent.VK_6);
                break;
            case '7':
                click(KeyEvent.VK_7);
                break;
            case '8':
                click(KeyEvent.VK_8);
                break;
            case '9':
                click(KeyEvent.VK_9);
                break;
            default:
                click(text[i] - 32);
                break;
        }
    }
    click(KeyEvent.VK_ENTER);
}
}

As you can see alot of cases... And if I want to use upper cases... (ABCDEFGHIJKLMON...) I would need 26 another case... Not talking about the symbols... Thats much more cases... And this is ugly, and it would be uglier if I'd make 150 another cases, and much time...

Is there any way if it gets a 'A' I do not have to do the next:

case 'A':
  oneModifier(KeyEvent.VK_SHIFT, KeyEvent.VK_A);
  break;

For 'B':

case 'B':
  oneModifier(KeyEvent.VK_SHIFT, KeyEvent.VK_B);
  break;
luator
  • 4,769
  • 3
  • 30
  • 51
Lkala299
  • 1
  • 1
  • 1
    Hi and welcome. Can you be a bit more specific about your question ? That would help contributors to understand quicker your end goal. – Benjamin Dubois Mar 14 '19 at 16:07
  • You could store the char-clickevent in a Hashmap, and then just look it up. – Steve Smith Mar 14 '19 at 16:09
  • Or just `click(Character.getNumericValue(text.charAt(i));` might work. – Steve Smith Mar 14 '19 at 16:10
  • Hashmap might be good idea, still have to type alot but less. The Character.getNumericValue does not work. Alot of exceptions. Do you mean the hashmap that the key would be the "case", and the value is... ? – Lkala299 Mar 14 '19 at 16:16
  • 1
    Possible duplicate of [Converting a Char into Java KeyEvent KeyCode](https://stackoverflow.com/questions/15260282/converting-a-char-into-java-keyevent-keycode) – Carcigenicate Mar 14 '19 at 16:24
  • The top answer seems to do exactly what you're trying to do. – Carcigenicate Mar 14 '19 at 16:24
  • Yes, it is working on uppercase, thanks. Sadly its not working on symbols like @, + etc... – Lkala299 Mar 14 '19 at 16:32
  • To reduce code, create a factory method for the click and modified methods creating Runnables, this you can put into a map by key and run when it's pressed. – daniu Mar 15 '19 at 10:55

1 Answers1

0

So here's how you can shorten the action creation and use a Map to avoid the extensive case construct.

The Map maintains a mapping between the actual character from your "script" file and the action that is going to be performed; I used the existing Runnable interface to wrap that.

class AutoClicker {

    private Robot robot;
    private final Map<Character, Runnable> runnables = new HashMap<>();

    public AutoClicker() {
        try {
            robot = new Robot();
        } catch (AWTException ex) {
            System.out.println("Problem in AutoClicker constructor: " + ex);
        }
        // fill the map
        runnables.put(' ', click(KeyEvent.VK_SPACE));
        runnables.put('.', click(KeyEvent.VK_PERIOD));
        runnables.put('"', oneModifier(KeyEvent.VK_SHIFT, KeyEvent.VK_QUOTE));
        runnables.put('/', click(KeyEvent.VK_SLASH));
        runnables.put('\\', click(KeyEvent.VK_BACK_SLASH));
        runnables.put('+', oneModifier(KeyEvent.VK_SHIFT, KeyEvent.VK_EQUALS));
        runnables.put('!', oneModifier(KeyEvent.VK_SHIFT, KeyEvent.VK_1));
        // the VK_<X> events are sequential, as are the keys being pressed
        for (int i = 0; i < 10; i++) {
            runnables.put((char) ('0' + i), click(KeyEvent.VK_0 + i));
        }
        // for upper case letters, you can add another for loop starting from 'A'
        // and adding oneModifier(KeyEvent.VK_SHIFT, KeyEvent.VK_A + i) actions
    }

    // create an action. You might want to split that into two methods,
    // one performing the click (without wrapping) and a parameter less.    
    private Runnable wrapInPressAndRelease(int button, Optional<Runnable> wrapped) {
        return () -> {
            robot.keyPress(button);
            robot.delay(10);
            // "click" does not run anything in between press/release,
            // the modified click runs the click itself
            wrapped.ifPresent(Runnable::run);
            robot.keyRelease(button);
            if (wrapped.isPresent()) {
                // why is there delay after modified action?
                robot.delay(10);
            }
        };
    }

    // you can inline those methods, I left them in to retain a connection to your original code
    public Runnable click(int button) {
        return wrapInPressAndRelease(button, Optional.empty());
    }

    public Runnable oneModifier(int pressing, int button) {
        return wrapInPressAndRelease(pressing, Optional.of(click(button)));
    }

    public Runnable twoModifier(int pressing1, int pressing2, int button) {
        // wrap the already wrapped click into another
        return wrapInPressAndRelease(pressing1, Optional.of(oneModifier(pressing2, button)));
    }

    // now we can use the stored actions.
    // not sure why you created the intermediate text int array, I removed that.
    public void clickingENG(String tmp) {

        for (int i = 0; i < tmp.length(); i++) {
            char fromEngine = tmp.charAt(i);
            Runnable robotAction = runnables.getOrDefault(fromEngine,
                    click(fromEngine - 32, Optional.empty()));
            robotAction.run();
        }
        click(KeyEvent.VK_ENTER, Optional.empty()).run();
    }
}
daniu
  • 14,137
  • 4
  • 32
  • 53