343 lines
9.3 KiB
C#
343 lines
9.3 KiB
C#
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||
|
// a copy of this software and associated documentation files (the
|
||
|
// "Software"), to deal in the Software without restriction, including
|
||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||
|
// the following conditions:
|
||
|
//
|
||
|
// The above copyright notice and this permission notice shall be
|
||
|
// included in all copies or substantial portions of the Software.
|
||
|
//
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
//
|
||
|
// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
|
||
|
//
|
||
|
// Authors:
|
||
|
// Peter Bartok (pbartok@novell.com)
|
||
|
// Andreia Gaita (avidigal@novell.com)
|
||
|
//
|
||
|
//
|
||
|
|
||
|
using System.Collections;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using System.Text;
|
||
|
|
||
|
namespace System.Windows.Forms {
|
||
|
|
||
|
|
||
|
public class SendKeys {
|
||
|
private struct Keyword {
|
||
|
public Keyword(string keyword, int vk) {
|
||
|
this.keyword = keyword;
|
||
|
this.vk = vk;
|
||
|
}
|
||
|
internal string keyword;
|
||
|
internal int vk;
|
||
|
}
|
||
|
|
||
|
#region Local variables
|
||
|
private static Queue keys = new Queue();
|
||
|
private static Hashtable keywords;
|
||
|
#endregion
|
||
|
|
||
|
static SendKeys() {
|
||
|
SendKeys.keywords = new Hashtable();
|
||
|
|
||
|
keywords.Add("BACKSPACE", (int)Keys.Back);
|
||
|
keywords.Add("BS", (int)Keys.Back);
|
||
|
keywords.Add("BKSP", (int)Keys.Back);
|
||
|
keywords.Add("BREAK", (int)Keys.Cancel);
|
||
|
keywords.Add("CAPSLOCK", (int)Keys.CapsLock);
|
||
|
keywords.Add("DELETE", (int)Keys.Delete);
|
||
|
keywords.Add("DEL", (int)Keys.Delete);
|
||
|
keywords.Add("DOWN", (int)Keys.Down);
|
||
|
keywords.Add("END", (int)Keys.End);
|
||
|
keywords.Add("ENTER", (int)Keys.Enter);
|
||
|
keywords.Add("~", (int)Keys.Enter);
|
||
|
keywords.Add("ESC", (int)Keys.Escape);
|
||
|
keywords.Add("HELP", (int)Keys.Help);
|
||
|
keywords.Add("HOME", (int)Keys.Home);
|
||
|
keywords.Add("INSERT", (int)Keys.Insert);
|
||
|
keywords.Add("INS", (int)Keys.Insert);
|
||
|
keywords.Add("LEFT", (int)Keys.Left);
|
||
|
keywords.Add("NUMLOCK", (int)Keys.NumLock);
|
||
|
keywords.Add("PGDN", (int)Keys.PageDown);
|
||
|
keywords.Add("PGUP", (int)Keys.PageUp);
|
||
|
keywords.Add("PRTSC", (int)Keys.PrintScreen);
|
||
|
keywords.Add("RIGHT", (int)Keys.Right);
|
||
|
keywords.Add("SCROLLLOCK", (int)Keys.Scroll);
|
||
|
keywords.Add("TAB", (int)Keys.Tab);
|
||
|
keywords.Add("UP", (int)Keys.Up);
|
||
|
keywords.Add("F1", (int)Keys.F1);
|
||
|
keywords.Add("F2", (int)Keys.F2);
|
||
|
keywords.Add("F3", (int)Keys.F3);
|
||
|
keywords.Add("F4", (int)Keys.F4);
|
||
|
keywords.Add("F5", (int)Keys.F5);
|
||
|
keywords.Add("F6", (int)Keys.F6);
|
||
|
keywords.Add("F7", (int)Keys.F7);
|
||
|
keywords.Add("F8", (int)Keys.F8);
|
||
|
keywords.Add("F9", (int)Keys.F9);
|
||
|
keywords.Add("F10", (int)Keys.F10);
|
||
|
keywords.Add("F11", (int)Keys.F11);
|
||
|
keywords.Add("F12", (int)Keys.F12);
|
||
|
keywords.Add("F13", (int)Keys.F13);
|
||
|
keywords.Add("F14", (int)Keys.F14);
|
||
|
keywords.Add("F15", (int)Keys.F15);
|
||
|
keywords.Add("F16", (int)Keys.F16);
|
||
|
keywords.Add("ADD", (int)Keys.Add);
|
||
|
keywords.Add("SUBTRACT", (int)Keys.Subtract);
|
||
|
keywords.Add("MULTIPLY", (int)Keys.Multiply);
|
||
|
keywords.Add("DIVIDE", (int)Keys.Divide);
|
||
|
keywords.Add("+", (int)Keys.ShiftKey);
|
||
|
keywords.Add("^", (int)Keys.ControlKey);
|
||
|
keywords.Add("%", (int)Keys.Menu);
|
||
|
}
|
||
|
|
||
|
#region Private methods
|
||
|
|
||
|
private SendKeys() {
|
||
|
}
|
||
|
|
||
|
|
||
|
private static void AddVKey(int vk, bool down)
|
||
|
{
|
||
|
MSG msg = new MSG();
|
||
|
msg.message = down ? Msg.WM_KEYDOWN : Msg.WM_KEYUP;
|
||
|
msg.wParam = new IntPtr(vk);
|
||
|
msg.lParam = IntPtr.Zero;
|
||
|
keys.Enqueue(msg);
|
||
|
}
|
||
|
|
||
|
private static void AddVKey(int vk, int repeat_count)
|
||
|
{
|
||
|
MSG msg;
|
||
|
|
||
|
for (int i = 0; i < repeat_count; i++ ) {
|
||
|
msg = new MSG();
|
||
|
msg.message = Msg.WM_KEYDOWN;
|
||
|
msg.wParam = new IntPtr(vk);
|
||
|
msg.lParam = (IntPtr)1;
|
||
|
keys.Enqueue(msg);
|
||
|
|
||
|
msg = new MSG();
|
||
|
msg.message = Msg.WM_KEYUP;
|
||
|
msg.wParam = new IntPtr(vk);
|
||
|
msg.lParam = IntPtr.Zero;
|
||
|
keys.Enqueue(msg);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void AddKey(char key, int repeat_count) {
|
||
|
MSG msg;
|
||
|
|
||
|
for (int i = 0; i < repeat_count; i++ ) {
|
||
|
msg = new MSG();
|
||
|
msg.message = Msg.WM_KEYDOWN;
|
||
|
msg.wParam = new IntPtr(key);
|
||
|
msg.lParam = IntPtr.Zero;
|
||
|
keys.Enqueue(msg);
|
||
|
|
||
|
msg = new MSG();
|
||
|
msg.message = Msg.WM_KEYUP;
|
||
|
msg.wParam = new IntPtr(key);
|
||
|
msg.lParam = IntPtr.Zero;
|
||
|
keys.Enqueue(msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void Parse(string key_string) {
|
||
|
bool isBlock = false;
|
||
|
bool isVkey = false;
|
||
|
bool isRepeat = false;
|
||
|
bool isShift = false;
|
||
|
bool isCtrl = false;
|
||
|
bool isAlt = false;
|
||
|
|
||
|
StringBuilder repeats = new StringBuilder();
|
||
|
StringBuilder group_string = new StringBuilder();
|
||
|
|
||
|
int key_len = key_string.Length;
|
||
|
for (int i = 0; i < key_len; i++) {
|
||
|
switch(key_string[i]) {
|
||
|
case '{':
|
||
|
|
||
|
group_string.Remove(0, group_string.Length);
|
||
|
repeats.Remove(0, repeats.Length);
|
||
|
int start = i+1;
|
||
|
for (; start < key_len && key_string[start] != '}'; start++) {
|
||
|
if (Char.IsWhiteSpace(key_string[start])) {
|
||
|
if (isRepeat)
|
||
|
throw new ArgumentException("SendKeys string {0} is not valid.", key_string);
|
||
|
|
||
|
isRepeat = true;
|
||
|
continue;
|
||
|
}
|
||
|
if (isRepeat) {
|
||
|
if (!Char.IsDigit(key_string[start]))
|
||
|
throw new ArgumentException("SendKeys string {0} is not valid.", key_string);
|
||
|
|
||
|
repeats.Append(key_string[start]);
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
group_string.Append(key_string[start]);
|
||
|
}
|
||
|
if (start == key_len || start == i+1)
|
||
|
throw new ArgumentException("SendKeys string {0} is not valid.", key_string);
|
||
|
|
||
|
else if (SendKeys.keywords.Contains(group_string.ToString().ToUpper())) {
|
||
|
isVkey = true;
|
||
|
}
|
||
|
else {
|
||
|
throw new ArgumentException("SendKeys string {0} is not valid.", key_string);
|
||
|
}
|
||
|
|
||
|
int repeat = 1;
|
||
|
if (repeats.Length > 0)
|
||
|
repeat = Int32.Parse(repeats.ToString());
|
||
|
if (isVkey)
|
||
|
AddVKey((int)keywords[group_string.ToString().ToUpper()], repeats.Length == 0 ? 1 : repeat);
|
||
|
else {
|
||
|
if (Char.IsUpper(Char.Parse(group_string.ToString()))) {
|
||
|
if (!isShift)
|
||
|
AddVKey((int)keywords["+"], true);
|
||
|
AddKey(Char.Parse(group_string.ToString()), 1);
|
||
|
if (!isShift)
|
||
|
AddVKey((int)keywords["+"], false);
|
||
|
}
|
||
|
else
|
||
|
AddKey(Char.Parse(group_string.ToString().ToUpper()), repeats.Length == 0 ? 1 : repeat);
|
||
|
}
|
||
|
|
||
|
i = start;
|
||
|
isRepeat = isVkey = false;
|
||
|
if (isShift)
|
||
|
AddVKey((int)keywords["+"], false);
|
||
|
if (isCtrl)
|
||
|
AddVKey((int)keywords["^"], false);
|
||
|
if (isAlt)
|
||
|
AddVKey((int)keywords["%"], false);
|
||
|
isShift = isCtrl = isAlt = false;
|
||
|
break;
|
||
|
|
||
|
case '+': {
|
||
|
AddVKey((int)keywords["+"], true);
|
||
|
isShift = true;;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case '^': {
|
||
|
AddVKey((int)keywords["^"], true);
|
||
|
isCtrl = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case '%': {
|
||
|
AddVKey((int)keywords["%"], true);
|
||
|
isAlt = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case '~': {
|
||
|
AddVKey((int)keywords["ENTER"], 1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case '(':
|
||
|
isBlock = true;
|
||
|
break;
|
||
|
|
||
|
case ')': {
|
||
|
if (isShift)
|
||
|
AddVKey((int)keywords["+"], false);
|
||
|
if (isCtrl)
|
||
|
AddVKey((int)keywords["^"], false);
|
||
|
if (isAlt)
|
||
|
AddVKey((int)keywords["%"], false);
|
||
|
isShift = isCtrl = isAlt = isBlock = false;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default: {
|
||
|
if (Char.IsUpper(key_string[i])) {
|
||
|
if (!isShift)
|
||
|
AddVKey((int)keywords["+"], true);
|
||
|
AddKey(key_string[i], 1);
|
||
|
if (!isShift)
|
||
|
AddVKey((int)keywords["+"], false);
|
||
|
}
|
||
|
else
|
||
|
AddKey(Char.Parse(key_string[i].ToString().ToUpper()), 1);
|
||
|
|
||
|
if (!isBlock) {
|
||
|
if (isShift)
|
||
|
AddVKey((int)keywords["+"], false);
|
||
|
if (isCtrl)
|
||
|
AddVKey((int)keywords["^"], false);
|
||
|
if (isAlt)
|
||
|
AddVKey((int)keywords["%"], false);
|
||
|
isShift = isCtrl = isAlt = isBlock = false;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (isBlock)
|
||
|
throw new ArgumentException("SendKeys string {0} is not valid.", key_string);
|
||
|
|
||
|
if (isShift)
|
||
|
AddVKey((int)keywords["+"], false);
|
||
|
if (isCtrl)
|
||
|
AddVKey((int)keywords["^"], false);
|
||
|
if (isAlt)
|
||
|
AddVKey((int)keywords["%"], false);
|
||
|
|
||
|
}
|
||
|
|
||
|
private static void SendInput() {
|
||
|
IntPtr hwnd = XplatUI.GetActive ();
|
||
|
|
||
|
if (hwnd != IntPtr.Zero) {
|
||
|
Form active = ((Form) Control.FromHandle (hwnd));
|
||
|
if (active != null && active.ActiveControl != null)
|
||
|
hwnd = active.ActiveControl.Handle;
|
||
|
else if (active != null)
|
||
|
hwnd = active.Handle;
|
||
|
}
|
||
|
XplatUI.SendInput(hwnd, keys);
|
||
|
keys.Clear();
|
||
|
}
|
||
|
|
||
|
#endregion // Private Methods
|
||
|
|
||
|
#region Public Static Methods
|
||
|
public static void Flush() {
|
||
|
Application.DoEvents();
|
||
|
}
|
||
|
|
||
|
public static void Send(string keys) {
|
||
|
Parse(keys);
|
||
|
SendInput();
|
||
|
}
|
||
|
|
||
|
private static object lockobj = new object();
|
||
|
public static void SendWait(string keys) {
|
||
|
lock(lockobj) {
|
||
|
Send(keys);
|
||
|
}
|
||
|
Flush();
|
||
|
}
|
||
|
|
||
|
#endregion // Public Static Methods
|
||
|
}
|
||
|
}
|