Skip to content

Commit

Permalink
Merge pull request #34 from widavies/1-4-improvements
Browse files Browse the repository at this point in the history
Bug fixes
  • Loading branch information
widavies authored Jan 27, 2024
2 parents f9c35b3 + 5d1d28d commit 8af388c
Show file tree
Hide file tree
Showing 11 changed files with 500 additions and 147 deletions.
24 changes: 20 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ Features:
- Group virtual desktops together and cycle through them with a custom shortcut key
- Configure a shortcut to jump back and forth between two virtual desktops
- Move applications to a specific desktop with a shortcut
- Scroll with your mouse over the taskbar to quickly navigate between
- Scroll with your mouse over the taskbar to quickly navigate between virtual desktops

## Installation
1. [Download](https://github.com/widavies/WinJump/releases/)
> Note, you may receive a Windows smartscreen warning when you try to run WinJump. Click "More options" and click "Run anyway"
2. Press Ctrl+R and type `shell:startup`
3. Drag the `WinJump.exe` to the shell startup folder
4. Double click `WinJump.exe` to run it

### Config file

Expand Down Expand Up @@ -61,9 +62,24 @@ Below is an example configuration file that changes the shortcut to `alt+N` to j
}
],
"jump-current-goes-to-last": false,
"move-window-to-desktop": {
"shortcut": "alt+shift"
},
"move-window-to": [
{
"shortcut": "alt+shift+d1",
"desktop": 1
},
{
"shortcut": "alt+shift+d2",
"desktop": 2
},
{
"shortcut": "alt+shift+d3",
"desktop": 3
},
{
"shortcut": "alt+shift+d4",
"desktop": 4
}
],
"change-desktops-with-scroll": false,
"jump-to": [
{
Expand Down
50 changes: 28 additions & 22 deletions WinJump/Core/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ internal sealed class Config {
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
".winjump");

[JsonProperty("move-window-to-desktop")]
public required JumpWindowToDesktop JumpWindowToDesktop { get; set; }
[JsonProperty("move-window-to")]
public required List<JumpWindowToDesktop> MoveWindowTo { get; set; }

[JsonProperty("toggle-groups")]
public required List<ToggleGroup> ToggleGroups { get; set; }
Expand All @@ -26,10 +26,10 @@ internal sealed class Config {

[JsonProperty("jump-current-goes-to-last")]
public required bool JumpCurrentGoesToLast { get; set; }

[JsonProperty("change-desktops-with-scroll")]
public required bool ChangeDesktopsWithScroll { get; set; }

public static Config Load() {
try {
EnsureCreated();
Expand Down Expand Up @@ -69,16 +69,19 @@ public static Config Load() {
}
}
}

// Make sure that the move window to desktop doesn't have overlapping modifiers with any of the others
var moveWindowToDesktopShortcut = config.JumpWindowToDesktop.Shortcut;

if(config.JumpTo.Any((jumpTo) => jumpTo.Shortcut.ModifiersEqual(moveWindowToDesktopShortcut))) {
throw new Exception("Move window to desktop shortcut overlaps with jump to shortcut");
}

if(config.ToggleGroups.Any((toggleGroup) => toggleGroup.Shortcut.ModifiersEqual(moveWindowToDesktopShortcut))) {
throw new Exception("Move window to desktop shortcut overlaps with toggle group shortcut");

// Check for move windows with duplicate shortcuts
for(int i = 0; i < config.MoveWindowTo.Count; i++) {
var shortcut = config.MoveWindowTo[i].Shortcut;
for(int j = i + 1; j < config.MoveWindowTo.Count; j++) {
if(config.MoveWindowTo[j].Shortcut.IsEqual(shortcut)) {
throw new Exception("Duplicate move window shortcut");
}

if(config.MoveWindowTo[i].Desktop <= 0) {
throw new Exception("Invalid desktop number");
}
}
}

return config;
Expand Down Expand Up @@ -114,14 +117,15 @@ private static Config Default() {
}

return new Config {
JumpWindowToDesktop = new JumpWindowToDesktop {
MoveWindowTo = jumpTo.Select(x => new JumpWindowToDesktop {
Shortcut = new Shortcut {
ModifierKeys = ModifierKeys.Alt,
Keys = Keys.Shift
}
},
Keys = x.Shortcut.Keys,
ModifierKeys = x.Shortcut.ModifierKeys | ModifierKeys.Shift
},
Desktop = x.Desktop
}).ToList(),
JumpTo = jumpTo,
ToggleGroups = new List<ToggleGroup>(),
ToggleGroups = [],
JumpCurrentGoesToLast = true,
ChangeDesktopsWithScroll = false
};
Expand All @@ -131,6 +135,8 @@ private static Config Default() {
public sealed class JumpWindowToDesktop {
[JsonConverter(typeof(ShortcutConverter))]
public required Shortcut Shortcut { get; set; }

public required uint Desktop { get; set; }
}

public sealed class ToggleGroup {
Expand Down Expand Up @@ -171,7 +177,7 @@ public sealed class Shortcut {
public bool IsEqual(Shortcut other) {
return ModifierKeys == other.ModifierKeys && Keys == other.Keys;
}

public bool ModifiersEqual(Shortcut other) {
return ModifierKeys == other.ModifierKeys;
}
Expand Down Expand Up @@ -229,4 +235,4 @@ public override object ReadJson(JsonReader reader, Type objectType, object? exis
public override bool CanConvert(Type objectType) {
return objectType == typeof(string) || objectType == typeof(Shortcut);
}
}
}
2 changes: 1 addition & 1 deletion WinJump/Core/ExplorerMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ private static bool IsLightMode() {
RegistryKey? startupApp = Registry.CurrentUser.OpenSubKey(
@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", false);

object? val = startupApp?.GetValue("SystemUseLightTheme");
object? val = startupApp?.GetValue("SystemUsesLightTheme") ?? startupApp?.GetValue("SystemUseLightTheme");

bool lightMode = (int) (val ?? 0) == 1;
return lightMode;
Expand Down
27 changes: 11 additions & 16 deletions WinJump/Core/VirtualDesktopDefinitions/IVirtualDesktopAPI.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Text.RegularExpressions;
using Microsoft.Win32;
using WinJump.Core.VirtualDesktopDefinitions.Windows11_22621_2215;

namespace WinJump.Core.VirtualDesktopDefinitions;

Expand Down Expand Up @@ -32,33 +31,29 @@ public interface IVirtualDesktopAPI : IDisposable {
/// </summary>
/// <param name="index"></param>
void MoveFocusedWindowToDesktop(int index);

/// <summary>
/// Creates the appropriate virtual desktop API definition for the current Windows version.
/// </summary>
/// <returns>A virtual desktop API for the installed Windows version</returns>
/// <exception cref="Exception">If the particular Windows version is unsupported</exception>
public static IVirtualDesktopAPI Create() {
OperatingSystem osInfo = Environment.OSVersion;

string? releaseBuild = Registry.LocalMachine.OpenSubKey("SOFTWARE")?.OpenSubKey("Microsoft")?
.OpenSubKey("Windows NT")?.OpenSubKey("CurrentVersion")?.GetValue("UBR")?.ToString();

if(!int.TryParse(releaseBuild, out int releaseBuildNumber)) {
throw new Exception($"Unrecognized Windows build version {osInfo.Version.Build}.{releaseBuild}");
}
WinVersion version = WinVersion.Determine();

return osInfo.Version.Build switch {
return version.Build switch {
>= 22631 => version.ReleaseBuild >= 3085
? new Windows11_22631_3085.VirtualDesktopApi()
: new VirtualDesktopApi(),
// Work out the proper desktop wrapper
>= 22621 => releaseBuildNumber >= 2215
? new Windows11_22621_2215.VirtualDesktopApi()
>= 22621 => version.ReleaseBuild >= 2215
? new VirtualDesktopApi()
: new Windows11_22621.VirtualDesktopApi(),
>= 22000 => new Windows11_22000.VirtualDesktopApi(),
>= 17763 => new Windows10_17763.VirtualDesktopApi(),
// Just try the most recent as a last ditch effort
_ => new Windows11_22621_2215.VirtualDesktopApi()
_ => new VirtualDesktopApi()
};
}
}

public delegate void OnDesktopChanged(int desktop);
public delegate void OnDesktopChanged(int desktop);
78 changes: 1 addition & 77 deletions WinJump/Core/VirtualDesktopDefinitions/Windows11_22621_2215.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ public void JumpToDesktop(int index) {
}

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

public void Dispose() {
Expand All @@ -36,17 +35,8 @@ 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 @@ -57,13 +47,8 @@ static DesktopManager() {

VirtualDesktopManagerInternal = (IVirtualDesktopManagerInternal) shell.QueryService(
Guids.CLSID_VirtualDesktopManagerInternal, typeof(IVirtualDesktopManagerInternal).GUID);
VirtualDesktopManager =
(IVirtualDesktopManager) Activator.CreateInstance(
Type.GetTypeFromCLSID(Guids.CLSID_VirtualDesktopManager));
VirtualDesktopNotificationService = (IVirtualDesktopNotificationService) shell.QueryService(
Guids.CLSID_VirtualDesktopNotificationService, typeof(IVirtualDesktopNotificationService).GUID);
ApplicationViewCollection = (IApplicationViewCollection) shell.QueryService(
typeof(IApplicationViewCollection).GUID, typeof(IApplicationViewCollection).GUID);
}

// Helpers
Expand Down Expand Up @@ -109,39 +94,6 @@ 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 @@ -192,8 +144,6 @@ internal static class Guids {
public static readonly Guid CLSID_VirtualDesktopManagerInternal =
new("C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B");

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

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

[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("3F07F4BE-B107-441A-AF0F-39D82529072C")]
Expand Down Expand Up @@ -355,15 +288,6 @@ void GetDesktopSwitchIncludeExcludeViews(IVirtualDesktop desktop, out IObjectArr
void WaitForAnimationToComplete();
}

[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 Expand Up @@ -422,4 +346,4 @@ internal interface IServiceProvider10 {

#endregion
}
}
}
Loading

0 comments on commit 8af388c

Please sign in to comment.