5
votes

QUESTION

How does one programmatically interrogate Win7 to get a list of all currently active global keyboard shortcuts?

Scenario

In many versions of Windows there is the so called "Windows Key", a.k.a. "flag", "start key", et cetera.

Microsoft has a support article "Keyboard shortcuts for Windows" that lists many of these under the section "Microsoft Natural Keyboard keys", as well as many others the do not involve using the "Windows Key" such as the global Ctrl+C, et cetera.

Other keyboard shortcuts can be discovered by accident. For example, Windows Key + Left arrow or Right arrow in Win7 moves the focused window around the display, and, with multiple monitors, from one display to the next.

Still other keyboard shortcuts can be found in the "options" settings, for example, Left-Ctrl+Alt+K is the default for "Show KeePass Window".

Additionally, there may be hardware specific keyboard shortcuts, for example, on my laptop, Fn+F8 toggles speaker muting.

Stolen Keyboard Shortcuts

When Snagit is running, I've configured PrtSc as my shortcut, but when Visual Studio(VS) is running, it steals PrtSc from Snagit.

Two time consuming methods of manually discovered keyboard shortcuts

(a) Global keyboard shortcuts can be discovered by having only the desktop and a couple of windows open and trying various key combinations.

(b) in VS, many VS keyboard shortcuts can be discovered by trying various combinations in the keyboard shortcuts window where, if a combination is already used, VS will notify one about the current usage for that combination.

Two reasons for wanting to discover all currently active global keyboard shortcuts

(a) to avoid annoying accidents like Windows Logo Key+L which locks the computer.

(b) to determine which keys are currently still available for assignment.

1
basically this is hard since there are several ways of implementing "global hotkeys"... you can even use some weird technique to implement conditionally active global hotkeys which are not discoverable programatically for example...Yahia
hehe, linking to "The Windows Key" might not be necessary in a programming community like StackOverflow. ;)Patrick
@ Patrick: good point ... i tend to think about novices and people whose first language is not English ... you're right, i'm guessing most programmers would realize that, even most beginners. B-)gerryLowry
@ Brad Rem ... thnx for the edit ... you've taught me at least two ways to make cleaner posts. much appreciated!gerryLowry
@gerryLowry: If I understand your question, AutoHotkey is not really what you're looking for. You are looking for a program that discovers all the shortcuts currently assigned on the system? Example of such programs are ActiveHotKeys and HotKey explorer. Also I'm curious as to your comment on my answer.Chibueze Opata

1 Answers

2
votes

This is a quite interesting but difficult issue. The Windows Operating System apparently does not offer a direct way to do this via maybe EnumerateHotKeys? However, when the RegisterHotKey function is called, there's a search using __FindHotKey. So it may be possible to hack into this function and find out available hot keys. See this C example. There's also a complete example in assembly languagedownloadable from here but this is likely not to work in Windows Vista +.

Another method is to scan all the shortcuts in the system. This can really take a long time if you want to scan all shortcuts on the system. However you can still grab most of them using the common shortcut directories such as:

%AllUsersProfile%\desktop %UserProfile%\Start Menu %AllUsersProfile%\Start Menu %appdata%\Microsoft\Internet Explorer\Quick Launch %appdata%\Microsoft\Internet Explorer\Quick Launch\User Pinned\StartMenu %appdata%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar

Here's a simple program I just wrote that scans all the shortcuts in the UserProfile directory.

using IWshRuntimeLibrary;//You can download this library from http://www.codeproject.com/KB/dotnet/ShellLink/ShellLink.zip


WshShell wsh = new WshShellClass();
var files = GetFiles(Environment.ExpandEnvironmentVariables("%userprofile%"), "*.lnk*");
foreach (string f in files)
{
    try
    {
        WshShortcut wa = wsh.CreateShortcut(f) as WshShortcut;
        if (wa.Hotkey != "")
        {
            MessageBox.Show("Shortcut Found! - " + wa.Hotkey, wa.TargetPath);
        }
    }
    catch
    {
        continue;
    }
}

Grap the GetFiles method from here if you want to use it. The major advantage of the method is just to avoid directory permission issues.

Good luck.