[Workspaces] fix hotkey behavior (#34497)

* [Workspaces] re-implementing hotkey handling

* [Workspaces] fix interop reference

* Reimplement message sending

* cleanup

* Do not recreate event

* bring back minimized logic

---------

Co-authored-by: Stefan Markovic <stefan@janeasystems.com>
This commit is contained in:
Laszlo Nemeth
2024-08-30 21:29:31 +02:00
committed by GitHub
parent d42cd4bd3b
commit 39741f492f
7 changed files with 84 additions and 38 deletions

View File

@@ -151,4 +151,8 @@ namespace winrt::PowerToys::Interop::implementation
{
return CommonSharedConstants::WORKSPACES_LAUNCH_EDITOR_EVENT;
}
hstring Constants::WorkspacesHotkeyEvent()
{
return CommonSharedConstants::WORKSPACES_HOTKEY_EVENT;
}
}

View File

@@ -41,6 +41,7 @@ namespace winrt::PowerToys::Interop::implementation
static hstring ShowEnvironmentVariablesSharedEvent();
static hstring ShowEnvironmentVariablesAdminSharedEvent();
static hstring WorkspacesLaunchEditorEvent();
static hstring WorkspacesHotkeyEvent();
};
}

View File

@@ -38,6 +38,7 @@ namespace PowerToys
static String ShowEnvironmentVariablesSharedEvent();
static String ShowEnvironmentVariablesAdminSharedEvent();
static String WorkspacesLaunchEditorEvent();
static String WorkspacesHotkeyEvent();
}
}
}

View File

@@ -43,7 +43,9 @@ namespace CommonSharedConstants
const wchar_t FANCY_ZONES_EDITOR_TOGGLE_EVENT[] = L"Local\\FancyZones-ToggleEditorEvent-1e174338-06a3-472b-874d-073b21c62f14";
// Path to the event used by Workspaces
const wchar_t WORKSPACES_LAUNCH_EDITOR_EVENT[] = L"Local\\Workspaces-LaunchEditorEvent-a55ff427-cf62-4994-a2cd-9f72139296bf";
const wchar_t WORKSPACES_HOTKEY_EVENT[] = L"Local\\PowerToys-Workspaces-HotkeyEvent-2625C3C8-BAC9-4DB3-BCD6-3B4391A26FD0";
const wchar_t SHOW_HOSTS_EVENT[] = L"Local\\Hosts-ShowHostsEvent-5a0c0aae-5ff5-40f5-95c2-20e37ed671f0";
@@ -100,8 +102,6 @@ namespace CommonSharedConstants
const wchar_t SHOW_ENVIRONMENT_VARIABLES_EVENT[] = L"Local\\PowerToysEnvironmentVariables-ShowEnvironmentVariablesEvent-1021f616-e951-4d64-b231-a8f972159978";
const wchar_t SHOW_ENVIRONMENT_VARIABLES_ADMIN_EVENT[] = L"Local\\PowerToysEnvironmentVariables-EnvironmentVariablesAdminEvent-8c95d2ad-047c-49a2-9e8b-b4656326cfb2";
const wchar_t WORKSPACES_EXIT_EVENT[] = L"Local\\PowerToys-Workspaces-ExitEvent-29a1566f-f4f8-4d56-9435-d2a437f727c6";
// Max DWORD for key code to disable keys.
const DWORD VK_DISABLED = 0x100;
}

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Threading;
using System.Windows;
using System.Windows.Interop;
using ManagedCommon;
@@ -14,10 +15,12 @@ namespace WorkspacesEditor
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
public partial class MainWindow : Window, IDisposable
{
public MainViewModel MainViewModel { get; set; }
private CancellationTokenSource cancellationToken = new CancellationTokenSource();
private static MainPage _mainPage;
public MainWindow(MainViewModel mainViewModel)
@@ -41,10 +44,36 @@ namespace WorkspacesEditor
MaxWidth = SystemParameters.PrimaryScreenWidth;
MaxHeight = SystemParameters.PrimaryScreenHeight;
Common.UI.NativeEventWaiter.WaitForEventLoop(
PowerToys.Interop.Constants.WorkspacesHotkeyEvent(),
() =>
{
if (ApplicationIsInFocus())
{
Environment.Exit(0);
}
else
{
if (WindowState == WindowState.Minimized)
{
WindowState = WindowState.Normal;
}
// Get the window handle of the Workspaces Editor window
IntPtr handle = new WindowInteropHelper(this).Handle;
WindowHelpers.BringToForeground(handle);
InvalidateVisual();
}
},
Application.Current.Dispatcher,
cancellationToken.Token);
}
private void OnClosing(object sender, EventArgs e)
{
cancellationToken.Dispose();
App.Current.Shutdown();
}
@@ -67,5 +96,25 @@ namespace WorkspacesEditor
{
ContentFrame.GoBack();
}
public static bool ApplicationIsInFocus()
{
var activatedHandle = NativeMethods.GetForegroundWindow();
if (activatedHandle == IntPtr.Zero)
{
return false; // No window is currently activated
}
var procId = Environment.ProcessId;
int activeProcId;
_ = NativeMethods.GetWindowThreadProcessId(activatedHandle, out activeProcId);
return activeProcId == procId;
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
}

