[Window Walker] Migrate to Launcher (#2093)

* Copy the existing calc. plugin foldeR

* Blindly rename a bunch of things to Window Walker

* Update the solution to reference the new plugin

* Get basic Yo returned

* Remove all the languages except english

* Lower quality of icon as well as test showing it

* Add the core non-ui parts to the plugin

* Delete calculator png

* Get it to compile

* Added the actual code which apparently doesn't work

* Finally start showing results

* Fix up strings

* Switch working

* Remove unused classes

* Remove unneeded async
This commit is contained in:
Betsegaw (Beta) Tadele 2020-04-17 16:43:34 -07:00 committed by GitHub
parent 0cf3c097fb
commit ffe9ec1c76
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 2081 additions and 0 deletions

View file

@ -160,6 +160,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wox", "src\modules\launcher
ProjectSection(ProjectDependencies) = postProject
{FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {FDB3555B-58EF-4AE6-B5F1-904719637AB4}
{59BD9891-3837-438A-958D-ADC7F91F6F7E} = {59BD9891-3837-438A-958D-ADC7F91F6F7E}
{74F1B9ED-F59C-4FE7-B473-7B453E30837E} = {74F1B9ED-F59C-4FE7-B473-7B453E30837E}
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} = {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4} = {787B8AA6-CA93-4C84-96FE-DF31110AD1C4}
{F8B870EB-D5F5-45BA-9CF7-A5C459818820} = {F8B870EB-D5F5-45BA-9CF7-A5C459818820}
@ -177,6 +178,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{4AFC
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wox.Plugin.Calculator", "src\modules\launcher\Plugins\Wox.Plugin.Calculator\Wox.Plugin.Calculator.csproj", "{59BD9891-3837-438A-958D-ADC7F91F6F7E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wox.Plugin.WindowWalker", "src\modules\launcher\Plugins\Wox.Plugin.WindowWalker\Wox.Plugin.WindowWalker.csproj", "{74F1B9ED-F59C-4FE7-B473-7B453E30837E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wox.Plugin.Program", "src\modules\launcher\Plugins\Wox.Plugin.Program\Wox.Plugin.Program.csproj", "{FDB3555B-58EF-4AE6-B5F1-904719637AB4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wox.Plugin.Shell", "src\modules\launcher\Plugins\Wox.Plugin.Shell\Wox.Plugin.Shell.csproj", "{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}"
@ -353,6 +356,10 @@ Global
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.Build.0 = Debug|x64
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.ActiveCfg = Release|x64
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.Build.0 = Release|x64
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x64.ActiveCfg = Debug|x64
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x64.Build.0 = Debug|x64
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x64.ActiveCfg = Release|x64
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x64.Build.0 = Release|x64
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x64.ActiveCfg = Debug|x64
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x64.Build.0 = Debug|x64
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Release|x64.ActiveCfg = Release|x64
@ -460,6 +467,7 @@ Global
{FF742965-9A80-41A5-B042-D6C7D3A21708} = {C140A3EF-6DBF-4084-9D4C-4EB5A99FEE68}
{4AFC9975-2456-4C70-94A4-84073C1CED93} = {C140A3EF-6DBF-4084-9D4C-4EB5A99FEE68}
{59BD9891-3837-438A-958D-ADC7F91F6F7E} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{74F1B9ED-F59C-4FE7-B473-7B453E30837E} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4} = {4AFC9975-2456-4C70-94A4-84073C1CED93}

View file

@ -0,0 +1,123 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
using System.Collections.Generic;
using System.Linq;
namespace Wox.Plugin.WindowWalker.Components
{
/// <summary>
/// Class housing fuzzy matching methods
/// </summary>
public class FuzzyMatching
{
/// <summary>
/// Finds the best match (the one with the most
/// number of letters adjecent to each other) and
/// returns the index location of each of the letters
/// of the matches
/// </summary>
/// <param name="text">The text to search inside of</param>
/// <param name="searchText">the text to search for</param>
/// <returns>returns the index location of each of the letters of the matches</returns>
public static List<int> FindBestFuzzyMatch(string text, string searchText)
{
searchText = searchText.ToLower();
text = text.ToLower();
// Create a grid to march matches like
// eg.
// a b c a d e c f g
// a x x
// c x x
bool[,] matches = new bool[text.Length, searchText.Length];
for (int firstIndex = 0; firstIndex < text.Length; firstIndex++)
{
for (int secondIndex = 0; secondIndex < searchText.Length; secondIndex++)
{
matches[firstIndex, secondIndex] =
searchText[secondIndex] == text[firstIndex] ?
true :
false;
}
}
// use this table to get all the possible matches
List<List<int>> allMatches = GetAllMatchIndexes(matches);
// return the score that is the max
int maxScore = allMatches.Count > 0 ? CalculateScoreForMatches(allMatches[0]) : 0;
List<int> bestMatch = allMatches.Count > 0 ? allMatches[0] : new List<int>();
foreach (var match in allMatches)
{
int score = CalculateScoreForMatches(match);
if (score > maxScore)
{
bestMatch = match;
maxScore = score;
}
}
return bestMatch;
}
/// <summary>
/// Gets all the possible matches to the search string with in the text
/// </summary>
/// <param name="matches"> a table showing the matches as generated by
/// a two dimentional array with the first dimention the text and the second
/// one the search string and each cell marked as an intersection between the two</param>
/// <returns>a list of the possible combinations that match the search text</returns>
public static List<List<int>> GetAllMatchIndexes(bool[,] matches)
{
List<List<int>> results = new List<List<int>>();
for (int secondIndex = 0; secondIndex < matches.GetLength(1); secondIndex++)
{
for (int firstIndex = 0; firstIndex < matches.GetLength(0); firstIndex++)
{
if (secondIndex == 0 && matches[firstIndex, secondIndex])
{
results.Add(new List<int> { firstIndex });
}
else if (matches[firstIndex, secondIndex])
{
var tempList = results.Where(x => x.Count == secondIndex && x[x.Count - 1] < firstIndex).Select(x => x.ToList()).ToList();
foreach (var pathSofar in tempList)
{
pathSofar.Add(firstIndex);
}
results.AddRange(tempList);
}
}
results = results.Where(x => x.Count == secondIndex + 1).ToList();
}
return results.Where(x => x.Count == matches.GetLength(1)).ToList();
}
/// <summary>
/// Calculates the score for a string
/// </summary>
/// <param name="matches">the index of the matches</param>
/// <returns>an integer representing the score</returns>
public static int CalculateScoreForMatches(List<int> matches)
{
var score = 0;
for (int currentIndex = 1; currentIndex < matches.Count; currentIndex++)
{
var previousIndex = currentIndex - 1;
score -= matches[currentIndex] - matches[previousIndex];
}
return score == 0 ? -10000 : score;
}
}
}

View file

@ -0,0 +1,842 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Wox.Plugin.WindowWalker.Components
{
/// <summary>
/// Interop calls with helper layers
/// </summary>
internal class InteropAndHelpers
{
public delegate bool CallBackPtr(IntPtr hwnd, IntPtr lParam);
/// <summary>
/// Some flags for interop calls to SetWindowPosition
/// </summary>
[Flags]
public enum SetWindowPosFlags : uint
{
/// <summary>
/// If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request.
/// </summary>
SWP_ASYNCWINDOWPOS = 0x4000,
/// <summary>
/// Prevents generation of the WM_SYNCPAINT message.
/// </summary>
SWP_DEFERERASE = 0x2000,
/// <summary>
/// Draws a frame (defined in the window's class description) around the window.
/// </summary>
SWP_DRAWFRAME = 0x0020,
/// <summary>
/// Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE is sent only when the window's size is being changed.
/// </summary>
SWP_FRAMECHANGED = 0x0020,
/// <summary>
/// Hides the window.
/// </summary>
SWP_HIDEWINDOW = 0x0080,
/// <summary>
/// Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter).
/// </summary>
SWP_NOACTIVATE = 0x0010,
/// <summary>
/// Discards the entire contents of the client area. If this flag is not specified, the valid contents of the client area are saved and copied back into the client area after the window is sized or repositioned.
/// </summary>
SWP_NOCOPYBITS = 0x0100,
/// <summary>
/// Retains the current position (ignores X and Y parameters).
/// </summary>
SWP_NOMOVE = 0x0002,
/// <summary>
/// Does not change the owner window's position in the Z order.
/// </summary>
SWP_NOOWNERZORDER = 0x0200,
/// <summary>
/// Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of the window being moved. When this flag is set, the application must explicitly invalidate or redraw any parts of the window and parent window that need redrawing.
/// </summary>
SWP_NOREDRAW = 0x0008,
/// <summary>
/// Same as the SWP_NOOWNERZORDER flag.
/// </summary>
SWP_NOREPOSITION = 0x0200,
/// <summary>
/// Prevents the window from receiving the WM_WINDOWPOSCHANGING message.
/// </summary>
SWP_NOSENDCHANGING = 0x0400,
/// <summary>
/// Retains the current size (ignores the cx and cy parameters).
/// </summary>
SWP_NOSIZE = 0x0001,
/// <summary>
/// Retains the current Z order (ignores the hWndInsertAfter parameter).
/// </summary>
SWP_NOZORDER = 0x0004,
/// <summary>
/// Displays the window.
/// </summary>
SWP_SHOWWINDOW = 0x0040,
}
/// <summary>
/// Flags for setting hotkeys
/// </summary>
[Flags]
public enum Modifiers
{
NoMod = 0x0000,
Alt = 0x0001,
Ctrl = 0x0002,
Shift = 0x0004,
Win = 0x0008,
}
/// <summary>
/// Options for DwmpActivateLivePreview
/// </summary>
public enum LivePreviewTrigger
{
/// <summary>
/// Show Desktop button
/// </summary>
ShowDesktop = 1,
/// <summary>
/// WIN+SPACE hotkey
/// </summary>
WinSpace,
/// <summary>
/// Hover-over Superbar thumbnails
/// </summary>
Superbar,
/// <summary>
/// Alt-Tab
/// </summary>
AltTab,
/// <summary>
/// Press and hold on Superbar thumbnails
/// </summary>
SuperbarTouch,
/// <summary>
/// Press and hold on Show desktop
/// </summary>
ShowDesktopTouch,
}
/// <summary>
/// Show Window Enums
/// </summary>
public enum ShowWindowCommands
{
/// <summary>
/// Hides the window and activates another window.
/// </summary>
Hide = 0,
/// <summary>
/// Activates and displays a window. If the window is minimized or
/// maximized, the system restores it to its original size and position.
/// An application should specify this flag when displaying the window
/// for the first time.
/// </summary>
Normal = 1,
/// <summary>
/// Activates the window and displays it as a minimized window.
/// </summary>
ShowMinimized = 2,
/// <summary>
/// Maximizes the specified window.
/// </summary>
Maximize = 3, // is this the right value?
/// <summary>
/// Activates the window and displays it as a maximized window.
/// </summary>
ShowMaximized = 3,
/// <summary>
/// Displays a window in its most recent size and position. This value
/// is similar to <see cref="Win32.ShowWindowCommand.Normal"/>, except
/// the window is not activated.
/// </summary>
ShowNoActivate = 4,
/// <summary>
/// Activates the window and displays it in its current size and position.
/// </summary>
Show = 5,
/// <summary>
/// Minimizes the specified window and activates the next top-level
/// window in the Z order.
/// </summary>
Minimize = 6,
/// <summary>
/// Displays the window as a minimized window. This value is similar to
/// <see cref="Win32.ShowWindowCommand.ShowMinimized"/>, except the
/// window is not activated.
/// </summary>
ShowMinNoActive = 7,
/// <summary>
/// Displays the window in its current size and position. This value is
/// similar to <see cref="Win32.ShowWindowCommand.Show"/>, except the
/// window is not activated.
/// </summary>
ShowNA = 8,
/// <summary>
/// Activates and displays the window. If the window is minimized or
/// maximized, the system restores it to its original size and position.
/// An application should specify this flag when restoring a minimized window.
/// </summary>
Restore = 9,
/// <summary>
/// Sets the show state based on the SW_* value specified in the
/// STARTUPINFO structure passed to the CreateProcess function by the
/// program that started the application.
/// </summary>
ShowDefault = 10,
/// <summary>
/// <b>Windows 2000/XP:</b> Minimizes a window, even if the thread
/// that owns the window is not responding. This flag should only be
/// used when minimizing windows from a different thread.
/// </summary>
ForceMinimize = 11,
}
/// <summary>
/// The rendering policy to use for set window attribute
/// </summary>
[Flags]
public enum DwmNCRenderingPolicy
{
UseWindowStyle,
Disabled,
Enabled,
Last,
}
/// <summary>
/// Window attribute
/// </summary>
[Flags]
public enum DwmWindowAttribute
{
NCRenderingEnabled = 1,
NCRenderingPolicy,
TransitionsForceDisabled,
AllowNCPaint,
CaptionButtonBounds,
NonClientRtlLayout,
ForceIconicRepresentation,
Flip3DPolicy,
ExtendedFrameBounds,
HasIconicBitmap,
DisallowPeek,
ExcludedFromPeek,
Last,
}
/// <summary>
/// Flags for accessing the process in trying to get icon for the process
/// </summary>
[Flags]
public enum ProcessAccessFlags
{
/// <summary>
/// Required to create a thread.
/// </summary>
CreateThread = 0x0002,
/// <summary>
///
/// </summary>
SetSessionId = 0x0004,
/// <summary>
/// Required to perform an operation on the address space of a process
/// </summary>
VmOperation = 0x0008,
/// <summary>
/// Required to read memory in a process using ReadProcessMemory.
/// </summary>
VmRead = 0x0010,
/// <summary>
/// Required to write to memory in a process using WriteProcessMemory.
/// </summary>
VmWrite = 0x0020,
/// <summary>
/// Required to duplicate a handle using DuplicateHandle.
/// </summary>
DupHandle = 0x0040,
/// <summary>
/// Required to create a process.
/// </summary>
CreateProcess = 0x0080,
/// <summary>
/// Required to set memory limits using SetProcessWorkingSetSize.
/// </summary>
SetQuota = 0x0100,
/// <summary>
/// Required to set certain information about a process, such as its priority class (see SetPriorityClass).
/// </summary>
SetInformation = 0x0200,
/// <summary>
/// Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken).
/// </summary>
QueryInformation = 0x0400,
/// <summary>
/// Required to suspend or resume a process.
/// </summary>
SuspendResume = 0x0800,
/// <summary>
/// Required to retrieve certain information about a process (see GetExitCodeProcess, GetPriorityClass, IsProcessInJob, QueryFullProcessImageName).
/// A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted PROCESS_QUERY_LIMITED_INFORMATION.
/// </summary>
QueryLimitedInformation = 0x1000,
/// <summary>
/// Required to wait for the process to terminate using the wait functions.
/// </summary>
Synchronize = 0x100000,
/// <summary>
/// Required to delete the object.
/// </summary>
Delete = 0x00010000,
/// <summary>
/// Required to read information in the security descriptor for the object, not including the information in the SACL.
/// To read or write the SACL, you must request the ACCESS_SYSTEM_SECURITY access right. For more information, see SACL Access Right.
/// </summary>
ReadControl = 0x00020000,
/// <summary>
/// Required to modify the DACL in the security descriptor for the object.
/// </summary>
WriteDac = 0x00040000,
/// <summary>
/// Required to change the owner in the security descriptor for the object.
/// </summary>
WriteOwner = 0x00080000,
StandardRightsRequired = 0x000F0000,
/// <summary>
/// All possible access rights for a process object.
/// </summary>
AllAccess = StandardRightsRequired | Synchronize | 0xFFFF,
}
/// <summary>
/// Contains information about the placement of a window on the screen.
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
internal struct WINDOWPLACEMENT
{
/// <summary>
/// The length of the structure, in bytes. Before calling the GetWindowPlacement or SetWindowPlacement functions, set this member to sizeof(WINDOWPLACEMENT).
/// <para>
/// GetWindowPlacement and SetWindowPlacement fail if this member is not set correctly.
/// </para>
/// </summary>
public int Length;
/// <summary>
/// Specifies flags that control the position of the minimized window and the method by which the window is restored.
/// </summary>
public int Flags;
/// <summary>
/// The current show state of the window.
/// </summary>
public ShowWindowCommands ShowCmd;
/// <summary>
/// The coordinates of the window's upper-left corner when the window is minimized.
/// </summary>
public POINT MinPosition;
/// <summary>
/// The coordinates of the window's upper-left corner when the window is maximized.
/// </summary>
public POINT MaxPosition;
/// <summary>
/// The window's coordinates when the window is in the restored position.
/// </summary>
public RECT NormalPosition;
/// <summary>
/// Gets the default (empty) value.
/// </summary>
public static WINDOWPLACEMENT Default
{
get
{
WINDOWPLACEMENT result = default;
result.Length = Marshal.SizeOf(result);
return result;
}
}
}
/// <summary>
/// Required pointless variables that we don't use in making a windows show
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public RECT(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public RECT(System.Drawing.Rectangle r)
: this(r.Left, r.Top, r.Right, r.Bottom)
{
}
public int X
{
get
{
return Left;
}
set
{
Right -= Left - value;
Left = value;
}
}
public int Y
{
get
{
return Top;
}
set
{
Bottom -= Top - value;
Top = value;
}
}
public int Height
{
get { return Bottom - Top; }
set { Bottom = value + Top; }
}
public int Width
{
get { return Right - Left; }
set { Right = value + Left; }
}
public System.Drawing.Point Location
{
get
{
return new System.Drawing.Point(Left, Top);
}
set
{
X = value.X;
Y = value.Y;
}
}
public System.Drawing.Size Size
{
get
{
return new System.Drawing.Size(Width, Height);
}
set
{
Width = value.Width;
Height = value.Height;
}
}
public static implicit operator System.Drawing.Rectangle(RECT r)
{
return new System.Drawing.Rectangle(r.Left, r.Top, r.Width, r.Height);
}
public static implicit operator RECT(System.Drawing.Rectangle r)
{
return new RECT(r);
}
public static bool operator ==(RECT r1, RECT r2)
{
return r1.Equals(r2);
}
public static bool operator !=(RECT r1, RECT r2)
{
return !r1.Equals(r2);
}
public bool Equals(RECT r)
{
return r.Left == Left && r.Top == Top && r.Right == Right && r.Bottom == Bottom;
}
public override bool Equals(object obj)
{
if (obj is RECT)
{
return Equals((RECT)obj);
}
else if (obj is System.Drawing.Rectangle)
{
return Equals(new RECT((System.Drawing.Rectangle)obj));
}
return false;
}
public override int GetHashCode()
{
return ((System.Drawing.Rectangle)this).GetHashCode();
}
public override string ToString()
{
return string.Format(System.Globalization.CultureInfo.CurrentCulture, "{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom);
}
}
/// <summary>
/// Same as the RECT struct above
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
X = x;
Y = y;
}
public POINT(System.Drawing.Point pt)
: this(pt.X, pt.Y)
{
}
public static implicit operator System.Drawing.Point(POINT p)
{
return new System.Drawing.Point(p.X, p.Y);
}
public static implicit operator POINT(System.Drawing.Point p)
{
return new POINT(p.X, p.Y);
}
}
/// <summary>
/// GetWindow relationship between the specified window and the window whose handle is to be retrieved.
/// </summary>
public enum GetWindowCmd : uint
{
/// <summary>
/// The retrieved handle identifies the window of the same type that is highest in the Z order.
/// </summary>
GW_HWNDFIRST = 0,
/// <summary>
/// The retrieved handle identifies the window of the same type that is lowest in the Z order.
/// </summary>
GW_HWNDLAST = 1,
/// <summary>
/// The retrieved handle identifies the window below the specified window in the Z order.
/// </summary>
GW_HWNDNEXT = 2,
/// <summary>
/// The retrieved handle identifies the window above the specified window in the Z order.
/// </summary>
GW_HWNDPREV = 3,
/// <summary>
/// The retrieved handle identifies the specified window's owner window, if any.
/// </summary>
GW_OWNER = 4,
/// <summary>
/// The retrieved handle identifies the child window at the top of the Z order, if the specified window
/// is a parent window.
/// </summary>
GW_CHILD = 5,
/// <summary>
/// The retrieved handle identifies the enabled popup window owned by the specified window.
/// </summary>
GW_ENABLEDPOPUP = 6
}
/// <summary>
/// GetWindowLong index to retrieves the extended window styles.
/// </summary>
public const int GWL_EXSTYLE = -20;
/// <summary>
/// The following are the extended window styles
/// </summary>
[Flags]
public enum ExtendedWindowStyles : UInt32
{
/// <summary>
/// The window has a double border; the window can, optionally, be created with a title bar by specifying
/// the WS_CAPTION style in the dwStyle parameter.
/// </summary>
WS_EX_DLGMODALFRAME = 0X0001,
/// <summary>
/// The child window created with this style does not send the WM_PARENTNOTIFY message to its parent window
/// when it is created or destroyed.
/// </summary>
WS_EX_NOPARENTNOTIFY = 0X0004,
/// <summary>
/// The window should be placed above all non-topmost windows and should stay above all non-topmost windows
/// and should stay above them, even when the window is deactivated.
/// </summary>
WS_EX_TOPMOST = 0X0008,
/// <summary>
/// The window accepts drag-drop files.
/// </summary>
WS_EX_ACCEPTFILES = 0x0010,
/// <summary>
/// The window should not be painted until siblings beneath the window (that were created by the same thread)
/// have been painted.
/// </summary>
WS_EX_TRANSPARENT = 0x0020,
/// <summary>
/// The window is a MDI child window.
/// </summary>
WS_EX_MDICHILD = 0x0040,
/// <summary>
/// The window is intended to be used as a floating toolbar. A tool window has a title bar that is shorter
/// than a normal title bar, and the window title is drawn using a smaller font. A tool window does not
/// appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
/// </summary>
WS_EX_TOOLWINDOW = 0x0080,
/// <summary>
/// The window has a border with a raised edge.
/// </summary>
WS_EX_WINDOWEDGE = 0x0100,
/// <summary>
/// The window has a border with a sunken edge.
/// </summary>
WS_EX_CLIENTEDGE = 0x0200,
/// <summary>
/// The title bar of the window includes a question mark.
/// </summary>
WS_EX_CONTEXTHELP = 0x0400,
/// <summary>
/// The window has generic "right-aligned" properties. This depends on the window class. This style has
/// an effect only if the shell language supports reading-order alignment, otherwise is ignored.
/// </summary>
WS_EX_RIGHT = 0x1000,
/// <summary>
/// The window has generic left-aligned properties. This is the default.
/// </summary>
WS_EX_LEFT = 0x0,
/// <summary>
/// If the shell language supports reading-order alignment, the window text is displayed using right-to-left
/// reading-order properties. For other languages, the styles is ignored.
/// </summary>
WS_EX_RTLREADING = 0x2000,
/// <summary>
/// The window text is displayed using left-to-right reading-order properties. This is the default.
/// </summary>
WS_EX_LTRREADING = 0x0,
/// <summary>
/// If the shell language supports reading order alignment, the vertical scroll bar (if present) is to
/// the left of the client area. For other languages, the style is ignored.
/// </summary>
WS_EX_LEFTSCROLLBAR = 0x4000,
/// <summary>
/// The vertical scroll bar (if present) is to the right of the client area. This is the default.
/// </summary>
WS_EX_RIGHTSCROLLBAR = 0x0,
/// <summary>
/// The window itself contains child windows that should take part in dialog box, navigation. If this
/// style is specified, the dialog manager recurses into children of this window when performing
/// navigation operations such as handling tha TAB key, an arrow key, or a keyboard mnemonic.
/// </summary>
WS_EX_CONTROLPARENT = 0x10000,
/// <summary>
/// The window has a three-dimensional border style intended to be used for items that do not accept
/// user input.
/// </summary>
WS_EX_STATICEDGE = 0x20000,
/// <summary>
/// Forces a top-level window onto the taskbar when the window is visible.
/// </summary>
WS_EX_APPWINDOW = 0x40000,
/// <summary>
/// The window is an overlapped window.
/// </summary>
WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
/// <summary>
/// The window is palette window, which is a modeless dialog box that presents an array of commands.
/// </summary>
WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
/// <summary>
/// The window is a layered window. This style cannot be used if the window has a class style of either
/// CS_OWNDC or CS_CLASSDC. Only for top level window before Windows 8, and child windows from Windows 8.
/// </summary>
WS_EX_LAYERED = 0x80000,
/// <summary>
/// The window does not pass its window layout to its child windows.
/// </summary>
WS_EX_NOINHERITLAYOUT = 0x100000,
/// <summary>
/// If the shell language supports reading order alignment, the horizontal origin of the window is on the
/// right edge. Increasing horizontal values advance to the left.
/// </summary>
WS_EX_LAYOUTRTL = 0x400000,
/// <summary>
/// Paints all descendants of a window in bottom-to-top painting order using double-buffering.
/// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and
/// transparency (color-key) effects, but only if the descendent window also has the WS_EX_TRANSPARENT
/// bit set. Double-buffering allows the window and its descendents to be painted without flicker.
/// </summary>
WS_EX_COMPOSITED = 0x2000000,
/// <summary>
/// A top-level window created with this style does not become the foreground window when the user
/// clicks it. The system does not bring this window to the foreground when the user minimizes or closes
/// the foreground window.
/// </summary>
WS_EX_NOACTIVATE = 0x8000000
}
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int EnumWindows(CallBackPtr callPtr, int lPar);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetWindow(IntPtr hWnd, GetWindowCmd uCmd);
[DllImport("user32.dll", SetLastError = true)]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int EnumChildWindows(IntPtr hWnd, CallBackPtr callPtr, int lPar);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool IsWindow(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SetWindowPosFlags uFlags);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);
[DllImport("user32.dll")]
public static extern bool FlashWindow(IntPtr hwnd, bool bInvert);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("psapi.dll")]
public static extern uint GetProcessImageFileName(IntPtr hProcess, [Out] StringBuilder lpImageFileName, [In] [MarshalAs(UnmanagedType.U4)] int nSize);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetProp(IntPtr hWnd, string lpString);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
[DllImport("dwmapi.dll", EntryPoint = "#113", CallingConvention = CallingConvention.StdCall)]
public static extern int DwmpActivateLivePreview([MarshalAs(UnmanagedType.Bool)]bool fActivate, IntPtr hWndExclude, IntPtr hWndInsertBefore, LivePreviewTrigger lpt, IntPtr prcFinalRect);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out int pvAttribute, int cbAttribute);
[DllImport("user32.dll")]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl);
}
}

