| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- using Microsoft.Win32;
- using System;
- using System.Diagnostics;
- using System.IO;
- using System.Runtime.InteropServices;
- using System.Threading;
- using System.Threading.Tasks;
- namespace CCDCount.DLL.Tools
- {
- public static class OnScreenKeyboard
- {
- [DllImport("kernel32.dll")]
- private static extern IntPtr GetModuleHandle(string lpModuleName);
- [DllImport("user32.dll")]
- private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
- [DllImport("user32.dll")]
- private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
- [DllImport("user32.dll")]
- private static extern bool SetForegroundWindow(IntPtr hWnd);
- [DllImport("user32.dll")]
- private static extern bool IsIconic(IntPtr hWnd);
- private const int SW_SHOW = 5;
- private const int SW_RESTORE = 9;
- private const int SW_HIDE = 0;
- /// <summary>
- /// 启动软键盘(兼容Windows 10及以上版本)
- /// </summary>
- public static void KeyBoardShow()
- {
- //// 检查是否为Windows 10或更高版本
- //if (IsWindows10OrHigher())
- //{
- // // 尝试启动TabTip
- // if (TryStartTabTip())
- // return;
- //}
- // 回退到传统osk
- //StartOnScreenKeyboardRobust();
- StartOnScreenKeyboard();
- }
- /// <summary>
- /// 隐藏软键盘
- /// </summary>
- public static void KeyBoardHide()
- {
- try
- {
- // 隐藏TabTip窗口
- //IntPtr tabTipHwnd = FindWindow("IPTip_Main_Window", null);
- //if (tabTipHwnd != IntPtr.Zero)
- //{
- // ShowWindow(tabTipHwnd, SW_HIDE);
- //}
- // 隐藏OSK窗口
- IntPtr oskHwnd = FindWindow("OSKMainClass", "屏幕键盘");
- if (oskHwnd != IntPtr.Zero)
- {
- ShowWindow(oskHwnd, SW_HIDE);
- }
- }
- catch
- {
- // 忽略异常
- }
- }
- private static void StartOnScreenKeyboard()
- {
- try
- {
- // 检查是否已经运行
- Process[] oskProcesses = Process.GetProcessesByName("osk");
- if (oskProcesses.Length > 0)
- {
- Console.WriteLine("进入了分支");
- // 如果已经运行,尝试显示窗口
- IntPtr oskHwnd = FindWindow("OSKMainClass", "屏幕键盘");
- if (oskHwnd != IntPtr.Zero)
- {
- // 【修改点】:判断是否最小化
- if (IsIconic(oskHwnd))
- {
- // 如果最小化,使用 SW_RESTORE (9) 恢复窗口
- ShowWindow(oskHwnd, SW_RESTORE);
- }
- else
- {
- // 如果未最小化,使用 SW_SHOW (5) 显示/激活
- ShowWindow(oskHwnd, SW_SHOW);
- }
- // 确保窗口前置
- SetForegroundWindow(oskHwnd);
- return;
- }
- else
- {
- // 如果找不到窗口,杀死进程重新启动
- foreach (var process in oskProcesses)
- {
- try { process.Kill(); } catch { }
- }
- }
- }
- Console.WriteLine("执行开启软键盘");
- Process.Start(Path.Combine(Environment.SystemDirectory, "osk.exe"));
- }
- catch (Exception ex)
- {
- throw new InvalidOperationException("无法启动屏幕键盘", ex);
- }
- }
- /// <summary>
- /// 健壮的 OSK 启动方法
- /// </summary>
- private static void StartOnScreenKeyboardRobust()
- {
- try
- {
- // 1. 彻底清理已存在的 osk 进程,防止句柄冲突
- KillOskProcess();
- // 2. 准备启动信息
- string oskPath = Path.Combine(Environment.SystemDirectory, "osk.exe");
- if (!File.Exists(oskPath))
- {
- throw new FileNotFoundException("未找到 osk.exe", oskPath);
- }
- ProcessStartInfo startInfo = new ProcessStartInfo
- {
- FileName = oskPath,
- UseShellExecute = true, // 关键:使用 Shell 执行,有助于权限处理
- Verb = "open"
- };
- // 3. 启动进程
- Process proc = Process.Start(startInfo);
- // 4. 等待窗口出现并激活
- // osk.exe 启动较慢,需要轮询等待窗口句柄
- IntPtr hwnd = IntPtr.Zero;
- int retryCount = 0;
- const int maxRetries = 50; // 最多等待 5秒 (50 * 100ms)
- while (retryCount < maxRetries)
- {
- // 查找窗口类名 OSKMainClass,标题可能是 "屏幕键盘" 或 "On-Screen Keyboard" (取决于系统语言)
- hwnd = FindWindow("OSKMainClass", null);
- if (hwnd != IntPtr.Zero)
- {
- break;
- }
- Thread.Sleep(100);
- retryCount++;
- }
- if (hwnd != IntPtr.Zero)
- {
- // 确保窗口不是最小化状态
- if (IsIconic(hwnd))
- {
- ShowWindow(hwnd, SW_RESTORE);
- }
- else
- {
- ShowWindow(hwnd, SW_SHOW);
- }
- // 尝试将窗口前置
- SetForegroundWindow(hwnd);
- }
- else
- {
- System.Diagnostics.Debug.WriteLine("警告: OSK 进程已启动,但未检测到窗口句柄。可能需要管理员权限。");
- }
- }
- catch (Exception ex)
- {
- System.Diagnostics.Debug.WriteLine($"启动 OSK 失败: {ex.Message}");
- // 在生产环境中,建议记录日志而不是直接抛出异常,以免崩溃主程序
- }
- }
- /// <summary>
- /// 强制杀死所有 osk 进程
- /// </summary>
- private static void KillOskProcess()
- {
- try
- {
- Process[] processes = Process.GetProcessesByName("osk");
- foreach (var p in processes)
- {
- try
- {
- if (!p.HasExited)
- {
- p.Kill();
- p.WaitForExit(1000); // 等待进程完全退出
- }
- }
- catch { }
- }
- }
- catch { }
- }
- private static bool IsWindows10OrHigher()
- {
- var os = Environment.OSVersion;
- if (os.Version.Major >= 10)
- return true;
- try
- {
- using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"))
- {
- var currentBuild = key?.GetValue("CurrentBuild")?.ToString();
- if (int.TryParse(currentBuild, out int buildNumber))
- {
- // Windows 10 build 10240及以上
- return buildNumber >= 10240;
- }
- }
- }
- catch
- {
- // 忽略异常
- }
- // 兼容性检查:Windows 8.1及以后版本的Major是6,但Minor版本不同
- return os.Version.Major == 10 || (os.Version.Major == 6 && os.Version.Minor >= 2);
- }
- private static bool TryStartTabTip()
- {
- try
- {
- // 检查是否已经运行
- Process[] tabTipProcesses = Process.GetProcessesByName("TabTip");
- if (tabTipProcesses.Length > 0)
- {
- // 如果找不到窗口,杀死进程重新启动
- foreach (var process in tabTipProcesses)
- {
- try { process.Kill(); } catch { }
- }
- }
- // 方法1:通过注册表查找路径
- string tabTipPath = GetTabTipPathFromRegistry();
- if (!string.IsNullOrEmpty(tabTipPath) && File.Exists(tabTipPath))
- {
- Process.Start(tabTipPath);
- return true;
- }
- // 方法2:通过系统路径查找
- string systemPath = Path.Combine(Environment.SystemDirectory, "TabTip.exe");
- if (File.Exists(systemPath))
- {
- Process.Start(systemPath);
- return true;
- }
- // 方法3:使用modern Windows 10路径
- string modernPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
- @"TabletTip\1.7\TabTip.exe");
- if (File.Exists(modernPath))
- {
- Process.Start(modernPath);
- return true;
- }
- // 方法4:使用默认路径
- string defaultPath = @"C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe";
- if (File.Exists(defaultPath))
- {
- Process.Start(defaultPath);
- return true;
- }
- }
- catch (Exception ex)
- {
- // 记录异常但不中断
- System.Diagnostics.Debug.WriteLine($"启动TabTip失败: {ex.Message}");
- }
- return false;
- }
- private static string GetTabTipPathFromRegistry()
- {
- try
- {
- using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications"))
- {
- if (key != null)
- {
- foreach (var subKeyName in key.GetSubKeyNames())
- {
- if (subKeyName.Contains("Microsoft.Windows.Keyboard"))
- {
- using (var subKey = key.OpenSubKey(subKeyName))
- {
- var installPath = subKey?.GetValue("Path")?.ToString();
- if (!string.IsNullOrEmpty(installPath))
- {
- string tabTipPath = Path.Combine(installPath, "TabTip.exe");
- if (File.Exists(tabTipPath))
- return tabTipPath;
- }
- }
- }
- }
- }
- }
- }
- catch
- {
- // 忽略注册表访问异常
- }
- return null;
- }
- }
- }
|