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 }