Convert String to KeyEvents

Viewed 71441

I want to convert a String into KeyEvent to do something like this :

writeKeyboard(myBot,"abcd");

public void writeKeyboard(Robot bot, String st){
     char[] arr = arr.toCharArray();
     int i = arr.length();
     int j = 0;
     int keycode;
     while (j<i) {
         keycode = arr[j].something;
         bot.keyPress(keycode);
         bot.keyRelease(keycode);
         j++;
     }
}
16 Answers

I'm basically using a glorified switch statement. Simple and fast:

import static java.awt.event.KeyEvent.*;

public class Keyboard {

    private Robot robot;

    public static void main(String... args) throws Exception {
        Keyboard keyboard = new Keyboard();
        keyboard.type("Hello there, how are you?");
    }

    public Keyboard() throws AWTException {
        this.robot = new Robot();
    }

    public Keyboard(Robot robot) {
        this.robot = robot;
    }

    public void type(CharSequence characters) {
        int length = characters.length();
        for (int i = 0; i < length; i++) {
            char character = characters.charAt(i);
            type(character);
        }
    }

    public void type(char character) {
        switch (character) {
        case 'a': doType(VK_A); break;
        case 'b': doType(VK_B); break;
        case 'c': doType(VK_C); break;
        case 'd': doType(VK_D); break;
        case 'e': doType(VK_E); break;
        case 'f': doType(VK_F); break;
        case 'g': doType(VK_G); break;
        case 'h': doType(VK_H); break;
        case 'i': doType(VK_I); break;
        case 'j': doType(VK_J); break;
        case 'k': doType(VK_K); break;
        case 'l': doType(VK_L); break;
        case 'm': doType(VK_M); break;
        case 'n': doType(VK_N); break;
        case 'o': doType(VK_O); break;
        case 'p': doType(VK_P); break;
        case 'q': doType(VK_Q); break;
        case 'r': doType(VK_R); break;
        case 's': doType(VK_S); break;
        case 't': doType(VK_T); break;
        case 'u': doType(VK_U); break;
        case 'v': doType(VK_V); break;
        case 'w': doType(VK_W); break;
        case 'x': doType(VK_X); break;
        case 'y': doType(VK_Y); break;
        case 'z': doType(VK_Z); break;
        case 'A': doType(VK_SHIFT, VK_A); break;
        case 'B': doType(VK_SHIFT, VK_B); break;
        case 'C': doType(VK_SHIFT, VK_C); break;
        case 'D': doType(VK_SHIFT, VK_D); break;
        case 'E': doType(VK_SHIFT, VK_E); break;
        case 'F': doType(VK_SHIFT, VK_F); break;
        case 'G': doType(VK_SHIFT, VK_G); break;
        case 'H': doType(VK_SHIFT, VK_H); break;
        case 'I': doType(VK_SHIFT, VK_I); break;
        case 'J': doType(VK_SHIFT, VK_J); break;
        case 'K': doType(VK_SHIFT, VK_K); break;
        case 'L': doType(VK_SHIFT, VK_L); break;
        case 'M': doType(VK_SHIFT, VK_M); break;
        case 'N': doType(VK_SHIFT, VK_N); break;
        case 'O': doType(VK_SHIFT, VK_O); break;
        case 'P': doType(VK_SHIFT, VK_P); break;
        case 'Q': doType(VK_SHIFT, VK_Q); break;
        case 'R': doType(VK_SHIFT, VK_R); break;
        case 'S': doType(VK_SHIFT, VK_S); break;
        case 'T': doType(VK_SHIFT, VK_T); break;
        case 'U': doType(VK_SHIFT, VK_U); break;
        case 'V': doType(VK_SHIFT, VK_V); break;
        case 'W': doType(VK_SHIFT, VK_W); break;
        case 'X': doType(VK_SHIFT, VK_X); break;
        case 'Y': doType(VK_SHIFT, VK_Y); break;
        case 'Z': doType(VK_SHIFT, VK_Z); break;
        case '`': doType(VK_BACK_QUOTE); break;
        case '0': doType(VK_0); break;
        case '1': doType(VK_1); break;
        case '2': doType(VK_2); break;
        case '3': doType(VK_3); break;
        case '4': doType(VK_4); break;
        case '5': doType(VK_5); break;
        case '6': doType(VK_6); break;
        case '7': doType(VK_7); break;
        case '8': doType(VK_8); break;
        case '9': doType(VK_9); break;
        case '-': doType(VK_MINUS); break;
        case '=': doType(VK_EQUALS); break;
        case '~': doType(VK_SHIFT, VK_BACK_QUOTE); break;
        case '!': doType(VK_EXCLAMATION_MARK); break;
        case '@': doType(VK_AT); break;
        case '#': doType(VK_NUMBER_SIGN); break;
        case '$': doType(VK_DOLLAR); break;
        case '%': doType(VK_SHIFT, VK_5); break;
        case '^': doType(VK_CIRCUMFLEX); break;
        case '&': doType(VK_AMPERSAND); break;
        case '*': doType(VK_ASTERISK); break;
        case '(': doType(VK_LEFT_PARENTHESIS); break;
        case ')': doType(VK_RIGHT_PARENTHESIS); break;
        case '_': doType(VK_UNDERSCORE); break;
        case '+': doType(VK_PLUS); break;
        case '\t': doType(VK_TAB); break;
        case '\n': doType(VK_ENTER); break;
        case '[': doType(VK_OPEN_BRACKET); break;
        case ']': doType(VK_CLOSE_BRACKET); break;
        case '\\': doType(VK_BACK_SLASH); break;
        case '{': doType(VK_SHIFT, VK_OPEN_BRACKET); break;
        case '}': doType(VK_SHIFT, VK_CLOSE_BRACKET); break;
        case '|': doType(VK_SHIFT, VK_BACK_SLASH); break;
        case ';': doType(VK_SEMICOLON); break;
        case ':': doType(VK_COLON); break;
        case '\'': doType(VK_QUOTE); break;
        case '"': doType(VK_QUOTEDBL); break;
        case ',': doType(VK_COMMA); break;
        case '<': doType(VK_SHIFT, VK_COMMA); break;
        case '.': doType(VK_PERIOD); break;
        case '>': doType(VK_SHIFT, VK_PERIOD); break;
        case '/': doType(VK_SLASH); break;
        case '?': doType(VK_SHIFT, VK_SLASH); break;
        case ' ': doType(VK_SPACE); break;
        default:
            throw new IllegalArgumentException("Cannot type character " + character);
        }
    }

