Skip to content

Commit

Permalink
Handle "Home" page, Some Improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
w4po committed Dec 3, 2023
1 parent cb0aa58 commit dee59a9
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 69 deletions.
2 changes: 1 addition & 1 deletion ExplorerTabUtility/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<value>True</value>
</setting>
<setting name="WindowHook" serializeAs="String">
<value>False</value>
<value>True</value>
</setting>
</ExplorerTabUtility.Properties.Settings>
</userSettings>
Expand Down
2 changes: 2 additions & 0 deletions ExplorerTabUtility/ExplorerTabUtility.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
<InvariantGlobalization>true</InvariantGlobalization>
<UseWindowsForms>True</UseWindowsForms>
<ApplicationIcon>Icon.ico</ApplicationIcon>
<Version>1.1.0</Version>
<LangVersion>latest</LangVersion>
<Title>Explorer Tab Utility</Title>
<Authors>w4po</Authors>
<Company>$(AssemblyName)</Company>
Expand Down
5 changes: 2 additions & 3 deletions ExplorerTabUtility/Forms/TrayIcon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,16 @@ private static async Task OnNewWindow(Window window)

UiAutomation.AddNewTab(windowElement);

// If it is just a new (This PC) window, return.
// If it is just a new (This PC | Home), return.
if (string.IsNullOrWhiteSpace(window.Path)) return;
if (!Uri.TryCreate(window.Path, UriKind.Absolute, out var uri)) return;

var newTabHandle = WinApi.ListenForNewExplorerTab(oldTabs);
if (newTabHandle == default) return;

var newTabElement = UiAutomation.FromHandle(newTabHandle);
if (newTabElement == default) return;

UiAutomation.GoToLocation(uri.LocalPath, windowElement);
UiAutomation.GoToLocation(window.Path, windowElement);

if (window.SelectedItems is not { } selectedItems) return;

Expand Down
31 changes: 13 additions & 18 deletions ExplorerTabUtility/Helpers/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,25 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Threading;

namespace ExplorerTabUtility.Helpers;

public static class Helper
{
public static T DoUntilCondition<T>(Func<T> action, Predicate<T> predicate, int timeMs = 500, CancellationToken cancellationToken = default)
{
var startTicks = Stopwatch.GetTimestamp();

while (!cancellationToken.IsCancellationRequested && !IsTimeUp(startTicks, timeMs))
{
var result = action.Invoke();
if (predicate(result))
return result;
}

return action.Invoke();
}
public static T DoUntilNotDefault<T>(Func<T> action, int timeMs = 500, CancellationToken cancellationToken = default)
{
var startTicks = Stopwatch.GetTimestamp();
Expand Down Expand Up @@ -59,21 +71,4 @@ public static TimeSpan GetElapsedTime(long startTicks)

return Icon.ExtractAssociatedIcon(location);
}

public static string GetFullPath(string path)
{
// Check if the path contains environment variables
if (path.StartsWith("%") && path.EndsWith("%"))
{
// Replace environment variables with their values
path = Environment.ExpandEnvironmentVariables(path);
}

// If it has : or \, assume it's a regular path
if (path.Contains(":") || path.Contains("\\")) return path;

// Check if the path is a special folder
var fullPath = $"{Environment.GetEnvironmentVariable("USERPROFILE")}\\{path}";
return Directory.Exists(fullPath) ? fullPath : path;
}
}
90 changes: 45 additions & 45 deletions ExplorerTabUtility/Hooks/UiAutomation.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using FlaUI.Core.AutomationElements;
Expand Down Expand Up @@ -49,18 +48,15 @@ private void OnWindowOpened(AutomationElement element, EventId _)
if (_cache.Contains(hWnd)) return;
_cache.Add(hWnd);

