aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Touch/Keyboard/KeyboardView.cs
blob: 3f9106089a282c138dc10a002a000fec5af1f36d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78<
<mahapps:MetroWindow x:Class="Tango.RemoteRunner.UI.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls"
        xmlns:local="clr-namespace:Tango.RemoteRunner.UI"
        mc:Ignorable="d"
        Title="Tango Remote Process Runner" Height="500" Width="800" ResizeMode="NoResize" TitlebarHeight="40" TitleCaps="False" BorderBrush="Gray" BorderThickness="1" WindowStartupLocation="CenterScreen" Background="#202020" Foreground="Gainsboro" DataContext="{StaticResource MainWindowVM}" d:DataContext="{d:DesignInstance Type=local:MainWindowVM, IsDesignTimeCreatable=False}">

    <mahapps:MetroWindow.TitleTemplate>
        <DataTemplate>
            <TextBlock Foreground="Gray" Text="{Binding}" VerticalAlignment="Center"></TextBlock>
        </DataTemplate>
    </mahapps:MetroWindow.TitleTemplate>
    <mahapps:MetroWindow.IconTemplate>
        <DataTemplate>
            <Image Source="/process.ico" Width="16" Height="16"></Image>
        </DataTemplate>
    </mahapps:MetroWindow.IconTemplate>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="80"/>
        </Grid.RowDefinitions>

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="456*"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="329*"/>
            </Grid.ColumnDefinitions>

            <GridSplitter Grid.Column="1" Width="5" Background="#383838" HorizontalAlignment="Center" VerticalAlignment="Stretch" />
            <Rectangle VerticalAlignment="Bottom" Stroke="#383838" StrokeThickness="5" Grid.ColumnSpan="3" />

            <DockPanel Margin="20">
                <TextBlock DockPanel.Dock="Top">Running Processes</TextBlock>
                <DataGrid Margin="0 10 0 0" CanUserAddRows="False" RowHeight="40" CanUserDeleteRows="False" CanUserReorderColumns="False" ItemsSource="{Binding RunningProcesses}" AutoGenerateColumns="False">
                    <DataGrid.Columns>
                        <DataGridTemplateColumn Width="40">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Image Source="/Images/cogwheel.png" Width="24" />
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                        
                        <DataGridTextColumn Header="ID" Binding="{Binding ProcessID}" />
                        <DataGridTextColumn Header="Name" Width="1*" Binding="{Binding ProcessName}" />

                        <DataGridTemplateColumn>
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Button Width="70">Kill</Button>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                    </DataGrid.Columns>
                </DataGrid>
            </DockPanel>

            <Grid Grid.Column="2">
                <DockPanel Margin="20">
                    <TextBlock DockPanel.Dock="Top">Log</TextBlock>
                    <TextBox Text="{Binding Log,Mode=OneWay}" IsReadO
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
{
    /// <summary>
    /// Interaction logic for KeyboardView.xaml
    /// </summary>
    [ContentProperty(nameof(View))]
    public partial class KeyboardView : Control
    {
        public event EventHandler KeyboardOpened;
        public event EventHandler KeyboardClosed;
        private static KeyboardView _instance;
        private List<Object> _has_focus_objects = new List<object>();

        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));

        /// <summary>
        /// Mode changed.
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void ModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            RegisterElement(d as FrameworkElement);
        }

        /// <summary>
        /// Sets the Mode attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public static void SetMode(FrameworkElement element, TouchKeyboardMode? value)
        {
            element.SetValue(ModeProperty, value);
        }

        /// <summary>
        /// Gets the Mode attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        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<LightTouchScrollViewer>().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));

        /// <summary>
        /// Sets the Container attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public static void SetContainer(FrameworkElement element, FrameworkElement value)
        {
            element.SetValue(ContainerProperty, value);
        }

        /// <summary>
        /// Gets the Container attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        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));

        /// <summary>
        /// Sets the Action attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public static void SetAction(FrameworkElement element, KeyboardActionKeyMode value)
        {
            element.SetValue(ActionProperty, value);
        }

        /// <summary>
        /// Gets the Action attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        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));

        /// <summary>
        /// Sets the ContainerOffset attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public static void SetContainerOffset(FrameworkElement element, double value)
        {
            element.SetValue(ContainerOffsetProperty, value);
        }

        /// <summary>
        /// Gets the ContainerOffset attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static double GetContainerOffset(FrameworkElement element)
        {
            return (double)element.GetValue(ContainerOffsetProperty);
        }

        #endregion

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="KeyboardView"/> class.
        /// </summary>
        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)));
        }
    }
}