Skip to content

Commit

Permalink
Add following window during move to window.
Browse files Browse the repository at this point in the history
  • Loading branch information
widavies committed Feb 7, 2024
1 parent 8af388c commit da392d5
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 18 deletions.
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,23 @@ Below is an example configuration file that changes the shortcut to `alt+N` to j
"move-window-to": [
{
"shortcut": "alt+shift+d1",
"desktop": 1
"desktop": 1,
"follow": false
},
{
"shortcut": "alt+shift+d2",
"desktop": 2
"desktop": 2,
"follow": false
},
{
"shortcut": "alt+shift+d3",
"desktop": 3
"desktop": 3,
"follow": false
},
{
"shortcut": "alt+shift+d4",
"desktop": 4
"desktop": 4,
"follow": false
}
],
"change-desktops-with-scroll": false,
Expand Down
5 changes: 4 additions & 1 deletion WinJump/Core/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ private static Config Default() {
Keys = x.Shortcut.Keys,
ModifierKeys = x.Shortcut.ModifierKeys | ModifierKeys.Shift
},
Desktop = x.Desktop
Desktop = x.Desktop,
Follow = false
}).ToList(),
JumpTo = jumpTo,
ToggleGroups = [],
Expand All @@ -137,6 +138,8 @@ public sealed class JumpWindowToDesktop {
public required Shortcut Shortcut { get; set; }

public required uint Desktop { get; set; }

public required bool Follow { get; set; }
}

