Skip to content

Commit da392d5

Browse files
committed
Add following window during move to window.
1 parent 8af388c commit da392d5

File tree

7 files changed

+180
-18
lines changed

7 files changed

+180
-18
lines changed

README.md

+8-4
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,23 @@ Below is an example configuration file that changes the shortcut to `alt+N` to j
6565
"move-window-to": [
6666
{
6767
"shortcut": "alt+shift+d1",
68-
"desktop": 1
68+
"desktop": 1,
69+
"follow": false
6970
},
7071
{
7172
"shortcut": "alt+shift+d2",
72-
"desktop": 2
73+
"desktop": 2,
74+
"follow": false
7375
},
7476
{
7577
"shortcut": "alt+shift+d3",
76-
"desktop": 3
78+
"desktop": 3,
79+
"follow": false
7780
},
7881
{
7982
"shortcut": "alt+shift+d4",
80-
"desktop": 4
83+
"desktop": 4,
84+
"follow": false
8185
}
8286
],
8387
"change-desktops-with-scroll": false,

WinJump/Core/Config.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ private static Config Default() {
122122
Keys = x.Shortcut.Keys,
123123
ModifierKeys = x.Shortcut.ModifierKeys | ModifierKeys.Shift
124124
},
125-
Desktop = x.Desktop
125+
Desktop = x.Desktop,
126+
Follow = false
126127
}).ToList(),
127128
JumpTo = jumpTo,
128129
ToggleGroups = [],
@@ -137,6 +138,8 @@ public sealed class JumpWindowToDesktop {
137138
public required Shortcut Shortcut { get; set; }
138139

139140
public required uint Desktop { get; set; }
141+
142+
public required bool Follow { get; set; }
140143
}
141144

