001package com.randomnoun.common; 002 003/* (c) 2013 randomnoun. All Rights Reserved. This work is licensed under a 004 * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html) 005 */ 006import static java.awt.event.KeyEvent.VK_0; 007import static java.awt.event.KeyEvent.VK_1; 008import static java.awt.event.KeyEvent.VK_2; 009import static java.awt.event.KeyEvent.VK_3; 010import static java.awt.event.KeyEvent.VK_4; 011import static java.awt.event.KeyEvent.VK_5; 012import static java.awt.event.KeyEvent.VK_6; 013import static java.awt.event.KeyEvent.VK_7; 014import static java.awt.event.KeyEvent.VK_8; 015import static java.awt.event.KeyEvent.VK_9; 016import static java.awt.event.KeyEvent.VK_A; 017import static java.awt.event.KeyEvent.VK_AMPERSAND; 018import static java.awt.event.KeyEvent.VK_ASTERISK; 019import static java.awt.event.KeyEvent.VK_AT; 020import static java.awt.event.KeyEvent.VK_B; 021import static java.awt.event.KeyEvent.VK_BACK_QUOTE; 022import static java.awt.event.KeyEvent.VK_BACK_SLASH; 023import static java.awt.event.KeyEvent.VK_C; 024import static java.awt.event.KeyEvent.VK_CIRCUMFLEX; 025import static java.awt.event.KeyEvent.VK_CLOSE_BRACKET; 026import static java.awt.event.KeyEvent.VK_COMMA; 027import static java.awt.event.KeyEvent.VK_D; 028import static java.awt.event.KeyEvent.VK_DOLLAR; 029import static java.awt.event.KeyEvent.VK_E; 030import static java.awt.event.KeyEvent.VK_ENTER; 031import static java.awt.event.KeyEvent.VK_EQUALS; 032import static java.awt.event.KeyEvent.VK_EXCLAMATION_MARK; 033import static java.awt.event.KeyEvent.VK_F; 034import static java.awt.event.KeyEvent.VK_G; 035import static java.awt.event.KeyEvent.VK_GREATER; 036import static java.awt.event.KeyEvent.VK_H; 037import static java.awt.event.KeyEvent.VK_I; 038import static java.awt.event.KeyEvent.VK_J; 039import static java.awt.event.KeyEvent.VK_K; 040import static java.awt.event.KeyEvent.VK_L; 041import static java.awt.event.KeyEvent.VK_LEFT_PARENTHESIS; 042import static java.awt.event.KeyEvent.VK_LESS; 043import static java.awt.event.KeyEvent.VK_M; 044import static java.awt.event.KeyEvent.VK_MINUS; 045import static java.awt.event.KeyEvent.VK_N; 046import static java.awt.event.KeyEvent.VK_NUMBER_SIGN; 047import static java.awt.event.KeyEvent.VK_O; 048import static java.awt.event.KeyEvent.VK_OPEN_BRACKET; 049import static java.awt.event.KeyEvent.VK_P; 050import static java.awt.event.KeyEvent.VK_PERIOD; 051import static java.awt.event.KeyEvent.VK_PLUS; 052import static java.awt.event.KeyEvent.VK_Q; 053import static java.awt.event.KeyEvent.VK_QUOTE; 054import static java.awt.event.KeyEvent.VK_QUOTEDBL; 055import static java.awt.event.KeyEvent.VK_R; 056import static java.awt.event.KeyEvent.VK_RIGHT_PARENTHESIS; 057import static java.awt.event.KeyEvent.VK_S; 058import static java.awt.event.KeyEvent.VK_SEMICOLON; 059import static java.awt.event.KeyEvent.VK_SHIFT; 060import static java.awt.event.KeyEvent.VK_SLASH; 061import static java.awt.event.KeyEvent.VK_SPACE; 062import static java.awt.event.KeyEvent.VK_T; 063import static java.awt.event.KeyEvent.VK_TAB; 064import static java.awt.event.KeyEvent.VK_U; 065import static java.awt.event.KeyEvent.VK_UNDERSCORE; 066import static java.awt.event.KeyEvent.VK_V; 067import static java.awt.event.KeyEvent.VK_W; 068import static java.awt.event.KeyEvent.VK_X; 069import static java.awt.event.KeyEvent.VK_Y; 070import static java.awt.event.KeyEvent.VK_Z; 071 072import java.awt.AWTException; 073import java.awt.Robot; 074 075/** Use the AWT Robot class to send strings to another application. 076 * Based on the code at 077 * <a href="http://stackoverflow.com/questions/1248510/convert-string-to-keyevents">http://stackoverflow.com/questions/1248510/convert-string-to-keyevents</a> 078 * 079 * @author knoxg 080 */ 081public class Keyboard { 082 083 /** Robot class responsible for creating virtual keystrokes */ 084 private Robot robot; 085 086 /** The size of the 'keyboard buffer'. Once this many characters have been 087 * typed using the {@link #type(CharSequence)} method, an artificial delay is 088 * introduced to allow the program handling input to process keystrokes. 089 */ 090 private int bufferSize = -1; 091 092 /** Internal counter of number of characters typed so far */ 093 private int delayChars = 0; 094 095 /** Delay to introduce after {@link #bufferSize} characters have been typed, 096 * in milliseconds */ 097 private int delayMillis = 100; 098 099 /** Create a new Keyboard object */ 100 public Keyboard() throws AWTException { 101 this.robot = new Robot(); 102 } 103 104 /** Create a new Keyboard object, using the supplied AWT Robot class to create 105 * virtual keystrokes. 106 * 107 * @param robot AWT Robot class to create virtual keystrokes. 108 */ 109 public Keyboard(Robot robot) { 110 this.robot = robot; 111 } 112 113 /** Sets the size of the 'keyboard buffer'. Once this many characters have been 114 * typed using the {@link #type(CharSequence)} method, an artificial delay is 115 * introduced to allow the program handling input to process keystrokes. 116 * 117 * @param bufferSize the size of the 'keyboard buffer' 118 */ 119 public void setBufferSize(int bufferSize) { 120 this.bufferSize = bufferSize; 121 } 122 123 /** Sets the delay to introduce after {@link #bufferSize} characters have been typed, 124 * in milliseconds 125 * 126 * @param delayMillis delay in milliseconds 127 */ 128 public void setDelayMillis(int delayMillis) { 129 this.delayMillis = delayMillis; 130 } 131 132 /** Resets the keyboard buffer; i.e. sets the internal count of number of characters 133 * typed to zero. 134 */ 135 public void resetBuffer() { 136 this.delayChars = 0; 137 } 138 139 /** Type the supplied character sequence (typically a {@link java.lang.String}). 140 * An artificial delay will be introduced every bufferSize characters, of size 141 * delayMillis. 142 * 143 * @param characters characters to type 144 */ 145 public void type(CharSequence characters) { 146 int length = characters.length(); 147 for (int i = 0; i < length; i++) { 148 char character = characters.charAt(i); 149 type(character); 150 delayChars++; 151 if (bufferSize>0 && delayChars % bufferSize==0) { 152 try { Thread.sleep(delayMillis); } catch (InterruptedException ie) { } 153 } 154 } 155 } 156 157 /** Type an individual character 158 * 159 * @param character character to type 160 */ 161 public void type(char character) { 162 switch (character) { 163 case 'a': doType(VK_A); break; 164 case 'b': doType(VK_B); break; 165 case 'c': doType(VK_C); break; 166 case 'd': doType(VK_D); break; 167 case 'e': doType(VK_E); break; 168 case 'f': doType(VK_F); break; 169 case 'g': doType(VK_G); break; 170 case 'h': doType(VK_H); break; 171 case 'i': doType(VK_I); break; 172 case 'j': doType(VK_J); break; 173 case 'k': doType(VK_K); break; 174 case 'l': doType(VK_L); break; 175 case 'm': doType(VK_M); break; 176 case 'n': doType(VK_N); break; 177 case 'o': doType(VK_O); break; 178 case 'p': doType(VK_P); break; 179 case 'q': doType(VK_Q); break; 180 case 'r': doType(VK_R); break; 181 case 's': doType(VK_S); break; 182 case 't': doType(VK_T); break; 183 case 'u': doType(VK_U); break; 184 case 'v': doType(VK_V); break; 185 case 'w': doType(VK_W); break; 186 case 'x': doType(VK_X); break; 187 case 'y': doType(VK_Y); break; 188 case 'z': doType(VK_Z); break; 189 case 'A': doType(VK_SHIFT, VK_A); break; 190 case 'B': doType(VK_SHIFT, VK_B); break; 191 case 'C': doType(VK_SHIFT, VK_C); break; 192 case 'D': doType(VK_SHIFT, VK_D); break; 193 case 'E': doType(VK_SHIFT, VK_E); break; 194 case 'F': doType(VK_SHIFT, VK_F); break; 195 case 'G': doType(VK_SHIFT, VK_G); break; 196 case 'H': doType(VK_SHIFT, VK_H); break; 197 case 'I': doType(VK_SHIFT, VK_I); break; 198 case 'J': doType(VK_SHIFT, VK_J); break; 199 case 'K': doType(VK_SHIFT, VK_K); break; 200 case 'L': doType(VK_SHIFT, VK_L); break; 201 case 'M': doType(VK_SHIFT, VK_M); break; 202 case 'N': doType(VK_SHIFT, VK_N); break; 203 case 'O': doType(VK_SHIFT, VK_O); break; 204 case 'P': doType(VK_SHIFT, VK_P); break; 205 case 'Q': doType(VK_SHIFT, VK_Q); break; 206 case 'R': doType(VK_SHIFT, VK_R); break; 207 case 'S': doType(VK_SHIFT, VK_S); break; 208 case 'T': doType(VK_SHIFT, VK_T); break; 209 case 'U': doType(VK_SHIFT, VK_U); break; 210 case 'V': doType(VK_SHIFT, VK_V); break; 211 case 'W': doType(VK_SHIFT, VK_W); break; 212 case 'X': doType(VK_SHIFT, VK_X); break; 213 case 'Y': doType(VK_SHIFT, VK_Y); break; 214 case 'Z': doType(VK_SHIFT, VK_Z); break; 215 case '`': doType(VK_BACK_QUOTE); break; 216 case '0': doType(VK_0); break; 217 case '1': doType(VK_1); break; 218 case '2': doType(VK_2); break; 219 case '3': doType(VK_3); break; 220 case '4': doType(VK_4); break; 221 case '5': doType(VK_5); break; 222 case '6': doType(VK_6); break; 223 case '7': doType(VK_7); break; 224 case '8': doType(VK_8); break; 225 case '9': doType(VK_9); break; 226 case '-': doType(VK_MINUS); break; 227 case '=': doType(VK_EQUALS); break; 228 case '~': doType(VK_SHIFT, VK_BACK_QUOTE); break; 229 case '!': doType(VK_EXCLAMATION_MARK); break; 230 case '@': doType(VK_AT); break; 231 case '#': doType(VK_NUMBER_SIGN); break; 232 case '$': doType(VK_DOLLAR); break; 233 case '%': doType(VK_SHIFT, VK_5); break; 234 case '^': doType(VK_CIRCUMFLEX); break; 235 case '&': doType(VK_AMPERSAND); break; 236 case '*': doType(VK_ASTERISK); break; 237 case '(': doType(VK_LEFT_PARENTHESIS); break; 238 case ')': doType(VK_RIGHT_PARENTHESIS); break; 239 case '_': doType(VK_UNDERSCORE); break; 240 case '+': doType(VK_PLUS); break; 241 case '\t': doType(VK_TAB); break; 242 case '\n': doType(VK_ENTER); break; 243 case '[': doType(VK_OPEN_BRACKET); break; 244 case ']': doType(VK_CLOSE_BRACKET); break; 245 case '\\': doType(VK_BACK_SLASH); break; 246 case '{': doType(VK_SHIFT, VK_OPEN_BRACKET); break; 247 case '}': doType(VK_SHIFT, VK_CLOSE_BRACKET); break; 248 case '|': doType(VK_SHIFT, VK_BACK_SLASH); break; 249 case ';': doType(VK_SEMICOLON); break; 250 // case ':': doType(VK_COLON); break; 251 case ':': doType(VK_SHIFT, VK_SEMICOLON); break; 252 case '\'': doType(VK_QUOTE); break; 253 case '"': doType(VK_QUOTEDBL); break; 254 case ',': doType(VK_COMMA); break; 255 case '<': doType(VK_LESS); break; 256 case '.': doType(VK_PERIOD); break; 257 case '>': doType(VK_GREATER); break; 258 case '/': doType(VK_SLASH); break; 259 case '?': doType(VK_SHIFT, VK_SLASH); break; 260 case ' ': doType(VK_SPACE); break; 261 default: 262 throw new IllegalArgumentException("Cannot type character " + character); 263 } 264 } 265 266 /** Type a series of keyCodes. 267 * Is equivalent to calling <code>doType(keyCodes, 0, keyCodes.length);</code>. 268 * The bufferSize and delayMillis settings are not used by this method. 269 * 270 * @param keyCodes keyCodes to type 271 * 272 * @see #doType(int[], int, int) 273 */ 274 public void doType(int... keyCodes) { 275 doType(keyCodes, 0, keyCodes.length); 276 } 277 278 /** Type a series of keyCodes. The bufferSize and delayMillis settings are not 279 * used by this method. 280 * 281 * @param keyCodes keyCodes to type 282 */ 283 public void doType(int[] keyCodes, int offset, int length) { 284 if (length == 0) { 285 return; 286 } 287 robot.keyPress(keyCodes[offset]); 288 doType(keyCodes, offset + 1, length - 1); 289 robot.keyRelease(keyCodes[offset]); 290 } 291 292}