using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Tango.Core.EventArguments;
using Tango.Touch.Controls;
namespace Tango.Touch.Keyboard
{
///
/// Interaction logic for KeyboardView.xaml
///
[ContentProperty(nameof(View))]
public partial class KeyboardView : Control
{
public event EventHandler KeyboardOpened;
public event EventHandler KeyboardClosed;
private static KeyboardView _instance;
private List _has_focus_objects = new List();
private TouchKeyboard keyboard;
private Grid gridContent;
private ContentPresenter _content_presenter;
private FrameworkElement _lastFocusedElement;
private DateTime _lastFocusTime = DateTime.Now;
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(int hwnd);
[DllImport("user32.dll")]
private static extern int GetDesktopWindow();
#region Properties
public static KeyboardView Default
{
get { return _instance; }
}
public static TouchKeyboard Keyboard
{
get
{
return Default.keyboard;
}
}
public bool IsOpened
{
get { return (bool)GetValue(IsOpenedProperty); }
set { SetValue(IsOpenedProperty, value); }
}
public static readonly DependencyProperty IsOpenedProperty =
DependencyProperty.Register("IsOpened", typeof(bool), typeof(KeyboardView), new PropertyMetadata(false, (d, e) => (d as KeyboardView).IsOpenedChanged()));
public FrameworkElement View
{
get { return (FrameworkElement)GetValue(ViewProperty); }
set { SetValue(ViewProperty, value); }
}
public static readonly DependencyProperty ViewProperty =
DependencyProperty.Register("View", typeof(FrameworkElement), typeof(KeyboardView), new PropertyMetadata(null));
public KeyboardOutputMode OutputMode
{
get { return (KeyboardOutputMode)GetValue(OutputModeProperty); }
set { SetValue(OutputModeProperty, value); }
}
public static readonly DependencyProperty OutputModeProperty =
DependencyProperty.Register("OutputMode", typeof(KeyboardOutputMode), typeof(KeyboardView), new PropertyMetadata(KeyboardOutputMode.Wpf));
#endregion
#region Attached Properties
#region Mode
public static readonly DependencyProperty ModeProperty =
DependencyProperty.RegisterAttached("Mode",
typeof(TouchKeyboardMode?), typeof(KeyboardView),
new FrameworkPropertyMetadata(null, ModeChanged));
///
/// Mode changed.
///
/// The d.
/// The instance containing the event data.
private static void ModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
RegisterElement(d as FrameworkElement);
}
///
/// Sets the Mode attached property.
///
/// The element.
/// if set to true [value].
public static void SetMode(FrameworkElement element, TouchKeyboardMode? value)
{
element.SetValue(ModeProperty, value);
}
///
/// Gets the Mode attached property.
///
/// The element.
///
public static TouchKeyboardMode? GetMode(FrameworkElement element)
{
return (TouchKeyboardMode?)element.GetValue(ModeProperty);
}
private static void RegisterElement(FrameworkElement element)
{
element.GotFocus -= Element_GotFocus;
element.LostFocus -= Element_LostFocus;
element.GotFocus += Element_GotFocus;
element.LostFocus += Element_LostFocus;
}
private void IsOpenedChanged()
{
if (!IsOpened)
{
if (OutputMode == KeyboardOutputMode.Wpf)
{
if (GetContainer(_lastFocusedElement) != null)
{
var scrollViewers = this.FindVisualChildren().ToList();
scrollViewers.ForEach(x => x.DisableScrolling = true);
ThicknessAnimation ani = new ThicknessAnimation();
ani.Completed += (_, __) =>
{
scrollViewers.ForEach(x => x.DisableScrolling = false);
};
ani.To = new Thickness(0);
ani.Duration = TimeSpan.FromSeconds(0.2);
GetContainer(_lastFocusedElement).BeginAnimation(FrameworkElement.MarginProperty, ani);
}
}
KeyboardClosed?.Invoke(this, new EventArgs());
}
else
{
KeyboardOpened?.Invoke(this, new EventArgs());
}
}
private static async void Element_LostFocus(object sender, RoutedEventArgs e)
{
if (_instance == null) return;
FrameworkElement element = sender as FrameworkElement;
DateTime _last = _instance._lastFocusTime;
await Task.Delay(300);
if (_last == _instance._lastFocusTime)
{
_instance.IsOpened = false;
}
}
private async static void Element_GotFocus(object sender, RoutedEventArgs e)
{
if (_instance == null) return;
var element = sender as FrameworkElement;
IInputElement focusedControl = FocusManager.GetFocusedElement(Application.Current.MainWindow);
_instance._lastFocusTime = DateTime.Now;
_instance._lastFocusedElement = element;
_instance.keyboard.ActionKeyMode = GetAction(element);
_instance.keyboard.Mode = GetMode(element).Value;
_instance.keyboard.IsSpecialCharactersOn = false;
if (!_instance.IsOpened)
{
_instance.IsOpened = true;
await Task.Delay(200);
}
if (!_instance._has_focus_objects.Contains(element))
{
SetForegroundWindow(GetDesktopWindow());
Application.Current.MainWindow.Activate();
_instance._has_focus_objects.Add(element);
}
FrameworkElement container = GetContainer(element);
if (container != null)
{
double viewPort = _instance.ActualHeight - _instance.keyboard.ActualHeight;
double centerViewPort = viewPort / 2;
Point relativeLocation = element.TranslatePoint(new Point(0, 0), _instance.gridContent);
double y = relativeLocation.Y + -container.Margin.Top;
if (relativeLocation.Y + element.ActualHeight + 10 > viewPort || relativeLocation.Y < 0)
{
var offset = GetContainerOffset(container);
double requiredMargin = ((y + (element.ActualHeight / 2)) - centerViewPort) + -offset;
ThicknessAnimation ani = new ThicknessAnimation();
ani.To = new Thickness(0, -requiredMargin, 0, 0);
ani.Duration = TimeSpan.FromSeconds(0.2);
container.BeginAnimation(FrameworkElement.MarginProperty, ani);
}
}
}
#endregion
#region Container
public static readonly DependencyProperty ContainerProperty =
DependencyProperty.RegisterAttached("Container",
typeof(FrameworkElement), typeof(KeyboardView),
new FrameworkPropertyMetadata(null));
///
/// Sets the Container attached property.
///
/// The element.
/// if set to true [value].
public static void SetContainer(FrameworkElement element, FrameworkElement value)
{
element.SetValue(ContainerProperty, value);
}
///
/// Gets the Container attached property.
///
/// The element.
///
public static FrameworkElement GetContainer(FrameworkElement element)
{
return (FrameworkElement)element.GetValue(ContainerProperty);
}
#endregion
#region Action
public static readonly DependencyProperty ActionProperty =
DependencyProperty.RegisterAttached("Action",
typeof(KeyboardActionKeyMode), typeof(KeyboardView),
new FrameworkPropertyMetadata(KeyboardActionKeyMode.Next));
///
/// Sets the Action attached property.
///
/// The element.
/// if set to true [value].
public static void SetAction(FrameworkElement element, KeyboardActionKeyMode value)
{
element.SetValue(ActionProperty, value);
}
///
/// Gets the Action attached property.
///
/// The element.
///
public static KeyboardActionKeyMode GetAction(FrameworkElement element)
{
return (KeyboardActionKeyMode)element.GetValue(ActionProperty);
}
#endregion
#region Container Offset
public static readonly DependencyProperty ContainerOffsetProperty =
DependencyProperty.RegisterAttached("ContainerOffset",
typeof(double), typeof(KeyboardView),
new FrameworkPropertyMetadata(0.0));
///
/// Sets the ContainerOffset attached property.
///
/// The element.
/// if set to true [value].
public static void SetContainerOffset(FrameworkElement element, double value)
{
element.SetValue(ContainerOffsetProperty, value);
}
///
/// Gets the ContainerOffset attached property.
///
/// The element.
///
public static double GetContainerOffset(FrameworkElement element)
{
return (double)element.GetValue(ContainerOffsetProperty);
}
#endregion
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
public KeyboardView()
{
_instance = this;
}
#endregion
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
keyboard = GetTemplateChild("PART_Keyboard") as TouchKeyboard;
gridContent = GetTemplateChild("PART_GridContent") as Grid;
_content_presenter = GetTemplateChild("PART_ContentPresenter") as ContentPresenter;
keyboard.ActionKeyPressed += OnActionKeyPressed;
gridContent.RegisterForMouseOrTouchDown(OnMouseDown);
}
private void OnMouseDown(object sender, MouseOrTouchEventArgs e)
{
if (e.OriginalSource.GetType().Name != "TextBoxView" && e.Source == _content_presenter && IsOpened && OutputMode == KeyboardOutputMode.Wpf)
{
IsOpened = false;
}
}
private void OnActionKeyPressed(object sender, KeyboardActionKeyMode mode)
{
if (mode == KeyboardActionKeyMode.Go || mode == KeyboardActionKeyMode.Search)
{
IsOpened = false;
}
}
static KeyboardView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(KeyboardView), new FrameworkPropertyMetadata(typeof(KeyboardView)));
}
}
}