Processing Ajax...

Title

Message

Confirm

Confirm

Confirm

Confirm

Are you sure you want to delete this item?

Confirm

Are you sure you want to delete this item?

Confirm

Are you sure?

User Image
trainwreck
12 discussion posts
Does DisplayFustion work with WIN10 virtual desktops?

I've switched from a dual monitor setup to a 34" ultrawide (lovin' it, btw) and spend most of my time moving windows between virtual desktops. But the Functions area doesn't have anything to move the window to the next virtual desktop. Is this supported? Script?
Sep 16, 2016  • #1
Keith Lammers (BFS)'s profile on WallpaperFusion.com
Not at the moment, but this is currently on our feature request list, so I've added your vote to it. We'll be sure to let you know if/when we're able to implement it in the future.

Thanks!
Sep 16, 2016  • #2
User Image
Maggew.com
31 discussion posts
Any good news? I hope so.
Apr 13, 2017  • #3
Keith Lammers (BFS)'s profile on WallpaperFusion.com
Not yet, sorry!
Apr 20, 2017  • #4
User Image
Maggew.com
31 discussion posts
Mr. Keith, might you have an update or ETA on when this could be ready. A guesstimate? 1 month, 3 months, 6 months, not on the TO-DO list? Anything will be helpful.

Thanks for rapid response.
Apr 20, 2017  • #5
User Image
EngineerWilky
1 discussion post
I'd find a feature like this very helpful since I do the same on both my desktop and my laptop. My desktop I have multiple monitors, but I do different things like personal stuff and work and have different virtual desktops to keep related windows separated.
Apr 21, 2017  • #6
Keith Lammers (BFS)'s profile on WallpaperFusion.com
We're hoping to include it in the next version, but our priorities can shift to other things depending on how development goes, so no promises! :)
Apr 21, 2017  • #7
User Image
DTM
2 discussion posts
Yes please! This would be a perfect addition to DisplayFusion.
Currently I'm using a scheduled task to run this utility but it's clunky and has to be restarted each time I resume from sleep: https://github.com/Eun/MoveToDesktop
Jun 5, 2017  • #8
PabloMartinez's profile on WallpaperFusion.com
As a workaround, you can use this script. It just moves the focused window to the next desktop.

Code

using System;
using System.Drawing;

public static class DisplayFusionFunction
{
    public static void Run(IntPtr windowHandle)
    {
        BFS.Window.GetFocusedWindow();
        // Win+Tab Apps M D
BFS.Input.SendKeys("{WIN}({VK_9}){VK_93}{VK_77}{VK_68}");
    }
}
Jun 5, 2017  • #9
PabloMartinez's profile on WallpaperFusion.com
I found a solution. Using this https://github.com/Grabacr07/VirtualDesktop/tree/master library, to make script in DF for managing virtual desktops.

I tried to describe all possible cases, but I might have forgotten or missed something, write if something was unclear or not working correctly.

If you do not have a NuGet package manager or VS, use this http://packages.nuget.org/api/v1/package/VirtualDesktop/2.0.0-beta3 for download package. After downloading, rename .nupkg package to .zip. Unzip and copy the VirtualDesktop.dll from lib\net46 folder to a separate folder for simple use.

@Keith, send to repository?

Code

using System;
using System.Drawing;
using System.Collections.Generic;
using WindowsDesktop;

// Add to reference | Disk:\YourPathToDll\VirtualDesktop.dll from (https://github.com/Grabacr07/VirtualDesktop/tree/master)

// If you do not have a NuGet package manager or VS,
// use this (http://packages.nuget.org/api/v1/package/VirtualDesktop/2.0.0-beta3) for download.
// After downloading, rename .nupkg package to .zip.
// Unzip and copy the "VirtualDesktop.dll" from lib/net46 folder to a separate folder for simple use.