142145
public sealed class ToggleGroup {

WinJump/Core/VirtualDesktopDefinitions/Windows11_22000.cs

+10-10
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public void JumpToDesktop(int index) {
2222
}
2323

2424
public void MoveFocusedWindowToDesktop(int index) {
25-
throw new NotImplementedException();
25+
DesktopManager.MoveCurrentlyFocusedToDesktop(index);
2626
}
2727

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

4343
[DllImport("user32.dll")]
4444
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
45-
45+
4646
private static IVirtualDesktopManagerInternal VirtualDesktopManagerInternal;
4747
internal static IVirtualDesktopNotificationService VirtualDesktopNotificationService;
4848
internal static IApplicationViewCollection ApplicationViewCollection;
4949
internal static IVirtualDesktopManager VirtualDesktopManager;
50-
50+
5151
static DesktopManager() {
5252
if(Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_ImmersiveShell) ??
5353
throw new Exception("Failed to get shell")) is not IServiceProvider10
@@ -109,15 +109,15 @@ internal static int GetCurrentDesktopNum() {
109109

110110
return GetIndex(vd);
111111
}
112-
112+
113113
internal static void MoveCurrentlyFocusedToDesktop(int index) {
114114
int processId;
115115
IntPtr hWnd = GetForegroundWindow();
116116
if(hWnd == IntPtr.Zero) throw new ArgumentNullException();
117117
GetWindowThreadProcessId(hWnd, out processId);
118118

119119
var desktop = GetDesktop(index);
120-
120+
121121
if(Environment.ProcessId == processId) {
122122
// window of process
123123
try // the easy way (if we are owner)
@@ -192,8 +192,8 @@ internal static class Guids {
192192
public static readonly Guid CLSID_VirtualDesktopManagerInternal =
193193
new("C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B");
194194

195-
public static readonly Guid CLSID_VirtualDesktopManager = new("AA509086-5CA9-4C25-8F95-589D3C07B48A");
196-
195+
public static readonly Guid CLSID_VirtualDesktopManager = new("AA509086-5CA9-4C25-8F95-589D3C07B48A");
196+
197197
public static readonly Guid CLSID_VirtualDesktopNotificationService =
198198
new("A501FDEC-4A09-464C-AE4E-1B9C21B84918");
199199
}
@@ -286,7 +286,7 @@ internal interface IApplicationView {
286286
int Unknown11(int unknown);
287287
int Unknown12(out Size size1);
288288
}
289-
289+
290290
[ComImport]
291291
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
292292
[Guid("1841C6D7-4F9D-42C0-AF41-8747538F10E5")]
@@ -303,7 +303,7 @@ internal interface IApplicationViewCollection {
303303
int RegisterForApplicationViewChanges(object listener, out int cookie);
304304
int UnregisterForApplicationViewChanges(int cookie);
305305
}
306-
306+
307307
[ComImport]
308308
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
309309
[Guid("536D3495-B208-4CC9-AE26-DE8111275BF8")]
@@ -357,7 +357,7 @@ internal interface IVirtualDesktopManager {
357357
Guid GetWindowDesktopId(IntPtr topLevelWindow);
358358
void MoveWindowToDesktop(IntPtr topLevelWindow, ref Guid desktopId);
359359
}
360-
360+
361361
[ComImport]
362362
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
363363
[Guid("0CD45E71-D927-4F15-8B0A-8FEF525337BF")]

WinJump/Core/VirtualDesktopDefinitions/Windows11_22621_2215.cs

+75
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public void JumpToDesktop(int index) {
2222
}
2323

2424
public void MoveFocusedWindowToDesktop(int index) {
25+
DesktopManager.MoveCurrentlyFocusedToDesktop(index);
2526
}
2627

2728
public void Dispose() {
@@ -35,8 +36,17 @@ public void Dispose() {
3536
*/
3637

3738
internal static class DesktopManager {
39+
// get handle of active window
40+
[DllImport("user32.dll")]
41+
private static extern IntPtr GetForegroundWindow();
42+
43+
[DllImport("user32.dll")]
44+
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
45+
3846
private static IVirtualDesktopManagerInternal VirtualDesktopManagerInternal;
3947
internal static IVirtualDesktopNotificationService VirtualDesktopNotificationService;
48+
internal static IApplicationViewCollection ApplicationViewCollection;
49+
internal static IVirtualDesktopManager VirtualDesktopManager;
4050

4151
static DesktopManager() {
4252
if(Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_ImmersiveShell) ??
@@ -49,6 +59,11 @@ static DesktopManager() {
4959
Guids.CLSID_VirtualDesktopManagerInternal, typeof(IVirtualDesktopManagerInternal).GUID);
5060
VirtualDesktopNotificationService = (IVirtualDesktopNotificationService) shell.QueryService(
5161
Guids.CLSID_VirtualDesktopNotificationService, typeof(IVirtualDesktopNotificationService).GUID);
62+
VirtualDesktopManager =
63+
(IVirtualDesktopManager) Activator.CreateInstance(
64+
Type.GetTypeFromCLSID(Guids.CLSID_VirtualDesktopManager));
65+
ApplicationViewCollection = (IApplicationViewCollection) shell.QueryService(
66+
typeof(IApplicationViewCollection).GUID, typeof(IApplicationViewCollection).GUID);
5267
}
5368

5469
// Helpers
@@ -94,6 +109,39 @@ internal static int GetCurrentDesktopNum() {
94109

95110
return GetIndex(vd);
96111
}
112+
113+
internal static void MoveCurrentlyFocusedToDesktop(int index) {
114+
int processId;
115+
IntPtr hWnd = GetForegroundWindow();
116+
if(hWnd == IntPtr.Zero) throw new ArgumentNullException();
117+
GetWindowThreadProcessId(hWnd, out processId);
118+
119+
var desktop = GetDesktop(index);
120+
121+
if(Environment.ProcessId == processId) {
122+
// window of process
123+
try // the easy way (if we are owner)
124+
{
125+
VirtualDesktopManager.MoveWindowToDesktop(hWnd, desktop.GetId());
126+
} catch // window of process, but we are not the owner
127+
{
128+
IApplicationView view;
129+
ApplicationViewCollection.GetViewForHwnd(hWnd, out view);
130+
VirtualDesktopManagerInternal.MoveViewToDesktop(view, desktop);
131+
}
132+
} else {
133+
// window of other process
134+
ApplicationViewCollection.GetViewForHwnd(hWnd, out var view);
135+
try {
136+
VirtualDesktopManagerInternal.MoveViewToDesktop(view, desktop);
137+
} catch {
138+
// could not move active window, try main window (or whatever windows thinks is the main window)
139+
ApplicationViewCollection.GetViewForHwnd(
140+
System.Diagnostics.Process.GetProcessById(processId).MainWindowHandle, out view);
141+
VirtualDesktopManagerInternal.MoveViewToDesktop(view, desktop);
142+
}
143+
}
144+
}
97145
}
98146

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

195+
public static readonly Guid CLSID_VirtualDesktopManager = new("AA509086-5CA9-4C25-8F95-589D3C07B48A");
196+
147197
public static readonly Guid CLSID_VirtualDesktopNotificationService =
148198
new("A501FDEC-4A09-464C-AE4E-1B9C21B84918");
149199
}
@@ -328,6 +378,31 @@ void VirtualDesktopWallpaperChanged(IVirtualDesktop pDesktop,
328378
void RemoteVirtualDesktopConnected(IVirtualDesktop pDesktop);
329379
}
330380

381+
[ComImport]
382+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
383+
[Guid("A5CD92FF-29BE-454C-8D04-D82879FB3F1B")]
384+
internal interface IVirtualDesktopManager {
385+
bool IsWindowOnCurrentVirtualDesktop(IntPtr topLevelWindow);
386+
Guid GetWindowDesktopId(IntPtr topLevelWindow);
387+
void MoveWindowToDesktop(IntPtr topLevelWindow, ref Guid desktopId);
388+
}
389+
390+
[ComImport]
391+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
392+
[Guid("1841C6D7-4F9D-42C0-AF41-8747538F10E5")]
393+
internal interface IApplicationViewCollection {
394+
int GetViews(out IObjectArray array);
395+
int GetViewsByZOrder(out IObjectArray array);
396+
int GetViewsByAppUserModelId(string id, out IObjectArray array);
397+
int GetViewForHwnd(IntPtr hwnd, out IApplicationView view);
398+
int GetViewForApplication(object application, out IApplicationView view);
399+
int GetViewForAppUserModelId(string id, out IApplicationView view);
400+
int GetViewInFocus(out IntPtr view);
401+
int Unknown1(out IntPtr view);
402+
void RefreshCollection();
403+
int RegisterForApplicationViewChanges(object listener, out int cookie);
404+
int UnregisterForApplicationViewChanges(int cookie);
405+
}
331406
[ComImport]
332407
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
333408
[Guid("92CA9DCD-5622-4BBA-A805-5E9F541BD8C9")]

WinJump/Core/VirtualDesktopDefinitions/Windows11_22631_3085.cs

+76
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public void JumpToDesktop(int index) {
2222
}
2323

2424
public void MoveFocusedWindowToDesktop(int index) {
25+
DesktopManager.MoveCurrentlyFocusedToDesktop(index);
2526
}
2627

2728
public void Dispose() {
@@ -35,8 +36,17 @@ public void Dispose() {
3536
*/
3637

3738
internal static class DesktopManager {
39+
// get handle of active window
40+
[DllImport("user32.dll")]
41+
private static extern IntPtr GetForegroundWindow();
42+
43+
[DllImport("user32.dll")]
44+
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
45+
3846
private static IVirtualDesktopManagerInternal VirtualDesktopManagerInternal;
3947
internal static IVirtualDesktopNotificationService VirtualDesktopNotificationService;
48+
internal static IApplicationViewCollection ApplicationViewCollection;
49+
internal static IVirtualDesktopManager VirtualDesktopManager;
4050

4151
static DesktopManager() {
4252
if(Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_ImmersiveShell) ??
@@ -49,6 +59,11 @@ static DesktopManager() {
4959
Guids.CLSID_VirtualDesktopManagerInternal, typeof(IVirtualDesktopManagerInternal).GUID);
5060
VirtualDesktopNotificationService = (IVirtualDesktopNotificationService) shell.QueryService(
5161
Guids.CLSID_VirtualDesktopNotificationService, typeof(IVirtualDesktopNotificationService).GUID);
62+
VirtualDesktopManager =
63+
(IVirtualDesktopManager) Activator.CreateInstance(
64+
Type.GetTypeFromCLSID(Guids.CLSID_VirtualDesktopManager));
65+
ApplicationViewCollection = (IApplicationViewCollection) shell.QueryService(
66+
typeof(IApplicationViewCollection).GUID, typeof(IApplicationViewCollection).GUID);
5267
}
5368

5469
// Helpers
@@ -94,6 +109,39 @@ internal static int GetCurrentDesktopNum() {
94109

95110
return GetIndex(vd);
96111
}
112+
113+
internal static void MoveCurrentlyFocusedToDesktop(int index) {
114+
int processId;
115+
IntPtr hWnd = GetForegroundWindow();
116+
if(hWnd == IntPtr.Zero) throw new ArgumentNullException();
117+
GetWindowThreadProcessId(hWnd, out processId);
118+
119+
var desktop = GetDesktop(index);
120+
121+
if(Environment.ProcessId == processId) {
122+
// window of process
123+
try // the easy way (if we are owner)
124+
{
125+
VirtualDesktopManager.MoveWindowToDesktop(hWnd, desktop.GetId());
126+
} catch // window of process, but we are not the owner
127+
{
128+
IApplicationView view;
129+
ApplicationViewCollection.GetViewForHwnd(hWnd, out view);
130+
VirtualDesktopManagerInternal.MoveViewToDesktop(view, desktop);
131+
}
132+
} else {
133+
// window of other process
134+
ApplicationViewCollection.GetViewForHwnd(hWnd, out var view);
135+
try {
136+
VirtualDesktopManagerInternal.MoveViewToDesktop(view, desktop);
137+
} catch {
138+
// could not move active window, try main window (or whatever windows thinks is the main window)
139+
ApplicationViewCollection.GetViewForHwnd(
140+
System.Diagnostics.Process.GetProcessById(processId).MainWindowHandle, out view);
141+
VirtualDesktopManagerInternal.MoveViewToDesktop(view, desktop);
142+
}
143+
}
144+
}
97145
}
98146

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

192+
public static readonly Guid CLSID_VirtualDesktopManager = new("AA509086-5CA9-4C25-8F95-589D3C07B48A");
193+
144194
public static readonly Guid CLSID_VirtualDesktopManagerInternal =
145195
new("C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B");
146196

@@ -288,6 +338,32 @@ void GetDesktopSwitchIncludeExcludeViews(IVirtualDesktop desktop, out IObjectArr
288338
void WaitForAnimationToComplete();
289339
}
290340

341+
[ComImport]
342+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
343+
[Guid("1841C6D7-4F9D-42C0-AF41-8747538F10E5")]
344+
internal interface IApplicationViewCollection {
345+
int GetViews(out IObjectArray array);
346+
int GetViewsByZOrder(out IObjectArray array);
347+
int GetViewsByAppUserModelId(string id, out IObjectArray array);
348+
int GetViewForHwnd(IntPtr hwnd, out IApplicationView view);
349+
int GetViewForApplication(object application, out IApplicationView view);
350+
int GetViewForAppUserModelId(string id, out IApplicationView view);
351+
int GetViewInFocus(out IntPtr view);
352+
int Unknown1(out IntPtr view);
353+
void RefreshCollection();
354+
int RegisterForApplicationViewChanges(object listener, out int cookie);
355+
int UnregisterForApplicationViewChanges(int cookie);
356+
}
357+
358+
[ComImport]
359+
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
360+
[Guid("A5CD92FF-29BE-454C-8D04-D82879FB3F1B")]
361+
internal interface IVirtualDesktopManager {
362+
bool IsWindowOnCurrentVirtualDesktop(IntPtr topLevelWindow);
363+
Guid GetWindowDesktopId(IntPtr topLevelWindow);
364+
void MoveWindowToDesktop(IntPtr topLevelWindow, ref Guid desktopId);
365+
}
366+
291367
[ComImport]
292368
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
293369
[Guid("0CD45E71-D927-4F15-8B0A-8FEF525337BF")]

WinJump/Core/WinJumpManager.cs

+4
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ public WinJumpManager(DesktopChanged desktopChanged) {
105105
if(moveTo != null) {
106106
// Move the current window to the specified desktop
107107
_thread?.MoveWindowToDesktop(moveTo.Desktop - 1);
108+
109+
if(moveTo.Follow) {
110+
_thread?.JumpTo(moveTo.Desktop - 1);
111+
}
108112
}
109113

110114
// Finally, look for a toggle group

WinJump/WinJump.csproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
<TargetFramework>net8.0-windows</TargetFramework>
66
<Nullable>enable</Nullable>
77
<UseWPF>true</UseWPF>
8-
<Version>2.0.12</Version>
9-
<AssemblyVersion>2.0.12</AssemblyVersion>
10-
<FileVersion>2.0.12</FileVersion>
8+
<Version>2.0.13</Version>
9+
<AssemblyVersion>2.0.13</AssemblyVersion>
10+
<FileVersion>2.0.13</FileVersion>
1111
</PropertyGroup>
1212

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

0 commit comments

Comments
 (0)