    private void doType(int... keyCodes) {
        doType(keyCodes, 0, keyCodes.length);
    }

    private void doType(int[] keyCodes, int offset, int length) {
        if (length == 0) {
            return;
        }

        robot.keyPress(keyCodes[offset]);
        doType(keyCodes, offset + 1, length - 1);
        robot.keyRelease(keyCodes[offset]);
    }

}

If you want some custom key typing, you can extend the class and override the type(char) method. For example:

import static java.awt.event.KeyEvent.*;

public class WindowUnicodeKeyboard extends Keyboard {

    private Robot robot;

    public WindowUnicodeKeyboard(Robot robot) {
        super(robot);
        this.robot = robot;
    }

    @Override
    public void type(char character) {
        try {
            super.type(character);
        } catch (IllegalArgumentException e) {
            String unicodeDigits = String.valueOf(Character.getCodePoint(character));
            robot.keyPress(VK_ALT);
            for (int i = 0; i < unicodeDigits.length(); i++) {
                typeNumPad(Integer.parseInt(unicodeDigits.substring(i, i + 1)));
            }
            robot.keyRelease(VK_ALT);
        }
    }

    private void typeNumPad(int digit) {
        switch (digit) {
        case 0: doType(VK_NUMPAD0); break;
        case 1: doType(VK_NUMPAD1); break;
        case 2: doType(VK_NUMPAD2); break;
        case 3: doType(VK_NUMPAD3); break;
        case 4: doType(VK_NUMPAD4); break;
        case 5: doType(VK_NUMPAD5); break;
        case 6: doType(VK_NUMPAD6); break;
        case 7: doType(VK_NUMPAD7); break;
        case 8: doType(VK_NUMPAD8); break;
        case 9: doType(VK_NUMPAD9); break;
        }
    }

}

There is, of course, room for improvement, but you get the idea.

It's a bit of a Kludge, but you can use the Command pattern to encapsulate the keystrokes for each character in the String, then get the Command for each character in turn and invoke the method. The advantage of this is that you only have to set up the map once. The disadvantage is it still involves a bunch of bolierplate:

public interface Command {
    void pressKey(Robot bot);
}

//add a command to the map for each keystroke
commandMap.put("A", new Command() {
    void pressKey(Robot bot) {
        pressWithShift(KeyEvent.VK_A);
    }
});
commandMap.put ("a", new Command() {
    void pressKey (Robot bot) {
        press (KeyEvent.VK_A);
    }
});
commandMap.put("B", new Command() {
    void pressKey(Robot bot) {
        pressWithShift(KeyEvent.VK_B);
    }
});
...
//loads more definitions here

