diff --git a/QuickLook/FocusMonitor.cs b/QuickLook/FocusMonitor.cs new file mode 100644 index 0000000..49bfeb9 --- /dev/null +++ b/QuickLook/FocusMonitor.cs @@ -0,0 +1,63 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using QuickLook.Helpers; + +namespace QuickLook +{ + internal class FocusMonitor + { + public delegate void FocusedItemChangedEventHandler(FocusedItemChangedEventArgs e); + + private static FocusMonitor _instance; + + public bool IsRunning { get; private set; } + + public event FocusedItemChangedEventHandler FocusedItemChanged; + + public void Start() + { + IsRunning = true; + + new Task(() => + { + var currentPath = NativeMethods.QuickLook.GetCurrentSelectionFirst(); + + while (IsRunning) + { + Thread.Sleep(500); + + if (WindowHelper.IsFocusedControlExplorerItem()) + { + var file = NativeMethods.QuickLook.GetCurrentSelectionFirst(); + if (file != currentPath) + { + FocusedItemChanged?.Invoke(new FocusedItemChangedEventArgs(file)); + currentPath = file; + } + } + } + }).Start(); + } + + public void Stop() + { + IsRunning = false; + } + + internal static FocusMonitor GetInstance() + { + return _instance ?? (_instance = new FocusMonitor()); + } + } + + internal class FocusedItemChangedEventArgs : EventArgs + { + public FocusedItemChangedEventArgs(string files) + { + FocusedFile = files; + } + + public string FocusedFile { get; } + } +} \ No newline at end of file diff --git a/QuickLook/Helpers/AutoStartupHelper.cs b/QuickLook/Helpers/AutoStartupHelper.cs index c30c483..62cee1f 100644 --- a/QuickLook/Helpers/AutoStartupHelper.cs +++ b/QuickLook/Helpers/AutoStartupHelper.cs @@ -1,7 +1,7 @@ using System; using System.IO; using System.Runtime.InteropServices.ComTypes; -using QuickLook.NativeMethods; +using QuickLook.NativeMethods.Shell32; namespace QuickLook.Helpers { diff --git a/QuickLook/Helpers/FileHelper.cs b/QuickLook/Helpers/FileHelper.cs index af5b8c2..cb164d9 100644 --- a/QuickLook/Helpers/FileHelper.cs +++ b/QuickLook/Helpers/FileHelper.cs @@ -5,7 +5,7 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; -using QuickLook.NativeMethods; +using QuickLook.NativeMethods.Shell32; namespace QuickLook.Helpers { diff --git a/QuickLook/MainWindowTransparent.xaml.cs b/QuickLook/MainWindowTransparent.xaml.cs index 7e7c88e..1cdb049 100644 --- a/QuickLook/MainWindowTransparent.xaml.cs +++ b/QuickLook/MainWindowTransparent.xaml.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Windows; +using System.Windows.Forms; using System.Windows.Threading; using QuickLook.Helpers; using QuickLook.Helpers.BlurLibrary; @@ -42,7 +43,8 @@ namespace QuickLook OpenWithAssocApp(); };*/ - buttonOpenWith.Click += (sender, e) => RunAndClose(); + buttonOpenWith.Click += (sender, e) => ViewWindowManager.GetInstance() + .InvokeRoutine(new KeyEventArgs(Keys.Escape)); } public ContextObject ContextObject { get; private set; } diff --git a/QuickLook/NativeMethods/QuickLook.cs b/QuickLook/NativeMethods/QuickLook.cs index 5c0dee3..65cd5b8 100644 --- a/QuickLook/NativeMethods/QuickLook.cs +++ b/QuickLook/NativeMethods/QuickLook.cs @@ -1,5 +1,7 @@ -using System.Runtime.InteropServices; +using System.Linq; +using System.Runtime.InteropServices; using System.Text; +using System.Threading.Tasks; namespace QuickLook.NativeMethods { @@ -16,5 +18,30 @@ namespace QuickLook.NativeMethods [DllImport("QuickLook.Native.Shell32.dll", CallingConvention = CallingConvention.Cdecl)] internal static extern void GetCurrentSelectionBuffer([MarshalAs(UnmanagedType.LPWStr)] StringBuilder buffer); + + internal static string[] GetCurrentSelection() + { + StringBuilder sb = null; + // communicate with COM in a separate thread + Task.Run(() => + { + SaveCurrentSelection(); + + var n = GetCurrentSelectionCount(); + if (n != 0) + { + sb = new StringBuilder(n * 261); // MAX_PATH + NULL = 261 + GetCurrentSelectionBuffer(sb); + } + }).Wait(); + return sb == null || sb.Length == 0 ? new string[0] : sb.ToString().Split('|'); + } + + internal static string GetCurrentSelectionFirst() + { + var files = GetCurrentSelection(); + + return files.Any() ? files.First() : string.Empty; + } } } \ No newline at end of file diff --git a/QuickLook/NativeMethods/ShellLink.cs b/QuickLook/NativeMethods/Shell32/IShellLink.cs similarity index 61% rename from QuickLook/NativeMethods/ShellLink.cs rename to QuickLook/NativeMethods/Shell32/IShellLink.cs index 574f7d6..bc136c6 100644 --- a/QuickLook/NativeMethods/ShellLink.cs +++ b/QuickLook/NativeMethods/Shell32/IShellLink.cs @@ -2,14 +2,8 @@ using System.Runtime.InteropServices; using System.Text; -namespace QuickLook.NativeMethods +namespace QuickLook.NativeMethods.Shell32 { - [ComImport] - [Guid("00021401-0000-0000-C000-000000000046")] - internal class ShellLink - { - } - [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("000214F9-0000-0000-C000-000000000046")] @@ -42,36 +36,4 @@ namespace QuickLook.NativeMethods void Resolve(IntPtr hwnd, int fFlags); void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); } - - [ComImport] - [Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8")] - internal class WshShell - { - } - - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - [Guid("F935DC21-1CF0-11D0-ADB9-00C04FD58A0B")] - internal interface IWshShell - { - IWshShortcut CreateShortcut(string pathLink); - } - - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - [Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B")] - internal interface IWshShortcut - { - string FullName { get; } - string Arguments { get; set; } - string Description { get; set; } - string Hotkey { get; set; } - string IconLocation { get; set; } - string RelativePath { set; } - string TargetPath { get; set; } - int WindowStyle { get; set; } - string WorkingDirectory { get; set; } - void Load([In] string pathLink); - void Save(); - } } \ No newline at end of file diff --git a/QuickLook/NativeMethods/Shell32/IWshShell.cs b/QuickLook/NativeMethods/Shell32/IWshShell.cs new file mode 100644 index 0000000..174e59d --- /dev/null +++ b/QuickLook/NativeMethods/Shell32/IWshShell.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace QuickLook.NativeMethods.Shell32 +{ + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + [Guid("F935DC21-1CF0-11D0-ADB9-00C04FD58A0B")] + internal interface IWshShell + { + IWshShortcut CreateShortcut(string pathLink); + } +} \ No newline at end of file diff --git a/QuickLook/NativeMethods/Shell32/IWshShortcut.cs b/QuickLook/NativeMethods/Shell32/IWshShortcut.cs new file mode 100644 index 0000000..bd25b16 --- /dev/null +++ b/QuickLook/NativeMethods/Shell32/IWshShortcut.cs @@ -0,0 +1,22 @@ +using System.Runtime.InteropServices; + +namespace QuickLook.NativeMethods.Shell32 +{ + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + [Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B")] + internal interface IWshShortcut + { + string FullName { get; } + string Arguments { get; set; } + string Description { get; set; } + string Hotkey { get; set; } + string IconLocation { get; set; } + string RelativePath { set; } + string TargetPath { get; set; } + int WindowStyle { get; set; } + string WorkingDirectory { get; set; } + void Load([In] string pathLink); + void Save(); + } +} \ No newline at end of file diff --git a/QuickLook/NativeMethods/Shell32/ShellLink.cs b/QuickLook/NativeMethods/Shell32/ShellLink.cs new file mode 100644 index 0000000..f637363 --- /dev/null +++ b/QuickLook/NativeMethods/Shell32/ShellLink.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace QuickLook.NativeMethods.Shell32 +{ + [ComImport] + [Guid("00021401-0000-0000-C000-000000000046")] + internal class ShellLink + { + } +} \ No newline at end of file diff --git a/QuickLook/NativeMethods/Shell32/WshShell.cs b/QuickLook/NativeMethods/Shell32/WshShell.cs new file mode 100644 index 0000000..49ecfb2 --- /dev/null +++ b/QuickLook/NativeMethods/Shell32/WshShell.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace QuickLook.NativeMethods.Shell32 +{ + [ComImport] + [Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8")] + internal class WshShell + { + } +} \ No newline at end of file diff --git a/QuickLook/QuickLook.csproj b/QuickLook/QuickLook.csproj index 28f5406..d1298b9 100644 --- a/QuickLook/QuickLook.csproj +++ b/QuickLook/QuickLook.csproj @@ -83,6 +83,7 @@ + @@ -108,7 +109,11 @@ - + + + + + diff --git a/QuickLook/ViewWindowManager.cs b/QuickLook/ViewWindowManager.cs index 6389718..51e808b 100644 --- a/QuickLook/ViewWindowManager.cs +++ b/QuickLook/ViewWindowManager.cs @@ -1,9 +1,6 @@ using System; using System.Diagnostics; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows; using System.Windows.Forms; using QuickLook.Helpers; @@ -14,11 +11,13 @@ namespace QuickLook internal class ViewWindowManager { private static ViewWindowManager _instance; + private readonly MainWindowNoTransparent _viewWindowNoTransparent; private readonly MainWindowTransparent _viewWindowTransparentTransparent; - private MainWindowTransparent _currentMainWindow; + private string _path = string.Empty; + internal ViewWindowManager() { _viewWindowTransparentTransparent = new MainWindowTransparent(); @@ -43,17 +42,17 @@ namespace QuickLook TogglePreview(kea); break; case Keys.Escape: - ClosePreview(kea, false); + ClosePreview(kea); break; case Keys.Enter: - ClosePreview(kea, true); + RunAndClosePreview(kea); break; default: break; } } - private void ClosePreview(KeyEventArgs kea, bool runBeforeClose) + private void RunAndClosePreview(KeyEventArgs kea = null) { if (!WindowHelper.IsFocusedControlExplorerItem() && !WindowHelper.IsFocusedWindowSelf()) return; @@ -61,26 +60,40 @@ namespace QuickLook if (_currentMainWindow.Visibility != Visibility.Visible) return; - if (runBeforeClose) - _currentMainWindow.RunAndClose(); - else - _currentMainWindow.BeginHide(); - kea.Handled = true; + StopFocusMonitor(); + _currentMainWindow.RunAndClose(); + if (kea != null) + kea.Handled = true; } - private void TogglePreview(KeyEventArgs kea) + internal void ClosePreview(KeyEventArgs kea = null) + { + StopFocusMonitor(); + _currentMainWindow.BeginHide(); + + if (kea != null) + kea.Handled = true; + } + + private void TogglePreview(KeyEventArgs kea = null) { if (!WindowHelper.IsFocusedControlExplorerItem() && !WindowHelper.IsFocusedWindowSelf()) return; if (_currentMainWindow.Visibility == Visibility.Visible) - _currentMainWindow.BeginHide(); + { + ClosePreview(); + } else - InvokeViewer(GetCurrentSelection()); - kea.Handled = true; + { + _path = NativeMethods.QuickLook.GetCurrentSelectionFirst(); + InvokeViewer(); + } + if (kea != null) + kea.Handled = true; } - private void SwitchPreview(KeyEventArgs kea) + private void SwitchPreview(KeyEventArgs kea = null) { if (_currentMainWindow.Visibility != Visibility.Visible) return; @@ -88,21 +101,72 @@ namespace QuickLook if (!WindowHelper.IsFocusedControlExplorerItem()) return; - _currentMainWindow.UnloadPlugin(); - InvokeViewer(GetCurrentSelection()); - kea.Handled = false; + _path = NativeMethods.QuickLook.GetCurrentSelectionFirst(); + + InvokeViewer(); + if (kea != null) + kea.Handled = false; } - internal void InvokeViewer(string path) + private void SwitchPreviewRemoteInvoke(FocusedItemChangedEventArgs e) { + Debug.WriteLine("SwitchPreviewRemoteInvoke"); + + if (e.FocusedFile == _path) + return; + + if (string.IsNullOrEmpty(e.FocusedFile)) + return; + + _currentMainWindow?.Dispatcher.Invoke(() => + { + if (_currentMainWindow.Visibility != Visibility.Visible) + return; + + if (!WindowHelper.IsFocusedControlExplorerItem()) + return; + + _path = NativeMethods.QuickLook.GetCurrentSelectionFirst(); + + InvokeViewer(); + }); + } + + private void RunFocusMonitor() + { + if (!FocusMonitor.GetInstance().IsRunning) + { + FocusMonitor.GetInstance().Start(); + FocusMonitor.GetInstance().FocusedItemChanged += SwitchPreviewRemoteInvoke; + } + } + + private void StopFocusMonitor() + { + if (FocusMonitor.GetInstance().IsRunning) + { + FocusMonitor.GetInstance().Stop(); + FocusMonitor.GetInstance().FocusedItemChanged -= SwitchPreviewRemoteInvoke; + } + } + + internal bool InvokeViewer(string path = null) + { + if (path == null) + path = _path; + if (string.IsNullOrEmpty(path)) - return; + return false; if (!Directory.Exists(path) && !File.Exists(path)) - return; + return false; + + RunFocusMonitor(); var matchedPlugin = PluginManager.GetInstance().FindMatch(path); BeginShowNewWindow(matchedPlugin, path); + + return true; } private void BeginShowNewWindow(IViewer matchedPlugin, string path) @@ -143,34 +207,6 @@ namespace QuickLook } } - private string GetCurrentSelection() - { - var path = string.Empty; - - // communicate with COM in a separate thread - Task.Run(() => - { - var paths = GetCurrentSelectionNative(); - - if (paths.Any()) - path = paths.First(); - }) - .Wait(); - - return string.IsNullOrEmpty(path) ? string.Empty : path; - } - - private string[] GetCurrentSelectionNative() - { - NativeMethods.QuickLook.SaveCurrentSelection(); - - var n = NativeMethods.QuickLook.GetCurrentSelectionCount(); - var sb = new StringBuilder(n * 261); // MAX_PATH + NULL = 261 - NativeMethods.QuickLook.GetCurrentSelectionBuffer(sb); - - return sb.Length == 0 ? new string[0] : sb.ToString().Split('|'); - } - internal static ViewWindowManager GetInstance() { return _instance ?? (_instance = new ViewWindowManager());