public sealed class ToggleGroup {
Expand Down
20 changes: 10 additions & 10 deletions WinJump/Core/VirtualDesktopDefinitions/Windows11_22000.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public void JumpToDesktop(int index) {
}

public void MoveFocusedWindowToDesktop(int index) {
throw new NotImplementedException();
DesktopManager.MoveCurrentlyFocusedToDesktop(index);
}

public void Dispose() {
Expand All @@ -42,12 +42,12 @@ internal static class DesktopManager {

[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

private static IVirtualDesktopManagerInternal VirtualDesktopManagerInternal;
internal static IVirtualDesktopNotificationService VirtualDesktopNotificationService;
internal static IApplicationViewCollection ApplicationViewCollection;
internal static IVirtualDesktopManager VirtualDesktopManager;

static DesktopManager() {
if(Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_ImmersiveShell) ??
throw new Exception("Failed to get shell")) is not IServiceProvider10
Expand Down Expand Up @@ -109,15 +109,15 @@ internal static int GetCurrentDesktopNum() {

return GetIndex(vd);
}

internal static void MoveCurrentlyFocusedToDesktop(int index) {
int processId;
IntPtr hWnd = GetForegroundWindow();
if(hWnd == IntPtr.Zero) throw new ArgumentNullException();
GetWindowThreadProcessId(hWnd, out processId);

var desktop = GetDesktop(index);

if(Environment.ProcessId == processId) {
// window of process
try // the easy way (if we are owner)
Expand Down Expand Up @@ -192,8 +192,8 @@ internal static class Guids {
public static readonly Guid CLSID_VirtualDesktopManagerInternal =
new("C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B");

public static readonly Guid CLSID_VirtualDesktopManager = new("AA509086-5CA9-4C25-8F95-589D3C07B48A");
public static readonly Guid CLSID_VirtualDesktopManager = new("AA509086-5CA9-4C25-8F95-589D3C07B48A");

public static readonly Guid CLSID_VirtualDesktopNotificationService =
new("A501FDEC-4A09-464C-AE4E-1B9C21B84918");
}
Expand Down Expand Up @@ -286,7 +286,7 @@ internal interface IApplicationView {
int Unknown11(int unknown);
int Unknown12(out Size size1);
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("1841C6D7-4F9D-42C0-AF41-8747538F10E5")]
Expand All @@ -303,7 +303,7 @@ internal interface IApplicationViewCollection {
int RegisterForApplicationViewChanges(object listener, out int cookie);
int UnregisterForApplicationViewChanges(int cookie);
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("536D3495-B208-4CC9-AE26-DE8111275BF8")]
Expand Down Expand Up @@ -357,7 +357,7 @@ internal interface IVirtualDesktopManager {
Guid GetWindowDesktopId(IntPtr topLevelWindow);
void MoveWindowToDesktop(IntPtr topLevelWindow, ref Guid desktopId);
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("0CD45E71-D927-4F15-8B0A-8FEF525337BF")]
Expand Down
75 changes: 75 additions & 0 deletions WinJump/Core/VirtualDesktopDefinitions/Windows11_22621_2215.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public void JumpToDesktop(int index) {
}

public void MoveFocusedWindowToDesktop(int index) {
DesktopManager.MoveCurrentlyFocusedToDesktop(index);
}

public void Dispose() {
Expand All @@ -35,8 +36,17 @@ public void Dispose() {
*/

internal static class DesktopManager {
// get handle of active window
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

private static IVirtualDesktopManagerInternal VirtualDesktopManagerInternal;
internal static IVirtualDesktopNotificationService VirtualDesktopNotificationService;
internal static IApplicationViewCollection ApplicationViewCollection;
internal static IVirtualDesktopManager VirtualDesktopManager;

static DesktopManager() {
if(Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_ImmersiveShell) ??
Expand All @@ -49,6 +59,11 @@ static DesktopManager() {
Guids.CLSID_VirtualDesktopManagerInternal, typeof(IVirtualDesktopManagerInternal).GUID);
VirtualDesktopNotificationService = (IVirtualDesktopNotificationService) shell.QueryService(
Guids.CLSID_VirtualDesktopNotificationService, typeof(IVirtualDesktopNotificationService).GUID);
VirtualDesktopManager =
(IVirtualDesktopManager) Activator.CreateInstance(
Type.GetTypeFromCLSID(Guids.CLSID_VirtualDesktopManager));
ApplicationViewCollection = (IApplicationViewCollection) shell.QueryService(
typeof(IApplicationViewCollection).GUID, typeof(IApplicationViewCollection).GUID);
}

// Helpers
Expand Down Expand Up @@ -94,6 +109,39 @@ internal static int GetCurrentDesktopNum() {

return GetIndex(vd);
}

internal static void MoveCurrentlyFocusedToDesktop(int index) {
int processId;
IntPtr hWnd = GetForegroundWindow();
if(hWnd == IntPtr.Zero) throw new ArgumentNullException();
GetWindowThreadProcessId(hWnd, out processId);

var desktop = GetDesktop(index);

if(Environment.ProcessId == processId) {
// window of process
try // the easy way (if we are owner)
{
VirtualDesktopManager.MoveWindowToDesktop(hWnd, desktop.GetId());
} catch // window of process, but we are not the owner
{
IApplicationView view;
ApplicationViewCollection.GetViewForHwnd(hWnd, out view);
VirtualDesktopManagerInternal.MoveViewToDesktop(view, desktop);
}
} else {
// window of other process
ApplicationViewCollection.GetViewForHwnd(hWnd, out var view);
try {
VirtualDesktopManagerInternal.MoveViewToDesktop(view, desktop);
} catch {
// could not move active window, try main window (or whatever windows thinks is the main window)
ApplicationViewCollection.GetViewForHwnd(
System.Diagnostics.Process.GetProcessById(processId).MainWindowHandle, out view);
VirtualDesktopManagerInternal.MoveViewToDesktop(view, desktop);
}
}
}
}

internal class VirtualDesktopNotification : IVirtualDesktopNotification {
Expand Down Expand Up @@ -144,6 +192,8 @@ internal static class Guids {
public static readonly Guid CLSID_VirtualDesktopManagerInternal =
new("C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B");

public static readonly Guid CLSID_VirtualDesktopManager = new("AA509086-5CA9-4C25-8F95-589D3C07B48A");

public static readonly Guid CLSID_VirtualDesktopNotificationService =
new("A501FDEC-4A09-464C-AE4E-1B9C21B84918");
}
Expand Down Expand Up @@ -328,6 +378,31 @@ void VirtualDesktopWallpaperChanged(IVirtualDesktop pDesktop,
void RemoteVirtualDesktopConnected(IVirtualDesktop pDesktop);
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("A5CD92FF-29BE-454C-8D04-D82879FB3F1B")]
internal interface IVirtualDesktopManager {
bool IsWindowOnCurrentVirtualDesktop(IntPtr topLevelWindow);
Guid GetWindowDesktopId(IntPtr topLevelWindow);
void MoveWindowToDesktop(IntPtr topLevelWindow, ref Guid desktopId);
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("1841C6D7-4F9D-42C0-AF41-8747538F10E5")]
internal interface IApplicationViewCollection {
int GetViews(out IObjectArray array);
int GetViewsByZOrder(out IObjectArray array);
int GetViewsByAppUserModelId(string id, out IObjectArray array);
int GetViewForHwnd(IntPtr hwnd, out IApplicationView view);
int GetViewForApplication(object application, out IApplicationView view);
int GetViewForAppUserModelId(string id, out IApplicationView view);
int GetViewInFocus(out IntPtr view);
int Unknown1(out IntPtr view);
void RefreshCollection();
int RegisterForApplicationViewChanges(object listener, out int cookie);
int UnregisterForApplicationViewChanges(int cookie);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("92CA9DCD-5622-4BBA-A805-5E9F541BD8C9")]
Expand Down
76 changes: 76 additions & 0 deletions WinJump/Core/VirtualDesktopDefinitions/Windows11_22631_3085.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public void JumpToDesktop(int index) {
}

public void MoveFocusedWindowToDesktop(int index) {
DesktopManager.MoveCurrentlyFocusedToDesktop(index);
}

public void Dispose() {
Expand All @@ -35,8 +36,17 @@ public void Dispose() {
*/

internal static class DesktopManager {
// get handle of active window
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

private static IVirtualDesktopManagerInternal VirtualDesktopManagerInternal;
internal static IVirtualDesktopNotificationService VirtualDesktopNotificationService;
internal static IApplicationViewCollection ApplicationViewCollection;
internal static IVirtualDesktopManager VirtualDesktopManager;

static DesktopManager() {
if(Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_ImmersiveShell) ??
Expand All @@ -49,6 +59,11 @@ static DesktopManager() {
Guids.CLSID_VirtualDesktopManagerInternal, typeof(IVirtualDesktopManagerInternal).GUID);
VirtualDesktopNotificationService = (IVirtualDesktopNotificationService) shell.QueryService(
Guids.CLSID_VirtualDesktopNotificationService, typeof(IVirtualDesktopNotificationService).GUID);
VirtualDesktopManager =
(IVirtualDesktopManager) Activator.CreateInstance(
Type.GetTypeFromCLSID(Guids.CLSID_VirtualDesktopManager));
ApplicationViewCollection = (IApplicationViewCollection) shell.QueryService(
typeof(IApplicationViewCollection).GUID, typeof(IApplicationViewCollection).GUID);
}

// Helpers
Expand Down Expand Up @@ -94,6 +109,39 @@ internal static int GetCurrentDesktopNum() {

return GetIndex(vd);
}

internal static void MoveCurrentlyFocusedToDesktop(int index) {
int processId;
IntPtr hWnd = GetForegroundWindow();
if(hWnd == IntPtr.Zero) throw new ArgumentNullException();
GetWindowThreadProcessId(hWnd, out processId);

var desktop = GetDesktop(index);

if(Environment.ProcessId == processId) {
// window of process
try // the easy way (if we are owner)
{
VirtualDesktopManager.MoveWindowToDesktop(hWnd, desktop.GetId());
} catch // window of process, but we are not the owner
{
IApplicationView view;
ApplicationViewCollection.GetViewForHwnd(hWnd, out view);
VirtualDesktopManagerInternal.MoveViewToDesktop(view, desktop);
}
} else {
// window of other process
ApplicationViewCollection.GetViewForHwnd(hWnd, out var view);
try {
VirtualDesktopManagerInternal.MoveViewToDesktop(view, desktop);
} catch {
// could not move active window, try main window (or whatever windows thinks is the main window)
ApplicationViewCollection.GetViewForHwnd(
System.Diagnostics.Process.GetProcessById(processId).MainWindowHandle, out view);
VirtualDesktopManagerInternal.MoveViewToDesktop(view, desktop);
}
}
}
}

internal class VirtualDesktopNotification : IVirtualDesktopNotification {
Expand Down Expand Up @@ -141,6 +189,8 @@ public void RemoteVirtualDesktopConnected(IVirtualDesktop pDesktop) {
internal static class Guids {
public static readonly Guid CLSID_ImmersiveShell = new("C2F03A33-21F5-47FA-B4BB-156362A2F239");

public static readonly Guid CLSID_VirtualDesktopManager = new("AA509086-5CA9-4C25-8F95-589D3C07B48A");

public static readonly Guid CLSID_VirtualDesktopManagerInternal =
new("C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B");

Expand Down Expand Up @@ -288,6 +338,32 @@ void GetDesktopSwitchIncludeExcludeViews(IVirtualDesktop desktop, out IObjectArr
void WaitForAnimationToComplete();
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("1841C6D7-4F9D-42C0-AF41-8747538F10E5")]
internal interface IApplicationViewCollection {
int GetViews(out IObjectArray array);
int GetViewsByZOrder(out IObjectArray array);
int GetViewsByAppUserModelId(string id, out IObjectArray array);
int GetViewForHwnd(IntPtr hwnd, out IApplicationView view);
int GetViewForApplication(object application, out IApplicationView view);
int GetViewForAppUserModelId(string id, out IApplicationView view);
int GetViewInFocus(out IntPtr view);
int Unknown1(out IntPtr view);
void RefreshCollection();
int RegisterForApplicationViewChanges(object listener, out int cookie);
int UnregisterForApplicationViewChanges(int cookie);
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("A5CD92FF-29BE-454C-8D04-D82879FB3F1B")]
internal interface IVirtualDesktopManager {
bool IsWindowOnCurrentVirtualDesktop(IntPtr topLevelWindow);
Guid GetWindowDesktopId(IntPtr topLevelWindow);
void MoveWindowToDesktop(IntPtr topLevelWindow, ref Guid desktopId);
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("0CD45E71-D927-4F15-8B0A-8FEF525337BF")]
Expand Down
4 changes: 4 additions & 0 deletions WinJump/Core/WinJumpManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ public WinJumpManager(DesktopChanged desktopChanged) {
if(moveTo != null) {
// Move the current window to the specified desktop
_thread?.MoveWindowToDesktop(moveTo.Desktop - 1);
if(moveTo.Follow) {
_thread?.JumpTo(moveTo.Desktop - 1);
}
}
// Finally, look for a toggle group
Expand Down
6 changes: 3 additions & 3 deletions WinJump/WinJump.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<Version>2.0.12</Version>
<AssemblyVersion>2.0.12</AssemblyVersion>
<FileVersion>2.0.12</FileVersion>
<Version>2.0.13</Version>
<AssemblyVersion>2.0.13</AssemblyVersion>
<FileVersion>2.0.13</FileVersion>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
Expand Down

0 comments on commit da392d5

Please sign in to comment.