SoftKeyboard.xaml.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. using System;
  2. using System.Text;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Controls.Primitives;
  6. using System.Windows.Media;
  7. namespace ivf_tl_Operate.CustomUserControls
  8. {
  9. /// <summary>
  10. /// 软键盘模式。
  11. /// </summary>
  12. public enum SoftKeyboardMode
  13. {
  14. /// <summary>数字键盘(0-9 / 退格 / 清除 / 确定)—— 数字/参数输入。</summary>
  15. Number,
  16. /// <summary>密码/全键盘(字母+数字+常用符号)—— 登录/调试密码。</summary>
  17. Password
  18. }
  19. /// <summary>
  20. /// M4-04-1 · 自绘内置软键盘控件(数字键盘 + 密码/全键盘)。
  21. /// <para>
  22. /// 取代 osk.exe(需求 11)。键盘维护一份内部输入缓冲,所有按键只在缓冲上增删,
  23. /// 每次变化通过 <see cref="KeyInput"/> 把「当前完整文本」抛给宿主(SoftKeyboardHost),
  24. /// 由宿主写回目标 TextBox/PasswordBox。点 确定/× 触发 <see cref="RequestClose"/>,
  25. /// 由宿主收起键盘。键盘不直接引用任何页面或具体输入框,做到代码隔离、可复用。
  26. /// </para>
  27. /// <para>不涉及任何业务/密码校验逻辑:tl13579 比对、参数阈值校验仍在原页面,键盘只负责录入。</para>
  28. /// </summary>
  29. public partial class SoftKeyboard : UserControl
  30. {
  31. private readonly StringBuilder _buffer = new StringBuilder();
  32. private bool _shift; // 全键盘大小写
  33. private bool _fullPadBuilt;
  34. /// <summary>当前缓冲文本变化(参数为当前完整文本)。宿主据此写回目标输入框。</summary>
  35. public event Action<string> KeyInput;
  36. /// <summary>用户点「确定」或「×」请求收起键盘(参数:true=确定提交,false=取消/关闭)。</summary>
  37. public event Action<bool> RequestClose;
  38. public SoftKeyboard()
  39. {
  40. InitializeComponent();
  41. }
  42. #region 依赖属性
  43. /// <summary>键盘模式(数字 / 密码全键盘)。</summary>
  44. public SoftKeyboardMode KeyboardMode
  45. {
  46. get => (SoftKeyboardMode)GetValue(KeyboardModeProperty);
  47. set => SetValue(KeyboardModeProperty, value);
  48. }
  49. public static readonly DependencyProperty KeyboardModeProperty =
  50. DependencyProperty.Register(nameof(KeyboardMode), typeof(SoftKeyboardMode), typeof(SoftKeyboard),
  51. new PropertyMetadata(SoftKeyboardMode.Number, OnKeyboardModeChanged));
  52. private static void OnKeyboardModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  53. {
  54. if (d is SoftKeyboard kb) kb.ApplyMode();
  55. }
  56. /// <summary>预览/回显时是否按密码掩码(●)显示。默认随模式:Password=掩码。可被宿主覆盖。</summary>
  57. public bool MaskPreview
  58. {
  59. get => (bool)GetValue(MaskPreviewProperty);
  60. set => SetValue(MaskPreviewProperty, value);
  61. }
  62. public static readonly DependencyProperty MaskPreviewProperty =
  63. DependencyProperty.Register(nameof(MaskPreview), typeof(bool), typeof(SoftKeyboard),
  64. new PropertyMetadata(false));
  65. #endregion
  66. /// <summary>当前键盘缓冲内容。</summary>
  67. public string Text => _buffer.ToString();
  68. /// <summary>
  69. /// 重置键盘:设定模式 + 初始文本(用于绑定输入框时把已有值带入)。宿主弹出前调用。
  70. /// </summary>
  71. public void Reset(SoftKeyboardMode mode, string initialText, bool mask)
  72. {
  73. _buffer.Clear();
  74. if (!string.IsNullOrEmpty(initialText)) _buffer.Append(initialText);
  75. _shift = false;
  76. MaskPreview = mask;
  77. KeyboardMode = mode; // 触发 ApplyMode
  78. ApplyMode();
  79. UpdatePreview();
  80. }
  81. private void ApplyMode()
  82. {
  83. if (_numberPad == null) return; // 未加载
  84. if (KeyboardMode == SoftKeyboardMode.Password)
  85. {
  86. BuildFullPadOnce();
  87. _numberPad.Visibility = Visibility.Collapsed;
  88. _fullPad.Visibility = Visibility.Visible;
  89. }
  90. else
  91. {
  92. _numberPad.Visibility = Visibility.Visible;
  93. _fullPad.Visibility = Visibility.Collapsed;
  94. }
  95. }
  96. #region 全键盘按键动态构建(触控基准统一应用)
  97. private void BuildFullPadOnce()
  98. {
  99. if (_fullPadBuilt) return;
  100. FillRow(_rowDigits, "1234567890");
  101. FillRow(_rowQ, "qwertyuiop");
  102. FillRow(_rowA, "asdfghjkl");
  103. FillRow(_rowZ, "zxcvbnm");
  104. _fullPadBuilt = true;
  105. }
  106. private void FillRow(System.Windows.Controls.Primitives.UniformGrid host, string chars)
  107. {
  108. foreach (char c in chars)
  109. {
  110. var b = new Button
  111. {
  112. Content = c.ToString(),
  113. Tag = c.ToString(),
  114. Margin = new Thickness(2)
  115. };
  116. b.Click += Key_Click;
  117. host.Children.Add(b);
  118. }
  119. }
  120. #endregion
  121. #region 按键事件
  122. private void Key_Click(object sender, RoutedEventArgs e)
  123. {
  124. if (!(sender is Button b) || b.Tag == null) return;
  125. string ch = b.Tag.ToString();
  126. // 全键盘 Shift:字母大写
  127. if (KeyboardMode == SoftKeyboardMode.Password && _shift && ch.Length == 1 && char.IsLetter(ch[0]))
  128. ch = ch.ToUpperInvariant();
  129. _buffer.Append(ch);
  130. EmitChanged();
  131. }
  132. private void Back_Click(object sender, RoutedEventArgs e)
  133. {
  134. if (_buffer.Length > 0) _buffer.Remove(_buffer.Length - 1, 1);
  135. EmitChanged();
  136. }
  137. private void Clear_Click(object sender, RoutedEventArgs e)
  138. {
  139. _buffer.Clear();
  140. EmitChanged();
  141. }
  142. private void Shift_Click(object sender, RoutedEventArgs e)
  143. {
  144. _shift = !_shift;
  145. if (_shiftBtn != null)
  146. _shiftBtn.Background = _shift
  147. ? new SolidColorBrush(Color.FromRgb(0x4D, 0x75, 0xAC))
  148. : new SolidColorBrush(Color.FromRgb(0xB0, 0xB4, 0xB9));
  149. }
  150. private void Enter_Click(object sender, RoutedEventArgs e)
  151. {
  152. RequestClose?.Invoke(true);
  153. }
  154. private void Close_Click(object sender, RoutedEventArgs e)
  155. {
  156. RequestClose?.Invoke(false);
  157. }
  158. #endregion
  159. private void EmitChanged()
  160. {
  161. UpdatePreview();
  162. KeyInput?.Invoke(_buffer.ToString());
  163. }
  164. private void UpdatePreview()
  165. {
  166. if (_preview == null) return;
  167. if (MaskPreview)
  168. _preview.Text = new string('●', _buffer.Length);
  169. else
  170. _preview.Text = _buffer.ToString();
  171. }
  172. }
  173. }