View file

@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
using System;
namespace Wox.Plugin.WindowWalker.Components
{
/// <summary>
/// Class containg methods to control the live preview
/// </summary>
internal class LivePreview
{
/// <summary>
/// Makes sure that a window is excluded from the live preview
/// </summary>
/// <param name="hwnd">handle to the window to exclude</param>
public static void SetWindowExlusionFromLivePreview(IntPtr hwnd)
{
int renderPolicy = (int)InteropAndHelpers.DwmNCRenderingPolicy.Enabled;
InteropAndHelpers.DwmSetWindowAttribute(
hwnd,
12,
ref renderPolicy,
sizeof(int));
}
/// <summary>
/// Activates the live preview
/// </summary>
/// <param name="targetWindow">the window to show by making all other windows transparent</param>
/// <param name="windowToSpare">the window which should not be transparent but is not the target window</param>
public static void ActivateLivePreview(IntPtr targetWindow, IntPtr windowToSpare)
{
InteropAndHelpers.DwmpActivateLivePreview(
true,
targetWindow,
windowToSpare,
InteropAndHelpers.LivePreviewTrigger.Superbar,
IntPtr.Zero);
}
/// <summary>
/// Deactivates the live preview
/// </summary>
public static void DeactivateLivePreview()
{
InteropAndHelpers.DwmpActivateLivePreview(
false,
IntPtr.Zero,
IntPtr.Zero,
InteropAndHelpers.LivePreviewTrigger.AltTab,
IntPtr.Zero);
}
}
}