public static class DisplayFusionFunction
{
    public static void Run(IntPtr windowHandle)
    {
        // Examples usage
        
        var vDesktop = new VirtualDesktops();
        var wHandle = BFS.Application.GetMainWindowByFile("*spotify.exe");
        
        /// Get a dictionary of all desktops
        var desktops = vDesktop.GetAllDesktops();
        
        /// Get desired desktop and move spotify on it 
        /*
        var deskSecond = desktops["Desktop 2"];
        vDesktop.MoveWindowToDesktop(wHandle, deskSecond);
        BFS.Window.Focus(wHandle);
        */
        
        /// Move spotify from either virtual desktop to current
        /*
        vDesktop.MoveWindowToCurrent(wHandle);
        BFS.Window.Focus(wHandle);
        */
        
        /// Switch to desired virtual desktop. Move spotify on it, wait 5sec and remove it
        /*
        var deskThird = desktops["Desktop 3"];
        vDesktop.SwitchToDesktop(deskThird);
        vDesktop.MoveWindowToCurrent(wHandle);
        BFS.General.ThreadWait(5000);
        vDesktop.Remove();
        */
        
        /// Switch to the desktop where the desired app is located
        /*
        vDesktop.GetCurrentWindowDesktop(wHandle).Switch();
        */
        
        /// Pin\Unpin app
        /*
        vDesktop.TogglePinApp(wHandle);
        */
    }
}

class VirtualDesktops
{
    // Create new virtual desktop
    
    public void Create()
    {
        VirtualDesktop.Create();
    }
    
    
    // Remove current virtual desktop
    
    public void Remove()
    {
        VirtualDesktop.Current.Remove();
    }
        
    
    // Switch to the left virtual desktop relative to the current
    
    public void SwitchToLeft()
    {
        VirtualDesktop.Current.GetLeft().Switch();
    }
    
    
    // Switch to the right virtual desktop relative to the current
    
    public void SwitchToRight()
    {
        VirtualDesktop.Current.GetRight().Switch();
    }
    
    
    // Switch to desired virtual desktop by key
    
    public void SwitchToDesktop(VirtualDesktop vDesktop)
    {
        vDesktop.Switch();
    }
    
    // Move the window to the left virtual desktop relative to the current
    
    public void MoveWindowToLeft(IntPtr wHandle)
    {
        var left = VirtualDesktop.Current.GetLeft();
        VirtualDesktopHelper.MoveToDesktop(wHandle, left);
    }
    
    
    // Move the window to the right virtual desktop relative to the current
    
    public void MoveWindowToRight(IntPtr wHandle)
    {
        var right = VirtualDesktop.Current.GetRight();
        VirtualDesktopHelper.MoveToDesktop(wHandle, right);
    }
    
    
    // Move the window from either virtual desktop to the current
    
    public void MoveWindowToCurrent(IntPtr wHandle)
    {
        var currentDesktop = VirtualDesktop.Current;
        
        if(!VirtualDesktopHelper.IsCurrentVirtualDesktop(wHandle))
            VirtualDesktopHelper.MoveToDesktop(wHandle, currentDesktop);
    }
    
    
    // Move the window to specified virtual desktop
    
    public void MoveWindowToDesktop(IntPtr wHandle, VirtualDesktop virtualDesktop)
    {
        VirtualDesktopHelper.MoveToDesktop(wHandle, virtualDesktop);
    }
    
    
    // Pin window. Show this window on all desktops
    
    public void TogglePin(IntPtr wHandle)
    {
        (VirtualDesktop.IsPinnedWindow(wHandle) ? VirtualDesktop.UnpinWindow :
            (Action<IntPtr>)VirtualDesktop.PinWindow)(wHandle);
    }
    
    
    // Pin app. Show windows from this app on all desktops
    
    public void TogglePinApp(IntPtr wHandle)
    {
        var appId = ApplicationHelper.GetAppId(wHandle);
        (VirtualDesktop.IsPinnedApplication(appId) ? VirtualDesktop.UnpinApplication :
            (Action<string>)VirtualDesktop.PinApplication)(appId);
    }
    
    
    // Returns a virtual desktop that window is located
    
