using System; using System.ComponentModel; using Android.Content; using Android.Runtime; using Android.Views; using Android.Views.InputMethods; using Avalonia.Android.Platform.Input; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Platform; namespace Avalonia.Android.Platform.Specific.Helpers { public class AndroidKeyboardEventsHelper : IDisposable where TView :ITopLevelImpl, IAndroidView { private TView _view; private IInputElement _lastFocusedElement; public bool HandleEvents { get; set; } public AndroidKeyboardEventsHelper(TView view) { this._view = view; HandleEvents = true; } public bool? DispatchKeyEvent(KeyEvent e, out bool callBase) { if (!HandleEvents) { callBase = true; return null; } return DispatchKeyEventInternal(e, out callBase); } private bool? DispatchKeyEventInternal(KeyEvent e, out bool callBase) { if (e.Action == KeyEventActions.Multiple) { callBase = true; return null; } var rawKeyEvent = new RawKeyEventArgs( AndroidKeyboardDevice.Instance, Convert.ToUInt32(e.EventTime), e.Action == KeyEventActions.Down ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, AndroidKeyboardDevice.ConvertKey(e.KeyCode), GetModifierKeys(e)); _view.Input(rawKeyEvent); if (e.Action == KeyEventActions.Down && e.UnicodeChar >= 32) { var rawTextEvent = new RawTextInputEventArgs( AndroidKeyboardDevice.Instance, Convert.ToUInt32(e.EventTime), Convert.ToChar(e.UnicodeChar).ToString() ); _view.Input(rawTextEvent); } if (e.Action == KeyEventActions.Up) { //nothing to do here more call base no need of more events callBase = true; return null; } callBase = false; return false; } private static InputModifiers GetModifierKeys(KeyEvent e) { var rv = InputModifiers.None; if (e.IsCtrlPressed) rv |= InputModifiers.Control; if (e.IsShiftPressed) rv |= InputModifiers.Shift; return rv; } private bool NeedsKeyboard(IInputElement element) { //may be some other elements return element is TextBox; } private void TryShowHideKeyboard(IInputElement element, bool value) { var input = _view.View.Context.GetSystemService(Context.InputMethodService).JavaCast(); if (value) { //show keyboard //may be in the future different keyboards support e.g. normal, only digits etc. //Android.Text.InputTypes input.ToggleSoftInput(ShowFlags.Forced, HideSoftInputFlags.ImplicitOnly); } else { //hide keyboard input.HideSoftInputFromWindow(_view.View.WindowToken, HideSoftInputFlags.None); } } public void UpdateKeyboardState(IInputElement element) { var focusedElement = element; bool oldValue = NeedsKeyboard(_lastFocusedElement); bool newValue = NeedsKeyboard(focusedElement); if (newValue != oldValue || newValue) { TryShowHideKeyboard(focusedElement, newValue); } _lastFocusedElement = element; } public void ActivateAutoShowKeyboard() { var kbDevice = (KeyboardDevice.Instance as INotifyPropertyChanged); //just in case we've called more than once the method kbDevice.PropertyChanged -= KeyboardDevice_PropertyChanged; kbDevice.PropertyChanged += KeyboardDevice_PropertyChanged; } private void KeyboardDevice_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(KeyboardDevice.FocusedElement)) { UpdateKeyboardState(KeyboardDevice.Instance.FocusedElement); } } public void Dispose() { HandleEvents = false; } } }