MainWindow.xaml.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using System.Windows;
  8. using System.Windows.Controls;
  9. using System.Windows.Data;
  10. using System.Windows.Documents;
  11. using System.Windows.Input;
  12. using System.Windows.Media;
  13. using System.Windows.Media.Imaging;
  14. using System.Windows.Navigation;
  15. using System.Windows.Shapes;
  16. namespace KeyBoard
  17. {
  18. /// <summary>
  19. /// MainWindow.xaml 的交互逻辑
  20. /// </summary>
  21. public partial class MainWindow : Window
  22. {
  23. // Windows API 导入
  24. [DllImport("user32.dll")]
  25. static extern IntPtr GetForegroundWindow();
  26. [DllImport("user32.dll")]
  27. static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
  28. [DllImport("user32.dll")]
  29. static extern IntPtr GetFocus();
  30. [DllImport("user32.dll")]
  31. static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
  32. [DllImport("user32.dll")]
  33. static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
  34. [DllImport("user32.dll")]
  35. static extern bool PostThreadMessage(uint idThread, uint Msg, IntPtr wParam, IntPtr lParam);
  36. [DllImport("kernel32.dll")]
  37. static extern uint GetCurrentThreadId();
  38. // 消息常量
  39. const uint WM_CHAR = 0x0102;
  40. const uint WM_KEYDOWN = 0x0100;
  41. const uint WM_KEYUP = 0x0101;
  42. const uint WM_LBUTTONDOWN = 0x0201;
  43. const uint WM_LBUTTONUP = 0x0202;
  44. // 当前活动窗口句柄
  45. private IntPtr targetWindow = IntPtr.Zero;
  46. private uint targetThreadId = 0;
  47. private uint currentThreadId = 0;
  48. public MainWindow()
  49. {
  50. InitializeComponent();
  51. }
  52. private void Window_Loaded(object sender, RoutedEventArgs e)
  53. {
  54. // 创建按钮样式
  55. if (!this.Resources.Contains("KeyboardButtonStyle"))
  56. {
  57. var style = new System.Windows.Style(typeof(System.Windows.Controls.Button));
  58. style.Setters.Add(new System.Windows.Setter(System.Windows.Controls.Button.WidthProperty, 60.0));
  59. style.Setters.Add(new System.Windows.Setter(System.Windows.Controls.Button.HeightProperty, 50.0));
  60. style.Setters.Add(new System.Windows.Setter(System.Windows.Controls.Button.MarginProperty, new Thickness(2)));
  61. this.Resources.Add("KeyboardButtonStyle", style);
  62. }
  63. // 获取当前线程ID
  64. currentThreadId = GetCurrentThreadId();
  65. }
  66. // 在窗口失去焦点时保存目标窗口信息
  67. private void Window_Deactivated(object sender, EventArgs e)
  68. {
  69. // 获取当前活动窗口
  70. targetWindow = GetForegroundWindow();
  71. if (targetWindow != IntPtr.Zero)
  72. {
  73. GetWindowThreadProcessId(targetWindow, out targetThreadId);
  74. }
  75. }
  76. // 使用PreviewMouseDown事件而不是Click事件
  77. private void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
  78. {
  79. e.Handled = true; // 阻止事件继续传播
  80. var button = sender as System.Windows.Controls.Button;
  81. if (button?.Tag != null)
  82. {
  83. char keyChar = button.Tag.ToString()[0];
  84. SendCharacter(keyChar);
  85. }
  86. // 防止按钮获得焦点
  87. this.Focus();
  88. }
  89. private void Space_PreviewMouseDown(object sender, MouseButtonEventArgs e)
  90. {
  91. e.Handled = true;
  92. SendCharacter(' ');
  93. this.Focus();
  94. }
  95. private void Backspace_PreviewMouseDown(object sender, MouseButtonEventArgs e)
  96. {
  97. e.Handled = true;
  98. SendBackspace();
  99. this.Focus();
  100. }
  101. // 发送字符到目标窗口
  102. private void SendCharacter(char ch)
  103. {
  104. if (targetWindow != IntPtr.Zero && targetThreadId != 0)
  105. {
  106. // 附加到目标线程的输入队列
  107. AttachThreadInput(currentThreadId, targetThreadId, true);
  108. // 发送字符消息
  109. PostMessage(targetWindow, WM_CHAR, new IntPtr(ch), IntPtr.Zero);
  110. // 分离线程输入
  111. AttachThreadInput(currentThreadId, targetThreadId, false);
  112. }
  113. else
  114. {
  115. // 如果没有保存目标窗口,则发送到当前活动窗口
  116. IntPtr currentForegroundWindow = GetForegroundWindow();
  117. if (currentForegroundWindow != IntPtr.Zero)
  118. {
  119. PostMessage(currentForegroundWindow, WM_CHAR, new IntPtr(ch), IntPtr.Zero);
  120. }
  121. }
  122. }
  123. // 发送退格键
  124. private void SendBackspace()
  125. {
  126. IntPtr windowToSend = targetWindow != IntPtr.Zero ? targetWindow : GetForegroundWindow();
  127. if (windowToSend != IntPtr.Zero)
  128. {
  129. uint threadId = targetThreadId != 0 ? targetThreadId : GetWindowThreadProcessId(windowToSend, out _);
  130. if (threadId != 0)
  131. {
  132. AttachThreadInput(currentThreadId, threadId, true);
  133. PostMessage(windowToSend, WM_KEYDOWN, new IntPtr(0x08), IntPtr.Zero); // VK_BACK
  134. PostMessage(windowToSend, WM_KEYUP, new IntPtr(0x08), IntPtr.Zero);
  135. AttachThreadInput(currentThreadId, threadId, false);
  136. }
  137. }
  138. }
  139. // 关闭按钮
  140. private void CloseButton_Click(object sender, RoutedEventArgs e)
  141. {
  142. this.Close();
  143. }
  144. }
  145. }