    public VirtualDesktop GetCurrentWindowDesktop(IntPtr wHandle)
    {
        return VirtualDesktop.FromHwnd(wHandle);
    }
    
    
    // Return all the virtual desktops of currently valid
    
    public Dictionary<string, VirtualDesktop> GetAllDesktops()
    {
        var desktopArray = VirtualDesktop.GetDesktops();
        var desktopDictionary = new Dictionary<string, VirtualDesktop>();
        
        // To simplify selection by key, used (j+1)
        for (var j = 0; j < desktopArray.Length; j++)
            desktopDictionary.Add(string.Format("Desktop {0}", j+1), desktopArray[j]);
            
        return desktopDictionary;
    }
}
Jun 8, 2017  • #10
User Image
Maggew.com
31 discussion posts
Thanks for the status update @Pablo - gonna check this out and see if it works with the new DF update.

:)
Jun 5, 2018  • #11
User Image
AbhishekTripathi
6 discussion posts
Awesome feature request. I came to this page looking for similar functionality. Windows 10 doesn't have any inbuilt shortcut to move windows across the virtual desktop. While Microsoft adds this, I would like if Display Fusion can have an elegant solution. I don't need anything fancy. A simple keyboard shortcut to move the active window to another virtual desktop would suffice. Additional management feature and intuitiveness of functionality would be an added bonus. Please keep up the good work. Love your product.
Jul 17, 2018  • #12
User Image
Mike A
21 discussion posts
I would also like this functionality. I find it a pain to have to bring up the desktop switcher to move a window between desktops.
Apr 12, 2019  • #13
User Image
Monitizer
1 discussion post
Any ideas when and if this feature would be added to the DF?
Dec 2, 2019  • #14
Keith Lammers (BFS)'s profile on WallpaperFusion.com
We don't have an ETA on it yet, sorry!
Dec 2, 2019  • #15
User Image
Erik-the-Red
39 discussion posts
Resurrecting this one, any new information on this feature request?

thanks
Jul 8, 2021  • #16
Owen Muhlethaler (BFS)'s profile on WallpaperFusion.com
Hello,

This is still on our list, but no updates on it yet.

Thanks!
Jul 9, 2021  • #17
User Image
Lahma
28 discussion posts
For anyone coming across this thread now, as I did, you will likely find that one problem or another when trying to create custom VirtualDesktop scripted functions in DF. One of the problems is that the VirtualDesktop Github has not been updated in awhile and its latest release is broken for .NET Framework applications (including DisplayFusion and its 'Scripted Functions' functionality). Also, if you download the VirtualDesktop script using DisplayFusion's built-in 'Download Scripted Function' feature, the dropbox URL noted in that script's comments (to download the VirtualDesktop library) is broken and no longer accessible. Thanks to the info in this thread and a commit made by a user on the VirtualDesktop Github, I was able to recompile the latest VirtualDesktop release with the changes required to fix it and make it functional with .NET Framework apps once again.

I've included some notes below about the changes made and a URL where the updated/fixed VirtualDesktop library can be downloaded.

As of 2021/07/17, the VirtualDesktop project located at 'https://github.com/Grabacr07/VirtualDesktop/' is broken for .NET Framwork apps. To fix it so that the project works on both .NET Framework apps and .NET Core apps, a few small changes must be made to the source file 'source/VirtualDesktop/Interop/ComInterfaceAssemblyProvider.cs'. These changes have already been made in commit 'https://github.com/Grabacr07/VirtualDesktop/commit/429b3d84e684e042127a9d50a3afe58c913cef45' by user 'vegardlarsen' but the author of the VirtualDesktop project has not accepted these changes into mainline branch of the library.

