Skip to content

Commit c0f46f2

Browse files
authored
Merge pull request #1275 from stefnotch/search-open-explorer-window-tweaks
Insert active explorer path
2 parents e215c3f + 2212eac commit c0f46f2

File tree

3 files changed

+94
-2
lines changed

3 files changed

+94
-2
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Runtime.InteropServices;
6+
7+
namespace Flow.Launcher.Infrastructure
8+
{
9+
public static class FileExplorerHelper
10+
{
11+
/// <summary>
12+
/// Gets the path of the file explorer that is currently in the foreground
13+
/// </summary>
14+
public static string GetActiveExplorerPath()
15+
{
16+
var explorerWindow = GetActiveExplorer();
17+
string locationUrl = explorerWindow?.LocationURL;
18+
return !string.IsNullOrEmpty(locationUrl) ? new Uri(locationUrl).LocalPath : null;
19+
}
20+
21+
/// <summary>
22+
/// Gets the file explorer that is currently in the foreground
23+
/// </summary>
24+
private static dynamic GetActiveExplorer()
25+
{
26+
Type type = Type.GetTypeFromProgID("Shell.Application");
27+
if (type == null) return null;
28+
dynamic shell = Activator.CreateInstance(type);
29+
if (shell == null)
30+
{
31+
return null;
32+
}
33+
34+
var explorerWindows = new List<dynamic>();
35+
var openWindows = shell.Windows();
36+
for (int i = 0; i < openWindows.Count; i++)
37+
{
38+
var window = openWindows.Item(i);
39+
if (window == null) continue;
40+
41+
// find the desired window and make sure that it is indeed a file explorer
42+
// we don't want the Internet Explorer or the classic control panel
43+
// ToLower() is needed, because Windows can report the path as "C:\\Windows\\Explorer.EXE"
44+
if (Path.GetFileName((string)window.FullName)?.ToLower() == "explorer.exe")
45+
{
46+
explorerWindows.Add(window);
47+
}
48+
}
49+
50+
if (explorerWindows.Count == 0) return null;
51+
52+
var zOrders = GetZOrder(explorerWindows);
53+
54+
return explorerWindows.Zip(zOrders).MinBy(x => x.Second).First;
55+
}
56+
57+
[DllImport("user32.dll")]
58+
[return: MarshalAs(UnmanagedType.Bool)]
59+
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
60+
61+
private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
62+
63+
/// <summary>
64+
/// Gets the z-order for one or more windows atomically with respect to each other. In Windows, smaller z-order is higher. If the window is not top level, the z order is returned as -1.
65+
/// </summary>
66+
private static IEnumerable<int> GetZOrder(List<dynamic> hWnds)
67+
{
68+
var z = new int[hWnds.Count];
69+
for (var i = 0; i < hWnds.Count; i++) z[i] = -1;
70+
71+
var index = 0;
72+
var numRemaining = hWnds.Count;
73+
EnumWindows((wnd, _) =>
74+
{
75+
var searchIndex = hWnds.FindIndex(x => x.HWND == wnd.ToInt32());
76+
if (searchIndex != -1)
77+
{
78+
z[searchIndex] = index;
79+
numRemaining--;
80+
if (numRemaining == 0) return false;
81+
}
82+
index++;
83+
return true;
84+
}, IntPtr.Zero);
85+
86+
return z;
87+
}
88+
}
89+
}

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,10 @@ public string QuerySearchPrecisionString
192192
public ObservableCollection<CustomShortcutModel> CustomShortcuts { get; set; } = new ObservableCollection<CustomShortcutModel>();
193193

194194
[JsonIgnore]
195-
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new ObservableCollection<BuiltinShortcutModel>() {
196-
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText)
195+
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new()
196+
{
197+
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText),
198+
new BuiltinShortcutModel("{active_explorer_path}", "shortcut_active_explorer_path", FileExplorerHelper.GetActiveExplorerPath)
197199
};
198200

199201
public bool DontPromptUpdateMsg { get; set; }

Flow.Launcher/Languages/en.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@
176176
<system:String x:Key="deleteCustomHotkeyWarning">Are you sure you want to delete {0} plugin hotkey?</system:String>
177177
<system:String x:Key="deleteCustomShortcutWarning">Are you sure you want to delete shortcut: {0} with expansion {1}?</system:String>
178178
<system:String x:Key="shortcut_clipboard_description">Get text from clipboard.</system:String>
179+
<system:String x:Key="shortcut_active_explorer_path">Get path from active explorer.</system:String>
179180
<system:String x:Key="queryWindowShadowEffect">Query window shadow effect</system:String>
180181
<system:String x:Key="shadowEffectCPUUsage">Shadow effect has a substantial usage of GPU. Not recommended if your computer performance is limited.</system:String>
181182
<system:String x:Key="windowWidthSize">Window Width Size</system:String>

0 commit comments

Comments
 (0)