csharp WPF对指定控件发送按键
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了csharp WPF对指定控件发送按键相关的知识,希望对你有一定的参考价值。
using System.Collections.Generic;namespace System.Windows.Input.Test{ internal class SendKeysParser { private string text; private int current = 0; private bool insideParentheses = false; private ModifierKeys currentModifiers = ModifierKeys.None; private List<KeyPressInfo> result = new List<KeyPressInfo>(); public static IEnumerable<KeyPressInfo> Parse(string text) { return new SendKeysParser().ParseSendKeysString(text); } public IEnumerable<KeyPressInfo> ParseSendKeysString(string text) { this.text = text; current = 0; int oldCurrent = current; while (current < text.Length) { if (CurrentChar == '{') { ParseCurly(); if (!insideParentheses && currentModifiers != ModifierKeys.None) { currentModifiers = ModifierKeys.None; } } else if (CurrentChar == '~') { current++; Add(Key.Return); if (!insideParentheses && currentModifiers != ModifierKeys.None) { currentModifiers = ModifierKeys.None; } } else if (CurrentChar == '+') { currentModifiers = currentModifiers | ModifierKeys.Shift; current++; } else if (CurrentChar == '^') { currentModifiers = currentModifiers | ModifierKeys.Control; current++; } else if (CurrentChar == '%') { currentModifiers = currentModifiers | ModifierKeys.Alt; current++; } else if (CurrentChar == '(') { if (insideParentheses) { Error("Unbalanced parentheses: unexpected second ("); } insideParentheses = true; current++; } else if (CurrentChar == ')') { if (!insideParentheses) { Error("Unbalanced parentheses: unexpected closing )"); } insideParentheses = false; currentModifiers = ModifierKeys.None; current++; } else if (IsPrintableChar()) { ParseChar(); if (!insideParentheses && currentModifiers != ModifierKeys.None) { currentModifiers = ModifierKeys.None; } } else { Error("Unexpected character: '" + CurrentChar + "'"); } if (oldCurrent == current) { Error("Didn't advance forward, stuck at parsing character '" + CurrentChar + "'"); } oldCurrent = current; } return result; } private void Error(string p) { throw new Exception(p + Environment.NewLine + " at position " + current); } private Dictionary<string, KeyPressInfo> specialValues = new Dictionary<string, KeyPressInfo>() { {"+", new KeyPressInfo(Key.OemPlus, ModifierKeys.Shift)}, {"^", new KeyPressInfo(Key.D6, ModifierKeys.Shift)}, {"%", new KeyPressInfo(Key.D5, ModifierKeys.Shift)}, {"{", new KeyPressInfo(Key.OemOpenBrackets, ModifierKeys.Shift)}, {"}", new KeyPressInfo(Key.Oem6, ModifierKeys.Shift)}, {"[", new KeyPressInfo(Key.OemOpenBrackets)}, {"]", new KeyPressInfo(Key.Oem6)}, {"(", new KeyPressInfo(Key.D9, ModifierKeys.Shift)}, {")", new KeyPressInfo(Key.D0, ModifierKeys.Shift)}, {"~", new KeyPressInfo(Key.Oem3, ModifierKeys.Shift)}, {"BACKSPACE", new KeyPressInfo(Key.Back)}, {"BS", new KeyPressInfo(Key.Back)}, {"BKSP", new KeyPressInfo(Key.Back)}, {"CAPSLOCK", new KeyPressInfo(Key.CapsLock)}, {"DEL", new KeyPressInfo(Key.Delete)}, {"DELETE", new KeyPressInfo(Key.Delete)}, {"DOWN", new KeyPressInfo(Key.Down)}, {"END", new KeyPressInfo(Key.End)}, {"ENTER", new KeyPressInfo(Key.Enter)}, {"ESC", new KeyPressInfo(Key.Escape)}, {"HELP", new KeyPressInfo(Key.Help)}, {"HOME", new KeyPressInfo(Key.Home)}, {"INSERT", new KeyPressInfo(Key.Insert)}, {"INS", new KeyPressInfo(Key.Insert)}, {"LEFT", new KeyPressInfo(Key.Left)}, {"NUMLOCK", new KeyPressInfo(Key.NumLock)}, {"PGDN", new KeyPressInfo(Key.PageDown)}, {"PGUP", new KeyPressInfo(Key.PageUp)}, {"PRTSC", new KeyPressInfo(Key.PrintScreen)}, {"RIGHT", new KeyPressInfo(Key.Right)}, {"SCROLLOCK", new KeyPressInfo(Key.Scroll)}, {"TAB", new KeyPressInfo(Key.Tab)}, {"UP", new KeyPressInfo(Key.Up)}, {"F1", new KeyPressInfo(Key.F1)}, {"F2", new KeyPressInfo(Key.F2)}, {"F3", new KeyPressInfo(Key.F3)}, {"F4", new KeyPressInfo(Key.F4)}, {"F5", new KeyPressInfo(Key.F5)}, {"F6", new KeyPressInfo(Key.F6)}, {"F7", new KeyPressInfo(Key.F7)}, {"F8", new KeyPressInfo(Key.F8)}, {"F9", new KeyPressInfo(Key.F9)}, {"F10", new KeyPressInfo(Key.F10)}, {"F11", new KeyPressInfo(Key.F11)}, {"F12", new KeyPressInfo(Key.F12)}, {"F13", new KeyPressInfo(Key.F13)}, {"F14", new KeyPressInfo(Key.F14)}, {"F15", new KeyPressInfo(Key.F15)}, {"F16", new KeyPressInfo(Key.F16)}, }; private void ParseCurly() { foreach (var specialValue in specialValues) { var name = specialValue.Key; if (current + name.Length + 2 > text.Length) { continue; } if (text.Substring(current + 1, name.Length + 1).Equals(name + "}", StringComparison.OrdinalIgnoreCase)) { current += name.Length + 2; var gesture = specialValue.Value; Add(gesture); return; } } int closing = text.IndexOf('}', current); if (closing == -1) { Error("Closing curly missing"); } Error("Unknown key: " + text.Substring(current, closing - current + 1)); } private void Add(KeyPressInfo gesture) { if (currentModifiers != ModifierKeys.None) { gesture = new KeyPressInfo(gesture.Key, gesture.Modifiers | currentModifiers); } result.Add(gesture); } private void Add(Key key) { Add(new KeyPressInfo(key)); } private void ParseChar() { var key = Key.None; var modifiers = ModifierKeys.None; var ch = CurrentChar.ToString(); KeyPressInfo knownKeyPress = KeyboardLayout.Instance.GetKeyGestureForChar(ch[0]); if (knownKeyPress != null) { key = knownKeyPress.Key; modifiers = knownKeyPress.Modifiers; } else { if (char.IsUpper(ch, 0)) { ch = ch.ToLower(); modifiers = ModifierKeys.Shift; } key = (Key)new KeyConverter().ConvertFromInvariantString(ch); } if (key != Key.None) { Add(new KeyPressInfo(key, modifiers)); current++; } } private bool IsPrintableChar() { return char.IsLetterOrDigit(CurrentChar) || KeyboardLayout.Instance.GetKeyGestureForChar(CurrentChar) != null; } private char CurrentChar { get { return text[current]; } } }}
using System.Runtime.InteropServices;using System.Text;using System.Windows.Forms;namespace System.Windows.Input.Test{ internal class SendKeys { public static void Send(UIElement element, string text) { var sequence = SendKeysParser.Parse(text); foreach (var keyPressInfo in sequence) { Send(element, keyPressInfo.Key, keyPressInfo.Modifiers); } } public static void Send(UIElement element, Key key, ModifierKeys modifiers) { KeyboardDevice keyboardDevice = InputManager.Current.PrimaryKeyboardDevice; if (modifiers != ModifierKeys.None) { MockKeyboardDevice mockKeyboardDevice = MockKeyboardDevice.Instance; mockKeyboardDevice.Modifiers = modifiers; keyboardDevice = mockKeyboardDevice; } RaiseKeyEvent(element, key, modifiers, keyboardDevice); } public static void SendInput(UIElement element, string text) { InputManager inputManager = InputManager.Current; InputDevice inputDevice = inputManager.PrimaryKeyboardDevice; TextComposition composition = new TextComposition(inputManager, element, text); TextCompositionEventArgs args = new TextCompositionEventArgs(inputDevice, composition); args.RoutedEvent = UIElement.PreviewTextInputEvent; element.RaiseEvent(args); args.RoutedEvent = UIElement.TextInputEvent; element.RaiseEvent(args); } private static void RaiseKeyEvent(UIElement element, Key key, ModifierKeys modifiers, KeyboardDevice keyboardDevice) { PresentationSource presentationSource = PresentationSource.FromVisual(element); int timestamp = Environment.TickCount; KeyEventArgs args = new KeyEventArgs(keyboardDevice, presentationSource, timestamp, key); // 1) PreviewKeyDown args.RoutedEvent = Keyboard.PreviewKeyDownEvent; element.RaiseEvent(args); // 2) KeyDown args.RoutedEvent = Keyboard.KeyDownEvent; element.RaiseEvent(args); // 3) TextInput SendInputIfNecessary(element, key, modifiers, keyboardDevice); // 4) PreviewKeyUp args.RoutedEvent = Keyboard.PreviewKeyUpEvent; element.RaiseEvent(args); // 5) KeyUp args.RoutedEvent = Keyboard.KeyUpEvent; element.RaiseEvent(args); } private static void SendInputIfNecessary(UIElement element, Key key, ModifierKeys modifiers, KeyboardDevice keyboardDevice) { if (modifiers.HasFlag(ModifierKeys.Control) || modifiers.HasFlag(ModifierKeys.Alt)) { return; } string input = ""; input = KeyboardLayout.Instance.GetInputForGesture(new KeyPressInfo(key, modifiers)); if (input == "") { input = GetInputFromKey(key); } if (string.IsNullOrEmpty(input)) { return; } if (modifiers == ModifierKeys.Shift) { input = input.ToUpperInvariant(); } else { input = input.ToLowerInvariant(); } SendInput(element, input); } private static string GetInputFromKey(Key key) { switch (key) { case Key.Left: case Key.Up: case Key.Right: case Key.Down: case Key.Home: case Key.End: case Key.Insert: case Key.Delete: case Key.PageUp: case Key.PageDown: case Key.Back: case Key.Escape: case Key.Enter: case Key.Tab: case Key.Space: return ""; } return ToAscii((Keys)KeyInterop.VirtualKeyFromKey(key)); } [DllImport("user32.dll")] public static extern int ToAscii(uint uVirtKey, uint uScanCode, byte[] lpKeyState, [Out]StringBuilder lpwTransKey, uint fuState); private static string ToAscii(Keys key) { string keystring = key.ToString(); var keyState = new byte[256]; var outputBuilder = new StringBuilder(2); int result = ToAscii((uint)key, 0, keyState, outputBuilder, 0); if (result == 1) { if (outputBuilder.Length > 0) { keystring = outputBuilder[0].ToString(); } } return keystring.ToUpper(); } }}
using System.Reflection;namespace System.Windows.Input.Test{ /// <summary> /// This serves to mock the state of the modifier keys Shift, Alt and Ctrl. /// We pass this keyboard device to KeyEventArgs, so that whenever the user /// says args.KeyboardDevice.Modifiers, we can provide our own Modifiers value /// instead of going to the operating system and fetching the actual key states /// from the driver (normally done by KeyboardDevice and Win32KeyboardDevice). /// </summary> /// <remarks> /// An unfortunate side effect of creating our own derived KeyboardDevice is /// that we'll have to call the KeyboardDevice's protected ctor, which does /// a lot of damage by subscribing itself to a whole bunch of static events. /// Not only will these events prevent our MockKeyboardDevice from ever being /// collected, but also every instance of us will start "typing" whenever real /// input from the user comes into the system. For example, by merely creating /// an instance of MockKeyboardDevice, we achieve the effect that when the user /// types a key such as w, it will be duplicated and all the events will be called /// twice, resulting in a 'ww' on the screen. /// </remarks> internal class MockKeyboardDevice : KeyboardDevice { /// <summary> /// Fake state of the Shift, Alt and Ctrl keys desired by the test /// </summary> public new ModifierKeys Modifiers { get; set; } private static MockKeyboardDevice mInstance; public static MockKeyboardDevice Instance { get { if (mInstance == null) { mInstance = new MockKeyboardDevice(); } return mInstance; } } /// <summary> /// To prevent contaminating the system with test side effects /// (basically, to prevent our MockKeyboardDevice from listening and reacting to real /// keyboard input), we need to undo the damage done by the /// base KeyboardDevice's constructor where it subscribes to some events. /// By unsubscribing from these events we make sure our KeyboardDevice /// won't respond to real input and will be used solely to provide the /// desired state of the Shift, Alt and Ctrl modifier keys when asked for. /// </summary> private MockKeyboardDevice() : base(InputManager.Current) { // There's only one global input manager in the system InputManager inputManager = InputManager.Current; // First, unsubscribe our 3 handlers from the InputManager. // 1) // Undo the effect of the following line in the KeyboardDevice ctor: // this._inputManager.Value.PreProcessInput += new PreProcessInputEventHandler(this.PreProcessInput); PreProcessInputEventHandler preProcessInputHandler = GetDelegateForMethod<PreProcessInputEventHandler>(this, "PreProcessInput"); inputManager.PreProcessInput -= preProcessInputHandler; // 2) // Undo the effect of the following line in the KeyboardDevice ctor: // this._inputManager.Value.PreNotifyInput += new NotifyInputEventHandler(this.PreNotifyInput); NotifyInputEventHandler preNotifyInputHandler = GetDelegateForMethod<NotifyInputEventHandler>(this, "PreNotifyInput"); inputManager.PreNotifyInput -= preNotifyInputHandler; // 3) // Undo the effect of the following line in the KeyboardDevice ctor: // this._inputManager.Value.PostProcessInput += new ProcessInputEventHandler(this.PostProcessInput); ProcessInputEventHandler postProcessInputHandler = GetDelegateForMethod<ProcessInputEventHandler>(this, "PostProcessInput"); inputManager.PostProcessInput -= postProcessInputHandler; // Now undo the damage done by creating a new TextServicesManager // this._TsfManager = new SecurityCriticalDataClass<TextServicesManager>(new TextServicesManager(inputManager)); var textServicesManager = this.GetFieldValue("_TsfManager").GetFieldValue("_value"); // this._inputManager.PreProcessInput += new PreProcessInputEventHandler(this.PreProcessInput); preProcessInputHandler = GetDelegateForMethod<PreProcessInputEventHandler>(textServicesManager, "PreProcessInput"); inputManager.PreProcessInput -= preProcessInputHandler; // this._inputManager.PostProcessInput += new ProcessInputEventHandler(this.PostProcessInput); postProcessInputHandler = GetDelegateForMethod<ProcessInputEventHandler>(textServicesManager, "PostProcessInput"); inputManager.PostProcessInput -= postProcessInputHandler; // And finally, revert the changes done by creating a new TextCompositionManager // this._textcompositionManager = new SecurityCriticalData<TextCompositionManager>(new TextCompositionManager(inputManager)); var textCompositionManager = this.GetFieldValue("_textcompositionManager").GetFieldValue("_value"); // this._inputManager.PreProcessInput += new PreProcessInputEventHandler(this.PreProcessInput); preProcessInputHandler = GetDelegateForMethod<PreProcessInputEventHandler>(textCompositionManager, "PreProcessInput"); inputManager.PreProcessInput -= preProcessInputHandler; // his._inputManager.PostProcessInput += new ProcessInputEventHandler(this.PostProcessInput); postProcessInputHandler = GetDelegateForMethod<ProcessInputEventHandler>(textCompositionManager, "PostProcessInput"); inputManager.PostProcessInput -= postProcessInputHandler; } private T GetDelegateForMethod<T>(object target, string methodName) { object result = Delegate.CreateDelegate(typeof(T), target, methodName); return (T)result; } protected override KeyStates GetKeyStatesFromSystem(Key key) { return GetKeyStatesCore(key, this.Modifiers); } private KeyStates GetKeyStatesCore(Key key, ModifierKeys Modifiers) { switch (key) { case Key.LeftAlt: case Key.RightAlt: return (Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt ? KeyStates.Down : KeyStates.None; case Key.LeftCtrl: case Key.RightCtrl: return (Modifiers & ModifierKeys.Control) == ModifierKeys.Control ? KeyStates.Down : KeyStates.None; case Key.LeftShift: case Key.RightShift: return (Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift ? KeyStates.Down : KeyStates.None; } return KeyStates.None; } } internal static class ReflectionExtensions { public static object GetFieldValue(this object instance, string fieldName) { Type type = instance.GetType(); FieldInfo fieldInfo = null; while (type != null) { fieldInfo = type.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (fieldInfo != null) { break; } type = type.BaseType; } if (fieldInfo == null) { throw new FieldAccessException("Field " + fieldName + " was not found on type " + type.ToString()); } object result = fieldInfo.GetValue(instance); return result; // you can place a breakpoint here (for debugging purposes) } }}
using System.Collections.Generic;namespace System.Windows.Input.Test{ internal class KeyboardLayout { public static readonly KeyboardLayout Instance = new KeyboardLayout(); public KeyPressInfo GetKeyGestureForChar(char index) { KeyPressInfo result = null; printableChars.TryGetValue(index, out result); return result; } public string GetInputForGesture(KeyPressInfo gesture) { foreach (var item in printableChars) { if (item.Value.Key == gesture.Key && item.Value.Modifiers == gesture.Modifiers) { return item.Key.ToString(); } } return ""; } private static readonly Dictionary<char, KeyPressInfo> printableChars = new Dictionary<char, KeyPressInfo> { {' ', new KeyPressInfo(Key.Space)}, {',', new KeyPressInfo(Key.OemComma)}, {'<', new KeyPressInfo(Key.OemComma, ModifierKeys.Shift)}, {'.', new KeyPressInfo(Key.OemPeriod)}, {'>', new KeyPressInfo(Key.OemPeriod, ModifierKeys.Shift)}, {'/', new KeyPressInfo(Key.OemQuestion)}, {'?', new KeyPressInfo(Key.OemQuestion, ModifierKeys.Shift)}, {'-', new KeyPressInfo(Key.OemMinus)}, {'_', new KeyPressInfo(Key.OemMinus, ModifierKeys.Shift)}, {'=', new KeyPressInfo(Key.OemPlus)}, {'+', new KeyPressInfo(Key.OemPlus, ModifierKeys.Shift)}, {'[', new KeyPressInfo(Key.OemOpenBrackets)}, {'{', new KeyPressInfo(Key.OemOpenBrackets, ModifierKeys.Shift)}, {']', new KeyPressInfo(Key.Oem6)}, {'}', new KeyPressInfo(Key.Oem6, ModifierKeys.Shift)}, {'\\', new KeyPressInfo(Key.Oem5)}, {'|', new KeyPressInfo(Key.Oem5, ModifierKeys.Shift)}, {';', new KeyPressInfo(Key.Oem1)}, {':', new KeyPressInfo(Key.Oem1, ModifierKeys.Shift)}, {'`', new KeyPressInfo(Key.Oem3)}, {'~', new KeyPressInfo(Key.Oem3, ModifierKeys.Shift)}, {'\'', new KeyPressInfo(Key.OemQuotes)}, {'"', new KeyPressInfo(Key.OemQuotes, ModifierKeys.Shift)}, {'!', new KeyPressInfo(Key.D1, ModifierKeys.Shift)}, {'@', new KeyPressInfo(Key.D2, ModifierKeys.Shift)}, {'#', new KeyPressInfo(Key.D3, ModifierKeys.Shift)}, {'$', new KeyPressInfo(Key.D4, ModifierKeys.Shift)}, {'%', new KeyPressInfo(Key.D5, ModifierKeys.Shift)}, {'^', new KeyPressInfo(Key.D6, ModifierKeys.Shift)}, {'&', new KeyPressInfo(Key.D7, ModifierKeys.Shift)}, {'*', new KeyPressInfo(Key.D8, ModifierKeys.Shift)}, {'(', new KeyPressInfo(Key.D9, ModifierKeys.Shift)}, {')', new KeyPressInfo(Key.D0, ModifierKeys.Shift)}, }; }}
namespace System.Windows.Input.Test{ internal class KeyPressInfo { public KeyPressInfo(Key key) { this.Key = key; this.Modifiers = ModifierKeys.None; } public KeyPressInfo(Key key, ModifierKeys modifierKeys) { this.Key = key; this.Modifiers = modifierKeys; } public Key Key { get; set; } public ModifierKeys Modifiers { get; set; } public override string ToString() { var result = Key.ToString(); if (Modifiers != ModifierKeys.None) { result = Modifiers.ToString() + " + " + result; } return result; } }}
以上是关于csharp WPF对指定控件发送按键的主要内容,如果未能解决你的问题,请参考以下文章
csharp 在WPF VisualTree中按名称查找控件