2015-05-11 6 views
2

мне нужно отправить нажатие клавиши на RichTextBox, который в конце должен выполнить некоторые команды, как ToggleBold или SelectAll т.д.Wpf RichTextBox выполнить команду, отправив ПРОГРАММНЫЕ нажатия клавиша

я зову следующий код в цикле перебирать SomeEvent и SomeKey.

PresentationSource presentationSource = PresentationSource.FromVisual(RichTextBoxControl); 

if (presentationSource == null) 
{ 
    return; 
} 

if(SomeEvent == KeyDownEvent) 
{ 
    //InputManager.Current.ProcessInput(new KeyEventArgs(Keyboard.PrimaryDevice, presentationSource, 100, SomeKey) { RoutedEvent = PreviewKeyDownEvent }); 
    InputManager.Current.ProcessInput(new KeyEventArgs(Keyboard.PrimaryDevice, presentationSource, 100, SomeKey) { RoutedEvent = KeyDownEvent }); 
} 
else if (SomeEvent == KeyUpEvent) 
{ 
    //InputManager.Current.ProcessInput(new KeyEventArgs(Keyboard.PrimaryDevice, presentationSource, 100, SomeKey) { RoutedEvent = PreviewKeyUpEvent }); 
    InputManager.Current.ProcessInput(new KeyEventArgs(Keyboard.PrimaryDevice, presentationSource, 100, SomeKey) { RoutedEvent = KeyUpEvent }); 
} 

Например, чтобы активировать ToggleBold я называю следующие пары в цикле:

KeyDownEvent, Keys.Control 
KeyDownEvent, Keys.B 
KeyUpEvent, Keys.B 
KeyUpEvent, Keys.Control 

Я попытался KeyDownEvent - KeyUpEvent, PreviewKeyDownEvent - PreviewKeyUpEvent и PreviewKeyDownEvent - KeyDownEvent - PreviewKeyUpEvent - KeyUpEvent, но ни один из них не работал.

RichTextBox на самом деле ловит события, но не реагирует на них. Это также происходит, если я отправляю буквенно-цифровые символы (они не печатаются на RichTextBox). Однако, если я отправляю Keys.Back, он фактически распознает и удаляет символ из текста.

Решения, подобные SendKeys и keybd_event, неприменимы, так как программа будет находиться на заднем плане при нажатии клавиш.

Есть ли способ отправить нажатия клавиш в элемент управления, как будто они действительно отправлены пользователем?

ответ

2

Update

Вы спросили

Есть ли способ отправки нажатия клавиш управления, как они действительно отправляемые пользователем?

Решения, подобные SendKeys и keybd_event, неприменимы, так как программа будет находиться на заднем плане при нажатии клавиш.

От просмотра WPF reference source кажется, что это не может быть возможным, чтобы удовлетворить ваше требование делать это в фоновом режиме:

  1. Когда RichTextBox является constructed, вызов производится в TextEditor.RegisterCommandHandlers() для регистрации глобальные команды для класса RichTextBox, включая ярлыки.

  2. TextEditor.RegisterCommandHandlers() в свою очередь вызывает методы, подобные TextEditorParagraphs._RegisterClassHandlers(), для регистрации определенных команд для класса.

  3. Это, в свою очередь, вызывает CommandHelpers.RegisterCommandHandler(), чтобы зарегистрировать каждую команду и связанный (жесткий) ярлык для класса. Ярлыки кодируются как KeyGesture.

  4. RegisterCommandHandler() в свою очередь вызывает CommandManager.RegisterClassInputBinding(), чтобы зарегистрировать каждый ярлык ярлыка для класса.

  5. В CommandManager хранит быстрые жесты в private static dictionary:

    private static HybridDictionary _classInputBindings = new HybridDictionary(); 
    
  6. Там нет "получить" доступ к этому словарю. Единственное место, она используется в 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; 
          } 
         } 
        } 
    
  7. classInputBindings.FindMatch() звонки KeyGesture.Matches().

  8. Но 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); 
    } 
} 
+0

Фактически я уже реализовал это как временное решение. Однако этого не хватает общности, так как я должен разбирать ключи и находить соответствующую команду жестко. Кроме того, я уже использую пары «Ключ» и «Событие», чтобы отправить нажатия клавиш в программу переднего плана с помощью 'keybd_event'. (Отправка приложения или приложения переднего плана является необязательным и выбирается пользователем.). Поэтому я хочу, чтобы две функции имели одну и ту же структуру. –

+0

@ qqww2 - Я думал, вы написали, что 'keybd_event' не применимо, поскольку программа работает в фоновом режиме? – dbc

+0

@ qqww2 - ответ обновлен. – dbc