In order for these changes to be incorporated, the source file has to be modified and the project recompiled. That is exactly what this package is. A recompilation of the project source files exactly as they were on 2021/07/17 with the only changes being those of commit '429b3d84e684e042127a9d50a3afe58c913cef45'. Nothing more, nothing less. The files included in this package are the contents of the 'bin/Release' folder after compilation. In order to use the DLL in DisplayFusion, you will likely only need the contents of the 'lib/net472' folder in this package. Simply extract this folder somewhere onto your computer where it will not be deleted, and then, inside of the 'Scripted Function' window in DisplayFusion, select the 'References' tab, right click, select 'Add Reference (browse for assembly)', and choose the file '{ExtractionLocation}/lib/net472/VirtualDesktop.dll'.

The updated/fixed package can be downloaded at the following URL:
https://mega.nz/file/wygAGBDQ#W6l8y5dx0LAtXtUGHfgdQIyjPd_V3UWJ9oJWS4b3luA
Note: I also included this file as an attachment to this post.


For anyone who is interested, I also create a package containing pre-made 'Scripted Functions' for the following VirtualDesktop operations (thanks to PabloMartinez for supplying the original functions):
  • Create New Desktop
  • Move Window Left
  • Move Window Right
  • Move Window to Current Desktop
  • Remove Current Desktop
  • Switch Desktop Left
  • Switch Desktop Right
  • Toggle App Pin
  • Toggle Window Pin

I bundled them all into a single archive and that archive can be downloaded at the following URL:
https://mega.nz/file/5uwExZ7D#JGu2KX03n5nwVSD0c5Xxv2nX5vXRB9B122wOFkl6dUc
Note: I also included this file as an attachment to this post.
• Attachment: VirtualDesktop-NETFrameworkFixed_2021-07-17.rar [4,680,202 bytes]
Jul 18, 2021 (modified Jul 18, 2021)  • #18
User Image
Eric S Ma
2 discussion posts
Has there been an updated solution for Windows 11? I tried using the VirtualDesktop.dll from Lahma's above message and got this error in DisplayFusion Scripted Function output:
Run Failed.
Exception has been thrown by the target of an invocation.
You must target Windows 10 in your app.manifest and run without debugging.
[System.NotSupportedException]
[System.Reflection.TargetInvocationException]
Nov 13, 2022 (modified Nov 13, 2022)  • #19
User Image
Lahma
28 discussion posts
Quote:
Has there been an updated solution for Windows 11? I tried using the VirtualDesktop.dll from Lahma's above message and got this error in DisplayFusion Scripted Function output:
Run Failed.
Exception has been thrown by the target of an invocation.
You must target Windows 10 in your app.manifest and run without debugging.
[System.NotSupportedException]
[System.Reflection.TargetInvocationException]


Hi Eric. Yes, I believe some things have changed in regards to using the virtual desktop functions on Windows 11. Honestly, it has been awhile now and I've messed with this a number of times, so I forget exactly what has changed since my last post, but I will post instructions for the way I am currently doing things. Give me just a bit and I will try to document the procedure I'm currently using and I will post another reply below this one.
Nov 18, 2022  • #20
User Image
Lahma
28 discussion posts
Ok, so this is the solution I am currently using. The only reason this is still accessible is thanks to the hard work by Markus Scholtes to keep the COM API methods updated for each specific version of Windows. You will find his work at:
https://github.com/MScholtes/VirtualDesktop
You will need to download the following files from his repository:
  • 'VirtualDesktop[version].cs'
  • 'Compile.bat'
  • 'MScholtes.ico'
If you're running Windows 11 21H2, you need to download 'VirtualDesktop11-21H2.cs'. If you're running Windows 11 22H2, you need to download 'VirtualDesktop11.cs'. Once you've downloaded all those file and put them into the same folder, simply run 'Compile.bat' and you should get the needed 'VirtualDesktop11.exe' file (or possibly 'VirtualDesktop11-21H2.exe' if using that version).
Put that exe file somewhere you want to store it permanently as you will need to know the path to it to access it in the DisplayFusion functions.
    For each function in DisplayFusion ('Switch Virtual Desktop Left', 'Switch Virtual Desktop Right', 'Move Window to Virtual Desktop Left', 'Toggle Pin Window Virtual Desktop', etc), you will use the same script I've posted below. The only thing you need to change in each individual script is the command inside the 'public static void Run(IntPtr windowsHandle)' function.
      Here are a few of the commands I'm using inside the Run function. Note: I believe I set up the functions so that they will wrap to the 1st/last virtual desktop if needed (say for example, you try to switch to the prev virtual desktop but you're already on the 1st, then it will switch to the last, and vice versa).
      • Vd.TogglePinWindow(windowHandle); // Toggle's the 'Pin' status of the window such that it will show on all virtual desktops
      • Vd.GoToNextDesktop(); // Switch Virtual Desktop - Right
      • Vd.GoToPrevDesktop(); // Switch Virtual Desktop - Left
      • Vd.MoveWindowToNextDesktop(windowHandle); // Move Window to Next (Right) Virtual Desktop
      • Vd.MoveWindowToPrevDesktop(windowHandle); // Move Window to Prev (Left) Virtual Desktop
      Obviously there are many more functions you can implement but these examples should help you understand how things work. Below is the actual script. A few things to note:
      • You need to change the path to the 'VirtualDesktop11.exe' inside the 'ExecCmd' function
      • Running the script will not produce any type of console window or anything... it all happens entirely invisible to the user
      • The functions inside of '#region Helpers' are meant to be functions for carrying out very specific functionality whereas the other functions are more general in nature... I believe I wrote all of the code in the entire script but it has been a while so don't quote me on that
      If you have any questions or need any help, just let me know. I'll try to keep an eye on this thread in case you post a reply. Oh, and if anyone gets any use out of my post, please let me know.. Would be nice to know I didn't spend all the time making this post for nothing. :)

      Code

      using System;
      using System.Drawing;
      using System.Text.RegularExpressions;
      // The 'windowHandle' parameter will contain the window handle for the:
      //   - Active window when run by hotkey
      //   - Trigger target when run by a Trigger rule
      //   - TitleBar Button owner when run by a TitleBar Button
      //   - Jump List owner when run from a Taskbar Jump List
      //   - Currently focused window if none of these match
      public static class DisplayFusionFunction
      {
      public static void Run(IntPtr windowHandle)
      {
      // Example command:
      // Vd.TogglePinWindow(windowHandle);
      }
      }
      public static class Vd
      {
      #region Helpers
      public static int GetDesktopLeftOfDesktop(int number)
      {
      var prevDesktop = number - 1;
      if (prevDesktop < 0)
      prevDesktop = GetDesktopCount() - 1;
      return prevDesktop;
      }
      public static int GetDesktopRightOfDesktop(int number)
      {
      var nextDesktop = number + 1;
      if (nextDesktop > (GetDesktopCount() - 1))
      nextDesktop = 0;
      return nextDesktop;
      }
      public static int GetDesktopLeftOfCurrent()
      {
      return GetDesktopLeftOfDesktop(GetCurrentDesktopNumber());
      }
      public static int GetDesktopRightOfCurrent()
      {
      return GetDesktopRightOfDesktop(GetCurrentDesktopNumber());
      }
      public static void GoToPrevDesktop()
      {
      ExecCmd($"/Switch:{GetDesktopLeftOfCurrent()}");
      }
      public static void GoToNextDesktop()
      {
      ExecCmd($"/Switch:{GetDesktopRightOfCurrent()}");
      }
      public static void MoveWindowToPrevDesktop(IntPtr handle)
      {
      MoveWindowToDesktopNumber(handle, GetDesktopLeftOfCurrent());
      }
      public static void MoveWindowToNextDesktop(IntPtr handle)
      {
      MoveWindowToDesktopNumber(handle, GetDesktopRightOfCurrent());
      }
      public static void TogglePinWindow(IntPtr handle)
      {
      if (IsPinnedWindow(handle))
      UnPinWindow(handle);
      else
      PinWindow(handle);
      }
      public static void TogglePinApp(int processId)
      {
      if (IsPinnedApp(processId))
      UnPinApp(processId);
      else
      PinApp(processId);
      }
      #endregion
      public static int GetCurrentDesktopNumber()
      {
      return ParseLastNumber(ExecCmd("/GetCurrentDesktop"));
      }
      public static int GetDesktopCount()
      {
      return ParseLastNumber(ExecCmd("/Count"));
      }
      public static int GetWindowDesktopNumber(IntPtr handle)
      {
      return ParseLastNumber(ExecCmd($"/GetDesktopFromWindowHandle:{handle}"));
      }
      public static bool IsWindowOnCurrentVirtualDesktop(IntPtr handle)
      {
      return ParseBool(ExecCmd($"/GetCurrentDesktop /IsWindowHandleOnDesktop:{handle}"));
      }
      public static void MoveWindowToDesktopNumber(IntPtr handle, int number)
      {
      ExecCmd($"/GetDesktop:{number} /MoveWindowHandle:{handle}");
      }
      public static void GoToDesktopNumber(int number)
      {
      ExecCmd($"/Switch:{number}");
      }
      public static bool IsPinnedWindow(IntPtr handle)
      {
      return ParseBool(ExecCmd($"/IsWindowHandlePinned:{handle}"));
      }
      public static void PinWindow(IntPtr handle)
      {
      ExecCmd($"/PinWindowHandle:{handle}");
      }
      public static void UnPinWindow(IntPtr handle)
      {
      ExecCmd($"/UnPinWindowHandle:{handle}");
      }
      public static bool IsPinnedApp(int processId)
      {
      return ParseBool(ExecCmd($"/IsApplicationPinned:{processId}"));
      }
      public static void PinApp(int processId)
      {
      ExecCmd($"/PinApplication:{processId}");
      }
      public static void UnPinApp(int processId)
      {
      ExecCmd($"/UnPinApplication:{processId}");
      }
      public static bool IsWindowOnDesktopNumber(IntPtr handle, int number)
      {
      return ParseBool(ExecCmd($"/GetDesktop:{number} /IsWindowHandleOnDesktop:{handle}"));
      }
      private static (int, string) ExecCmd(string args)
      {
      var p = new System.Diagnostics.Process();
      p.StartInfo.FileName = @"C:\libraries\dotNET\VirtualDesktop11\VirtualDesktop11.exe";
      p.StartInfo.RedirectStandardInput = true;
      p.StartInfo.RedirectStandardOutput = true;
      p.StartInfo.Arguments = args;
      p.StartInfo.UseShellExecute = false;
      p.StartInfo.CreateNoWindow = true;
      p.Start();
      p.WaitForExit();
      return (p.ExitCode, p.StandardOutput.ReadLine());
      }
      private static int ParseLastNumber((int exitCode, string output) t)
      {
      var match = Regex.Match(t.output, @"\d+(?!\D*\d)");
      var num = match.Groups[0].Value;
      return Int32.Parse(num);
      }
      private static bool ParseBool((int exitCode, string output) t)
      {
      return t.exitCode == 0;
      }
      private static int ParseDesktopNumber(string cmdOutput)
      {
      var match = Regex.Match(cmdOutput, @".*desktop number (\d+)");
      var num = match.Groups[1].Value;
      return Int32.Parse(num);
      }
      }
      Nov 18, 2022 (modified Nov 18, 2022)  • #21
      User Image
      Eric S Ma
      2 discussion posts
      Lahma's new solution has worked like a charm. I am able to switch to another virtual desktop in Windows 11 21H2. Thank you, Lahma. :)
      Nov 22, 2022  • #22
      User Image
      Lahma
      28 discussion posts
      Quote:
      Lahma's new solution has worked like a charm. I am able to switch to another virtual desktop in Windows 11 21H2. Thank you, Lahma. :)

      No problem! Glad I could help.
      Nov 22, 2022  • #23
      Subscribe to this discussion topic using RSS
      Was this helpful?  Login to Vote(1)  Login to Vote(-)