Response to all selectionchanged event by using a task

This commit is contained in:
Paddy Xu
2017-05-27 23:06:55 +03:00
parent 6471125a0b
commit 93e1512b94
12 changed files with 244 additions and 95 deletions

63
QuickLook/FocusMonitor.cs Normal file
View File

@@ -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; }
}
}

View File

@@ -1,7 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Runtime.InteropServices.ComTypes; using System.Runtime.InteropServices.ComTypes;
using QuickLook.NativeMethods; using QuickLook.NativeMethods.Shell32;
namespace QuickLook.Helpers namespace QuickLook.Helpers
{ {

View File

@@ -5,7 +5,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using QuickLook.NativeMethods; using QuickLook.NativeMethods.Shell32;
namespace QuickLook.Helpers namespace QuickLook.Helpers
{ {

View File

@@ -2,6 +2,7 @@
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Windows; using System.Windows;
using System.Windows.Forms;
using System.Windows.Threading; using System.Windows.Threading;
using QuickLook.Helpers; using QuickLook.Helpers;
using QuickLook.Helpers.BlurLibrary; using QuickLook.Helpers.BlurLibrary;
@@ -42,7 +43,8 @@ namespace QuickLook
OpenWithAssocApp(); OpenWithAssocApp();
};*/ };*/
buttonOpenWith.Click += (sender, e) => RunAndClose(); buttonOpenWith.Click += (sender, e) => ViewWindowManager.GetInstance()
.InvokeRoutine(new KeyEventArgs(Keys.Escape));
} }
public ContextObject ContextObject { get; private set; } public ContextObject ContextObject { get; private set; }

View File

@@ -1,5 +1,7 @@
using System.Runtime.InteropServices; using System.Linq;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace QuickLook.NativeMethods namespace QuickLook.NativeMethods
{ {
@@ -16,5 +18,30 @@ namespace QuickLook.NativeMethods
[DllImport("QuickLook.Native.Shell32.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("QuickLook.Native.Shell32.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern void GetCurrentSelectionBuffer([MarshalAs(UnmanagedType.LPWStr)] StringBuilder buffer); 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;
}
} }
} }

View File

@@ -2,14 +2,8 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
namespace QuickLook.NativeMethods namespace QuickLook.NativeMethods.Shell32
{ {
[ComImport]
[Guid("00021401-0000-0000-C000-000000000046")]
internal class ShellLink
{
}
[ComImport] [ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214F9-0000-0000-C000-000000000046")] [Guid("000214F9-0000-0000-C000-000000000046")]
@@ -42,36 +36,4 @@ namespace QuickLook.NativeMethods
void Resolve(IntPtr hwnd, int fFlags); void Resolve(IntPtr hwnd, int fFlags);
void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); 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();
}
} }

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -0,0 +1,10 @@
using System.Runtime.InteropServices;
namespace QuickLook.NativeMethods.Shell32
{
[ComImport]
[Guid("00021401-0000-0000-C000-000000000046")]
internal class ShellLink
{
}
}

View File