//helper methods
private void pressWithShift (Robot bot, KeyEvent event) {
    bot.keyPress (KeyEvent.VK_SHIFT);
    press(bot, event);
    bot.keyRelase(KeyEvent.VK_SHIFT);
}

private void press(Robot bot, KeyEvent event) {
    bot.keyPress(event);
    bot.keyRelease(event);
}

Then to use the Map:

for (int i = 0; i < st.length(); i++) {
    String subString = st.substring(i, i + 1);

    commandMap.get(subString).pressKey(bot);
}

I'm basically using the Command pattern as Rich Seller does in his answer, with two minor modifications for the brevity's sake:

  • use of the Decoration pattern for reusing instances of a-z command
  • use of reflection to remove KeyEvent.VK_???

Command interface:

interface Command {

    void pressKey(Robot robot);
}

and the decorator (for modification #1):

class ShiftCommand implements Command {

    private final Command command;

    public ShiftCommand(Command command) {
        this.command = command;
    }

    public void pressKey(Robot robot) {
        robot.keyPress(KeyEvent.VK_SHIFT);
        command.pressKey(robot);
        robot.keyRelease(KeyEvent.VK_SHIFT);
    }

    @Override
    public String toString() {
        return "SHIFT + " + command.toString();
    }
}

using this helper (for modification #2):

public static int getKeyEvent(Character c) {
    Field f = KeyEvent.class.getField("VK_" + Character.toUpperCase(c));
    f.setAccessible(true);
    return (Integer) f.get(null);
}

BEWARE: I'm not handling exceptions here, this is left as exercise for you :))

then populating the command using a for loop:

Map<Character, Command> commandMap = new HashMap<Character, Command>();

    for (int i = 'a'; i <= 'z'; i++) {
        final Character c = Character.valueOf((char) i);
        Command pressKeyCommand = new Command() {

            public void pressKey(Robot robot) {
                int keyEventCode = getKeyEvent(c);
                robot.keyPress(c);
                robot.keyRelease(c);
            }

            @Override
            public String toString() {
                return String.format("%c", c);
            }
        };

        // 'a' .. 'z'
        commandMap.put(c, pressKeyCommand);
        // 'A' .. 'Z' by decorating pressKeyCommand
        commandMap.put(Character.toUpperCase(c), new ShiftCommand(pressKeyCommand));
    }

TestCase

String test = "aaaBBB";
for (int i = 0; i < test.length(); i++) {
     System.out.println(commandMap.get(test.charAt(i)));
}

as expected this outputs:

a
a
a
SHIFT + b
SHIFT + b
SHIFT + b

Slight modification to Adam Paynter's answer because code was not working for all keys e.g. !, @, #, $ etc. (Needed to press VK_SHIFT first)

public void type(char character) {
    switch (character) {
    case 'a': doType(VK_A); break;
    case 'b': doType(VK_B); break;
    case 'c': doType(VK_C); break;
    case 'd': doType(VK_D); break;
    case 'e': doType(VK_E); break;
    case 'f': doType(VK_F); break;
    case 'g': doType(VK_G); break;
    case 'h': doType(VK_H); break;
    case 'i': doType(VK_I); break;
    case 'j': doType(VK_J); break;
    case 'k': doType(VK_K); break;
    case 'l': doType(VK_L); break;
    case 'm': doType(VK_M); break;
    case 'n': doType(VK_N); break;
    case 'o': doType(VK_O); break;
    case 'p': doType(VK_P); break;
    case 'q': doType(VK_Q); break;
    case 'r': doType(VK_R); break;
    case 's': doType(VK_S); break;
    case 't': doType(VK_T); break;
    case 'u': doType(VK_U); break;
    case 'v': doType(VK_V); break;
    case 'w': doType(VK_W); break;
    case 'x': doType(VK_X); break;
    case 'y': doType(VK_Y); break;
    case 'z': doType(VK_Z); break;
    case 'A': doType(VK_SHIFT, VK_A); break;
    case 'B': doType(VK_SHIFT, VK_B); break;
    case 'C': doType(VK_SHIFT, VK_C); break;
    case 'D': doType(VK_SHIFT, VK_D); break;
    case 'E': doType(VK_SHIFT, VK_E); break;
    case 'F': doType(VK_SHIFT, VK_F); break;
    case 'G': doType(VK_SHIFT, VK_G); break;
    case 'H': doType(VK_SHIFT, VK_H); break;
    case 'I': doType(VK_SHIFT, VK_I); break;
    case 'J': doType(VK_SHIFT, VK_J); break;
    case 'K': doType(VK_SHIFT, VK_K); break;
    case 'L': doType(VK_SHIFT, VK_L); break;
    case 'M': doType(VK_SHIFT, VK_M); break;
    case 'N': doType(VK_SHIFT, VK_N); break;
    case 'O': doType(VK_SHIFT, VK_O); break;
    case 'P': doType(VK_SHIFT, VK_P); break;
    case 'Q': doType(VK_SHIFT, VK_Q); break;
    case 'R': doType(VK_SHIFT, VK_R); break;
    case 'S': doType(VK_SHIFT, VK_S); break;
    case 'T': doType(VK_SHIFT, VK_T); break;
    case 'U': doType(VK_SHIFT, VK_U); break;
    case 'V': doType(VK_SHIFT, VK_V); break;
    case 'W': doType(VK_SHIFT, VK_W); break;
    case 'X': doType(VK_SHIFT, VK_X); break;
    case 'Y': doType(VK_SHIFT, VK_Y); break;
    case 'Z': doType(VK_SHIFT, VK_Z); break;
    case '`': doType(VK_BACK_QUOTE); break;
    case '0': doType(VK_0); break;
    case '1': doType(VK_1); break;
    case '2': doType(VK_2); break;
    case '3': doType(VK_3); break;
    case '4': doType(VK_4); break;
    case '5': doType(VK_5); break;
    case '6': doType(VK_6); break;
    case '7': doType(VK_7); break;
    case '8': doType(VK_8); break;
    case '9': doType(VK_9); break;
    case '-': doType(VK_MINUS); break;
    case '=': doType(VK_EQUALS); break;
    case '~': doType(VK_BACK_QUOTE); break;
    case '!': doType(VK_SHIFT, VK_EXCLAMATION_MARK); break;
    case '@': doType(VK_SHIFT, VK_AT); break;
    case '#': doType(VK_SHIFT, VK_NUMBER_SIGN); break;
    case '$': doType(VK_SHIFT, VK_DOLLAR); break;
    case '%': doType(VK_SHIFT, VK_5); break;
    case '^': doType(VK_SHIFT, VK_CIRCUMFLEX); break;
    case '&': doType(VK_SHIFT, VK_AMPERSAND); break;
    case '*': doType(VK_SHIFT, VK_ASTERISK); break;
    case '(': doType(VK_LEFT_PARENTHESIS); break;
    case ')': doType(VK_RIGHT_PARENTHESIS); break;
    case '_': doType(VK_SHIFT, VK_UNDERSCORE); break;
    case '+': doType(VK_SHIFT, VK_PLUS); break;
    case '\t': doType(VK_TAB); break;
    case '\n': doType(VK_ENTER); break;
    case '[': doType(VK_OPEN_BRACKET); break;
    case ']': doType(VK_CLOSE_BRACKET); break;
    case '\\': doType(VK_BACK_SLASH); break;
    case '{': doType(VK_SHIFT, VK_OPEN_BRACKET); break;
    case '}': doType(VK_SHIFT, VK_CLOSE_BRACKET); break;
    case '|': doType(VK_SHIFT, VK_BACK_SLASH); break;
    case ';': doType(VK_SEMICOLON); break;
    case ':': doType(VK_SHIFT, VK_COLON); break;
    case '\'': doType(VK_QUOTE); break;
    case '"': doType(VK_SHIFT, VK_QUOTEDBL); break;
    case ',': doType(VK_COMMA); break;
    case '<': doType(VK_SHIFT, VK_COMMA); break;
    case '.': doType(VK_PERIOD); break;
    case '>': doType(VK_SHIFT, VK_PERIOD); break;
    case '/': doType(VK_SLASH); break;
    case '?': doType(VK_SHIFT, VK_SLASH); break;
    case ' ': doType(VK_SPACE); break;
    case '\b': doType(VK_BACK_SPACE); break;
    default:
        throw new IllegalArgumentException("Cannot type character " + character);
    }
}

I don't know the commandmap method but looks good, I'll have a look.

Finally I discover that the keycode for a to z is 65 to 90. So

private void write(Robot bot, String st) {
    char[] arr = st.toCharArray();
    int i = arr.length;
    int j = 0;
    while (j<i) {
        int kcode = (int) arr[j] - 32;
        bot.keyPress(kcode);
        bot.keyRelease(kcode);
        j++;
    }       
}

It just works for lowercase letters (you can easily correct it with a simple test for uppercase).

For what I was looking for it works perfectly :-)

Related