Convert bytecode type to java type - java

I want to convert bytecode type to java using an api instead of manually coding for it, Is there any api for that? Since the requirement goes high I have to keep adding the convertion type manually which is bit tedious.
[Ljava/lang/StackTraceElement;
J[Ljava/lang/StackTraceElement;
Ljava/util/Map;
Ljava/util/LinkedList;
Ljava/lang/String;
Ljava/net/URL;
Z
Ljava/lang/String;
[Ljava/net/URL;
Previously I used code it manually as below.
private static Type getType(final char[] buf, final int off) {
int len;
switch (buf[off]) {
case 'V':
return VOID_TYPE;
case 'Z':
return BOOLEAN_TYPE;
case 'C':
return CHAR_TYPE;
case 'B':
return BYTE_TYPE;
case 'S':
return SHORT_TYPE;
case 'I':
return INT_TYPE;
case 'F':
return FLOAT_TYPE;
case 'J':
return LONG_TYPE;
case 'D':
return DOUBLE_TYPE;
}
}
And when I used asm library for this,
Type.getArgumentTypes(desc);
it showed me an error as below.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 44
at org.objectweb.asm.Type.getArgumentTypes(Unknown Source)

I would add a method getTypeLength:
private static int getTypeLength(final char[] buf, final int off) {
switch (buf[off]) {
case 'V':
case 'Z':
case 'C':
case 'B':
case 'S':
case 'I':
case 'F':
case 'J':
case 'D':
return 1;
case 'L':
{
int i = offs+1;
while (buf[i] != ';') {
++i;
}
return i-offs+1;
}
case '[':
return getTypeLength(buf, off+1)+1;
}
}
And then:
private static Type getType(final char[] buf, final int off) {
int len;
switch (buf[off]) {
case 'V':
return VOID_TYPE;
case 'Z':
return BOOLEAN_TYPE;
case 'C':
return CHAR_TYPE;
case 'B':
return BYTE_TYPE;
case 'S':
return SHORT_TYPE;
case 'I':
return INT_TYPE;
case 'F':
return FLOAT_TYPE;
case 'J':
return LONG_TYPE;
case 'D':
return DOUBLE_TYPE;
case 'L':
{
int len = getTypeLength(buf, offs);
String name = new String(buf, offs+1, len-2).replace('/', '.');
return Class.forName(name);
}
case '[':
int len = getTypeLength(buf, offs);
return Class.forName(new String(buf, offs, len));
}
}

If you are using asm it would be like this,
Type.getType(desc).getClassName();
Type class from asm library and its static method getType which accepts a string will convert bytecode type to java type.

Related

Converting char to int for in java switch statement [duplicate]

This question already has answers here:
In a switch statement, why are all the cases being executed?
(8 answers)
Closed last year.
I am working on the game where the columns of the board are represented by the characters but i would like to assign them an index.
I have decided to use the switch statement in that case, however it does produce the wrong result.
With the current code I attach, it gives me 14 as an index, however since the string is 7h, and it takes h as a char, it should give an index of 7. What Could be an issue? Thanks in advance!
public class Check {
public int columnToInt(char c) {
int index=0;
switch(c) {
case 'a':
index=0;
case 'b':
index=1;
case 'c':
index=2;
case 'd':
index=3;
case 'e':
index=4;
case 'f':
index=5;
case 'g':
index=6;
case 'h':
index=7;
case 'i':
index=8;
case 'j':
index=9;
case 'k':
index=10;
case 'l':
index=11;
case 'm':
index=12;
case 'n':
index=13;
case 'o':
index=14;
}
return index;
}
public static void main(String[] args) {
String myStr = "7h";
char c =myStr.charAt(1);
System.out.println("the char at position 1 is "+c);
Check check = new Check();
int result = check.columnToInt(c);
System.out.println(result);
}
}
Java switch statements can be a bit annoying to use. You need to use break or all the cases after the expected one will be executed as well.
switch(c) {
case 'a':
index=0;
break;
Alternatively you can use a return.
switch(c) {
case 'a':
return 0;
You must add the break keyword for each case.
For example:
case 'a':
index=0;
break;
otherwise next assignments are applied.

Take character and return the Keypad equivalant

So I am writing code that will take a character and return its alpha-numeric keypad equivalent as a character.
The problem is, I am getting a question mark in a box as a return. I have checked that the input is correct. For example, with a char 'h' input, i should get a char '4' return. Hoping someone is able to spot my error.
Code is below:
public char getDigit(char letter) throws Exception{
switch (letter) {
case 'a': case 'b': case 'c': case '2':
return 2;
case 'd': case 'e': case 'f': case '3':
return 3;
case 'g': case 'h': case 'i': case '4':
return 4;
case 'j': case 'k': case 'l': case '5':
return 5;
case 'm': case 'n': case 'o': case '6':
return 6;
case 'p': case 'q': case 'r': case 's': case '7':
return 7;
case 't': case 'u': case 'v': case '8':
return 8;
case 'w': case 'x': case 'y': case 'z': case '9':
return 9;
default:
throw new IllegalArgumentException("Must be a letter or number on the Alpha-Numeric Keypad.");
}
}
The return type of your method is char.
Now take your switch statement. You return char values in the range from 2 to 9. Now look at an ASCII table.
Surprise: these chars are all "unprintable" control characters. Thus your console gives you "?" when you print them!
If you want '4', your code has to return '4', not 4! Or 52, because that entry in the ASCII table represents '4'.
You are not getting proper output because you are using char as a return type of getDigit(..) function. You should use int as a return type instead of char as in switch case you are comparing with characters and returning digit values So replace your code with the following code, this will work:
public int getDigit(char letter) throws Exception{
switch (letter) {
case 'a': case 'b': case 'c': case '2':
return 2;
case 'd': case 'e': case 'f': case '3':
return 3;
case 'g': case 'h': case 'i': case '4':
return 4;
case 'j': case 'k': case 'l': case '5':
return 5;
case 'm': case 'n': case 'o': case '6':
return 6;
case 'p': case 'q': case 'r': case 's': case '7':
return 7;
case 't': case 'u': case 'v': case '8':
return 8;
case 'w': case 'x': case 'y': case 'z': case '9':
return 9;
default:
throw new IllegalArgumentException("Must be a letter or number on the Alpha-Numeric Keypad.");
}
}

Having trouble creating a bag of objects - Scrabble word search

I have to create a scrabble word search for my data structures class. I haven't reached the actual search yet. First, I need to create a bag of scrabble tiles. However, I keep getting errors when trying to add ScrabbleTile objects to my bag.
I have four classes: ScrabbleTile, ScrabbleBag, ScrabbleHand, and WordFinder.
Here is ScrabbleTile:
public class ScrabbleTile {
private char letter;
private int points;
ScrabbleTile (char letter)
{
this.letter = letter;
switch (letter)
{
case '_':
points = 0;
case 'e':
case 'a':
case 'i':
case 'o':
case 'n':
case 'r':
case 't':
case 'l':
case 's':
case 'u':
points = 1; break;
case 'd':
case 'g':
points = 2; break;
case 'b':
case 'c':
case 'm':
case 'p':
points = 3; break;
case 'f':
case 'h':
case 'v':
case 'w':
case 'y':
points = 4; break;
case 'k':
points = 5; break;
case 'j':
case 'x':
points = 8; break;
case 'q':
case 'z':
points = 10; break;
default: System.out.println("Incorrect character. Please enter a lowercase letter, a-z.");
break;
}
}
public char getLetter()
{
return letter;
}
public int getPoints()
{
return points;
}
}
Here is my ScrabbleBag class:
import DSLib.*;
public class ScrabbleBag {
private BagADT<ScrabbleTile> letterBag;
ScrabbleBag()
{
letterBag = new Bag<>();
for (int i = 0; i < 12; i++) {letterBag.add(ScrabbleTile('e'));}
}
}
In the ScrabbleBag constructor, I'm trying to add the correct number of each letter tile, starting with "e". Netbeans had a few suggestions which I tried, but then it was telling me the line syntax was wrong, after creating a few more instance variables in the ScrabbleBag class. How can I properly add ScrabbleTile objects to the bag?
My professor was very clear that we cannot use methods ahead of what we've gone over in class. Thanks in advance!
I think you missed new when create ScrabbleTitle object
for (int i = 0; i < 12; i++) {
letterBag.add(new ScrabbleTile('e'));
}
To create a ScrabbleTile you need the new keyword:
for (int i = 0; i < 12; i++) {
ScrabbleTile tile = new ScrabbleTile('e');
letterBag.add(tile);
}

Switch Statement Inside a method of another class [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
public int alphCheck(char check){
switch(check){
case 'a':
return 1;
break;
case 'b':
return 2;
break;
case 'c':
return 3;
break;
case 'd':
return 4;
break;
case 'e':
return 5;
break;
case 'f':
return 6;
break;
case 'g':
return 7;
break;
case 'h':
return 8;
break;
case 'i':
return 9;
break;
case 'j':
return 10;
break;
case 'k':
return 11;
break;
case 'l':
return 12;
break;
case 'm':
return 13;
break;
case 'n':
return 14;
break;
case 'o':
return 15;
break;
case 'p':
return 16;
break;
case 'q':
return 17;
break;
case 'r':
return 18;
break;
case 's':
return 19;
break;
case 't':
return 20;
break;
case 'u':
return 21;
break;
case 'v':
return 22;
break;
case 'w':
return 23;
break;
case 'x':
return 24;
break;
case 'y':
return 25;
break;
case 'z':
return 26;
break;
}
}
PS.This was done in another class
I want to be able to use this method in the main class, to input a letter, and return a number/index for that letter.
But I kept getting: this method must return a result of type int.
Very Confused. Please help. Thx.
Here's a question to consider: What happens if the inputted letter isn't one of the cases you described?
While you may know that you're only feeding in letters, the compiler doesn't know that, and because it can't figure out what to return if one of the cases you defined isn't hit, emits an error as a result. You'll need to put in a default case, so the compiler knows that the method is guaranteed to return something:
switch(check) {
case 'a':
...
default:
// return something or maybe print/throw an error
}
A better solution for this may be to use the fact that chars are just numbers in a different form. For example, 'a' is equivalent to the integer 97 (check out the table here for a table of characters and their ASCII numerical equivalents). So you can do a math trick to get equivalent results:
public int alphCheck(char check) {
return check - 'a' + 1;
}
you have to provide return type like return 0; at the end of your switch statement.or in default: case
switch(check) {
..
default:
return 0;
}

Convert String to KeyEvents

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++;
}
}
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.
I used the clipboard to solve the problem...
public static void type(String characters) {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection stringSelection = new StringSelection( characters );
clipboard.setContents(stringSelection, clipboardOwner);
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_CONTROL);
}
You can do it simply via Java reflection API:
public void writeKeyboard(Robot bot, String st) {
String upperCase = st.toUpperCase();
for(int i = 0; i < upperCase.length(); i++) {
String letter = Character.toString(upperCase.charAt(i));
String code = "VK_" + letter
Field f = KeyEvent.class.getField(code);
int keyEvent = f.getInt(null);
bot.press(keyEvent);
bot.release(keyEvent);
}
}
I recently wrote a class to do this. It enters the Alt code of each character, instead of figuring out the key combination for every case individually. Not the fastest solution, but it's concise and works for a very wide range of characters.
import java.awt.AWTException;
import java.awt.Robot;
import static java.awt.event.KeyEvent.VK_ALT;
import static java.awt.event.KeyEvent.VK_NUMPAD0;
public class Altbot extends Robot{
Altbot()throws AWTException{}
public void type(CharSequence cs){
for(int i=0;i<cs.length();i++){
type(cs.charAt(i));
}
}
public void type(char c){
keyPress(VK_ALT);
keyPress(VK_NUMPAD0);
keyRelease(VK_NUMPAD0);
String altCode=Integer.toString(c);
for(int i=0;i<altCode.length();i++){
c=(char)(altCode.charAt(i)+'0');
//delay(20);//may be needed for certain applications
keyPress(c);
//delay(20);//uncomment if necessary
keyRelease(c);
}
keyRelease(VK_ALT);
}
}
This is how I managed to use all available keys. Create a Map and fill the map using the method fillKeyMap. Now you can use String representation of key events and convert it back into KeyEvent codes using the map.
/** Create map with string values to integer pairs
*/
public static final void fillKeyMap(Map<String, Integer> into) {
try {
Field[] fields = KeyEvent.class.getDeclaredFields();
for(Field f : fields) {
if(f.getName().startsWith("VK_")) { //we only want these fields
int code = ((Integer)f.get(null)).intValue();
into.put(f.getName().substring(3), code);
}
}
} catch(Exception ex) {}
}
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
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);
}
The accepted answer seems very bloated to me. Here is a little more concise solution that is sort of based off of the accepted answer. It should handle pretty much any use case. Also handles \n (newline), \t (tab), and \b (backspace), as demonstrated in the example.
import java.awt.AWTException;
import java.awt.AWTKeyStroke;
import static java.awt.AWTKeyStroke.getAWTKeyStroke;
import java.awt.Robot;
import static java.awt.event.InputEvent.SHIFT_DOWN_MASK;
import java.awt.event.KeyEvent;
public class Keyboard {
private final Robot robot;
public Keyboard() throws AWTException {
this.robot = new Robot();
}
public static void main(String[] args) throws Exception {
Runtime.getRuntime().exec("notepad.exe");
Thread.sleep(3000L);
Keyboard keyboard = new Keyboard();
keyboard.type("`1234567890-=[]\\;',./\n");
keyboard.type("~!##$%^&*()_+{}|:\"<>?\n");
keyboard.type("abcdefghijklmnopqrstuvwxyz\n\tABCDEFGHIJKLMNOPQRSTUVWXYZ");
keyboard.type("\n\n\twh\bat");
}
private static AWTKeyStroke getKeyStroke(char c) {
String upper = "`~'\"!##$%^&*()_+{}|:<>?";
String lower = "`~'\"1234567890-=[]\\;,./";
int index = upper.indexOf(c);
if (index != -1) {
int keyCode;
boolean shift = false;
switch (c) {
// these chars need to be handled specially because
// they don't directly translate into the correct keycode
case '~':
shift = true;
case '`':
keyCode = KeyEvent.VK_BACK_QUOTE;
break;
case '\"':
shift = true;
case '\'':
keyCode = KeyEvent.VK_QUOTE;
break;
default:
keyCode = (int) Character.toUpperCase(lower.charAt(index));
shift = true;
}
return getAWTKeyStroke(keyCode, shift ? SHIFT_DOWN_MASK : 0);
}
return getAWTKeyStroke((int) Character.toUpperCase(c), 0);
}
public void type(CharSequence chars) {
type(chars, 0);
}
public void type(CharSequence chars, int ms) {
ms = ms > 0 ? ms : 0;
for (int i = 0, len = chars.length(); i < len; i++) {
char c = chars.charAt(i);
AWTKeyStroke keyStroke = getKeyStroke(c);
int keyCode = keyStroke.getKeyCode();
boolean shift = Character.isUpperCase(c) || keyStroke.getModifiers() == (SHIFT_DOWN_MASK + 1);
if (shift) {
robot.keyPress(KeyEvent.VK_SHIFT);
}
robot.keyPress(keyCode);
robot.keyRelease(keyCode);
if (shift) {
robot.keyRelease(KeyEvent.VK_SHIFT);
}
if (ms > 0) {
robot.delay(ms);
}
}
}
}
Your code will work as long as you are using alpha numeric characters only, it will not work for characters like ":". SmartRobot class will handle this.
I wish I had 50 reputation points to comment on Adam Paynter solution, but not yet....
His Keyboard class worked good, but I had issues with keys that aren't alphabetical, such as :, \ and /.
The solution I found was pressing and holding <ALT> while the <ASCII code> of such keys are typed.
First of all, I changed the method doType() to hold only SHIFT and/or ALTpressed, but not every single key that composes the ASCII code. Pretty much, that's how humans use keyboards :)
private void doType(int[] keyCodes, int offset, int length) {
if (length == 0) {
return;
}
robot.keyPress(keyCodes[offset]);
if (keyCodes[offset] == KeyEvent.VK_ALT
|| keyCodes[offset] == KeyEvent.VK_SHIFT) {
doType(keyCodes, offset + 1, length - 1);
robot.keyRelease(keyCodes[offset]);
} else {
robot.keyRelease(keyCodes[offset]);
doType(keyCodes, offset + 1, length - 1);
}
}
Then, I changed the switch case to pass ALT and the ASCII code:
case '\\' :
doType(KeyEvent.VK_ALT, KeyEvent.VK_NUMPAD9,
KeyEvent.VK_NUMPAD2);
case ':' :
doType(KeyEvent.VK_ALT, KeyEvent.VK_NUMPAD5,
KeyEvent.VK_NUMPAD8);
case '/' :
doType(KeyEvent.VK_ALT, KeyEvent.VK_NUMPAD4,
KeyEvent.VK_NUMPAD7);
=======================================================
ADDITION
I tweaked this class a little more:
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Keyboard {
private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
private Robot robot;
public Keyboard() {
try {
this.robot = new Robot();
} catch (AWTException e) {
LOG.error("Unable to create Robot object", e);
throw new RuntimeException(e);
}
}
public void type(String text) {
char c;
for (int ii = 0; ii < text.length(); ii++) {
c = text.charAt(ii);
if (c <= 31 || c == 129) {
pressControlKey(c);
} else {
typeAsciiCode(c);
}
}
}
private void pressControlKey(char c) {
robot.keyPress(c);
robot.keyRelease(c);
}
private void typeAsciiCode(char c) {
robot.keyPress(KeyEvent.VK_ALT);
String asciiCode = Integer.toString(c);
for (int i = 0; i < asciiCode.length(); i++) {
c = (char) (asciiCode.charAt(i) + '0');
robot.keyPress(c);
robot.keyRelease(c);
}
robot.keyRelease(KeyEvent.VK_ALT);
}
}
import java.awt.Robot;
import java.awt.event.KeyEvent;
/**
* #author Trevor
* Handles alpha numerics and common punctuation
*/
public class RobotKeyboard{
private Robot robot;
public RobotKeyboard(Robot robot){
this.robot = robot;
}
public void typeMessage(String message){
for (int i = 0; i < message.length(); i++){
handleRepeatCharacter(message, i);
type(message.charAt(i));
}
}
private void handleRepeatCharacter(String message, int i){
if(i == 0)
return;
//The robot won't type the same letter twice unless we release a key.
if(message.charAt(i) == message.charAt(i-1)){
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyRelease(KeyEvent.VK_SHIFT);
}
}
private void type(char character){
handleSpecialCharacter(character);
if (Character.isLowerCase(character)){
typeCharacter(Character.toUpperCase(character));
}
if (Character.isUpperCase(character)){
typeShiftCharacter(character);
}
if (Character.isDigit(character)){
typeCharacter(character);
}
}
private void handleSpecialCharacter(char character){
if (character == ' ')
typeCharacter(KeyEvent.VK_SPACE);
if (character == '.')
typeCharacter(KeyEvent.VK_PERIOD);
if (character == '!')
typeShiftCharacter(KeyEvent.VK_1);
if (character == '?')
typeShiftCharacter(KeyEvent.VK_SLASH);
if (character == ',')
typeCharacter(KeyEvent.VK_COMMA);
//More specials here as needed
}
private void typeCharacter(int character){
robot.keyPress(character);
}
private void typeShiftCharacter(int character){
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress(character);
robot.keyRelease(KeyEvent.VK_SHIFT);
}
}
I had the same issue. I found that the code below was a simple way to translate a string into key events. It seems that most people had very implementation specific fixes to account for the differences between lower & upper case. Because the VK keys don't care about upper/lower case, casting everything to upper case seems to fix the problem.
for(int i = 0; i < string.length(); i++){
char c = Character.toUpperCase(s.charAt(i));
KeyEvent ke = new KeyEvent(source, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0, (int)c, c);
//do whatever with key event
}
I also wanted to say this works well for letters and number, but it may not work for other characters. This technique translated the accent/backtick mark into numberpad 0 (VK_NUMPAD0)
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 :-)
I found that combining the answers of Ryan Hilbert and Adam Paynter gave me the best result. It combines the speed of single keys with the robustness of alt-codes. The combined code:
/**
* Created by Daniel on 25/8/2016.
*/
import java.awt.AWTException;
import java.awt.Robot;
import static java.awt.event.KeyEvent.VK_0;
import static java.awt.event.KeyEvent.VK_1;
import static java.awt.event.KeyEvent.VK_2;
import static java.awt.event.KeyEvent.VK_3;
import static java.awt.event.KeyEvent.VK_4;
import static java.awt.event.KeyEvent.VK_5;
import static java.awt.event.KeyEvent.VK_6;
import static java.awt.event.KeyEvent.VK_7;
import static java.awt.event.KeyEvent.VK_8;
import static java.awt.event.KeyEvent.VK_9;
import static java.awt.event.KeyEvent.VK_A;
import static java.awt.event.KeyEvent.VK_ALT;
import static java.awt.event.KeyEvent.VK_B;
import static java.awt.event.KeyEvent.VK_BACK_QUOTE;
import static java.awt.event.KeyEvent.VK_BACK_SLASH;
import static java.awt.event.KeyEvent.VK_C;
import static java.awt.event.KeyEvent.VK_CLOSE_BRACKET;
import static java.awt.event.KeyEvent.VK_COLON;
import static java.awt.event.KeyEvent.VK_COMMA;
import static java.awt.event.KeyEvent.VK_D;
import static java.awt.event.KeyEvent.VK_E;
import static java.awt.event.KeyEvent.VK_ENTER;
import static java.awt.event.KeyEvent.VK_EQUALS;
import static java.awt.event.KeyEvent.VK_F;
import static java.awt.event.KeyEvent.VK_G;
import static java.awt.event.KeyEvent.VK_H;
import static java.awt.event.KeyEvent.VK_I;
import static java.awt.event.KeyEvent.VK_J;
import static java.awt.event.KeyEvent.VK_K;
import static java.awt.event.KeyEvent.VK_L;
import static java.awt.event.KeyEvent.VK_M;
import static java.awt.event.KeyEvent.VK_MINUS;
import static java.awt.event.KeyEvent.VK_N;
import static java.awt.event.KeyEvent.VK_NUMPAD0;
import static java.awt.event.KeyEvent.VK_O;
import static java.awt.event.KeyEvent.VK_OPEN_BRACKET;
import static java.awt.event.KeyEvent.VK_P;
import static java.awt.event.KeyEvent.VK_PERIOD;
import static java.awt.event.KeyEvent.VK_Q;
import static java.awt.event.KeyEvent.VK_QUOTE;
import static java.awt.event.KeyEvent.VK_QUOTEDBL;
import static java.awt.event.KeyEvent.VK_R;
import static java.awt.event.KeyEvent.VK_S;
import static java.awt.event.KeyEvent.VK_SEMICOLON;
import static java.awt.event.KeyEvent.VK_SHIFT;
import static java.awt.event.KeyEvent.VK_SLASH;
import static java.awt.event.KeyEvent.VK_SPACE;
import static java.awt.event.KeyEvent.VK_T;
import static java.awt.event.KeyEvent.VK_TAB;
import static java.awt.event.KeyEvent.VK_U;
import static java.awt.event.KeyEvent.VK_V;
import static java.awt.event.KeyEvent.VK_W;
import static java.awt.event.KeyEvent.VK_X;
import static java.awt.event.KeyEvent.VK_Y;
import static java.awt.event.KeyEvent.VK_Z;
public class Keyboard { // http://stackoverflow.com/a/1248709/4330555
private Robot robot;
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);
try {
type(character);
} catch (IllegalArgumentException e) {
robot.keyPress(VK_ALT);
robot.keyPress(VK_NUMPAD0);
robot.keyRelease(VK_NUMPAD0);
String altCode = Integer.toString(character);
for (int j = 0; j < altCode.length(); j++) {
char c = (char) (altCode.charAt(j) + '0');
robot.keyPress(c);
robot.keyRelease(c);
}
robot.keyRelease(VK_ALT);
}
}
}
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_SHIFT, VK_1);
break;
case '#':
doType(VK_SHIFT, VK_2);
break;
case '#':
doType(VK_SHIFT, VK_3);
break;
case '$':
doType(VK_SHIFT, VK_4);
break;
case '%':
doType(VK_SHIFT, VK_5);
break;
case '^':
doType(VK_SHIFT, VK_6);
break;
case '&':
doType(VK_SHIFT, VK_7);
break;
case '*':
doType(VK_SHIFT, VK_8);
break;
case '(':
doType(VK_SHIFT, VK_9);
break;
case ')':
doType(VK_SHIFT, VK_0);
break;
case '_':
doType(VK_SHIFT, VK_MINUS);
break;
case '+':
doType(VK_SHIFT, VK_EQUALS);
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]);
}
}
Just another example. May become handy.
public void writeKeyboard(Robot robot, String string) {
int ascii;
for(int i = 0; i < string.length(); i++) {
ascii = (int)string.charAt(i);
robot.keyPress(ascii);
robot.delay(10);// choose your time or random it
robot.keyRelease(ascii);
robot.delay(10);
}
}

Categories