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