WinApi.GetWindowRect(hWnd, out var originalRect);
// Move the window outside the screen (Hide)
WinApi.SetWindowPos(hWnd, IntPtr.Zero, -1000, -1000, 0, 0, WinApi.SWP_NOSIZE | WinApi.SWP_NOZORDER);
var originalRect = HideWindow(hWnd);
var showAgain = true;
try
{
// a new "This PC" window (unless the opened folder is called "This PC"?)
// A new "This PC" window (unless the opened folder is called "This PC"?)
if (string.Equals(element.Name, "This PC"))
{
// the window suppose to have only one tab, so we should be okay.
CloseRandomTabOfAWindow(element);
_onNewWindow.Invoke(new Window(string.Empty));
CloseAndNotifyNewWindow(element, new Window(string.Empty, oldWindowHandle: hWnd));
showAgain = false;
return;
}

Expand All @@ -69,46 +65,54 @@ private void OnWindowOpened(AutomationElement element, EventId _)

// We have to invoke the suggestBox to populate the address bar :(
suggestBox.Patterns.Invoke.Pattern.Invoke();
Thread.Sleep(50);

// Invoke searchBox to hide the suggestPopup window.
searchBox.Patterns.Invoke.Pattern.Invoke();
Thread.Sleep(50);

var location = addressBar.Patterns.Value.Pattern.Value.Value;
var location = Helper.DoUntilCondition(
action: () => addressBar.Patterns.Value.Pattern.Value.Value,
predicate: l => !string.IsNullOrWhiteSpace(l));

if (string.IsNullOrWhiteSpace(location))
return;

// ("Home") For English version.
if (string.Equals(location, "Home"))
{
// Hmm... Let's try one more time.
Thread.Sleep(300);
location = addressBar.Patterns.Value.Pattern.Value.Value;
if (string.IsNullOrWhiteSpace(location)) return;
CloseAndNotifyNewWindow(element, new Window(string.Empty, oldWindowHandle: hWnd));
showAgain = false;
return;
}
location = Helper.GetFullPath(location);

var tab = element.FindFirstChild(c => c.ByClassName("ShellTabWindowClass"));

var folderView = tab?.FindFirstDescendant(c => c.ByClassName("UIItemsView"));
if (folderView == null) return;
if (folderView == default)
{
// ("Home") For non English versions.
var home = tab?.FindFirstDescendant(c => c.ByClassName("HomeListView"));
if (home == default) return;

var selectedNames = folderView.Patterns.Selection.Pattern.Selection.Value?
.Select(s => s.Name).ToList();
CloseAndNotifyNewWindow(element, new Window(string.Empty, oldWindowHandle: hWnd));
showAgain = false;
return;
}

var selectedNames = folderView.Patterns.Selection.Pattern.Selection.Value
?.Select(s => s.Name)
.ToList();

var tabHWnd = tab!.Properties.NativeWindowHandle.Value;

// the window suppose to have only one tab, so we should be okay.
CloseRandomTabOfAWindow(element);
CloseAndNotifyNewWindow(element, new Window(location, selectedNames, hWnd, tabHWnd));
showAgain = false;

_onNewWindow.Invoke(new Window(location, selectedNames, hWnd, tabHWnd));
}
finally
{
// Move the back to the screen (Show)
if (showAgain)
WinApi.SetWindowPos(hWnd, IntPtr.Zero, originalRect.Left, originalRect.Top, 0, 0, WinApi.SWP_NOSIZE | WinApi.SWP_NOZORDER);
}

}
public static AutomationElement? FromHandle(IntPtr hWnd) => Automation.FromHandle(hWnd);
public static void AddNewTab(AutomationElement windowElement)
Expand Down Expand Up @@ -143,35 +147,18 @@ public static void GoToLocation(string location, AutomationElement windowElement
GetHeaderElements(windowElement, out var suggestBox, out var searchBox, out var addressBar);
if (suggestBox == default || searchBox == default || addressBar == default) return;

// Set location
suggestBox.Patterns.Invoke.Pattern.Invoke();
addressBar.Patterns.Value.Pattern.SetValue(location);

// We have to invoke the suggestBox to Navigate :(
suggestBox.Patterns.Invoke.Pattern.Invoke();
Thread.Sleep(50);

// Invoke searchBox to hide the suggestPopup window.
searchBox.Patterns.Invoke.Pattern.Invoke();

var suggestList = Helper.DoUntilNotDefault(() => suggestBox.FindFirstChild("SuggestionsList"));
if (suggestList != default)
searchBox.Patterns.Invoke.Pattern.Invoke();

//var startTime = Stopwatch.GetTimestamp();
//while (Stopwatch.GetElapsedTime(startTime).TotalMilliseconds < 700)
//{
// var suggestList = suggestBox.FindFirstChild("SuggestionsList")?.FindAllChildren();
// if (suggestList == default) continue;

// foreach (var suggestItem in suggestList)
// {
// if (string.Equals(suggestItem.Name, location, StringComparison.OrdinalIgnoreCase))
// {
// suggestItem.Patterns.Invoke.Pattern.Invoke();
// return;
// }
// }
//}
//var suggestList = Helper.DoUntilNotDefault(() => suggestBox.FindFirstDescendant("SuggestionsList"));
//if (suggestList != default)
// searchBox.Patterns.Invoke.Pattern.Invoke();
}
public static void SelectItems(AutomationElement tabElement, ICollection<string> names)
{
Expand Down Expand Up @@ -224,7 +211,20 @@ private static void GetHeaderElements(AutomationElement window, out AutomationEl
suggestBox = headerBar.FindFirstChild("PART_AutoSuggestBox");
addressBar = suggestBox?.FindFirstChild(c => c.ByName("Address Bar"));
}
private static RECT HideWindow(IntPtr hWnd)
{
WinApi.GetWindowRect(hWnd, out var originalRect);
// Move the window outside the screen (Hide)
WinApi.SetWindowPos(hWnd, IntPtr.Zero, -1000, -1000, 0, 0, WinApi.SWP_NOSIZE | WinApi.SWP_NOZORDER);
return originalRect;
}
private void CloseAndNotifyNewWindow(AutomationElement element, Window window)
{
// the window suppose to have only one tab, so we should be okay.
CloseRandomTabOfAWindow(element);

_onNewWindow.Invoke(window);
}

public void Dispose()
{
Expand Down
2 changes: 1 addition & 1 deletion ExplorerTabUtility/Properties/Settings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ExplorerTabUtility/Properties/Settings.settings
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="WindowHook" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
<Value Profile="(Default)">True</Value>
</Setting>
</Settings>
</SettingsFile>

0 comments on commit dee59a9

Please sign in to comment.