@@ -0,0 +1,10 @@
using System.Runtime.InteropServices;
namespace QuickLook.NativeMethods.Shell32
{
[ComImport]
[Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8")]
internal class WshShell
{
}
}

View File

@@ -83,6 +83,7 @@
<Compile Include="Converters\BooleanToResizeModeConverter.cs" /> <Compile Include="Converters\BooleanToResizeModeConverter.cs" />
<Compile Include="Converters\BooleanToVisibilityCollapsedConverter.cs" /> <Compile Include="Converters\BooleanToVisibilityCollapsedConverter.cs" />
<Compile Include="Converters\BooleanToResizeBorderThicknessConverter.cs" /> <Compile Include="Converters\BooleanToResizeBorderThicknessConverter.cs" />
<Compile Include="FocusMonitor.cs" />
<Compile Include="Helpers\AutoStartupHelper.cs" /> <Compile Include="Helpers\AutoStartupHelper.cs" />
<Compile Include="Controls\BackgroundVisualHost.cs" /> <Compile Include="Controls\BackgroundVisualHost.cs" />
<Compile Include="Controls\BusyDecorator.cs" /> <Compile Include="Controls\BusyDecorator.cs" />
@@ -108,7 +109,11 @@
<Compile Include="Helpers\BlurLibrary\PlatformsImpl\WindowsVistaWindowBlurController.cs" /> <Compile Include="Helpers\BlurLibrary\PlatformsImpl\WindowsVistaWindowBlurController.cs" />
<Compile Include="Helpers\FileHelper.cs" /> <Compile Include="Helpers\FileHelper.cs" />
<Compile Include="MainWindowNoTransparent.cs" /> <Compile Include="MainWindowNoTransparent.cs" />
<Compile Include="NativeMethods\ShellLink.cs" /> <Compile Include="NativeMethods\Shell32\IShellLink.cs" />
<Compile Include="NativeMethods\Shell32\IWshShell.cs" />
<Compile Include="NativeMethods\Shell32\IWshShortcut.cs" />
<Compile Include="NativeMethods\Shell32\ShellLink.cs" />
<Compile Include="NativeMethods\Shell32\WshShell.cs" />
<Compile Include="PidHelper.cs" /> <Compile Include="PidHelper.cs" />
<Compile Include="PluginManager.cs" /> <Compile Include="PluginManager.cs" />
<Compile Include="Plugin\InfoPanel\DpiHelpers.cs" /> <Compile Include="Plugin\InfoPanel\DpiHelpers.cs" />

View File

@@ -1,9 +1,6 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Forms; using System.Windows.Forms;
using QuickLook.Helpers; using QuickLook.Helpers;
@@ -14,11 +11,13 @@ namespace QuickLook
internal class ViewWindowManager internal class ViewWindowManager
{ {
private static ViewWindowManager _instance; private static ViewWindowManager _instance;
private readonly MainWindowNoTransparent _viewWindowNoTransparent; private readonly MainWindowNoTransparent _viewWindowNoTransparent;
private readonly MainWindowTransparent _viewWindowTransparentTransparent; private readonly MainWindowTransparent _viewWindowTransparentTransparent;
private MainWindowTransparent _currentMainWindow; private MainWindowTransparent _currentMainWindow;
private string _path = string.Empty;
internal ViewWindowManager() internal ViewWindowManager()
{ {
_viewWindowTransparentTransparent = new MainWindowTransparent(); _viewWindowTransparentTransparent = new MainWindowTransparent();
@@ -43,17 +42,17 @@ namespace QuickLook
TogglePreview(kea); TogglePreview(kea);
break; break;
case Keys.Escape: case Keys.Escape:
ClosePreview(kea, false); ClosePreview(kea);
break; break;
case Keys.Enter: case Keys.Enter:
ClosePreview(kea, true); RunAndClosePreview(kea);
break; break;
default: default:
break; break;
} }
} }
private void ClosePreview(KeyEventArgs kea, bool runBeforeClose) private void RunAndClosePreview(KeyEventArgs kea = null)
{ {
if (!WindowHelper.IsFocusedControlExplorerItem() && !WindowHelper.IsFocusedWindowSelf()) if (!WindowHelper.IsFocusedControlExplorerItem() && !WindowHelper.IsFocusedWindowSelf())
return; return;
@@ -61,26 +60,40 @@ namespace QuickLook
if (_currentMainWindow.Visibility != Visibility.Visible) if (_currentMainWindow.Visibility != Visibility.Visible)
return; return;
if (runBeforeClose) StopFocusMonitor();
_currentMainWindow.RunAndClose(); _currentMainWindow.RunAndClose();
else if (kea != null)
_currentMainWindow.BeginHide(); kea.Handled = true;
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()) if (!WindowHelper.IsFocusedControlExplorerItem() && !WindowHelper.IsFocusedWindowSelf())
return; return;
if (_currentMainWindow.Visibility == Visibility.Visible) if (_currentMainWindow.Visibility == Visibility.Visible)
_currentMainWindow.BeginHide(); {
ClosePreview();
}
else 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) if (_currentMainWindow.Visibility != Visibility.Visible)
return; return;
@@ -88,21 +101,72 @@ namespace QuickLook
if (!WindowHelper.IsFocusedControlExplorerItem()) if (!WindowHelper.IsFocusedControlExplorerItem())
return; return;
_currentMainWindow.UnloadPlugin(); _path = NativeMethods.QuickLook.GetCurrentSelectionFirst();
InvokeViewer(GetCurrentSelection());
kea.Handled = false; 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)) if (string.IsNullOrEmpty(path))
return; return false;
if (!Directory.Exists(path) && !File.Exists(path)) if (!Directory.Exists(path) && !File.Exists(path))
return; return false;
RunFocusMonitor();
var matchedPlugin = PluginManager.GetInstance().FindMatch(path); var matchedPlugin = PluginManager.GetInstance().FindMatch(path);
BeginShowNewWindow(matchedPlugin, path); BeginShowNewWindow(matchedPlugin, path);
return true;
} }
private void BeginShowNewWindow(IViewer matchedPlugin, string path) 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() internal static ViewWindowManager GetInstance()
{ {
return _instance ?? (_instance = new ViewWindowManager()); return _instance ?? (_instance = new ViewWindowManager());