|
7 | 7 | using System.Collections.ObjectModel; |
8 | 8 | using System.Windows.Input; |
9 | 9 | using MenuItem = System.Windows.Controls.MenuItem; |
| 10 | +using User32=FlaUI.Core.WindowsAPI.User32; |
10 | 11 | namespace FlaUInspect.ViewModels; |
11 | 12 |
|
12 | 13 | public class ElementViewModel(AutomationElement? automationElement, ILogger? logger) : ObservableObject { |
13 | 14 | private readonly object _lockObject = new (); |
14 | 15 | public AutomationElement? AutomationElement { get; } = automationElement; |
15 | 16 | private RelayCommand? _refreshItemCommand; |
16 | 17 | private RelayCommand? _focusCommand; |
| 18 | + private RelayCommand? _focusNativeCommand; |
17 | 19 |
|
18 | 20 | public bool IsExpanded { |
19 | 21 | get => GetProperty<bool>(); |
@@ -47,24 +49,55 @@ public bool IsSelected { |
47 | 49 | }); |
48 | 50 |
|
49 | 51 | public ICommand FocusCommand => |
50 | | - _focusCommand ??= new((_) => { |
| 52 | + _focusCommand ??= CreateDelayedSafeCommand(AutomationElement.Focus); |
| 53 | + |
| 54 | + public ICommand FocusNativeCommand => |
| 55 | + _focusNativeCommand ??= CreateDelayedSafeCommand(DoNativeFocus); |
| 56 | + |
| 57 | + private async void DoNativeFocus() { |
| 58 | + try{ |
| 59 | + //await Task.Delay(250); |
| 60 | + if (AutomationElement.Properties.ProcessId.TryGetValue(out int processId)){ |
| 61 | + var proc = System.Diagnostics.Process.GetProcessById(processId); |
| 62 | + var res = User32.SetForegroundWindow(proc.MainWindowHandle); |
| 63 | + await Task.Delay(100); |
| 64 | + } |
| 65 | + AutomationElement.FocusNative(); |
| 66 | + }catch(Exception ex){ |
| 67 | + System.Diagnostics.Debug.WriteLine(ex.ToString()); |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + private static RelayCommand CreateDelayedSafeCommand(Action action, int delayMs=250){ |
| 72 | + var delayedAction = CreateDelayedSafeAction(action,delayMs); |
| 73 | + return new RelayCommand(_ => delayedAction()); |
| 74 | + } |
| 75 | + /// <summary> |
| 76 | + /// Mouse/focus related commands need a delay to allow our mosue action t obe handled first or we resteal the mouse |
| 77 | + /// </summary> |
| 78 | + /// <param name="action"></param> |
| 79 | + /// <param name="delayMs"></param> |
| 80 | + /// <returns></returns> |
| 81 | + public static Action CreateDelayedSafeAction(Action action, int delayMs=250) { |
| 82 | + return async () => { |
51 | 83 | try { |
52 | | - AutomationElement.Focus(); |
| 84 | + await Task.Delay(delayMs); |
| 85 | + action(); |
53 | 86 | } catch { } |
54 | | - }); |
55 | | - |
| 87 | + }; |
| 88 | + } |
56 | 89 |
|
57 | 90 | private ObservableCollection<MenuItem>? _mouseActions; |
58 | 91 | public ObservableCollection<MenuItem> MouseActions { get => _mouseActions ??= BuildMouseActions(); } |
59 | 92 |
|
60 | 93 | private ObservableCollection<MenuItem> BuildMouseActions() { |
61 | 94 | return [ |
62 | | - CreateMenuItem("Left Click", () => AutomationElement?.Click()), |
63 | | - CreateMenuItem("Right Click", () => AutomationElement?.RightClick()), |
64 | | - CreateMenuItem("Double Click", () => AutomationElement?.DoubleClick()), |
| 95 | + CreateMenuItem("Left Click", CreateDelayedSafeAction(() => AutomationElement?.Click())), |
| 96 | + CreateMenuItem("Right Click", CreateDelayedSafeAction(() => AutomationElement?.RightClick())), |
| 97 | + CreateMenuItem("Double Click", CreateDelayedSafeAction(() => AutomationElement?.DoubleClick())), |
65 | 98 | ]; |
66 | 99 | } |
67 | | - |
| 100 | + private MenuItem CreateMenuItem(string header, Action<object> value) => CreateMenuItem(header,()=>value(default)); |
68 | 101 | private MenuItem CreateMenuItem(string header, Action value) { |
69 | 102 | return new MenuItem { |
70 | 103 | Header = header, |
|
0 commit comments