Dreamine.UI.Wpf.Equipment 1.0.1
Dreamine.UI.Wpf.Equipment 사용자 인터페이스 기능과 구성 요소를 제공합니다.
로딩중...
검색중...
일치하는것 없음
DreamineVirtualKeyboardWindow.xaml.cs
이 파일의 문서화 페이지로 가기
1using System.ComponentModel;
2using System.Diagnostics;
3using System.Reflection;
4using System.Runtime.InteropServices;
5using System.Windows;
6using System.Windows.Controls;
7using System.Windows.Data;
8using System.Windows.Input;
9using System.Windows.Media;
11using Dreamine.UI.Abstractions.VirtualKeyboard;
12
14
23public partial class DreamineVirtualKeyboardWindow : Window
24{
33 private DependencyObject? _placementTarget;
34
52 {
53 InitializeComponent();
60 System.Windows.Application.Current.Exit += Application_Exit;
61 }
62
87 private void DreamineVirtualKeyboardWindow_SizeChanged(object sender, SizeChangedEventArgs e)
88 {
90 }
91
116 private void DreamineVirtualKeyboardWindow_LocationChanged(object? sender, EventArgs e)
117 {
118 VirtualKeyboardComp.FocusVkbTextBox();
119 }
120
153 private void DreamineVirtualKeyboardWindow_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
154 {
155 var isVisible = (bool)e.NewValue;
156 if (!isVisible)
157 {
159 VirtualKeyboardComp.ReleasePressedKeys();
160 VirtualKeyboardComp.RemoveNumericHandler();
161 BindingOperations.ClearBinding(VirtualKeyboardComp, DreamineVirtualKeyboardUI.ValueProperty);
162 ClearText();
163 SetPlacementTarget(null);
164 }
165 else
166 {
167 if (IsLoaded)
168 {
170 }
171 }
172 }
173
206 private void DreamineVirtualKeyboardWindow_MouseDown(object sender, MouseButtonEventArgs e)
207 {
208 if (Mouse.LeftButton == MouseButtonState.Pressed)
209 this.DragMove();
210 }
211
244 private async void DreamineVirtualKeyboardWindow_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
245 {
246 try { await HandleKeyUpAsync(e); }
247 catch (Exception ex) { Debug.WriteLine($"[VK] KeyUp error: {ex.Message}"); }
248 }
249
282 private async Task HandleKeyUpAsync(System.Windows.Input.KeyEventArgs e)
283 {
284 switch (e.Key)
285 {
286 case System.Windows.Input.Key.Enter:
288
289 var result = await InvokeProvdersAsync();
290 if (!result)
291 {
292 return;
293 }
294
296 ClearText();
297 await Task.Delay(100);
298 if (IsVisible) Hide();
299 break;
300 case System.Windows.Input.Key.Escape:
302 ClearText();
303 await Task.Delay(100);
304 if (IsVisible) Hide();
305 break;
306 default:
307 break;
308 }
309 }
310
327 private async Task<bool> InvokeProvdersAsync()
328 {
329 if (_placementTarget != null)
330 {
332 foreach (var provider in providers)
333 {
334 var result = await provider.ExecuteAsync();
335 result.Show(VirtualKeyboardComp.MsgTbl);
336 if (!result.IsAccepted())
337 {
338 if (provider.PlacementTarget != null && DreamineVirtualKeyboardAssist.TargetChanged(provider.PlacementTarget))
339 {
341 }
342
343 return false;
344 }
345 }
346 }
347
348 return true;
349 }
350
375 private void DreamineVirtualKeyboardWindow_Closing(object? sender, CancelEventArgs e)
376 {
378 VirtualKeyboardComp?.Dispose();
380 }
381
406 private void Application_Exit(object sender, ExitEventArgs e)
407 {
408 VirtualKeyboardComp?.Dispose();
409 }
410
411
428 private void CalcKeyboardPosition()
429 {
430 if (_placementTarget is not UIElement ui)
431 return;
432
433 Point ptDev = ui.PointToScreen(new Point(0, 0));
434
435 var ps = PresentationSource.FromVisual(ui);
436 Matrix fromDevice = ps?.CompositionTarget?.TransformFromDevice ?? Matrix.Identity;
437
438 Point ptDip = fromDevice.Transform(ptDev);
439
440 var hMonitor = NativeMethods.MonitorFromPoint(new NativeMethods.POINT { x = (int)ptDev.X, y = (int)ptDev.Y }, NativeMethods.MONITOR_DEFAULTTONEAREST);
441 var mi = new NativeMethods.MONITORINFO { cbSize = (uint)Marshal.SizeOf<NativeMethods.MONITORINFO>() };
442 NativeMethods.GetMonitorInfo(hMonitor, ref mi);
443 var waR = mi.rcWork;
444 Point waTopLeftDip = fromDevice.Transform(new Point(waR.left, waR.top));
445 Point waBottomRightDip = fromDevice.Transform(new Point(waR.right, waR.bottom));
446 var waDip = new Rect(waTopLeftDip, waBottomRightDip);
447
448 double windowHeight = ActualHeight;
449 double windowWidth = ActualWidth;
450 if (windowHeight <= 0 || windowWidth <= 0) return;
451
452 double desiredTop;
453 if (ptDip.Y + ui.RenderSize.Height + windowHeight > waDip.Bottom)
454 {
455 desiredTop = Math.Max(ptDip.Y - windowHeight, waDip.Top);
456 }
457 else
458 {
459 desiredTop = ptDip.Y + ui.RenderSize.Height;
460 }
461
462 double desiredLeft = Math.Min(Math.Max(ptDip.X, waDip.Left), waDip.Right - windowWidth);
463
464 Left = desiredLeft;
465 Top = desiredTop;
466
468 }
469
470
487 public void SetLayout(VkLayout layout)
488 {
489 VirtualKeyboardComp.Layout = layout;
490
492
493 SetDefaultMinMaxValue(layout);
494
496 }
497
514 private void SetDisplayKeyboardSize(VkLayout layout)
515 {
516 MaxWidth = layout == VkLayout.Text || layout == VkLayout.Password ? 948 : 548;
517 }
518
535 private void SetDefaultMinMaxValue(VkLayout layout)
536 {
537 if (layout == VkLayout.Decimal)
538 {
539 VirtualKeyboardComp.Minimum = decimal.MinValue;
540 VirtualKeyboardComp.Maximum = decimal.MaxValue;
541 }
542 else
543 {
544 VirtualKeyboardComp.Minimum = int.MinValue;
545 VirtualKeyboardComp.Maximum = int.MaxValue;
546 }
547 }
548
589 public void SetBinding(System.Windows.Data.Binding binding, decimal min = decimal.MinValue, decimal max = decimal.MaxValue, string decimalFormat = "")
590 {
591 if (binding == null) return;
592 if (_placementTarget is PasswordBox passwordBox)
593 {
594 VirtualKeyboardComp.VkbPasswordBox.Password = passwordBox.Password;
595 }
596 else
597 {
598 BindingOperations.SetBinding(VirtualKeyboardComp, DreamineVirtualKeyboardUI.ValueProperty, binding);
599 VirtualKeyboardComp.Minimum = min;
600 VirtualKeyboardComp.Maximum = max;
601 VirtualKeyboardComp.DecimalFormat = decimalFormat;
602 }
603
605 VirtualKeyboardComp.AddOrRemoveNumericHandler();
606 }
607
624 public void SetPlacementTarget(DependencyObject? placementTarget)
625 {
627
628 _placementTarget = placementTarget;
629
630 if (_placementTarget is PasswordBox passwordBox)
631 {
632 VirtualKeyboardComp.VkbPasswordBox.Visibility = Visibility.Visible;
633 VirtualKeyboardComp.VkbTextBox.Visibility = Visibility.Collapsed;
634 }
635 else
636 {
637 VirtualKeyboardComp.VkbPasswordBox.Visibility = Visibility.Collapsed;
638 VirtualKeyboardComp.VkbTextBox.Visibility = Visibility.Visible;
639 }
640
641 if (IsLoaded)
642 {
644 }
645
647 }
648
665 private void UpdateWindowOwner()
666 {
667 if (_placementTarget != null)
668 {
669 var ownerWindow = Window.GetWindow(_placementTarget);
670 ownerWindow.Closing -= OwnerWindow_Closing;
671 ownerWindow.Closing += OwnerWindow_Closing;
672 SetWindowOwner(ownerWindow);
673 }
674 else
675 {
676 SetWindowOwner(null);
677 }
678 }
679
704 private void OwnerWindow_Closing(object? sender, CancelEventArgs e)
705 {
706 if (IsVisible)
707 {
708 SetWindowOwner(null);
709 Hide();
710 }
711 }
712
737 private void SetWindowOwner(Window? owner)
738 {
739 Owner = owner;
740 }
741
750 private void UpdateSourceBinding()
751 {
752
753 if (VirtualKeyboardComp.VkbPasswordBox.Password != string.Empty)
754 {
756 {
757 if (sink is PasswordBox childPwd)
758 {
759 childPwd.Password = VirtualKeyboardComp.VkbPasswordBox.Password;
760 return;
761 }
762
763 if (TryWritePassword(sink, VirtualKeyboardComp.VkbPasswordBox.Password))
764 return;
765 }
766 }
767 else
768 {
769 VirtualKeyboardComp.UpdateSourceBinding();
770 }
771 }
772
805 private static bool TryFindPasswordLikeElement(DependencyObject root, out FrameworkElement element)
806 {
807 element = null!;
808
809 // A) 표준 PasswordBox 우선
810 if (root.FindFirstVisualChild<PasswordBox>() is { } pwdBox)
811 {
812 element = pwdBox;
813 return true;
814 }
815
816 // B) 루트 자체가 Password CLR 속성 보유면 사용
817 if (root is FrameworkElement feRoot && HasPasswordProperty(root))
818 {
819 element = feRoot;
820 return true;
821 }
822
823 // C) 하위에서 Password CLR 속성 보유 요소 탐색
824 if (FindDescendantWithPasswordProperty(root) is FrameworkElement fe)
825 {
826 element = fe;
827 return true;
828 }
829
830 return false;
831 }
832
865 private static bool HasPasswordProperty(DependencyObject target)
866 {
867 var t = target.GetType();
868 var p = t.GetProperty(
869 "Password",
870 BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy
871 );
872 return p != null && p.CanRead && p.CanWrite && p.PropertyType == typeof(string);
873 }
874
915 private static bool TryWritePassword(DependencyObject target, string value)
916 {
917 var t = target.GetType();
918 var p = t.GetProperty(
919 "Password",
920 BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy
921 );
922
923 if (p != null && p.CanWrite && p.PropertyType == typeof(string))
924 {
925 p.SetValue(target, value);
926 return true;
927 }
928 return false;
929 }
930
963 private static FrameworkElement? FindDescendantWithPasswordProperty(DependencyObject root)
964 {
965 int count = VisualTreeHelper.GetChildrenCount(root);
966 for (int i = 0; i < count; i++)
967 {
968 var child = VisualTreeHelper.GetChild(root, i);
969
970 if (child is FrameworkElement fe && HasPasswordProperty(child))
971 return fe;
972
973 var deeper = FindDescendantWithPasswordProperty(child);
974 if (deeper != null)
975 return deeper;
976 }
977 return null;
978 }
979
989 {
990 VirtualKeyboardComp.UpdateNumericLabelVisibility();
991 }
992
1001 private void ClearText()
1002 {
1003 VirtualKeyboardComp.VkbPasswordBox.Password = string.Empty;
1004 VirtualKeyboardComp.MsgTbl.Text = string.Empty;
1005 }
1006
1016 {
1017 if (_placementTarget?.FindFirstVisualChild<System.Windows.Controls.TextBox>() is { } textBox)
1018 {
1019 textBox.Focus();
1020 textBox.CaretIndex = textBox.Text.Length;
1021 }
1022 else if (_placementTarget is UIElement passwordBox)
1023 {
1024 passwordBox.Focus();
1025 }
1026 }
1027
1036 private static class NativeMethods
1037 {
1046 public const uint MONITOR_DEFAULTTONEAREST = 0x00000002;
1047
1056 [StructLayout(LayoutKind.Sequential)]
1057 public struct POINT
1058 {
1067 public int x;
1076 public int y;
1077 }
1078
1087 [StructLayout(LayoutKind.Sequential)]
1088 public struct RECT
1089 {
1098 public int left;
1107 public int top;
1116 public int right;
1125 public int bottom;
1126 }
1127
1136 [StructLayout(LayoutKind.Sequential)]
1137 public struct MONITORINFO
1138 {
1147 public uint cbSize;
1165 public RECT rcWork;
1174 public uint dwFlags;
1175 }
1176
1209 [DllImport("user32.dll")]
1210 public static extern IntPtr MonitorFromPoint(POINT pt, uint dwFlags);
1211
1244 [DllImport("user32.dll")]
1245 [return: MarshalAs(UnmanagedType.Bool)]
1246 public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
1247 }
1248}
static void SetVkbIconVisibility(DependencyObject? placementTarget, bool visible)
async void DreamineVirtualKeyboardWindow_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
void DreamineVirtualKeyboardWindow_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
void SetBinding(System.Windows.Data.Binding binding, decimal min=decimal.MinValue, decimal max=decimal.MaxValue, string decimalFormat="")
static bool TryFindPasswordLikeElement(DependencyObject root, out FrameworkElement element)