using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using Forms = System.Windows.Forms; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using Tango.Core.Commands; using System.Threading; using System.Collections.ObjectModel; using System.Media; using Tango.Core.Helpers; using Tango.Core.EventArguments; using System.Windows.Controls.Primitives; using Tango.Touch.Controls; using System.Diagnostics; namespace Tango.Touch.Keyboard { public class TouchKeyboard : Control { private SoundPlayer _soundPlayer; private Thumb _jogging_thumb; private RadialGradientBrush _jogging_brush; //The system keyboard event. [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)] static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo); public const int KEYEVENTF_EXTENDEDKEY = 0x0001; //Key down flag public const int KEYEVENTF_KEYUP = 0x0002; //Key up flag public const int VK_CONTROL = 0xA3; //Control key code private double _jog_start_value; private double _last_drag_delta; private IValueControl _jog_control; static TouchKeyboard() { DefaultStyleKeyProperty.OverrideMetadata(typeof(TouchKeyboard), new FrameworkPropertyMetadata(typeof(TouchKeyboard))); } private bool _isInitialized; public event EventHandler ActionKeyPressed; public event EventHandler KeyPressed; public bool IsSpecialCharactersOn { get { return (bool)GetValue(IsSpecialCharactersOnProperty); } set { SetValue(IsSpecialCharactersOnProperty, value); } } public static readonly DependencyProperty IsSpecialCharactersOnProperty = DependencyProperty.Register("IsSpecialCharactersOn", typeof(bool), typeof(TouchKeyboard), new PropertyMetadata(false, (d, e) => (d as TouchKeyboard).OnSpecialCharactersOnChanged())); public TouchKeyboardMode Mode { get { return (TouchKeyboardMode)GetValue(ModeProperty); } set { SetValue(ModeProperty, value); } } public static readonly DependencyProperty ModeProperty = DependencyProperty.Register("Mode", typeof(TouchKeyboardMode), typeof(TouchKeyboard), new PropertyMetadata(TouchKeyboardMode.AlphaNumeric)); public KeyboardActionKeyMode ActionKeyMode { get { return (KeyboardActionKeyMode)GetValue(ActionKeyModeProperty); } set { SetValue(ActionKeyModeProperty, value); } } public static readonly DependencyProperty ActionKeyModeProperty = DependencyProperty.Register("ActionKeyMode", typeof(KeyboardActionKeyMode), typeof(TouchKeyboard), new PropertyMetadata(KeyboardActionKeyMode.Next, (d, e) => (d as TouchKeyboard).OnActionKeyModeChanged())); public String ActionKeyText { get { return (String)GetValue(ActionKeyTextProperty); } private set { SetValue(ActionKeyTextProperty, value); } } public static readonly DependencyProperty ActionKeyTextProperty = DependencyProperty.Register("ActionKeyText", typeof(String), typeof(TouchKeyboard), new PropertyMetadata(null)); public KeyboardDefinition CurrentKeyboardDefinition { get { return (KeyboardDefinition)GetValue(CurrentKeyboardDefinitionProperty); } set { SetValue(CurrentKeyboardDefinitionProperty, value); } } public static readonly DependencyProperty CurrentKeyboardDefinitionProperty = DependencyProperty.Register("CurrentKeyboardDefinition", typeof(KeyboardDefinition), typeof(TouchKeyboard), new PropertyMetadata(null)); public int CurrentKeyboardDefinitionIndex { get { return (int)GetValue(CurrentKeyboardDefinitionIndexProperty); } set { SetValue(CurrentKeyboardDefinitionIndexProperty, value); } } public static readonly DependencyProperty CurrentKeyboardDefinitionIndexProperty = DependencyProperty.Register("CurrentKeyboardDefinitionIndex", typeof(int), typeof(TouchKeyboard), new PropertyMetadata(0)); public ObservableCollection KeyboardDefinitions { get { return (ObservableCollection)GetValue(KeyboardDefinitionsProperty); } set { SetValue(KeyboardDefinitionsProperty, value); } } public static readonly DependencyProperty KeyboardDefinitionsProperty = DependencyProperty.Register("KeyboardDefinitions", typeof(ObservableCollection), typeof(TouchKeyboard), new PropertyMetadata(null)); public Size KeySize { get { return (Size)GetValue(KeySizeProperty); } set { SetValue(KeySizeProperty, value); } } public static readonly DependencyProperty KeySizeProperty = DependencyProperty.Register("KeySize", typeof(Size), typeof(TouchKeyboard), new PropertyMetadata(Size.Empty)); public double MaxSpecialKeyWidth { get { return (double)GetValue(MaxSpecialKeyWidthProperty); } set { SetValue(MaxSpecialKeyWidthProperty, value); } } public static readonly DependencyProperty MaxSpecialKeyWidthProperty = DependencyProperty.Register("MaxSpecialKeyWidth", typeof(double), typeof(TouchKeyboard), new PropertyMetadata(0.0)); public KeysLineDefinition NumbersLineDefinition { get { return (KeysLineDefinition)GetValue(NumbersLineDefinitionProperty); } set { SetValue(NumbersLineDefinitionProperty, value); } } public static readonly DependencyProperty NumbersLineDefinitionProperty = DependencyProperty.Register("NumbersLineDefinition", typeof(KeysLineDefinition), typeof(TouchKeyboard), new PropertyMetadata(null)); public Brush CharactersBackground { get { return (Brush)GetValue(CharactersBackgroundProperty); } set { SetValue(CharactersBackgroundProperty, value); } } public static readonly DependencyProperty CharactersBackgroundProperty = DependencyProperty.Register("CharactersBackground", typeof(Brush), typeof(TouchKeyboard), new PropertyMetadata(Brushes.Gainsboro)); public Brush CharactersForeground { get { return (Brush)GetValue(CharactersForegroundProperty); } set { SetValue(CharactersForegroundProperty, value); } } public static readonly DependencyProperty CharactersForegroundProperty = DependencyProperty.Register("CharactersForeground", typeof(Brush), typeof(TouchKeyboard), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(20, 20, 20)))); public Brush SpecialCharactersBackground { get { return (Brush)GetValue(SpecialCharactersBackgroundProperty); } set { SetValue(SpecialCharactersBackgroundProperty, value); } } public static readonly DependencyProperty SpecialCharactersBackgroundProperty = DependencyProperty.Register("SpecialCharactersBackground", typeof(Brush), typeof(TouchKeyboard), new PropertyMetadata(Brushes.Gray)); public Brush SpecialCharactersForeground { get { return (Brush)GetValue(SpecialCharactersForegroundProperty); } set { SetValue(SpecialCharactersForegroundProperty, value); } } public static readonly DependencyProperty SpecialCharactersForegroundProperty = DependencyProperty.Register("SpecialCharactersForeground", typeof(Brush), typeof(TouchKeyboard), new PropertyMetadata(Brushes.Gainsboro)); public double VectorMarkupSize { get { return (double)GetValue(VectorMarkupSizeProperty); } set { SetValue(VectorMarkupSizeProperty, value); } } public static readonly DependencyProperty VectorMarkupSizeProperty = DependencyProperty.Register("VectorMarkupSize", typeof(double), typeof(TouchKeyboard), new PropertyMetadata(10.0)); public double DotsSize { get { return (double)GetValue(DotsSizeProperty); } set { SetValue(DotsSizeProperty, value); } } public static readonly DependencyProperty DotsSizeProperty = DependencyProperty.Register("DotsSize", typeof(double), typeof(TouchKeyboard), new PropertyMetadata(5.0)); public double CharactersCornerRadius { get { return (double)GetValue(CharactersCornerRadiusProperty); } set { SetValue(CharactersCornerRadiusProperty, value); } } public static readonly DependencyProperty CharactersCornerRadiusProperty = DependencyProperty.Register("CharactersCornerRadius", typeof(double), typeof(TouchKeyboard), new PropertyMetadata(5.0)); public CapsLockMode CapsLockMode { get { return (CapsLockMode)GetValue(CapsLockModeProperty); } set { SetValue(CapsLockModeProperty, value); } } public static readonly DependencyProperty CapsLockModeProperty = DependencyProperty.Register("CapsLockMode", typeof(CapsLockMode), typeof(TouchKeyboard), new PropertyMetadata(CapsLockMode.None)); public bool IsCapsLockOn { get { return (bool)GetValue(IsCapsLockOnProperty); } private set { SetValue(IsCapsLockOnProperty, value); } } public static readonly DependencyProperty IsCapsLockOnProperty = DependencyProperty.Register("IsCapsLockOn", typeof(bool), typeof(TouchKeyboard), new PropertyMetadata(false)); public RelayCommand KeyDefinitionCommand { get { return (RelayCommand)GetValue(KeyDefinitionCommandProperty); } set { SetValue(KeyDefinitionCommandProperty, value); } } public static readonly DependencyProperty KeyDefinitionCommandProperty = DependencyProperty.Register("KeyDefinitionCommand", typeof(RelayCommand), typeof(TouchKeyboard), new PropertyMetadata(null)); public RelayCommand SpecialKeyDefinitionCommand { get { return (RelayCommand)GetValue(SpecialKeyDefinitionCommandProperty); } set { SetValue(SpecialKeyDefinitionCommandProperty, value); } } public static readonly DependencyProperty SpecialKeyDefinitionCommandProperty = DependencyProperty.Register("SpecialKeyDefinitionCommand", typeof(RelayCommand), typeof(TouchKeyboard), new PropertyMetadata(null)); public RelayCommand SpecialCharactersCommand { get { return (RelayCommand)GetValue(SpecialCharactersCommandProperty); } set { SetValue(SpecialCharactersCommandProperty, value); } } public static readonly DependencyProperty SpecialCharactersCommandProperty = DependencyProperty.Register("SpecialCharactersCommand", typeof(RelayCommand), typeof(TouchKeyboard), new PropertyMetadata(null)); public RelayCommand FreeTextCommand { get { return (RelayCommand)GetValue(FreeTextCommandProperty); } set { SetValue(FreeTextCommandProperty, value); } } public static readonly DependencyProperty FreeTextCommandProperty = DependencyProperty.Register("FreeTextCommand", typeof(RelayCommand), typeof(TouchKeyboard), new PropertyMetadata(null)); public RelayCommand NextLanguageCommand { get { return (RelayCommand)GetValue(NextLanguageCommandProperty); } set { SetValue(NextLanguageCommandProperty, value); } } public static readonly DependencyProperty NextLanguageCommandProperty = DependencyProperty.Register("NextLanguageCommand", typeof(RelayCommand), typeof(TouchKeyboard), new PropertyMetadata(null)); public RelayCommand ActionKeyCommand { get { return (RelayCommand)GetValue(ActionKeyCommandProperty); } set { SetValue(ActionKeyCommandProperty, value); } } public static readonly DependencyProperty ActionKeyCommandProperty = DependencyProperty.Register("ActionKeyCommand", typeof(RelayCommand), typeof(TouchKeyboard), new PropertyMetadata(null)); public RelayCommand NumericKeyCommand { get { return (RelayCommand)GetValue(NumericKeyCommandProperty); } set { SetValue(NumericKeyCommandProperty, value); } } public static readonly DependencyProperty NumericKeyCommandProperty = DependencyProperty.Register("NumericKeyCommand", typeof(RelayCommand), typeof(TouchKeyboard), new PropertyMetadata(null)); public TouchKeyboard() { KeyboardDefinitions = new ObservableCollection(); Initialize(); this.SizeChanged += (_, __) => SetKeySize(); KeyDefinitionCommand = new RelayCommand(InvokeKeyDefinition); SpecialKeyDefinitionCommand = new RelayCommand(InvokeSpecialKeyDefinition); SpecialCharactersCommand = new RelayCommand(ToggleSpecialKeys); FreeTextCommand = new RelayCommand((x) => SendKeys(x)); NextLanguageCommand = new RelayCommand(NextLanguage); ActionKeyCommand = new RelayCommand(InvokeActionKey); NumericKeyCommand = new RelayCommand((x) => SendKeys(x.ToString().Replace("'", ""))); _soundPlayer = new SoundPlayer(EmbeddedResourceHelper.GetEmbeddedResourceStream("Tango.Touch.Keyboard.keyboard-iphone.wav")); } public override void OnApplyTemplate() { base.OnApplyTemplate(); _jogging_thumb = GetTemplateChild("PART_JoggingThumb") as Thumb; _jogging_brush = GetTemplateChild("PART_Jog_Gradient") as RadialGradientBrush; _jogging_thumb.DragStarted += _jogging_thumb_DragStarted; _jogging_thumb.DragCompleted += _jogging_thumb_DragCompleted; _jogging_thumb.DragDelta += _jogging_thumb_DragDelta; RepeatButton btnUp = GetTemplateChild("PART_JogUp") as RepeatButton; RepeatButton btnDown = GetTemplateChild("PART_JogDown") as RepeatButton; btnUp.Click += BtnUp_Click; btnDown.Click += BtnDown_Click; } private void BtnDown_Click(object sender, RoutedEventArgs e) { IInputElement focusedControl = FocusManager.GetFocusedElement(Application.Current.MainWindow); if (focusedControl != null) { IValueControl control = (focusedControl as DependencyObject).FindAncestor(); if (control != null) { control.Value -= 1; } } } private void BtnUp_Click(object sender, RoutedEventArgs e) { IInputElement focusedControl = FocusManager.GetFocusedElement(Application.Current.MainWindow); if (focusedControl != null) { IValueControl control = (focusedControl as DependencyObject).FindAncestor(); if (control != null) { control.Value += 1; } } } private void _jogging_thumb_DragStarted(object sender, DragStartedEventArgs e) { IInputElement focusedControl = FocusManager.GetFocusedElement(Application.Current.MainWindow); if (focusedControl != null) { IValueControl control = (focusedControl as DependencyObject).FindAncestor(); if (control != null) { _jog_control = control; _jog_start_value = _jog_control.Value; } } } private void _jogging_thumb_DragCompleted(object sender, DragCompletedEventArgs e) { _jogging_brush.GradientOrigin = new Point(0.5, 0.5); _jog_start_value = 0; _jog_control = null; } private void _jogging_thumb_DragDelta(object sender, DragDeltaEventArgs e) { if (_jog_control != null) { double min_origin = 0.4; double max_origin = 0.6; var factor = _jog_control.Maximum / Application.Current.MainWindow.Height; if (_jog_control.AutoCalculateJogStep) { _jog_control.Value = _jog_start_value + (((-e.VerticalChange) * factor) * _jog_control.JoggingFactor); } else { _jog_control.Value = _jog_start_value + (-e.VerticalChange * _jog_control.JoggingFactor); } if (_last_drag_delta > e.VerticalChange) { _jogging_brush.GradientOrigin = new Point(0.5, _jogging_brush.GradientOrigin.Y - 0.005); if (_jogging_brush.GradientOrigin.Y < min_origin) { _jogging_brush.GradientOrigin = new Point(0.5, min_origin); } } else if (_last_drag_delta < e.VerticalChange) { _jogging_brush.GradientOrigin = new Point(0.5, _jogging_brush.GradientOrigin.Y + 0.005); if (_jogging_brush.GradientOrigin.Y > max_origin) { _jogging_brush.GradientOrigin = new Point(0.5, max_origin); } } } _last_drag_delta = e.VerticalChange; } private void Initialize() { if (!_isInitialized) { var numbers = new KeysLineDefinition(); for (int i = 1; i < 10; i++) { numbers.KeyDefinitions.Add(new KeyDefinition() { StandardText = i.ToString(), CapsText = i.ToString(), }); } numbers.KeyDefinitions.Add(new KeyDefinition() { StandardText = "0", CapsText = "0", }); NumbersLineDefinition = numbers; CurrentKeyboardDefinition = KeyboardDefinition.Default; KeyboardDefinitions.Add(CurrentKeyboardDefinition); //KeyboardDefinitions.Add(KeyboardDefinition.CreateDefaultHebrewAlphaNumeric()); SetKeySize(); OnActionKeyModeChanged(); _isInitialized = true; } } private void SetKeySize() { KeySize = new Size(ActualWidth / NumbersLineDefinition.KeyDefinitions.Count, (ActualWidth / NumbersLineDefinition.KeyDefinitions.Count) * 0.90); MaxSpecialKeyWidth = KeySize.Width * 2; } private void InvokeKeyDefinition(KeyDefinition key) { if (IsCapsLockOn) { SendKeys(key.CapsText); } else { //UIAutomationHelper.GetActiveWindow(); //IInputElement focusedControl = FocusManager.GetFocusedElement(this); SendKeys(key.StandardText); } } private void InvokeSpecialKeyDefinition(SpecialKeyDefinition key) { switch (key.Type) { case SpecialKeyType.StandardText: SendKeys(key.Output); break; case SpecialKeyType.CapsLock: if (CapsLockMode == CapsLockMode.None) { CapsLockMode = CapsLockMode.SingleChar; } else if (CapsLockMode == CapsLockMode.SingleChar) { CapsLockMode = CapsLockMode.Locked; } else { CapsLockMode = CapsLockMode.None; } IsCapsLockOn = CapsLockMode != CapsLockMode.None; break; } } private void SendKeys(String key) { //Application.Current.MainWindow.Activate(); var isSpecialChar = IsSpecialCharactersOn; var definition = CurrentKeyboardDefinition; if (CapsLockMode == CapsLockMode.SingleChar) { CapsLockMode = CapsLockMode.None; IsCapsLockOn = false; } if (key.Length > 1 || (isSpecialChar && definition.KeysLinesDefinitions.SelectMany(x => x.KeyDefinitions).Select(x => x.StandardText).Contains(key))) { Core.Threading.ThreadFactory.StartNew(() => { if (key.Contains("{")) { Forms.SendKeys.SendWait(key); } else { Forms.SendKeys.SendWait("{" + key + "}"); } Forms.SendKeys.Flush(); }); } else { //Forms.SendKeys.SendWait(key); var text = key; var target = FocusManager.GetFocusedElement(Application.Current.MainWindow) as UIElement; Key k = Key.None; Enum.TryParse(key, out k); RaiseKeyUp(target, k); var routedEvent = TextCompositionManager.TextInputEvent; target.RaiseEvent(new TextCompositionEventArgs(InputManager.Current.PrimaryKeyboardDevice, new TextComposition(InputManager.Current, target, text)) { RoutedEvent = routedEvent } ); } _soundPlayer.Play(); } private void RaiseKeyDown(UIElement target, Key key) { target.RaiseEvent( new KeyEventArgs( System.Windows.Input.Keyboard.PrimaryDevice, PresentationSource.FromVisual(target), 0, key) { RoutedEvent = System.Windows.Input.Keyboard.PreviewKeyDownEvent }); target.RaiseEvent( new KeyEventArgs( System.Windows.Input.Keyboard.PrimaryDevice, PresentationSource.FromVisual(target), 0, key) { RoutedEvent = System.Windows.Input.Keyboard.KeyDownEvent }); } private void RaiseKeyUp(UIElement target, Key key) { target.RaiseEvent( new KeyEventArgs( System.Windows.Input.Keyboard.PrimaryDevice, PresentationSource.FromVisual(target), 0, key) { RoutedEvent = System.Windows.Input.Keyboard.PreviewKeyUpEvent }); target.RaiseEvent( new KeyEventArgs( System.Windows.Input.Keyboard.PrimaryDevice, PresentationSource.FromVisual(target), 0, key) { RoutedEvent = System.Windows.Input.Keyboard.KeyUpEvent } ); } public static void PressCtrl() { keybd_event(VK_CONTROL, 0, KEYEVENTF_EXTENDEDKEY, 0); } public static void ReleaseCtrl() { keybd_event(VK_CONTROL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); } private void OnSpecialCharactersOnChanged() { if (!IsSpecialCharactersOn) { CurrentKeyboardDefinition = KeyboardDefinitions[CurrentKeyboardDefinitionIndex]; } else { KeyboardDefinition definition = new KeyboardDefinition(); definition.EnterText = CurrentKeyboardDefinition.EnterText; definition.KeysLinesDefinitions = KeyboardDefinition.CreateDefaultSpecialCharacters(); CurrentKeyboardDefinition = definition; } } private void ToggleSpecialKeys() { IsSpecialCharactersOn = !IsSpecialCharactersOn; } private void NextLanguage() { IsCapsLockOn = false; CurrentKeyboardDefinitionIndex++; if (CurrentKeyboardDefinitionIndex > KeyboardDefinitions.Count - 1) { CurrentKeyboardDefinitionIndex = 0; } CurrentKeyboardDefinition = KeyboardDefinitions[CurrentKeyboardDefinitionIndex]; OnActionKeyModeChanged(); } private void OnActionKeyModeChanged() { switch (ActionKeyMode) { case KeyboardActionKeyMode.Go: ActionKeyText = CurrentKeyboardDefinition.EnterText; break; case KeyboardActionKeyMode.Return: ActionKeyText = "↵"; break; case KeyboardActionKeyMode.Next: ActionKeyText = CurrentKeyboardDefinition.TabText; break; case KeyboardActionKeyMode.Search: ActionKeyText = "Search"; // TODO: Make trigger in view and vector path. break; } } private void InvokeActionKey() { switch (ActionKeyMode) { case KeyboardActionKeyMode.Search: case KeyboardActionKeyMode.Return: case KeyboardActionKeyMode.Go: SendKeys("{ENTER}"); break; case KeyboardActionKeyMode.Next: SendKeys("{TAB}"); break; } ActionKeyPressed?.Invoke(this, ActionKeyMode); } } }