122 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C#
		
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Reactive.Concurrency;
 | 
						|
using System.Reactive.Linq;
 | 
						|
using System.Reactive.Subjects;
 | 
						|
using System.Windows;
 | 
						|
 | 
						|
namespace DM_Weight.util.TabTip
 | 
						|
{
 | 
						|
    public static class TabTipAutomation
 | 
						|
    {
 | 
						|
        static TabTipAutomation()
 | 
						|
        {
 | 
						|
            if (EnvironmentEx.GetOSVersion() == OSVersion.Win7)
 | 
						|
                return;
 | 
						|
 | 
						|
            TabTip.Closed += () => TabTipClosedSubject.OnNext(true);
 | 
						|
 | 
						|
            AutomateTabTipOpen(FocusSubject.AsObservable());
 | 
						|
            AutomateTabTipClose(FocusSubject.AsObservable(), TabTipClosedSubject);
 | 
						|
 | 
						|
            AnimationHelper.ExceptionCatched += exception => ExceptionCatched?.Invoke(exception);
 | 
						|
        }
 | 
						|
 | 
						|
        private static readonly Subject<Tuple<UIElement, bool>> FocusSubject = new Subject<Tuple<UIElement, bool>>();
 | 
						|
        private static readonly Subject<bool> TabTipClosedSubject = new Subject<bool>();
 | 
						|
 | 
						|
        private static readonly List<Type> BindedUIElements = new List<Type>();
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// By default TabTip automation happens only when no keyboard is connected to device.
 | 
						|
        /// Change IgnoreHardwareKeyboard if you want to automate
 | 
						|
        /// TabTip even if keyboard is connected.
 | 
						|
        /// </summary>
 | 
						|
        public static HardwareKeyboardIgnoreOptions IgnoreHardwareKeyboard
 | 
						|
        {
 | 
						|
            get { return HardwareKeyboard.IgnoreOptions; }
 | 
						|
            set { HardwareKeyboard.IgnoreOptions = value; } 
 | 
						|
        }
 | 
						|
      
 | 
						|
        /// <summary>
 | 
						|
        /// Subscribe to this event if you want to know about exceptions (errors) in this library
 | 
						|
        /// </summary>
 | 
						|
        public static event Action<Exception> ExceptionCatched;
 | 
						|
      
 | 
						|
        /// <summary>
 | 
						|
        /// Description of keyboards to ignore if there is only one instance of given keyboard.
 | 
						|
        /// If you want to ignore some ghost keyboard, add it's description to this list
 | 
						|
        /// </summary>
 | 
						|
        public static List<string> ListOfHardwareKeyboardsToIgnoreIfSingleInstance => HardwareKeyboard.ListOfKeyboardsToIgnore;
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Description of keyboards to ignore.
 | 
						|
        /// If you want to ignore some ghost keyboard, add it's description to this list
 | 
						|
        /// </summary>
 | 
						|
        public static List<string> ListOfKeyboardsToIgnore => HardwareKeyboard.ListOfKeyboardsToIgnore;
 | 
						|
 | 
						|
        private static void AutomateTabTipClose(IObservable<Tuple<UIElement, bool>> focusObservable, Subject<bool> tabTipClosedSubject)
 | 
						|
        {
 | 
						|
            focusObservable
 | 
						|
                .ObserveOn(Scheduler.Default)
 | 
						|
                .Where(_ => IgnoreHardwareKeyboard == HardwareKeyboardIgnoreOptions.IgnoreAll || !HardwareKeyboard.IsConnectedAsync().Result)
 | 
						|
                .Throttle(TimeSpan.FromMilliseconds(100)) // Close only if no other UIElement got focus in 100 ms
 | 
						|
                .Where(tuple => tuple.Item2 == false)
 | 
						|
                .Do(_ => TabTip.Close())
 | 
						|
                .Subscribe(_ => tabTipClosedSubject.OnNext(true));
 | 
						|
 | 
						|
            tabTipClosedSubject
 | 
						|
                .Subscribe(_ => AnimationHelper.GetEverythingInToWorkAreaWithTabTipClosed());
 | 
						|
        }
 | 
						|
 | 
						|
        private static void AutomateTabTipOpen(IObservable<Tuple<UIElement, bool>> focusObservable)
 | 
						|
        {
 | 
						|
            focusObservable
 | 
						|
                .ObserveOn(Scheduler.Default)
 | 
						|
                .Where(_ => IgnoreHardwareKeyboard == HardwareKeyboardIgnoreOptions.IgnoreAll || !HardwareKeyboard.IsConnectedAsync().Result)
 | 
						|
                .Where(tuple => tuple.Item2 == true)
 | 
						|
                .Do(_ => TabTip.OpenUndockedAndStartPoolingForClosedEvent())
 | 
						|
                .Subscribe(tuple => AnimationHelper.GetUIElementInToWorkAreaWithTabTipOpened(tuple.Item1));
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Automate TabTip for given UIElement.
 | 
						|
        /// Keyboard opens on GotFocusEvent or TouchDownEvent (if focused already) 
 | 
						|
        /// and closes on LostFocusEvent.
 | 
						|
        /// </summary>
 | 
						|
        /// <typeparam name="T"></typeparam>
 | 
						|
        public static void BindTo<T>() where T : UIElement
 | 
						|
        {
 | 
						|
            if (EnvironmentEx.GetOSVersion() == OSVersion.Win7)
 | 
						|
                return;
 | 
						|
 | 
						|
            if (BindedUIElements.Contains(typeof(T)))
 | 
						|
                return;
 | 
						|
 | 
						|
            EventManager.RegisterClassHandler(
 | 
						|
                classType: typeof(T),
 | 
						|
                routedEvent: UIElement.TouchDownEvent,
 | 
						|
                handler: new RoutedEventHandler((s, e) =>
 | 
						|
                {
 | 
						|
                    if (((UIElement)s).IsFocused)
 | 
						|
                        FocusSubject.OnNext(new Tuple<UIElement, bool>((UIElement)s, true));
 | 
						|
                }),
 | 
						|
                handledEventsToo: true);
 | 
						|
 | 
						|
            EventManager.RegisterClassHandler(
 | 
						|
                classType: typeof(T), 
 | 
						|
                routedEvent: UIElement.GotFocusEvent, 
 | 
						|
                handler: new RoutedEventHandler((s, e) => FocusSubject.OnNext(new Tuple<UIElement, bool>((UIElement) s, true))), 
 | 
						|
                handledEventsToo: true);
 | 
						|
 | 
						|
            EventManager.RegisterClassHandler(
 | 
						|
                classType: typeof(T), 
 | 
						|
                routedEvent: UIElement.LostFocusEvent, 
 | 
						|
                handler: new RoutedEventHandler((s, e) => FocusSubject.OnNext(new Tuple<UIElement, bool>((UIElement) s, false))), 
 | 
						|
                handledEventsToo: true);
 | 
						|
 | 
						|
            BindedUIElements.Add(typeof(T));
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |