Skip to content

Commit

Permalink
[PowerToys Run] Use global HotKey instead of low level keyboard hook (#…
Browse files Browse the repository at this point in the history
…13114)

* [PowerToys Run] Register global HotKey

Using low level keyboard hooks caused focus issues when invoking
PowerToys Run. Using a global HotKey solves this issue.

* Properly unregister hotkey on dispose

* fix spellchecker errors
  • Loading branch information
jaimecbernardo committed Sep 8, 2021
1 parent 2c58bdb commit 5963294
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 49 deletions.
3 changes: 3 additions & 0 deletions .github/actions/spell-check/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ FOF
FOFX
FOLDERID
folderpath
FORCEMINIMIZE
FORCEOFFLINE
foreach
formatetc
Expand Down Expand Up @@ -1891,7 +1892,9 @@ SHOWDEFAULT
SHOWELEVATIONPROMPT
SHOWMAXIMIZED
SHOWMINIMIZED
SHOWMINNOACTIVE
SHOWNA
SHOWNOACTIVATE
SHOWNORMAL
SHOWWINDOW
shtypes
Expand Down
4 changes: 4 additions & 0 deletions src/modules/launcher/Microsoft.Launcher/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,13 @@ class Microsoft_Launcher : public PowertoyModuleIface
enable();
}

/* Before we used the central keyboard hook to trigger PowerToys Run.
* Now, PowerToys Run uses a global hotkey so that it can get focus.
* This means we can't return true so that the hotkey can propagate to PowerToys Run.
Logger::trace("Set POWER_LAUNCHER_SHARED_EVENT");
SetEvent(m_hEvent);
return true;
*/
}

return false;
Expand Down
1 change: 0 additions & 1 deletion src/modules/launcher/PowerLauncher/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ private void OnStartup(object sender, StartupEventArgs e)
bootTime.Stop();
Log.Info(textToLog.ToString(), GetType());
_mainVM.RegisterHotkey();
PowerToysTelemetry.Log.WriteEvent(new LauncherBootEvent() { BootTimeMs = bootTime.ElapsedMilliseconds });
// [Conditional("RELEASE")]
Expand Down
24 changes: 1 addition & 23 deletions src/modules/launcher/PowerLauncher/Helper/EnvironmentHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using Microsoft.Win32.SafeHandles;
using Wox.Plugin.Logger;
Expand All @@ -17,32 +16,11 @@ namespace PowerLauncher.Helper
{
public static class EnvironmentHelper
{
private const string EnvironmentChangeType = "Environment";
private const string Username = "USERNAME";
private const string ProcessorArchitecture = "PROCESSOR_ARCHITECTURE";
private const string Path = "PATH";

[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1801:Review unused parameters", Justification = "Params are required for delegate signature requirements.")]
public static IntPtr ProcessWindowMessages(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
switch ((WM)msg)
{
case WM.SETTINGCHANGE:
string changeType = Marshal.PtrToStringUni(lparam);
if (changeType == EnvironmentChangeType)
{
Log.Info("Reload environment", typeof(EnvironmentHelper));
UpdateEnvironment();
handled = true;
}

break;
}

return IntPtr.Zero;
}

private static void UpdateEnvironment()
internal static void UpdateEnvironment()
{
// Username and process architecture are set by the machine vars, this
// may lead to incorrect values so save off the current values to restore.
Expand Down
42 changes: 42 additions & 0 deletions src/modules/launcher/PowerLauncher/Helper/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ internal static class NativeMethods
[DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

[DllImport("user32")]
internal static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);

[DllImport("user32")]
internal static extern bool UnregisterHotKey(IntPtr hWnd, int id);

[DllImport("user32.dll")]
internal static extern IntPtr SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.dll")]
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

[DllImport("user32.dll", SetLastError = true)]
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);

Expand Down Expand Up @@ -86,6 +98,34 @@ public static string[] CommandLineToArgvW(string cmdLine)
}
}

// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerhotkey
internal enum HOTKEY_MODIFIERS : uint
{
ALT = 0x0001,
CONTROL = 0x0002,
SHIFT = 0x0004,
WIN = 0x0008,
NOREPEAT = 0x4000,
CHECK_FLAGS = 0x000F, // modifiers to compare between keys.
}

// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
internal enum SW : int
{
HIDE = 0x0000,
SHOWNORMAL = 0x0001,
SHOWMINIMIZED = 0x0002,
SHOWMAXIMIZED = 0x0003,
SHOWNOACTIVATE = 0x0004,
SHOW = 0x0005,
MINIMIZE = 0x0006,
SHOWMINNOACTIVE = 0x0007,
SHOWNA = 0x0008,
RESTORE = 0x0009,
SHOWDEFAULT = 0x000A,
FORCEMINIMIZE = 0x000B,
}

internal enum WM
{
NULL = 0x0000,
Expand Down Expand Up @@ -185,6 +225,8 @@ internal enum WM

NCMOUSELEAVE = 0x02A2,

HOTKEY = 0x0312,

DWMCOMPOSITIONCHANGED = 0x031E,
DWMNCRENDERINGCHANGED = 0x031F,
DWMCOLORIZATIONCOLORCHANGED = 0x0320,
Expand Down
1 change: 1 addition & 0 deletions src/modules/launcher/PowerLauncher/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
SourceInitialized="OnSourceInitialized"
Loaded="OnLoaded"
Closing="OnClosing"
Closed="OnClosed"
Background="Transparent"
LocationChanged="OnLocationChanged"
Deactivated="OnDeactivated"
Expand Down
38 changes: 37 additions & 1 deletion src/modules/launcher/PowerLauncher/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
Expand Down Expand Up @@ -96,10 +97,39 @@ private void BringProcessToForeground()
Activate();
}

private const string EnvironmentChangeType = "Environment";

#pragma warning disable CA1801 // Review unused parameters
public IntPtr ProcessWindowMessages(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
#pragma warning restore CA1801 // Review unused parameters
{
switch ((WM)msg)
{
case WM.SETTINGCHANGE:
string changeType = Marshal.PtrToStringUni(lparam);
if (changeType == EnvironmentChangeType)
{
Log.Info("Reload environment", typeof(EnvironmentHelper));
EnvironmentHelper.UpdateEnvironment();
handled = true;
}

break;
case WM.HOTKEY:
handled = _viewModel.ProcessHotKeyMessages(wparam, lparam);
break;
}

return IntPtr.Zero;
}

private void OnSourceInitialized(object sender, EventArgs e)
{
_hwndSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
_hwndSource.AddHook(EnvironmentHelper.ProcessWindowMessages);
_hwndSource.AddHook(ProcessWindowMessages);

// Call RegisterHotKey only after a window handle can be used, so that a global hotkey can be registered.
_viewModel.RegisterHotkey(_hwndSource.Handle);
}

private void OnLoaded(object sender, RoutedEventArgs e)
Expand Down Expand Up @@ -489,5 +519,11 @@ public void Dispose()
Dispose(disposing: true);
GC.SuppressFinalize(this);
}

private void OnClosed(object sender, EventArgs e)
{
_hwndSource.RemoveHook(ProcessWindowMessages);
_hwndSource = null;
}
}
}

0 comments on commit 5963294

Please sign in to comment.