167 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C#
		
	
	
	
using System;
 | 
						||
using System.Diagnostics;
 | 
						||
using System.Diagnostics.CodeAnalysis;
 | 
						||
using System.Drawing;
 | 
						||
using System.Runtime.InteropServices;
 | 
						||
using System.Threading.Tasks;
 | 
						||
using Microsoft.Win32;
 | 
						||
 | 
						||
namespace DM_Weight.util.TabTip
 | 
						||
{
 | 
						||
    public static class TabTip
 | 
						||
    {
 | 
						||
        private const string TabTipWindowClassName = "IPTip_Main_Window";
 | 
						||
        private const string TabTipExecPath = @"C:\Program Files\Common Files\microsoft shared\ink\TabTip.exe";
 | 
						||
        private const string TabTipRegistryKeyName = @"HKEY_CURRENT_USER\Software\Microsoft\TabletTip\1.7";
 | 
						||
 | 
						||
        [DllImport("user32.dll")]
 | 
						||
        private static extern int SendMessage(int hWnd, uint msg, int wParam, int lParam);
 | 
						||
 | 
						||
        [DllImport("user32.dll")]
 | 
						||
        private static extern IntPtr FindWindow(String sClassName, String sAppName);
 | 
						||
 | 
						||
        [DllImport("user32.dll")]
 | 
						||
        [return: MarshalAs(UnmanagedType.Bool)]
 | 
						||
        private static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);
 | 
						||
 | 
						||
        [StructLayout(LayoutKind.Sequential)]
 | 
						||
        private struct RECT
 | 
						||
        {
 | 
						||
            public readonly int Left;        // x position of upper-left corner
 | 
						||
            public readonly int Top;         // y position of upper-left corner
 | 
						||
            public readonly int Right;       // x position of lower-right corner
 | 
						||
            public readonly int Bottom;      // y position of lower-right corner
 | 
						||
        }
 | 
						||
 | 
						||
        [DllImport("user32.dll", SetLastError = true)]
 | 
						||
        private static extern UInt32 GetWindowLong(IntPtr hWnd, int nIndex);
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// Signals that TabTip was closed after it was opened 
 | 
						||
        /// with a call to StartPoolingForTabTipClosedEvent method
 | 
						||
        /// </summary>
 | 
						||
        internal static event Action Closed;
 | 
						||
 | 
						||
        private static IntPtr GetTabTipWindowHandle() => FindWindow(TabTipWindowClassName, null);
 | 
						||
        
 | 
						||
        internal static void OpenUndockedAndStartPoolingForClosedEvent()
 | 
						||
        {
 | 
						||
            OpenUndocked();
 | 
						||
            StartPoolingForTabTipClosedEvent();
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// Open TabTip
 | 
						||
        /// </summary>
 | 
						||
        public static void Open()
 | 
						||
        {
 | 
						||
            if (EnvironmentEx.GetOSVersion() == OSVersion.Win10)
 | 
						||
                EnableTabTipOpenInDesctopModeOnWin10();
 | 
						||
 | 
						||
            Process.Start(new ProcessStartInfo(TabTipExecPath) { UseShellExecute = true});
 | 
						||
        }
 | 
						||
 | 
						||
        private static void EnableTabTipOpenInDesctopModeOnWin10()
 | 
						||
        {
 | 
						||
            const string TabTipAutoInvokeKey = "EnableDesktopModeAutoInvoke";
 | 
						||
 | 
						||
            int EnableDesktopModeAutoInvoke = (int) (Registry.GetValue(TabTipRegistryKeyName, TabTipAutoInvokeKey, -1) ?? -1);
 | 
						||
            if (EnableDesktopModeAutoInvoke != 1)
 | 
						||
                Registry.SetValue(TabTipRegistryKeyName, TabTipAutoInvokeKey, 1);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// Open TabTip in undocked state
 | 
						||
        /// </summary>
 | 
						||
        public static void OpenUndocked()
 | 
						||
        {
 | 
						||
            const string TabTipDockedKey = "EdgeTargetDockedState";
 | 
						||
            const string TabTipProcessName = "TabTip";
 | 
						||
 | 
						||
            int docked = (int) (Registry.GetValue(TabTipRegistryKeyName, TabTipDockedKey, 1) ?? 1);
 | 
						||
            if (docked == 1)
 | 
						||
            {
 | 
						||
                Registry.SetValue(TabTipRegistryKeyName, TabTipDockedKey, 0);
 | 
						||
                foreach (Process tabTipProcess in Process.GetProcessesByName(TabTipProcessName))
 | 
						||
                    tabTipProcess.Kill();
 | 
						||
            }
 | 
						||
            Open();
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// Close TabTip
 | 
						||
        /// </summary>
 | 
						||
        public static void Close()
 | 
						||
        {
 | 
						||
            const int WM_SYSCOMMAND = 274;
 | 
						||
            const int SC_CLOSE = 61536;
 | 
						||
            SendMessage(GetTabTipWindowHandle().ToInt32(), WM_SYSCOMMAND, SC_CLOSE, 0);
 | 
						||
        }
 | 
						||
 | 
						||
        private static void StartPoolingForTabTipClosedEvent()
 | 
						||
        {
 | 
						||
            PoolingTimer.PoolUntilTrue(
 | 
						||
                PoolingFunc: TabTipClosed,
 | 
						||
                Callback: () => Closed?.Invoke(),
 | 
						||
                dueTime: TimeSpan.FromMilliseconds(700),
 | 
						||
                period: TimeSpan.FromMilliseconds(50));
 | 
						||
        }
 | 
						||
 | 
						||
        private static bool TabTipClosed()
 | 
						||
        {
 | 
						||
            const int GWL_STYLE = -16; // Specifies we wish to retrieve window styles.
 | 
						||
            const uint KeyboardClosedStyle = 2617245696;
 | 
						||
            IntPtr KeyboardWnd = GetTabTipWindowHandle();
 | 
						||
            return (KeyboardWnd.ToInt32() == 0 || GetWindowLong(KeyboardWnd, GWL_STYLE) == KeyboardClosedStyle);
 | 
						||
        }
 | 
						||
 | 
						||
        // ReSharper disable once UnusedMember.Local
 | 
						||
        private static bool IsTabTipProcessRunning => GetTabTipWindowHandle() != IntPtr.Zero;
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// Gets TabTip Window Rectangle
 | 
						||
        /// </summary>
 | 
						||
        /// <returns></returns>
 | 
						||
        [SuppressMessage("ReSharper", "ConvertIfStatementToReturnStatement")]
 | 
						||
        public static Rectangle GetTabTipRectangle()
 | 
						||
        {
 | 
						||
            if (TabTipClosed())
 | 
						||
                return new Rectangle();
 | 
						||
 | 
						||
            return GetWouldBeTabTipRectangle();
 | 
						||
        }
 | 
						||
 | 
						||
        private static Rectangle previousTabTipRectangle;
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// Gets Window Rectangle which would be occupied by TabTip if TabTip was opened.
 | 
						||
        /// </summary>
 | 
						||
        /// <returns></returns>
 | 
						||
        [SuppressMessage("ReSharper", "ConvertIfStatementToReturnStatement")]
 | 
						||
        internal static Rectangle GetWouldBeTabTipRectangle()
 | 
						||
        {
 | 
						||
            RECT rect;
 | 
						||
 | 
						||
            if (!GetWindowRect(new HandleRef(null, GetTabTipWindowHandle()), out rect))
 | 
						||
            {
 | 
						||
                if (previousTabTipRectangle.Equals(new Rectangle())) //in case TabTip was closed and previousTabTipRectangle was not set
 | 
						||
                    Task.Delay(TimeSpan.FromSeconds(1)).ContinueWith(TryGetTabTipRectangleToСache);
 | 
						||
 | 
						||
                return previousTabTipRectangle;
 | 
						||
            }
 | 
						||
 | 
						||
            Rectangle wouldBeTabTipRectangle = new Rectangle(x: rect.Left, y: rect.Top, width: rect.Right - rect.Left + 1, height: rect.Bottom - rect.Top + 1);
 | 
						||
            previousTabTipRectangle = wouldBeTabTipRectangle;
 | 
						||
 | 
						||
            return wouldBeTabTipRectangle;
 | 
						||
        }
 | 
						||
 | 
						||
        private static void TryGetTabTipRectangleToСache(Task task)
 | 
						||
        {
 | 
						||
            RECT rect;
 | 
						||
            if (GetWindowRect(new HandleRef(null, GetTabTipWindowHandle()), out rect))
 | 
						||
                previousTabTipRectangle = new Rectangle(x: rect.Left, y: rect.Top, width: rect.Right - rect.Left + 1, height: rect.Bottom - rect.Top + 1);
 | 
						||
        }
 | 
						||
    }
 | 
						||
}
 |