View Javadoc
1   package com.randomnoun.common;
2   
3   /* (c) 2013 randomnoun. All Rights Reserved. This work is licensed under a
4    * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html)
5    */
6   import static java.awt.event.KeyEvent.VK_0;
7   import static java.awt.event.KeyEvent.VK_1;
8   import static java.awt.event.KeyEvent.VK_2;
9   import static java.awt.event.KeyEvent.VK_3;
10  import static java.awt.event.KeyEvent.VK_4;
11  import static java.awt.event.KeyEvent.VK_5;
12  import static java.awt.event.KeyEvent.VK_6;
13  import static java.awt.event.KeyEvent.VK_7;
14  import static java.awt.event.KeyEvent.VK_8;
15  import static java.awt.event.KeyEvent.VK_9;
16  import static java.awt.event.KeyEvent.VK_A;
17  import static java.awt.event.KeyEvent.VK_AMPERSAND;
18  import static java.awt.event.KeyEvent.VK_ASTERISK;
19  import static java.awt.event.KeyEvent.VK_AT;
20  import static java.awt.event.KeyEvent.VK_B;
21  import static java.awt.event.KeyEvent.VK_BACK_QUOTE;
22  import static java.awt.event.KeyEvent.VK_BACK_SLASH;
23  import static java.awt.event.KeyEvent.VK_C;
24  import static java.awt.event.KeyEvent.VK_CIRCUMFLEX;
25  import static java.awt.event.KeyEvent.VK_CLOSE_BRACKET;
26  import static java.awt.event.KeyEvent.VK_COMMA;
27  import static java.awt.event.KeyEvent.VK_D;
28  import static java.awt.event.KeyEvent.VK_DOLLAR;
29  import static java.awt.event.KeyEvent.VK_E;
30  import static java.awt.event.KeyEvent.VK_ENTER;
31  import static java.awt.event.KeyEvent.VK_EQUALS;
32  import static java.awt.event.KeyEvent.VK_EXCLAMATION_MARK;
33  import static java.awt.event.KeyEvent.VK_F;
34  import static java.awt.event.KeyEvent.VK_G;
35  import static java.awt.event.KeyEvent.VK_GREATER;
36  import static java.awt.event.KeyEvent.VK_H;
37  import static java.awt.event.KeyEvent.VK_I;
38  import static java.awt.event.KeyEvent.VK_J;
39  import static java.awt.event.KeyEvent.VK_K;
40  import static java.awt.event.KeyEvent.VK_L;
41  import static java.awt.event.KeyEvent.VK_LEFT_PARENTHESIS;
42  import static java.awt.event.KeyEvent.VK_LESS;
43  import static java.awt.event.KeyEvent.VK_M;
44  import static java.awt.event.KeyEvent.VK_MINUS;
45  import static java.awt.event.KeyEvent.VK_N;
46  import static java.awt.event.KeyEvent.VK_NUMBER_SIGN;
47  import static java.awt.event.KeyEvent.VK_O;
48  import static java.awt.event.KeyEvent.VK_OPEN_BRACKET;
49  import static java.awt.event.KeyEvent.VK_P;
50  import static java.awt.event.KeyEvent.VK_PERIOD;
51  import static java.awt.event.KeyEvent.VK_PLUS;
52  import static java.awt.event.KeyEvent.VK_Q;
53  import static java.awt.event.KeyEvent.VK_QUOTE;
54  import static java.awt.event.KeyEvent.VK_QUOTEDBL;
55  import static java.awt.event.KeyEvent.VK_R;
56  import static java.awt.event.KeyEvent.VK_RIGHT_PARENTHESIS;
57  import static java.awt.event.KeyEvent.VK_S;
58  import static java.awt.event.KeyEvent.VK_SEMICOLON;
59  import static java.awt.event.KeyEvent.VK_SHIFT;
60  import static java.awt.event.KeyEvent.VK_SLASH;
61  import static java.awt.event.KeyEvent.VK_SPACE;
62  import static java.awt.event.KeyEvent.VK_T;
63  import static java.awt.event.KeyEvent.VK_TAB;
64  import static java.awt.event.KeyEvent.VK_U;
65  import static java.awt.event.KeyEvent.VK_UNDERSCORE;
66  import static java.awt.event.KeyEvent.VK_V;
67  import static java.awt.event.KeyEvent.VK_W;
68  import static java.awt.event.KeyEvent.VK_X;
69  import static java.awt.event.KeyEvent.VK_Y;
70  import static java.awt.event.KeyEvent.VK_Z;
71  
72  import java.awt.AWTException;
73  import java.awt.Robot;
74  
75  /** Use the AWT Robot class to send strings to another application. 
76   * Based on the code at 
77   * <a href="http://stackoverflow.com/questions/1248510/convert-string-to-keyevents">http://stackoverflow.com/questions/1248510/convert-string-to-keyevents</a>
78   * 
79   * @author knoxg
80   */
81  public class Keyboard {
82  
83      /** Robot class responsible for creating virtual keystrokes */
84      private Robot robot;
85  
86      /** The size of the 'keyboard buffer'. Once this many characters have been
87       * typed using the {@link #type(CharSequence)} method, an artificial delay is
88       * introduced to allow the program handling input to process keystrokes.
89       */
90      private int bufferSize = -1;
91      
92      /** Internal counter of number of characters typed so far */
93      private int delayChars = 0;
94      
95      /** Delay to introduce after {@link #bufferSize} characters have been typed, 
96       * in milliseconds */
97      private int delayMillis = 100;
98  
99      /** 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 }