View file

@ -0,0 +1,103 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Wox.Plugin.WindowWalker.Components
{
/// <summary>
/// Class that represents the state of the desktops windows
/// </summary>
internal class OpenWindows
{
/// <summary>
/// Delegate handler for open windows updates
/// </summary>
public delegate void OpenWindowsUpdateHandler(object sender, SearchController.SearchResultUpdateEventArgs e);
/// <summary>
/// Event raised when there is an update to the list of open windows
/// </summary>
public event OpenWindowsUpdateHandler OnOpenWindowsUpdate;
/// <summary>
/// List of all the open windows
/// </summary>
private readonly List<Window> windows = new List<Window>();
/// <summary>
/// An instance of the class OpenWindows
/// </summary>
private static OpenWindows instance;
/// <summary>
/// Gets the list of all open windows
/// </summary>
public List<Window> Windows
{
get { return new List<Window>(windows); }
}
/// <summary>
/// Gets an instance property of this class that makes sure that
/// the first instance gets created and that all the requests
/// end up at that one instance
/// </summary>
public static OpenWindows Instance
{
get
{
if (instance == null)
{
instance = new OpenWindows();
}
return instance;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="OpenWindows"/> class.
/// Private constructor to make sure there is never
/// more than one instance of this class
/// </summary>
private OpenWindows()
{
}
/// <summary>
/// Updates the list of open windows
/// </summary>
public void UpdateOpenWindowsList()
{
windows.Clear();
InteropAndHelpers.CallBackPtr callbackptr = new InteropAndHelpers.CallBackPtr(WindowEnumerationCallBack);
InteropAndHelpers.EnumWindows(callbackptr, 0);
}
/// <summary>
/// Call back method for window enumeration
/// </summary>
/// <param name="hwnd">The handle to the current window being enumerated</param>
/// <param name="lParam">Value being passed from the caller (we don't use this but might come in handy
/// in the future</param>
/// <returns>true to make sure to contiue enumeration</returns>
public bool WindowEnumerationCallBack(IntPtr hwnd, IntPtr lParam)
{
Window newWindow = new Window(hwnd);
if (newWindow.IsWindow && newWindow.Visible && newWindow.IsOwner &&
(!newWindow.IsToolWindow || newWindow.IsAppWindow ) && !newWindow.TaskListDeleted &&
newWindow.ClassName != "Windows.UI.Core.CoreWindow")
{
windows.Add(newWindow);
}
return true;
}
}
}

View file

@ -0,0 +1,185 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Wox.Plugin.WindowWalker.Components
{
/// <summary>
/// Responsible for searching and finding matches for the strings provided.
/// Essentially the UI independent model of the application
/// </summary>
internal class SearchController
{
/// <summary>
/// the current search text
/// </summary>
private string searchText;
/// <summary>
/// Open window search results
/// </summary
private List<SearchResult> searchMatches;
/// <summary>
/// Singleton pattern
/// </summary>
private static SearchController instance;
/// <summary>
/// Delegate handler for open windows updates
/// </summary>
public delegate void SearchResultUpdateHandler(object sender, SearchResultUpdateEventArgs e);
/// <summary>
/// Event raised when there is an update to the list of open windows
/// </summary>
public event SearchResultUpdateHandler OnSearchResultUpdate;
/// <summary>
/// Gets or sets the current search text
/// </summary>
public string SearchText
{
get
{
return searchText;
}
set
{
searchText = value.ToLower().Trim();
}
}
/// <summary>
/// Gets the open window search results
/// </summary>
public List<SearchResult> SearchMatches
{
get { return new List<SearchResult>(searchMatches).OrderByDescending(x => x.Score).ToList(); }
}
/// <summary>
/// Gets singleton Pattern
/// </summary>
public static SearchController Instance
{
get
{
if (instance == null)
{
instance = new SearchController();
}
return instance;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SearchController"/> class.
/// Initializes the search controller object
/// </summary>
private SearchController()
{
searchText = string.Empty;
OpenWindows.Instance.OnOpenWindowsUpdate += OpenWindowsUpdateHandler;
}
/// <summary>
/// Event handler for when the search text has been updated
/// </summary>
public async Task UpdateSearchText(string searchText)
{
this.SearchText = searchText;
await SyncOpenWindowsWithModelAsync();
}
/// <summary>
/// Event handler called when the OpenWindows list changes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public async void OpenWindowsUpdateHandler(object sender, SearchResultUpdateEventArgs e)
{
await SyncOpenWindowsWithModelAsync();
}
/// <summary>
/// Syncs the open windows with the OpenWindows Model
/// </summary>
public async Task SyncOpenWindowsWithModelAsync()
{
System.Diagnostics.Debug.Print("Syncing WindowSearch result with OpenWindows Model");
List<Window> snapshotOfOpenWindows = OpenWindows.Instance.Windows;
if (SearchText == string.Empty)
{
searchMatches = new List<SearchResult>();
}
else
{
searchMatches = await FuzzySearchOpenWindowsAsync(snapshotOfOpenWindows);
}
OnSearchResultUpdate?.Invoke(this, new SearchResultUpdateEventArgs());
}
/// <summary>
/// Redirecting method for Fuzzy searching
/// </summary>
/// <param name="openWindows"></param>
/// <returns>Returns search results</returns>
private Task<List<SearchResult>> FuzzySearchOpenWindowsAsync(List<Window> openWindows)
{
return Task.Run(
() =>
FuzzySearchOpenWindows(openWindows));
}
/// <summary>
/// Search method that matches the title of windows with the user search text
/// </summary>
/// <param name="openWindows"></param>
/// <returns>Returns search results</returns>
private List<SearchResult> FuzzySearchOpenWindows(List<Window> openWindows)
{
List<SearchResult> result = new List<SearchResult>();
List<SearchString> searchStrings = new List<SearchString>();
searchStrings.Add(new SearchString(searchText, SearchResult.SearchType.Fuzzy));
foreach (var searchString in searchStrings)
{
foreach (var window in openWindows)
{
var titleMatch = FuzzyMatching.FindBestFuzzyMatch(window.Title, searchString.SearchText);
var processMatch = FuzzyMatching.FindBestFuzzyMatch(window.ProcessName, searchString.SearchText);
if ((titleMatch.Count != 0 || processMatch.Count != 0) &&
window.Title.Length != 0)
{
var temp = new SearchResult(window, titleMatch, processMatch, searchString.SearchType);
result.Add(temp);
}
}
}
System.Diagnostics.Debug.Print("Found " + result.Count + " windows that match the search text");
return result;
}
/// <summary>
/// Event args for a window list update event
/// </summary>
public class SearchResultUpdateEventArgs : EventArgs
{
}
}
}

View file

@ -0,0 +1,135 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
using System.Collections.Generic;
namespace Wox.Plugin.WindowWalker.Components
{
/// <summary>
/// Contains search result windows with each window including the reason why the result was included
/// </summary>
public class SearchResult
{
/// <summary>
/// Gets the actual window reference for the search result
/// </summary>
public Window Result
{
get;
private set;
}
/// <summary>
/// Gets the list of indexes of the matching characters for the search in the title window
/// </summary>
public List<int> SearchMatchesInTitle
{
get;
private set;
}
/// <summary>
/// Gets the list of indexes of the matching characters for the search in the
/// name of the process
/// </summary>
public List<int> SearchMatchesInProcessName
{
get;
private set;
}
/// <summary>
/// Gets the type of match (shortcut, fuzzy or nothing)
/// </summary>
public SearchType SearchResultMatchType
{
get;
private set;
}
/// <summary>
/// Gets a score indicating how well this matches what we are looking for
/// </summary>
public int Score
{
get;
private set;
}
/// <summary>
/// Gets the source of where the best score was found
/// </summary>
public TextType BestScoreSource
{
get;
private set;
}
/// <summary>
/// Initializes a new instance of the <see cref="SearchResult"/> class.
/// Constructor
/// </summary>
public SearchResult(Window window, List<int> matchesInTitle, List<int> matchesInProcessName, SearchType matchType)
{
Result = window;
SearchMatchesInTitle = matchesInTitle;
SearchMatchesInProcessName = matchesInProcessName;
SearchResultMatchType = matchType;
CalculateScore();
}
/// <summary>
/// Calculates the score for how closely this window matches the search string
/// </summary>
/// <remarks>
/// Higher Score is better
/// </remarks>
private void CalculateScore()
{
if (FuzzyMatching.CalculateScoreForMatches(SearchMatchesInProcessName) >
FuzzyMatching.CalculateScoreForMatches(SearchMatchesInTitle))
{
Score = FuzzyMatching.CalculateScoreForMatches(SearchMatchesInProcessName);
BestScoreSource = TextType.ProcessName;
}
else
{
Score = FuzzyMatching.CalculateScoreForMatches(SearchMatchesInTitle);
BestScoreSource = TextType.WindowTitle;
}
}
/// <summary>
/// The type of text that a string represents
/// </summary>
public enum TextType
{
ProcessName,
WindowTitle,
}
/// <summary>
/// The type of search
/// </summary>
public enum SearchType
{
/// <summary>
/// the search string is empty, which means all open windows are
/// going to be returned
/// </summary>
Empty,
/// <summary>
/// Regular fuzzy match search
/// </summary>
Fuzzy,
/// <summary>
/// The user has entered text that has been matched to a shortcut
/// and the shortcut is now being searched
/// </summary>
Shortcut,
}
}
}

View file

@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
namespace Wox.Plugin.WindowWalker.Components
{
/// <summary>
/// A class to represent a search string
/// </summary>
/// <remarks>Class was added inorder to be able to attach various context data to
/// a search string</remarks>
internal class SearchString
{
/// <summary>
/// Gets where is the search string coming from (is it a shortcut
/// or direct string, etc...)
/// </summary>
public SearchResult.SearchType SearchType
{
get;
private set;
}
/// <summary>
/// Gets the actual text we are searching for
/// </summary>
public string SearchText
{
get;
private set;
}
/// <summary>
/// Initializes a new instance of the <see cref="SearchString"/> class.
/// Constructor
/// </summary>
/// <param name="searchText"></param>
/// <param name="searchType"></param>
public SearchString(string searchText, SearchResult.SearchType searchType)
{
SearchText = searchText;
SearchType = searchType;
}
}
}

View file

@ -0,0 +1,401 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Wox.Plugin.WindowWalker.Components
{
/// <summary>
/// Represents a specific open window
/// </summary>
public class Window
{
/// <summary>
/// Maximum size of a file name
/// </summary>
private const int MaximumFileNameLength = 1000;
/// <summary>
/// The list of owners of a window so that we don't have to
/// constantly query for the process owning a specific window
/// </summary>
private static readonly Dictionary<IntPtr, string> _handlesToProcessCache = new Dictionary<IntPtr, string>();
/// <summary>
/// The list of icons from process so that we don't have to keep
/// loading them from disk
/// </summary>
private static readonly Dictionary<uint, ImageSource> _processIdsToIconsCache = new Dictionary<uint, ImageSource>();
/// <summary>
/// The handle to the window
/// </summary>
private readonly IntPtr hwnd;
/// <summary>
/// Gets the title of the window (the string displayed at the top of the window)
/// </summary>
public string Title
{
get
{
int sizeOfTitle = InteropAndHelpers.GetWindowTextLength(hwnd);
if (sizeOfTitle++ > 0)
{
StringBuilder titleBuffer = new StringBuilder(sizeOfTitle);
InteropAndHelpers.GetWindowText(hwnd, titleBuffer, sizeOfTitle);
return titleBuffer.ToString();
}
else
{
return string.Empty;
}
}
}
/// <summary>
/// Gets the handle to the window
/// </summary>
public IntPtr Hwnd
{
get { return hwnd; }
}
public uint ProcessID { get; set; }
/// <summary>
/// Gets returns the name of the process
/// </summary>
public string ProcessName
{
get
{
lock (_handlesToProcessCache)
{
if (_handlesToProcessCache.Count > 7000)
{
Debug.Print("Clearing Process Cache because it's size is " + _handlesToProcessCache.Count);
_handlesToProcessCache.Clear();
}
if (!_handlesToProcessCache.ContainsKey(Hwnd))
{
var processName = GetProcessNameFromWindowHandle(Hwnd);
if (processName.Length != 0)
{
_handlesToProcessCache.Add(
Hwnd,
processName.ToString().Split('\\').Reverse().ToArray()[0]);
}
else
{
_handlesToProcessCache.Add(Hwnd, string.Empty);
}
}
if (_handlesToProcessCache[hwnd].ToLower() == "applicationframehost.exe")
{
new Task(() =>
{
InteropAndHelpers.CallBackPtr callbackptr = new InteropAndHelpers.CallBackPtr((IntPtr hwnd, IntPtr lParam) =>
{
var childProcessId = GetProcessIDFromWindowHandle(hwnd);
if (childProcessId != this.ProcessID)
{
_handlesToProcessCache[Hwnd] = GetProcessNameFromWindowHandle(hwnd);
return false;
}
else
{
return true;
}
});
InteropAndHelpers.EnumChildWindows(Hwnd, callbackptr, 0);
}).Start();
}
return _handlesToProcessCache[hwnd];
}
}
}
/// <summary>
/// Gets returns the name of the class for the window represented
/// </summary>
public string ClassName
{
get
{
StringBuilder windowClassName = new StringBuilder(300);
InteropAndHelpers.GetClassName(Hwnd, windowClassName, windowClassName.MaxCapacity);
return windowClassName.ToString();
}
}
/// <summary>
/// Gets represents the Window Icon for the specified window
/// </summary>
public ImageSource WindowIcon
{
get
{
lock (_processIdsToIconsCache)
{
InteropAndHelpers.GetWindowThreadProcessId(Hwnd, out uint processId);
if (!_processIdsToIconsCache.ContainsKey(processId))
{
try
{
Process process = Process.GetProcessById((int)processId);
Icon tempIcon = Icon.ExtractAssociatedIcon(process.Modules[0].FileName);
_processIdsToIconsCache.Add(processId, Imaging.CreateBitmapSourceFromHIcon(
tempIcon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions()));
}
catch
{
BitmapImage failedImage = new BitmapImage(new Uri(@"Images\failedIcon.jpg", UriKind.Relative));
_processIdsToIconsCache.Add(processId, failedImage);
}
}
return _processIdsToIconsCache[processId];
}
}
}
/// <summary>
/// Gets a value indicating whether is the window visible (might return false if it is a hidden IE tab)
/// </summary>
public bool Visible
{
get
{
return InteropAndHelpers.IsWindowVisible(Hwnd);
}
}
/// <summary>
/// Determines whether the specified window handle identifies an existing window.
/// </summary>
public bool IsWindow
{
get
{
return InteropAndHelpers.IsWindow(Hwnd);
}
}
/// <summary>
/// Get a value indicating whether is the window GWL_EX_STYLE is a toolwindow
/// </summary>
public bool IsToolWindow
{
get
{
return (InteropAndHelpers.GetWindowLong(Hwnd, InteropAndHelpers.GWL_EXSTYLE) &
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_TOOLWINDOW) ==
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_TOOLWINDOW;
}
}
/// <summary>
/// Get a value indicating whether the window GWL_EX_STYLE is an appwindow
/// </summary>
public bool IsAppWindow
{
get
{
return (InteropAndHelpers.GetWindowLong(Hwnd, InteropAndHelpers.GWL_EXSTYLE) &
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_APPWINDOW) ==
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_APPWINDOW;
}
}
/// <summary>
/// Get a value indicating whether the window has ITaskList_Deleted property
/// </summary>
public bool TaskListDeleted
{
get
{
return InteropAndHelpers.GetProp(Hwnd, "ITaskList_Deleted") != IntPtr.Zero;
}
}
/// <summary>
/// Get a value indicating whether the app is a cloaked UWP app
/// </summary>
public bool IsUWPCloaked
{
get
{
return (this.IsWindowCloaked() && this.ClassName == "ApplicationFrameWindow");
}
}
/// <summary>
/// Determines whether the specified windows is the owner
/// </summary>
public bool IsOwner
{
get
{
return InteropAndHelpers.GetWindow(Hwnd, InteropAndHelpers.GetWindowCmd.GW_OWNER) != null;
}
}
/// <summary>
/// Gets a value indicating whether is the window cloaked. To detect UWP apps in background or win32 apps running in another virtual desktop
/// </summary>
public bool IsWindowCloaked()
{
int isCloaked = 0;
const int DWMWA_CLOAKED = 14;
InteropAndHelpers.DwmGetWindowAttribute(this.hwnd, DWMWA_CLOAKED, out isCloaked, sizeof(int));
return isCloaked != 0;
}
/// <summary>
/// Gets a value indicating whether returns true if the window is minimized
/// </summary>
public bool Minimized
{
get
{
return GetWindowSizeState() == WindowSizeState.Minimized;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="Window"/> class.
/// Initializes a new Window representation
/// </summary>
/// <param name="hwnd">the handle to the window we are representing</param>
public Window(IntPtr hwnd)
{
// TODO: Add verification as to whether the window handle is valid
this.hwnd = hwnd;
}
/// <summary>
/// Highlights a window to help the user identify the window that has been selected
/// </summary>
public void HighlightWindow()
{
throw new NotImplementedException();
}
/// <summary>
/// Switches dekstop focus to the window
/// </summary>
public void SwitchToWindow()
{
// The following block is necessary because
// 1) There is a weird flashing behaviour when trying
// to use ShowWindow for switching tabs in IE
// 2) SetForegroundWindow fails on minimized windows
if (ProcessName.ToLower().Equals("iexplore.exe") || !Minimized)
{
InteropAndHelpers.SetForegroundWindow(Hwnd);
}
else
{
InteropAndHelpers.ShowWindow(Hwnd, InteropAndHelpers.ShowWindowCommands.Restore);
}
InteropAndHelpers.FlashWindow(Hwnd, true);
}
/// <summary>
/// Converts the window name to string along with the process name
/// </summary>
/// <returns>The title of the window</returns>
public override string ToString()
{
return Title + " (" + ProcessName.ToUpper() + ")";
}
/// <summary>
/// Returns what the window size is
/// </summary>
/// <returns>The state (minimized, maximized, etc..) of the window</returns>
public WindowSizeState GetWindowSizeState()
{
InteropAndHelpers.GetWindowPlacement(Hwnd, out InteropAndHelpers.WINDOWPLACEMENT placement);
switch (placement.ShowCmd)
{
case InteropAndHelpers.ShowWindowCommands.Normal:
return WindowSizeState.Normal;
case InteropAndHelpers.ShowWindowCommands.Minimize:
case InteropAndHelpers.ShowWindowCommands.ShowMinimized:
return WindowSizeState.Minimized;
case InteropAndHelpers.ShowWindowCommands.Maximize: // No need for ShowMaximized here since its also of value 3
return WindowSizeState.Maximized;
default:
// throw new Exception("Don't know how to handle window state = " + placement.ShowCmd);
return WindowSizeState.Unknown;
}
}
/// <summary>
/// Enum to simplify the state of the window
/// </summary>
public enum WindowSizeState
{
Normal,
Minimized,
Maximized,
Unknown,
}
/// <summary>
/// Gets the name of the process using the window handle
/// </summary>
/// <param name="hwnd">The handle to the window</param>
/// <returns>A string representing the process name or an empty string if the function fails</returns>
private string GetProcessNameFromWindowHandle(IntPtr hwnd)
{
uint processId = GetProcessIDFromWindowHandle(hwnd);
ProcessID = processId;
IntPtr processHandle = InteropAndHelpers.OpenProcess(InteropAndHelpers.ProcessAccessFlags.AllAccess, true, (int)processId);
StringBuilder processName = new StringBuilder(MaximumFileNameLength);
if (InteropAndHelpers.GetProcessImageFileName(processHandle, processName, MaximumFileNameLength) != 0)
{
return processName.ToString().Split('\\').Reverse().ToArray()[0];
}
else
{
return string.Empty;
}
}
/// <summary>
/// Gets the process ID for the Window handle
/// </summary>
/// <param name="hwnd">The handle to the window</param>
/// <returns>The process ID</returns>
private uint GetProcessIDFromWindowHandle(IntPtr hwnd)
{
InteropAndHelpers.GetWindowThreadProcessId(hwnd, out uint processId);
return processId;
}
}
}

View file

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Wox.Plugin.WindowWalker.Components
{
class WindowResult:Window
{
/// <summary>
/// Number of letters in between constant for when
/// the result hasn't been set yet
/// </summary>
public const int NoResult = -1;
/// <summary>
/// Properties that signify how many characters (including spaces)
/// were found when matching the results
/// </summary>
public int LettersInBetweenScore
{
get;
set;
}
/// <summary>
/// Constructor for WindowResult
/// </summary>
public WindowResult(Window window):base(window.Hwnd)
{
LettersInBetweenScore = WindowResult.NoResult;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

View file

@ -0,0 +1,7 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="wox_plugin_windowwalker_plugin_name">Window Walker</system:String>
<system:String x:Key="wox_plugin_windowwalker_plugin_description">Alt-Tab alternative enabling searching through your windows.</system:String>
</ResourceDictionary>

View file

@ -0,0 +1,57 @@
using System.Collections.Generic;
using System.Linq;
using Wox.Plugin.WindowWalker.Components;
namespace Wox.Plugin.WindowWalker
{
public class Main : IPlugin, IPluginI18n
{
private static List<SearchResult> _results = new List<SearchResult>();
private static string IcoPath = "Images/windowwalker.png";
private PluginInitContext Context { get; set; }
static Main()
{
SearchController.Instance.OnSearchResultUpdate += SearchResultUpdated;
OpenWindows.Instance.UpdateOpenWindowsList();
}
public List<Result> Query(Query query)
{
SearchController.Instance.UpdateSearchText(query.RawQuery).Wait();
OpenWindows.Instance.UpdateOpenWindowsList();
return _results.Select(x => new Result()
{
Title = x.Result.Title,
IcoPath = IcoPath,
SubTitle = x.Result.ProcessName,
Action = c =>
{
x.Result.SwitchToWindow();
return true;
}
}
).ToList();
}
public void Init(PluginInitContext context)
{
Context = context;
}
public string GetTranslatedPluginTitle()
{
return Context.API.GetTranslation("wox_plugin_windowwalker_plugin_name");
}
public string GetTranslatedPluginDescription()
{
return Context.API.GetTranslation("wox_plugin_windowwalker_plugin_description");
}
private static void SearchResultUpdated(object sender, SearchController.SearchResultUpdateEventArgs e)
{
_results = SearchController.Instance.SearchMatches;
}
}
}

View file

@ -0,0 +1,71 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<ProjectGuid>{74F1B9ED-F59C-4FE7-B473-7B453E30837E}</ProjectGuid>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Wox.Plugin.WindowWalker</RootNamespace>
<AssemblyName>Wox.Plugin.WindowWalker</AssemblyName>
<useWPF>true</useWPF>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<Platforms>x64</Platforms>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Wox.Plugin.WindowWalker\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<WarningLevel>4</WarningLevel>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Wox.Plugin.WindowWalker\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<None Include="plugin.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Wox.Infrastructure\Wox.Infrastructure.csproj" />
<ProjectReference Include="..\..\Wox.Plugin\Wox.Plugin.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="Images\windowwalker.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Content Include="Languages\en.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
<PackageReference Include="Mages" Version="1.6.0" />
<PackageReference Include="System.Runtime" Version="4.3.1" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,12 @@
{
"ID":"CEA0FDFC6D3B4085823D60DC76F28855",
"ActionKeyword":"*",
"Name":"Window Walker",
"Description":"Alt-Tab alternative enabling searching through your windows.",
"Author":"betadele",
"Version":"1.0.0",
"Language":"csharp",
"Website":"http://www.windowwalker.com/",
"ExecuteFileName":"Wox.Plugin.WindowWalker.dll",
"IcoPath":"Images\\windowwalker.png"
}