OnScreenKeyboardTools.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. using Microsoft.Win32;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Runtime.InteropServices;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. namespace MvvmScaffoldFrame48.DLL.WindowsTools
  11. {
  12. public static class OnScreenKeyboardTools
  13. {
  14. [DllImport("kernel32.dll")]
  15. private static extern IntPtr GetModuleHandle(string lpModuleName);
  16. [DllImport("user32.dll")]
  17. private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
  18. [DllImport("user32.dll")]
  19. private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
  20. private const int SW_SHOW = 5;
  21. private const int SW_HIDE = 0;
  22. /// <summary>
  23. /// 启动软键盘(兼容Windows 10及以上版本)
  24. /// </summary>
  25. public static void KeyBoardShow()
  26. {
  27. try
  28. {
  29. // 检查是否为Windows 10或更高版本
  30. if (IsWindows10OrHigher())
  31. {
  32. // 尝试启动TabTip
  33. if (TryStartTabTip())
  34. return;
  35. }
  36. // 回退到传统osk
  37. StartOnScreenKeyboard();
  38. }
  39. catch (Exception ex)
  40. {
  41. throw new InvalidOperationException("无法启动软键盘", ex);
  42. }
  43. }
  44. /// <summary>
  45. /// 隐藏软键盘
  46. /// </summary>
  47. public static void KeyBoardHide()
  48. {
  49. try
  50. {
  51. // 隐藏TabTip窗口
  52. IntPtr tabTipHwnd = FindWindow("IPTip_Main_Window", null);
  53. if (tabTipHwnd != IntPtr.Zero)
  54. {
  55. ShowWindow(tabTipHwnd, SW_HIDE);
  56. }
  57. // 隐藏OSK窗口
  58. IntPtr oskHwnd = FindWindow("OSKMainClass", "屏幕键盘");
  59. if (oskHwnd != IntPtr.Zero)
  60. {
  61. ShowWindow(oskHwnd, SW_HIDE);
  62. }
  63. }
  64. catch
  65. {
  66. // 忽略异常
  67. }
  68. }
  69. private static void StartOnScreenKeyboard()
  70. {
  71. try
  72. {
  73. // 检查是否已经运行
  74. Process[] oskProcesses = Process.GetProcessesByName("osk");
  75. if (oskProcesses.Length > 0)
  76. {
  77. // 如果已经运行,尝试显示窗口
  78. IntPtr oskHwnd = FindWindow("OSKMainClass", "屏幕键盘");
  79. if (oskHwnd != IntPtr.Zero)
  80. {
  81. ShowWindow(oskHwnd, SW_SHOW);
  82. return;
  83. }
  84. else
  85. {
  86. // 如果找不到窗口,杀死进程重新启动
  87. foreach (var process in oskProcesses)
  88. {
  89. try { process.Kill(); } catch { }
  90. }
  91. }
  92. }
  93. Process.Start("osk.exe");
  94. }
  95. catch (Exception ex)
  96. {
  97. throw new InvalidOperationException("无法启动屏幕键盘", ex);
  98. }
  99. }
  100. private static bool IsWindows10OrHigher()
  101. {
  102. var os = Environment.OSVersion;
  103. if (os.Version.Major >= 10)
  104. return true;
  105. try
  106. {
  107. using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"))
  108. {
  109. var currentBuild = key?.GetValue("CurrentBuild")?.ToString();
  110. if (int.TryParse(currentBuild, out int buildNumber))
  111. {
  112. // Windows 10 build 10240及以上
  113. return buildNumber >= 10240;
  114. }
  115. }
  116. }
  117. catch
  118. {
  119. // 忽略异常
  120. }
  121. // 兼容性检查:Windows 8.1及以后版本的Major是6,但Minor版本不同
  122. return os.Version.Major == 10 || (os.Version.Major == 6 && os.Version.Minor >= 2);
  123. }
  124. private static bool TryStartTabTip()
  125. {
  126. try
  127. {
  128. // 检查是否已经运行
  129. Process[] tabTipProcesses = Process.GetProcessesByName("TabTip");
  130. if (tabTipProcesses.Length > 0)
  131. {
  132. // 如果找不到窗口,杀死进程重新启动
  133. foreach (var process in tabTipProcesses)
  134. {
  135. try { process.Kill(); } catch { }
  136. }
  137. }
  138. // 方法1:通过注册表查找路径
  139. string tabTipPath = GetTabTipPathFromRegistry();
  140. if (!string.IsNullOrEmpty(tabTipPath) && File.Exists(tabTipPath))
  141. {
  142. Process.Start(tabTipPath);
  143. return true;
  144. }
  145. // 方法2:通过系统路径查找
  146. string systemPath = Path.Combine(Environment.SystemDirectory, "TabTip.exe");
  147. if (File.Exists(systemPath))
  148. {
  149. Process.Start(systemPath);
  150. return true;
  151. }
  152. // 方法3:使用modern Windows 10路径
  153. string modernPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
  154. @"TabletTip\1.7\TabTip.exe");
  155. if (File.Exists(modernPath))
  156. {
  157. Process.Start(modernPath);
  158. return true;
  159. }
  160. // 方法4:使用默认路径
  161. string defaultPath = @"C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe";
  162. if (File.Exists(defaultPath))
  163. {
  164. Process.Start(defaultPath);
  165. return true;
  166. }
  167. }
  168. catch (Exception ex)
  169. {
  170. // 记录异常但不中断
  171. System.Diagnostics.Debug.WriteLine($"启动TabTip失败: {ex.Message}");
  172. }
  173. return false;
  174. }
  175. private static string GetTabTipPathFromRegistry()
  176. {
  177. try
  178. {
  179. using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications"))
  180. {
  181. if (key != null)
  182. {
  183. foreach (var subKeyName in key.GetSubKeyNames())
  184. {
  185. if (subKeyName.Contains("Microsoft.Windows.Keyboard"))
  186. {
  187. using (var subKey = key.OpenSubKey(subKeyName))
  188. {
  189. var installPath = subKey?.GetValue("Path")?.ToString();
  190. if (!string.IsNullOrEmpty(installPath))
  191. {
  192. string tabTipPath = Path.Combine(installPath, "TabTip.exe");
  193. if (File.Exists(tabTipPath))
  194. return tabTipPath;
  195. }
  196. }
  197. }
  198. }
  199. }
  200. }
  201. }
  202. catch
  203. {
  204. // 忽略注册表访问异常
  205. }
  206. return null;
  207. }
  208. }
  209. }