Skip to content

Add Win+[0-9] hotkeys to quickly switch between windows #1128

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

noxrim
Copy link

@noxrim noxrim commented Apr 5, 2025

Hi y'all, I've been using RetroBar for a little bit now and I love it, but I noticed it's missing a feature from the regular taskbar where you can press the Windows key + any number to quickly switch between windows in the taskbar. I use this feature a lot so I went ahead and tried implementing it myself.

Currently this is a draft because it has some issues:

  • ApplicationWindow.BringToFront() sometimes fails to bring a window into the foreground and instead makes the app icon flash in the taskbar. This usually happens when RetroBar first starts up and can be fixed by clicking on the Start button (idk why). For some reason this does not happen when a debugger is attached.
  • The hotkeys do not work when the current active foreground window has a higher "privilege level" than RetroBar (e.g. Task Manager). This is because of User Interface Privilege Isolation stuff, which is not explained very well on MSDN, but long story short the app would need to be signed with a special flag in the manifest and bundled in an installer in order to receive keyboard hook events from higher privilege processes, which is a lot of effort for one feature
    • Running RetroBar as admin resolves this, but causes some other issues like tray icons not appearing.
    • Another possible solution for this would be to read keyboard input via DirectInput instead of Windows hooks but I've never worked with DInput before so I'll have to look into that

All the issues above have been fixed, thx @xoascf!

@noxrim
Copy link
Author

noxrim commented Apr 7, 2025

Btw I tried using the regular RegisterHotKey function from user32.dll but the Win+[0-9] hotkeys seem to be reserved by the system and the app fails to register them

@xoascf
Copy link
Collaborator

xoascf commented Apr 7, 2025

Btw I tried using the regular RegisterHotKey function from user32.dll but the Win+[0-9] hotkeys seem to be reserved by the system and the app fails to register them

I think this is possible, we can just kill the explorer.exe process and register the hotkeys, or even better, ask the user beforehand if he want to gracefully restart explorer.exe (if open) with Restart Manager (to restore the session) to allow registration of the hotkeys, and that should do it, even with Task Manager in the foreground!

@xoascf
Copy link
Collaborator

xoascf commented Apr 7, 2025

I found another way to allow us to use RegisterHotKey, now without restarting explorer.exe (or only the first time), and that's just by creating the DisabledHotkeys string with the value "0123456789" in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced, restarting explorer.exe to apply it, and we can finally try to register the hotkeys. But we need to make sure that the user hasn't already created a registry value with that exact name, or try to handle that case.

Source: https://superuser.com/questions/1760485/disabling-three-key-snipping-tool-hotkey-via-disabledhotkeys-registry-value

@xoascf
Copy link
Collaborator

xoascf commented Apr 7, 2025

  • ApplicationWindow.BringToFront() sometimes fails to bring a window into the foreground and instead makes the app icon flash in the taskbar. This usually happens when RetroBar first starts up and can be fixed by clicking on the Start button (idk why). For some reason this does not happen when a debugger is attached.

I suspect #783 (comment) is a similar case, maybe calling AllowSetForegroundWindow() in ApplicationWindow.BringToFront() could fix it?

@noxrim
Copy link
Author

noxrim commented Apr 7, 2025

I found another way to allow us to use RegisterHotKey, now without restarting explorer.exe (or only the first time), and that's just by creating the DisabledHotkeys string with the value "0123456789" in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced, restarting explorer.exe to apply it, and we can finally try to register the hotkeys. But we need to make sure that the user hasn't already created a registry value with that exact name, or try to handle that case.

Wow tysm for finding this! Just tried it out and can confirm the hotkeys are able to be registered after first disabling them in the registry. Also for some reason reading the hotkeys this way magically fixed the first issue.... windows works in mysterious ways

@vindasal
Copy link

Just would like to request that this be an option instead of a default, because it would break Start menu functionality that Open-Shell replicates. In that I have always configured the Windows 95-2000 style Start menu with pinned apps that have names starting with 0-9, so I can do Win+number to instantly open new programs from the keyboard.

I assume it would be optional already, but figured I'd chime in. Not a bad option to have though.

@noxrim
Copy link
Author

noxrim commented Apr 11, 2025

@vindasal Yeah the current implementation adds an option for it in the advanced menu, it's almost ready just gotta fix some stuff
Thanks for commenting btw didn't know you could do that with OpenShell

@noxrim
Copy link
Author

noxrim commented Apr 12, 2025

Big news yall, I found an undocumented(?) window message in Shell_TrayWnd that lets you unregister hotkeys without restarting explorer, here's an example in C:

