| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- using System;
- using System.ComponentModel;
- using System.Linq;
- using Avalonia.Controls;
- using Avalonia.Input;
- using Avalonia.Input.Raw;
- using Avalonia.Platform;
- using ObjCRuntime;
- using UIKit;
- namespace Avalonia.iOS.Specific
- {
- /// <summary>
- /// In order to have properly handle of keyboard event in iOS View should already made some things in the View:
- /// 1. Adopt the UIKeyInput protocol - add [Adopts("UIKeyInput")] to your view class
- /// 2. Implement all the methods required by UIKeyInput:
- /// 2.1 Implement HasText
- /// example:
- /// [Export("hasText")]
- /// bool HasText => _keyboardHelper.HasText()
- /// 2.2 Implement InsertText
- /// example:
- /// [Export("insertText:")]
- /// void InsertText(string text) => _keyboardHelper.InsertText(text);
- /// 2.3 Implement InsertText
- /// example:
- /// [Export("deleteBackward")]
- /// void DeleteBackward() => _keyboardHelper.DeleteBackward();
- /// 3.Let iOS know that this can become a first responder:
- /// public override bool CanBecomeFirstResponder => _keyboardHelper.CanBecomeFirstResponder();
- /// or
- /// public override bool CanBecomeFirstResponder { get { return true; } }
- ///
- /// 4. To show keyboard:
- /// view.BecomeFirstResponder();
- /// 5. To hide keyboard
- /// view.ResignFirstResponder();
- /// </summary>
- /// <typeparam name="TView">View that needs keyboard events and show/hide keyboard</typeparam>
- internal class KeyboardEventsHelper<TView> where TView : UIView, ITopLevelImpl
- {
- private TView _view;
- private IInputElement _lastFocusedElement;
- public KeyboardEventsHelper(TView view)
- {
- _view = view;
- var uiKeyInputAttribute = view.GetType().GetCustomAttributes(typeof(AdoptsAttribute), true).OfType<AdoptsAttribute>().Where(a => a.ProtocolType == "UIKeyInput").FirstOrDefault();
- if (uiKeyInputAttribute == null) throw new NotSupportedException($"View class {typeof(TView).Name} should have class attribute - [Adopts(\"UIKeyInput\")] in order to access keyboard events!");
- HandleEvents = true;
- }
- /// <summary>
- /// HandleEvents in order to suspend keyboard notifications or resume it
- /// </summary>
- public bool HandleEvents { get; set; }
- public bool HasText() => false;
- public bool CanBecomeFirstResponder() => true;
- public void DeleteBackward()
- {
- HandleKey(Key.Back, RawKeyEventType.KeyDown);
- HandleKey(Key.Back, RawKeyEventType.KeyUp);
- }
- public void InsertText(string text)
- {
- var rawTextEvent = new RawTextInputEventArgs(KeyboardDevice.Instance, (uint)DateTime.Now.Ticks, text);
- _view.Input(rawTextEvent);
- }
- private void HandleKey(Key key, RawKeyEventType type)
- {
- var rawKeyEvent = new RawKeyEventArgs(KeyboardDevice.Instance, (uint)DateTime.Now.Ticks, type, key, RawInputModifiers.None);
- _view.Input(rawKeyEvent);
- }
- //currently not found a way to get InputModifiers state
- //private static InputModifiers GetModifierKeys(object e)
- //{
- // var im = InputModifiers.None;
- // //if (IsCtrlPressed) rv |= InputModifiers.Control;
- // //if (IsShiftPressed) rv |= InputModifiers.Shift;
- // return im;
- //}
- private bool NeedsKeyboard(IInputElement element)
- {
- //may be some other elements
- return element is TextBox;
- }
- private void TryShowHideKeyboard(IInputElement element, bool value)
- {
- if (value)
- {
- _view.BecomeFirstResponder();
- }
- else
- {
- _view.ResignFirstResponder();
- }
- }
- 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;
- }
- }
- }
|