Update
Вы спросили
Есть ли способ отправки нажатия клавиш управления, как они действительно отправляемые пользователем?
Решения, подобные SendKeys
и keybd_event
, неприменимы, так как программа будет находиться на заднем плане при нажатии клавиш.
От просмотра WPF reference source кажется, что это не может быть возможным, чтобы удовлетворить ваше требование делать это в фоновом режиме:
Когда RichTextBox
является constructed, вызов производится в TextEditor.RegisterCommandHandlers()
для регистрации глобальные команды для класса RichTextBox
, включая ярлыки.
TextEditor.RegisterCommandHandlers()
в свою очередь вызывает методы, подобные TextEditorParagraphs._RegisterClassHandlers()
, для регистрации определенных команд для класса.
Это, в свою очередь, вызывает CommandHelpers.RegisterCommandHandler()
, чтобы зарегистрировать каждую команду и связанный (жесткий) ярлык для класса. Ярлыки кодируются как KeyGesture
.
RegisterCommandHandler()
в свою очередь вызывает CommandManager.RegisterClassInputBinding()
, чтобы зарегистрировать каждый ярлык ярлыка для класса.
В CommandManager
хранит быстрые жесты в private static dictionary:
private static HybridDictionary _classInputBindings = new HybridDictionary();
Там нет "получить" доступ к этому словарю. Единственное место, она используется в CommandManager.TranslateInput(IInputElement targetElement, InputEventArgs inputEventArgs)
:
// Step 2: If no command, check class input bindings
if (command == null)
{
lock (_classInputBindings.SyncRoot)
{
Type classType = targetElement.GetType();
while (classType != null)
{
InputBindingCollection classInputBindings = _classInputBindings[classType] as InputBindingCollection;
if (classInputBindings != null)
{
InputBinding inputBinding = classInputBindings.FindMatch(targetElement, inputEventArgs);
if (inputBinding != null)
{
command = inputBinding.Command;
target = inputBinding.CommandTarget;
parameter = inputBinding.CommandParameter;
break;
}
}
classType = classType.BaseType;
}
}
}
classInputBindings.FindMatch()
звонки KeyGesture.Matches()
.
Но KeyGesture.Matches()
использует global static Keyboard
device, а не InputEventArgs
, чтобы определить, какой ключ модификатор нажата:
public override bool Matches(object targetElement, InputEventArgs inputEventArgs)
{
KeyEventArgs keyEventArgs = inputEventArgs as KeyEventArgs;
if(keyEventArgs != null && IsDefinedKey(keyEventArgs.Key))
{
return (((int)Key == (int)keyEventArgs.RealKey) && (this.Modifiers == Keyboard.Modifiers));
}
return false;
}
KeyEventArgs
даже не имеют свойство представлять, нажата ли элемент управления или альт ключ.
Если снять требование, чтобы сделать это в фоновом режиме, P/Вызов SendInput становится решением.
Таким образом, я думаю, что обходные команды hardcoding могут быть вашим лучшим решением.
Оригинал ответа
Не точно ответ на конкретный вопрос, но может решить вашу проблему.
Вы можете выполнить любого из standard public static editing commands таких как ToggleBold
или standard public static application commands таких как Undo
с помощью
command.Execute(null, richTextBox);
Где command
представляет собой любой из статических команд в документации, связанную выше. Кроме того, вы можете программно вставить текст в текущей позиции каретки с помощью this answer
richTextBox.CaretPosition = richTextBox.CaretPosition.GetPositionAtOffset(0, LogicalDirection.Forward);
richTextBox.CaretPosition.InsertTextInRun("Hello, I am some text\n\n\n");
richTextBox.CaretPosition.InsertTextInRun("And some more text\n\n\n");
Например, следующий будет вставить текст в текущей каретке расположении указанного RichTextBox
, затем анимировать различные редакционные изменения ко всему тексту :
const int delayInterval = 500;
static void Do(RoutedUICommand command, RichTextBox richTextBox, ref int delay)
{
// https://stackoverflow.com/questions/15599884/how-to-put-delay-before-doing-an-operation-in-wpf
var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(delay = delay + delayInterval)};
timer.Start();
timer.Tick += (sender, args) =>
{
timer.Stop();
command.Execute(null, richTextBox);
};
}
public static void TestTestProgrammaticCommandExecution(RichTextBox richTextBox)
{
// Insert some text at the caret position.
// https://stackoverflow.com/questions/2497291/how-do-i-move-the-caret-a-certain-number-of-positions-in-a-wpf-richtextbox
richTextBox.CaretPosition = richTextBox.CaretPosition.GetPositionAtOffset(0, LogicalDirection.Forward);
richTextBox.CaretPosition.InsertTextInRun("Hello, I am some text\n\n\n");
richTextBox.CaretPosition.InsertTextInRun("And some more text\n\n\n");
int delay = 0;
// Do a bunch of editing commands.
Do(EditingCommands.MoveToDocumentStart, richTextBox, ref delay);
Do(EditingCommands.SelectToDocumentEnd, richTextBox, ref delay);
Do(EditingCommands.AlignCenter, richTextBox, ref delay);
Do(EditingCommands.AlignLeft, richTextBox, ref delay);
Do(EditingCommands.AlignRight, richTextBox, ref delay);
Do(EditingCommands.DecreaseFontSize, richTextBox, ref delay);
Do(EditingCommands.IncreaseFontSize, richTextBox, ref delay);
Do(EditingCommands.IncreaseFontSize, richTextBox, ref delay);
Do(EditingCommands.IncreaseFontSize, richTextBox, ref delay);
Do(EditingCommands.IncreaseFontSize, richTextBox, ref delay);
Do(EditingCommands.Backspace, richTextBox, ref delay);
Do(ApplicationCommands.Undo, richTextBox, ref delay);
Do(EditingCommands.ToggleBold, richTextBox, ref delay);
Do(EditingCommands.ToggleBold, richTextBox, ref delay);
Do(EditingCommands.ToggleBold, richTextBox, ref delay);
Do(ApplicationCommands.Undo, richTextBox, ref delay);
Do(ApplicationCommands.Undo, richTextBox, ref delay);
Do(ApplicationCommands.Undo, richTextBox, ref delay);
Do(ApplicationCommands.Redo, richTextBox, ref delay);
Do(ApplicationCommands.Redo, richTextBox, ref delay);
Do(ApplicationCommands.Redo, richTextBox, ref delay);
}
}
Фактически я уже реализовал это как временное решение. Однако этого не хватает общности, так как я должен разбирать ключи и находить соответствующую команду жестко. Кроме того, я уже использую пары «Ключ» и «Событие», чтобы отправить нажатия клавиш в программу переднего плана с помощью 'keybd_event'. (Отправка приложения или приложения переднего плана является необязательным и выбирается пользователем.). Поэтому я хочу, чтобы две функции имели одну и ту же структуру. –
@ qqww2 - Я думал, вы написали, что 'keybd_event' не применимо, поскольку программа работает в фоновом режиме? – dbc
@ qqww2 - ответ обновлен. – dbc