HWND hTrayWnd = FindWindow(
    /*lpClassName:*/ "Shell_TrayWnd",
    /*lpWindowName:*/ ""
);

SendMessage(
    /*hWnd:*/ hTrayWnd,
    /*uMsg:*/ WM_USER + 231, // 0x4e7
    /*wParam:*/ hotkeyIdToUnregister, // current explorer uses 0x205-0x20e for taskbar hotkeys
    /*lParam:*/ 0
);

I implemented this in my most recent commit, so now explorer restarts are no longer required!*
*The only issue is that there's no way to have explorer re-register the hotkeys after they've been unregistered so currently the user has to manually restart explorer after exiting RetroBar if they want the hotkeys back.
I tried adding a routine to restart explorer when RetroBar shuts down, but couldn't get it to play nicely with ManagedShell... the taskbar would always end up frozen or stuck in autohide mode
But other than that the feature is complete and works as you would expect, let me know what yall think

@xoascf
Copy link
Collaborator

xoascf commented Apr 12, 2025

I've just tested this new method and can confirm that it works like a charm on Windows 8.1 and Windows 11 (with StartAllBack enabled or not), but I haven't been able to check its compatibility with other closed-source taskbar replacements, like the ExplorerPatcher taskbar or Start11. Unfortunately, it doesn't seem to disable the hotkeys on Windows 7 (yes, RetroBar supports this OS). Maybe you really need to restart Explorer there?

@xoascf
Copy link
Collaborator

xoascf commented Apr 12, 2025

@noxrim, check this! It seems that it has a different mapping (for Vista at least?): https://sourceforge.net/p/virtuawin/discussion/257054/thread/cbd60dd2/

@noxrim
Copy link
Author

noxrim commented Apr 14, 2025

Unfortunately, it doesn't seem to disable the hotkeys on Windows 7 (yes, RetroBar supports this OS). Maybe you really need to restart Explorer there?

Wow I can't believe this even runs on Windows 7

@noxrim, check this! It seems that it has a different mapping (for Vista at least?): https://sourceforge.net/p/virtuawin/discussion/257054/thread/cbd60dd2/

Did some testing on multiple versions of Windows, it appears that the hotkey IDs in explorer have shifted over the years, so RetroBar will have to account for this to unregister them properly:

Windows version Taskbar hotkey IDs
Windows 7 SP1 0x202-0x20b
Windows 10 RTM 0x204-0x20d
Current 0x205-0x20e

The taskbar hotkeys are stored sequentially in explorer.exe and registered in order starting from 500 (0x1f4), so I'll try and write an algorithm to find the hotkey table and determine the ID range for the current version of Windows.
image
This will probably be very Stupid & Overengineered but fortunately Stupid & Overengineered is my middle name

@xoascf
Copy link
Collaborator

xoascf commented Apr 14, 2025

That's interesting, on Windows 8.1 and Windows 10 21H2 LTSC the first hotkey ID for this starts at 0x205, Windows 8 at 0x204 and Windows 7 at 0x202, not sure if the updates have made some shift in the values for the same base Windows release/product version.

Also on Vista, the same Win+number hotkeys open the Quick Launch toolbar shortcuts instead of the taskbar items. It may be useful to have them as an option to switch to open them as well.

You could use WindowHelper.FindWindowsTray(WindowHelper.FindWindowsTray(IntPtr.Zero)) to get the real taskbar, using NativeMethods.FindWindow("Shell_TrayWnd", "") is discouraged as it's the same as WindowHelper.FindWindowsTray(IntPtr.Zero), which will actually get the RetroBar taskbar handle instead of the real taskbar (you can still use it since RetroBar redirects some of the messages it receives to the real taskbar anyway), but you can use the real taskbar handle to get the process ID with GetWindowThreadProcessId and then get the process with Process.GetProcessById (you may have to find another way, because if RetroBar is compiled for x86 and you try to run it on a x64 system it will probably fail) to get the info for the current Windows Explorer version (since as you said it might depend more on the explorer.exe rather than the Windows version). It's also possible that the user is trying a different version of explorer.exe than the current Windows version the user is using, so that's another case we should look at.

@noxrim
Copy link
Author

noxrim commented Apr 14, 2025

Alright it works on win7 now, I'll add an option to launch items from Quick Launch and then I'll mark this as ready for review since I'm kinda done with it
Thank u for all the support and ideas @xoascf

@noxrim noxrim marked this pull request as ready for review April 15, 2025 03:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants