Skip to content

Commit

Permalink
Unfocus all windows from switching
Browse files Browse the repository at this point in the history
Without unfocusing, the previous window on the previous workspace keeps
focused. This causes all keyboard inputs captured by the previous window
unless I explicitly change focus to the window on the current workspace
(by e.g. Alt+Tab). This is very dangerous --- for example, the text
editor focused previously in the previous workspace still gets keyboard
input, destroying the editing text. Or, the web browser previously
focused still has the focus, inserting random text into the text box on
some web page.

This can be solved by unfocusing all the windows on the previous
workspace before switching.

For reference:
Grabacr07/VirtualDesktop#19 (comment)
  • Loading branch information
statiolake committed Nov 10, 2021
1 parent 561697a commit 7a54fd4
Showing 1 changed file with 29 additions and 26 deletions.
55 changes: 29 additions & 26 deletions DynamicWorkspaceManager/State.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
Expand Down Expand Up @@ -115,7 +116,7 @@ public static void InitializeWorkspaces()
}

public void Switch(string name)
=> GetOrCreate(name).Switch();
=> GetOrCreate(name).UnfocusSwitch();

public void ShiftSwitch(string name)
=> GetOrCreate(name).ShiftSwitch(GetForegroundWindow());
Expand All @@ -128,7 +129,7 @@ public async void SwitchToWorkspacePrompt()
// Wait for window close
await Task.Delay(TimeSpan.FromMilliseconds(200));
var desktop = GetOrCreate(name);
desktop.Switch();
desktop.UnfocusSwitch();
}
catch (OperationCanceledException)
{
Expand All @@ -153,22 +154,22 @@ public async void ShiftSwitchToWorkspacePrompt()
}

public void SwitchToLastWorkspace()
=> this.lastWorkspace?.Switch();
=> this.lastWorkspace?.UnfocusSwitch();

public void ShiftSwitchToLastWorkspace()
=> this.lastWorkspace?.ShiftSwitch(GetForegroundWindow());

public void SwitchToLeftWorkspace()
=> VirtualDesktop.Current.GetLeft()?
.Switch();
.UnfocusSwitch();

public void ShiftSwitchToLeftWorkspace()
=> VirtualDesktop.Current.GetLeft()?
.ShiftSwitch(GetForegroundWindow());

public void SwitchToRightWorkspace()
=> VirtualDesktop.Current.GetRight()?
.Switch();
.UnfocusSwitch();

public void ShiftSwitchToRightWorkspace()
=> VirtualDesktop.Current.GetRight()?
Expand Down Expand Up @@ -266,24 +267,14 @@ public static VirtualDesktop GetOrCreate(string name)

public static class ShiftSwitchExtension
{
public static void RemoveSwitch(this VirtualDesktop desktop)
public static void UnfocusSwitch(this VirtualDesktop desktop)
{
// Remove current if empty
if (VirtualDesktop.Current.IsEmpty())
// Unfocus all windows before switching
foreach (var hwnd in desktop.AllWindows())
{
try
{
VirtualDesktop.Current.Remove(desktop);
}
catch (ArgumentException)
{
// sometimes already removed; ignore it
}
}
else
{
desktop.Switch();
SendMessage(hwnd, WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
}
desktop.Switch();
}

public static void ShiftSwitch(this VirtualDesktop desktop, IntPtr hWnd)
Expand All @@ -292,7 +283,7 @@ public static void ShiftSwitch(this VirtualDesktop desktop, IntPtr hWnd)
try
{
VirtualDesktopHelper.MoveToDesktop(hWnd, desktop);
desktop.RemoveSwitch();
desktop.UnfocusSwitch();
}
catch (COMException)
{
Expand All @@ -301,23 +292,28 @@ public static void ShiftSwitch(this VirtualDesktop desktop, IntPtr hWnd)
}

public static bool IsEmpty(this VirtualDesktop desktop)
=> desktop.AllWindows(firstOnly: true).Count == 0;

public static List<IntPtr> AllWindows(
this VirtualDesktop desktop, bool firstOnly = false)
{
bool found = false;
var hwnds = new List<IntPtr>();
bool callback(IntPtr hwnd, IntPtr _lparam)
{
if (VirtualDesktop.FromHwnd(hwnd) == desktop)
{
found = true;
// We don't have to continue enumeration, hence return false.
return false;
hwnds.Add(hwnd);
// if firstOnly is true, We don't have to continue
// enumeration, hence return false.
return !firstOnly;
}

// Continue enumeration, as this window does not belongs not
// the current desktop.
return true;
}
_ = EnumWindows(callback, IntPtr.Zero);
return !found;
return hwnds;
}

private delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lparam);
Expand All @@ -326,5 +322,12 @@ bool callback(IntPtr hwnd, IntPtr _lparam)
private static extern bool EnumWindows(
EnumWindowsDelegate lpEnumFunc,
IntPtr lparam);

[DllImport("user32.dll")]
private static extern int SendMessage(
IntPtr hWnd,
int Msg,
IntPtr wParam, IntPtr lParam);
private const int WM_KILLFOCUS = 0x0008;
}
}

0 comments on commit 7a54fd4

Please sign in to comment.