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);
///
/// Signals that TabTip was closed after it was opened
/// with a call to StartPoolingForTabTipClosedEvent method
///
internal static event Action Closed;
private static IntPtr GetTabTipWindowHandle() => FindWindow(TabTipWindowClassName, null);
internal static void OpenUndockedAndStartPoolingForClosedEvent()
{
OpenUndocked();
StartPoolingForTabTipClosedEvent();
}
///
/// Open TabTip
///
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);
}
///
/// Open TabTip in undocked state
///
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();
}
///
/// Close TabTip
///
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;
///
/// Gets TabTip Window Rectangle
///
///
[SuppressMessage("ReSharper", "ConvertIfStatementToReturnStatement")]
public static Rectangle GetTabTipRectangle()
{
if (TabTipClosed())
return new Rectangle();
return GetWouldBeTabTipRectangle();
}
private static Rectangle previousTabTipRectangle;
///
/// Gets Window Rectangle which would be occupied by TabTip if TabTip was opened.
///
///
[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);
}
}
}