HKC_Blazor/MasaBlazorApp3/Util/VirtualKeyboardHelper.cs

343 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Management;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
namespace MasaBlazorApp3.Util
{
public class VirtualKeyboardHelper
{
private const uint WS_VISIBLE = 0x10000000;
private const int GWL_STYLE = -16;
private const int WM_SYSCOMMAND = 0x0112;
private const uint SC_CLOSE = 0xF060;
private const int WS_DISABLED = 0x08000000;
private const int DWMWA_CLOAKED = 14;
private const string ApplicationFrameHostClassName = "ApplicationFrameWindow";
private const string CoreWindowClassName = "Windows.UI.Core.CoreWindow";
private const string TextInputApplicationCaption = "Microsoft Text Input Application";
/// <summary>
/// win10 虚拟键盘路径
/// </summary>
private const string Win10TabTipPath = @"C:\Program Files\Common Files\microsoft shared\ink\TabTip.exe";
/// <summary>
/// win7 虚拟键盘路径
/// </summary>
private const string Win7OskPath = @"C:\WINDOWS\system32\osk.exe";
/// <summary>
/// 虚拟键盘 窗口名称
/// </summary>
private const string TabTipWindowClassName = "IPTIP_Main_Window";
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass,
string lpszWindow);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool PostMessage(IntPtr hWnd, int msg, uint wParam, uint lParam);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);
[DllImport("user32.dll", EntryPoint = "GetDesktopWindow", SetLastError = false)]
private static extern IntPtr GetDesktopWindow();
[DllImport("dwmapi.dll", EntryPoint = "DwmGetWindowAttribute")]
private static extern int DwmGetWindowAttribute(IntPtr intPtr, int dwAttribute, out int pvAttribute,
uint cbAttribute);
/// <summary>
/// 判断键盘是否连接
/// </summary>
/// <returns></returns>
public static bool IsKeyboardAttached()
{
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_Keyboard");
int devCount = 0;
foreach (ManagementObject obj in searcher.Get())
{
if (obj["Status"].ToString().Contains("OK")) // if device is ready
{
//surface测试时发现HID设备不是键盘比较特殊
if (!obj["Description"].ToString().Contains("HID Keyboard Device"))
{
devCount++;
}
}
}
return devCount > 0;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// 打开虚拟键盘目前支持win7 64位win10 64位exe编译为x86。
/// </summary>
public static void ShowVirtualKeyboard()
{
//+------------------------------------------------------------------------------+
//| | PlatformID | Major version | Minor version |
//+------------------------------------------------------------------------------+
//| Windows 95 | Win32Windows | 4 | 0 |
//| Windows 98 | Win32Windows | 4 | 10 |
//| Windows Me | Win32Windows | 4 | 90 |
//| Windows NT 4.0 | Win32NT | 4 | 0 |
//| Windows 2000 | Win32NT | 5 | 0 |
//| Windows XP | Win32NT | 5 | 1 |
//| Windows 2003 | Win32NT | 5 | 2 |
//| Windows Vista | Win32NT | 6 | 0 |
//| Windows 2008 | Win32NT | 6 | 0 |
//| Windows 7 | Win32NT | 6 | 1 |
//| Windows 2008 R2 | Win32NT | 6 | 1 |
//| Windows 8 | Win32NT | 6 | 2 |
//| Windows 8.1 | Win32NT | 6 | 3 |
//+------------------------------------------------------------------------------+
//| Windows 10 | Win32NT | 10 | 0 |
try
{
var isWin7 = Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1;
var isWin8OrWin10 =
Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 2;
var isWin10 = Environment.OSVersion.Version.Major == 10 && Environment.OSVersion.Version.Minor == 0;
if (isWin7)
{
//win7
ShowWin7VirtualKeyboard();
}
else if (isWin8OrWin10 || isWin10)
{
//win10
ShowWin10VirtualKeyboard();
}
}
catch (Exception)
{
// ignored
}
}
/// <summary>
/// 关闭虚拟键盘
/// </summary>
public void CloseVirtualKeyboard()
{
var touchhWnd = FindWindow("IPTip_Main_Window", null);
if (touchhWnd == IntPtr.Zero)
{
return;
}
PostMessage(touchhWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
}
private static void ShowWin7VirtualKeyboard()
{
if (!Environment.Is64BitProcess && Environment.Is64BitOperatingSystem)
{
//32位程序 运行在64位系统上打开32位程序需要禁用文件重定向
var ptr = new IntPtr();
var isWow64FsRedirectionDisabled = Wow64DisableWow64FsRedirection(ref ptr);
Process.Start(Win7OskPath);
if (isWow64FsRedirectionDisabled)
{
Wow64RevertWow64FsRedirection(ptr);
}
}
else if (Environment.Is64BitProcess && Environment.Is64BitOperatingSystem)
{
Process.Start(Win7OskPath);
}
}
private static void ShowWin10VirtualKeyboard()
{
if (!IsTabTipProcessPresent())
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = Win10TabTipPath;
startInfo.UseShellExecute = true;
startInfo.Verb = "runas";
Process.Start(startInfo);
while (!IsValidHandle(FindWindow("IPTIP_Main_Window", "")))
{
Thread.Sleep(100);
}
}
//判断可见性
if (!IsWin10OnScreenKeyboardVisible())
{
ShowByCom();
}
}
private static bool IsWin10OnScreenKeyboardVisible()
{
var handle = FindWindow(TabTipWindowClassName, "");
if (!IsValidHandle(handle))
{
return false;
}
var isVisible = IsWindowVisibleByHandle(handle);
if (isVisible.HasValue)
{
return isVisible.Value;
}
// hard way
var textInputHandle = FindTextInputWindow();
return IsValidHandle(textInputHandle);
}
private static IntPtr FindTextInputWindow()
{
var lastProbed = IntPtr.Zero;
do
{
lastProbed = FindWindowEx(IntPtr.Zero, lastProbed, ApplicationFrameHostClassName, null);
if (IsValidHandle(lastProbed))
{
var textInput = FindWindowEx(lastProbed, IntPtr.Zero, CoreWindowClassName,
TextInputApplicationCaption);
return textInput;
}
} while (IsValidHandle(lastProbed));
return IntPtr.Zero;
}
private static bool? IsWindowVisibleByHandle(IntPtr handle)
{
var style = GetWindowLong(handle, GWL_STYLE);
//Console.WriteLine( "Style {0:X8}", style );
// if is disabled - not visible
if ((style & WS_DISABLED) != 0)
{
return false;
}
// if has visible style - visible :)
if ((style & WS_VISIBLE) != 0)
{
return true;
}
// DWM Window can be cloaked
// see https://social.msdn.microsoft.com/Forums/vstudio/en-US/f8341376-6015-4796-8273-31e0be91da62/difference-between-actually-visible-and-not-visiblewhich-are-there-but-we-cant-see-windows-of?forum=vcgeneral
if (DwmGetWindowAttribute(handle, DWMWA_CLOAKED, out var cloaked, 4) == 0)
{
if (cloaked != 0)
{
return false;
}
}
// undefined
return null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsValidHandle(IntPtr handle)
{
// if (?:) will be eliminated by jit
return IntPtr.Size == 4
? handle.ToInt32() > 0
: handle.ToInt64() > 0;
}
private static bool IsTabTipProcessPresent()
{
var handle = FindWindow(TabTipWindowClassName, "");
return IntPtr.Size == 4
? handle.ToInt32() > 0
: handle.ToInt64() > 0;
}
private static void ShowByCom()
{
ITipInvocation instance = null;
try
{
instance = (ITipInvocation)Activator.CreateInstance(ComTypes.TipInvocationType);
instance.Toggle(GetDesktopWindow());
}
finally
{
if (!ReferenceEquals(instance, null))
{
Marshal.ReleaseComObject(instance);
}
}
}
}
[ComImport]
[Guid("37c994e7-432b-4834-a2f7-dce1f13b834b")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface ITipInvocation
{
void Toggle(IntPtr hwnd);
}
internal static class ComTypes
{
internal static readonly Guid ImmersiveShellBrokerGuid;
internal static readonly Type ImmersiveShellBrokerType;
internal static readonly Guid TipInvocationGuid;
internal static readonly Type TipInvocationType;
static ComTypes()
{
TipInvocationGuid = Guid.Parse("4ce576fa-83dc-4F88-951c-9d0782b4e376");
TipInvocationType = Type.GetTypeFromCLSID(TipInvocationGuid);
ImmersiveShellBrokerGuid = new Guid("228826af-02e1-4226-a9e0-99a855e455a6");
ImmersiveShellBrokerType = Type.GetTypeFromCLSID(ImmersiveShellBrokerGuid);
}
}
}