/ src / Ryujinx / UI / Applet / AvaloniaDynamicTextInputHandler.cs
AvaloniaDynamicTextInputHandler.cs
  1  using Avalonia;
  2  using Avalonia.Controls;
  3  using Avalonia.Input;
  4  using Avalonia.Threading;
  5  using Ryujinx.Ava.Input;
  6  using Ryujinx.Ava.UI.Helpers;
  7  using Ryujinx.Ava.UI.Windows;
  8  using Ryujinx.HLE.UI;
  9  using System;
 10  using System.Threading;
 11  using HidKey = Ryujinx.Common.Configuration.Hid.Key;
 12  
 13  namespace Ryujinx.Ava.UI.Applet
 14  {
 15      class AvaloniaDynamicTextInputHandler : IDynamicTextInputHandler
 16      {
 17          private MainWindow _parent;
 18          private readonly OffscreenTextBox _hiddenTextBox;
 19          private bool _canProcessInput;
 20          private IDisposable _textChangedSubscription;
 21          private IDisposable _selectionStartChangedSubscription;
 22          private IDisposable _selectionEndtextChangedSubscription;
 23  
 24          public AvaloniaDynamicTextInputHandler(MainWindow parent)
 25          {
 26              _parent = parent;
 27  
 28              (_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyPressed += AvaloniaDynamicTextInputHandler_KeyPressed;
 29              (_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyRelease += AvaloniaDynamicTextInputHandler_KeyRelease;
 30              (_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).TextInput += AvaloniaDynamicTextInputHandler_TextInput;
 31  
 32              _hiddenTextBox = _parent.HiddenTextBox;
 33  
 34              Dispatcher.UIThread.Post(() =>
 35              {
 36                  _textChangedSubscription = _hiddenTextBox.GetObservable(TextBox.TextProperty).Subscribe(TextChanged);
 37                  _selectionStartChangedSubscription = _hiddenTextBox.GetObservable(TextBox.SelectionStartProperty).Subscribe(SelectionChanged);
 38                  _selectionEndtextChangedSubscription = _hiddenTextBox.GetObservable(TextBox.SelectionEndProperty).Subscribe(SelectionChanged);
 39              });
 40          }
 41  
 42          private void TextChanged(string text)
 43          {
 44              TextChangedEvent?.Invoke(text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, false);
 45          }
 46  
 47          private void SelectionChanged(int selection)
 48          {
 49              TextChangedEvent?.Invoke(_hiddenTextBox.Text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, false);
 50          }
 51  
 52          private void AvaloniaDynamicTextInputHandler_TextInput(object sender, string text)
 53          {
 54              Dispatcher.UIThread.InvokeAsync(() =>
 55              {
 56                  if (_canProcessInput)
 57                  {
 58                      _hiddenTextBox.SendText(text);
 59                  }
 60              });
 61          }
 62  
 63          private void AvaloniaDynamicTextInputHandler_KeyRelease(object sender, KeyEventArgs e)
 64          {
 65              var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);
 66  
 67              if (!(KeyReleasedEvent?.Invoke(key)).GetValueOrDefault(true))
 68              {
 69                  return;
 70              }
 71  
 72              e.RoutedEvent = OffscreenTextBox.GetKeyUpRoutedEvent();
 73  
 74              Dispatcher.UIThread.InvokeAsync(() =>
 75              {
 76                  if (_canProcessInput)
 77                  {
 78                      _hiddenTextBox.SendKeyUpEvent(e);
 79                  }
 80              });
 81          }
 82  
 83          private void AvaloniaDynamicTextInputHandler_KeyPressed(object sender, KeyEventArgs e)
 84          {
 85              var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);
 86  
 87              if (!(KeyPressedEvent?.Invoke(key)).GetValueOrDefault(true))
 88              {
 89                  return;
 90              }
 91  
 92              e.RoutedEvent = OffscreenTextBox.GetKeyUpRoutedEvent();
 93  
 94              Dispatcher.UIThread.InvokeAsync(() =>
 95              {
 96                  if (_canProcessInput)
 97                  {
 98                      _hiddenTextBox.SendKeyDownEvent(e);
 99                  }
100              });
101          }
102  
103          public bool TextProcessingEnabled
104          {
105              get
106              {
107                  return Volatile.Read(ref _canProcessInput);
108              }
109              set
110              {
111                  Volatile.Write(ref _canProcessInput, value);
112              }
113          }
114  
115          public event DynamicTextChangedHandler TextChangedEvent;
116          public event KeyPressedHandler KeyPressedEvent;
117          public event KeyReleasedHandler KeyReleasedEvent;
118  
119          public void Dispose()
120          {
121              (_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyPressed -= AvaloniaDynamicTextInputHandler_KeyPressed;
122              (_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyRelease -= AvaloniaDynamicTextInputHandler_KeyRelease;
123              (_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).TextInput -= AvaloniaDynamicTextInputHandler_TextInput;
124  
125              _textChangedSubscription?.Dispose();
126              _selectionStartChangedSubscription?.Dispose();
127              _selectionEndtextChangedSubscription?.Dispose();
128  
129              Dispatcher.UIThread.Post(() =>
130              {
131                  _hiddenTextBox.Clear();
132                  _parent.ViewModel.RendererHostControl.Focus();
133  
134                  _parent = null;
135              });
136          }
137  
138          public void SetText(string text, int cursorBegin)
139          {
140              Dispatcher.UIThread.Post(() =>
141              {
142                  _hiddenTextBox.Text = text;
143                  _hiddenTextBox.CaretIndex = cursorBegin;
144              });
145          }
146  
147          public void SetText(string text, int cursorBegin, int cursorEnd)
148          {
149              Dispatcher.UIThread.Post(() =>
150              {
151                  _hiddenTextBox.Text = text;
152                  _hiddenTextBox.SelectionStart = cursorBegin;
153                  _hiddenTextBox.SelectionEnd = cursorEnd;
154              });
155          }
156      }
157  }