Typo error
[mono.git] / mcs / class / System.Windows.Forms / System.Windows.Forms / SendKeys.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Peter Bartok    (pbartok@novell.com)
24 //  Andreia Gaita       (avidigal@novell.com)
25 //
26 //
27
28 using System.Collections;
29 using System.Runtime.InteropServices;
30 using System.Text;
31
32 namespace System.Windows.Forms {
33         
34
35         public class SendKeys {
36                 private struct Keyword {
37                         public Keyword(string keyword, int vk) {
38                                 this.keyword = keyword;
39                                 this.vk = vk;
40                         }
41                         internal string keyword;
42                         internal int vk;
43                 }
44
45                 #region Local variables
46                 private static Queue keys = new Queue();
47                 private static Hashtable keywords;
48                 #endregion
49
50                 static SendKeys() {
51                         SendKeys.keywords = new Hashtable();
52                         
53                         keywords.Add("BACKSPACE", (int)Keys.Back);
54                         keywords.Add("BS", (int)Keys.Back);
55                         keywords.Add("BKSP", (int)Keys.Back);
56                         keywords.Add("BREAK", (int)Keys.Cancel);
57                         keywords.Add("CAPSLOCK", (int)Keys.CapsLock);
58                         keywords.Add("DELETE", (int)Keys.Delete);
59                         keywords.Add("DEL", (int)Keys.Delete);
60                         keywords.Add("DOWN", (int)Keys.Down);
61                         keywords.Add("END", (int)Keys.End);
62                         keywords.Add("ENTER", (int)Keys.Enter);
63                         keywords.Add("~", (int)Keys.Enter);
64                         keywords.Add("ESC", (int)Keys.Escape);
65                         keywords.Add("HELP", (int)Keys.Help);
66                         keywords.Add("HOME", (int)Keys.Home);
67                         keywords.Add("INSERT", (int)Keys.Insert);
68                         keywords.Add("INS", (int)Keys.Insert);
69                         keywords.Add("LEFT", (int)Keys.Left);
70                         keywords.Add("NUMLOCK", (int)Keys.NumLock);
71                         keywords.Add("PGDN", (int)Keys.PageDown);
72                         keywords.Add("PGUP", (int)Keys.PageUp);
73                         keywords.Add("PRTSC", (int)Keys.PrintScreen);
74                         keywords.Add("RIGHT", (int)Keys.Right);
75                         keywords.Add("SCROLLLOCK", (int)Keys.Scroll);
76                         keywords.Add("TAB", (int)Keys.Tab);
77                         keywords.Add("UP", (int)Keys.Up);
78                         keywords.Add("F1", (int)Keys.F1);
79                         keywords.Add("F2", (int)Keys.F2);
80                         keywords.Add("F3", (int)Keys.F3);
81                         keywords.Add("F4", (int)Keys.F4);
82                         keywords.Add("F5", (int)Keys.F5);
83                         keywords.Add("F6", (int)Keys.F6);
84                         keywords.Add("F7", (int)Keys.F7);
85                         keywords.Add("F8", (int)Keys.F8);
86                         keywords.Add("F9", (int)Keys.F9);
87                         keywords.Add("F10", (int)Keys.F10);
88                         keywords.Add("F11", (int)Keys.F11);
89                         keywords.Add("F12", (int)Keys.F12);
90                         keywords.Add("F13", (int)Keys.F13);
91                         keywords.Add("F14", (int)Keys.F14);
92                         keywords.Add("F15", (int)Keys.F15);
93                         keywords.Add("F16", (int)Keys.F16);
94                         keywords.Add("ADD", (int)Keys.Add);
95                         keywords.Add("SUBTRACT", (int)Keys.Subtract);
96                         keywords.Add("MULTIPLY", (int)Keys.Multiply);
97                         keywords.Add("DIVIDE", (int)Keys.Divide);
98                         keywords.Add("+", (int)Keys.ShiftKey);
99                         keywords.Add("^", (int)Keys.ControlKey);
100                         keywords.Add("%", (int)Keys.Menu);
101                 }
102
103                 #region Private methods
104
105                 private SendKeys() {
106                 }
107
108
109                 private static void AddVKey(int vk, bool down) 
110                 {
111                         MSG msg = new MSG();
112                         msg.message = down ? Msg.WM_KEYDOWN : Msg.WM_KEYUP;
113                         msg.wParam = new IntPtr(vk);
114                         msg.lParam = IntPtr.Zero;
115                         keys.Enqueue(msg);
116                 }
117
118                 private static void AddVKey(int vk, int repeat_count) 
119                 {
120                         MSG     msg;
121
122                         for (int i = 0; i < repeat_count; i++ ) {
123                                 msg = new MSG();
124                                 msg.message = Msg.WM_KEYDOWN;
125                                 msg.wParam = new IntPtr(vk);
126                                 msg.lParam = (IntPtr)1;
127                                 keys.Enqueue(msg);
128
129                                 msg = new MSG();
130                                 msg.message = Msg.WM_KEYUP;
131                                 msg.wParam = new IntPtr(vk);
132                                 msg.lParam = IntPtr.Zero;
133                                 keys.Enqueue(msg);
134
135                         }
136                 }
137
138                 private static void AddKey(char key, int repeat_count) {
139                         MSG     msg;
140
141                         for (int i = 0; i < repeat_count; i++ ) {
142                                 msg = new MSG();
143                                 msg.message = Msg.WM_KEYDOWN;
144                                 msg.wParam = new IntPtr(key);
145                                 msg.lParam = IntPtr.Zero;
146                                 keys.Enqueue(msg);
147
148                                 msg = new MSG();
149                                 msg.message = Msg.WM_KEYUP;
150                                 msg.wParam = new IntPtr(key);
151                                 msg.lParam = IntPtr.Zero;
152                                 keys.Enqueue(msg);
153                         }
154                 }
155
156                 private static void Parse(string key_string) {
157                         bool isBlock = false;
158                         bool isVkey = false;
159                         bool isRepeat = false;
160                         bool isShift = false;
161                         bool isCtrl = false;
162                         bool isAlt = false;
163
164                         StringBuilder repeats = new StringBuilder();
165                         StringBuilder group_string = new StringBuilder();
166                         
167                         int key_len = key_string.Length;
168                         for (int i = 0; i < key_len; i++) {
169                                 switch(key_string[i]) {
170                                         case '{':
171
172                                                 group_string.Remove(0, group_string.Length);
173                                                 repeats.Remove(0, repeats.Length);
174                                                 int start = i+1;
175                                                 for (; start < key_len && key_string[start] != '}'; start++) {
176                                                         if (Char.IsWhiteSpace(key_string[start])) {
177                                                                 if (isRepeat)
178                                                                         throw new ArgumentException("SendKeys string {0} is not valid.", key_string);
179
180                                                                 isRepeat = true;
181                                                                 continue;
182                                                         }
183                                                         if (isRepeat) {
184                                                                 if (!Char.IsDigit(key_string[start]))
185                                                                         throw new ArgumentException("SendKeys string {0} is not valid.", key_string);
186                                                                 
187                                                                 repeats.Append(key_string[start]);
188
189                                                                 continue;
190                                                         }
191
192                                                         group_string.Append(key_string[start]);
193                                                 }
194                                                 if (start == key_len || start == i+1)
195                                                         throw new ArgumentException("SendKeys string {0} is not valid.", key_string);
196
197                                                 else if (SendKeys.keywords.Contains(group_string.ToString().ToUpper())) {
198                                                         isVkey = true;
199                                                 }
200                                                 else {
201                                                         throw new ArgumentException("SendKeys string {0} is not valid.", key_string);
202                                                 }
203
204                                                 int repeat = 1;
205                                                 if (repeats.Length > 0)
206                                                         repeat = Int32.Parse(repeats.ToString());
207                                                 if (isVkey)
208                                                         AddVKey((int)keywords[group_string.ToString().ToUpper()], repeats.Length == 0 ? 1 : repeat);
209                                                 else {
210                                                         if (Char.IsUpper(Char.Parse(group_string.ToString()))) {
211                                                                 if (!isShift)
212                                                                         AddVKey((int)keywords["+"], true);
213                                                                 AddKey(Char.Parse(group_string.ToString()), 1);
214                                                                 if (!isShift)
215                                                                         AddVKey((int)keywords["+"], false);
216                                                         }
217                                                         else
218                                                                 AddKey(Char.Parse(group_string.ToString().ToUpper()), repeats.Length == 0 ? 1 : repeat);
219                                                 }
220
221                                                 i = start;
222                                                 isRepeat = isVkey = false;
223                                                 if (isShift)
224                                                         AddVKey((int)keywords["+"], false);
225                                                 if (isCtrl)
226                                                         AddVKey((int)keywords["^"], false);
227                                                 if (isAlt)
228                                                         AddVKey((int)keywords["%"], false);
229                                                 isShift = isCtrl = isAlt = false;
230                                                 break;
231                                         
232                                         case '+': {
233                                                 AddVKey((int)keywords["+"], true);
234                                                 isShift = true;;
235                                                 break;
236                                         }
237
238                                         case '^': {
239                                                 AddVKey((int)keywords["^"], true);
240                                                 isCtrl = true;
241                                                 break;
242                                         }
243
244                                         case '%': {
245                                                 AddVKey((int)keywords["%"], true);
246                                                 isAlt = true;
247                                                 break;
248                                         }
249
250                                         case '~': {
251                                                 AddVKey((int)keywords["ENTER"], 1);
252                                                 break;
253                                         }
254
255                                         case '(':
256                                                 isBlock = true;
257                                                 break;
258
259                                         case ')': {
260                                                 if (isShift)
261                                                         AddVKey((int)keywords["+"], false);
262                                                 if (isCtrl)
263                                                         AddVKey((int)keywords["^"], false);
264                                                 if (isAlt)
265                                                         AddVKey((int)keywords["%"], false);
266                                                 isShift = isCtrl = isAlt = isBlock = false;
267                                                 break;
268                                         }
269
270                                         default: {
271                                                 if (Char.IsUpper(key_string[i])) {
272                                                         if (!isShift)
273                                                                 AddVKey((int)keywords["+"], true);
274                                                         AddKey(key_string[i], 1);
275                                                         if (!isShift)
276                                                                 AddVKey((int)keywords["+"], false);
277                                                 }
278                                                 else
279                                                         AddKey(Char.Parse(key_string[i].ToString().ToUpper()), 1);
280                                                 
281                                                 if (!isBlock) {
282                                                         if (isShift)
283                                                                 AddVKey((int)keywords["+"], false);
284                                                         if (isCtrl)
285                                                                 AddVKey((int)keywords["^"], false);
286                                                         if (isAlt)
287                                                                 AddVKey((int)keywords["%"], false);
288                                                         isShift = isCtrl = isAlt = isBlock = false;
289                                                 }
290                                                 break;
291                                         }
292                                 }
293                         }
294
295                         if (isBlock)
296                                 throw new ArgumentException("SendKeys string {0} is not valid.", key_string);
297
298                         if (isShift)
299                                 AddVKey((int)keywords["+"], false);
300                         if (isCtrl)
301                                 AddVKey((int)keywords["^"], false);
302                         if (isAlt)
303                                 AddVKey((int)keywords["%"], false);
304
305                 }
306
307                 private static void SendInput() {
308                         IntPtr hwnd = XplatUI.GetActive ();
309                         
310                         if (hwnd != IntPtr.Zero) {
311                                 Form active = ((Form) Control.FromHandle (hwnd));
312                                 if (active != null && active.ActiveControl != null)
313                                         hwnd = active.ActiveControl.Handle;
314                                 else if (active != null)
315                                         hwnd = active.Handle;
316                         }
317                         XplatUI.SendInput(hwnd, keys);
318                         keys.Clear();
319                 }
320
321                 #endregion      // Private Methods
322
323                 #region Public Static Methods
324                 public static void Flush() {
325                         Application.DoEvents();
326                 }
327
328                 public static void Send(string keys) {
329                         Parse(keys);
330                         SendInput();
331                 }
332
333                 private static object lockobj = new object();
334                 public static void SendWait(string keys) {
335                         lock(lockobj) {
336                                 Send(keys);
337                         }
338                         Flush();
339                 }
340
341                 #endregion      // Public Static Methods
342         }
343 }