View File

@@ -30,7 +30,7 @@ namespace WorkspacesEditor.Utils
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId);
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int processId);
[DllImport("kernel32.dll")]
public static extern uint GetCurrentThreadId();

View File

@@ -77,7 +77,7 @@ public:
{
if (is_process_running())
{
bring_process_to_front();
sendHotkeyEvent();
}
else
{
@@ -164,6 +164,12 @@ public:
m_toggleEditorEvent = nullptr;
}
if (m_hotkeyEvent)
{
CloseHandle(m_hotkeyEvent);
m_hotkeyEvent = nullptr;
}
delete this;
}
@@ -178,6 +184,12 @@ public:
LoggerHelpers::init_logger(app_key, L"ModuleInterface", "Workspaces");
init_settings();
m_hotkeyEvent = CreateEventW(nullptr, false, false, CommonSharedConstants::WORKSPACES_HOTKEY_EVENT);
if (!m_hotkeyEvent)
{
Logger::warn(L"Failed to create hotkey event. {}", get_last_error_or_default(GetLastError()));
}
m_toggleEditorEvent = CreateDefaultEvent(CommonSharedConstants::WORKSPACES_LAUNCH_EDITOR_EVENT);
if (!m_toggleEditorEvent)
{
@@ -210,23 +222,12 @@ private:
executable_args.append(std::to_wstring(powertoys_pid));
}
void SendCloseEvent()
void sendHotkeyEvent()
{
auto exitEvent = CreateEventW(nullptr, false, false, CommonSharedConstants::WORKSPACES_EXIT_EVENT);
if (!exitEvent)
Logger::trace(L"Signaled hotkey event");
if (!SetEvent(m_hotkeyEvent))
{
Logger::warn(L"Failed to create exitEvent. {}", get_last_error_or_default(GetLastError()));
}
else
{
Logger::trace(L"Signaled exitEvent");
if (!SetEvent(exitEvent))
{
Logger::warn(L"Failed to signal exitEvent. {}", get_last_error_or_default(GetLastError()));
}
ResetEvent(exitEvent);
CloseHandle(exitEvent);
Logger::warn(L"Failed to signal hotkey event. {}", get_last_error_or_default(GetLastError()));
}
}
@@ -244,10 +245,14 @@ private:
ResetEvent(m_toggleEditorEvent);
}
if (m_hotkeyEvent)
{
ResetEvent(m_hotkeyEvent);
}
if (m_hProcess)
{
TerminateProcess(m_hProcess, 0);
SendCloseEvent();
m_hProcess = nullptr;
}
}
@@ -330,23 +335,6 @@ private:
m_hProcess = sei.hProcess;
}
void bring_process_to_front()
{
auto enum_windows = [](HWND hwnd, LPARAM param) -> BOOL {
HANDLE process_handle = reinterpret_cast<HANDLE>(param);
DWORD window_process_id = 0;
GetWindowThreadProcessId(hwnd, &window_process_id);
if (GetProcessId(process_handle) == window_process_id)
{
SetForegroundWindow(hwnd);
}
return TRUE;
};
EnumWindows(enum_windows, (LPARAM)m_hProcess);
}
bool is_process_running() const
{
return WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT;
@@ -362,6 +350,9 @@ private:
// Handle to event used to invoke Workspaces Editor
HANDLE m_toggleEditorEvent;
// Handle to event used when hotkey is invoked
HANDLE m_hotkeyEvent;
// Hotkey to invoke the module
HotkeyEx m_hotkey{
.modifiersMask = MOD_CONTROL | MOD_WIN,