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.
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.
Related
I have an app that sometimes dynamically adds and removes entries from the start menu (and the Desktop), by placing shortcuts (created with WshShellClass) in the start menu folder (Environment.SpecialFolder.StartMenu). If any such changes occur, I already notify the shell of changes using SHChangeNotify, as described here. Specifically:
private static void _RefreshWindowsDesktop()
{
// http://stackoverflow.com/a/647286/1600
NativeMethods.SHChangeNotify(NativeMethods.HChangeNotifyEventID.SHCNE_ASSOCCHANGED,
NativeMethods.HChangeNotifyFlags.SHCNF_FLUSH,
IntPtr.Zero, IntPtr.Zero);
}
However, on Windows 10, Start Menu search frequently breaks (I've never seen this behavior in Windows Vista or 7), where a new shortcut often doesn't show up for days, and in turn, an old shortcut that has been deleted days ago still shows up as a "search result". This is presumably due to changes to make modern apps appear in the Start Menu alongside classic desktop apps, but I'm not sure; online guides to that effect frankly strike me as voodoo.
Worse, when invoking that shortcut, Windows 10 just does nothing — there's no error indicating that the shortcut points nowhere (because it doesn't exist), nor does Windows learn and remove it afterwards.
So, my hope is there's a method akin SHChangeNotify to explicitly tell Windows 10 to invalidate or rebuild its Start Menu cache, such as asking it to reindex that particular folder, or telling it to manually add/remove an item from the index.
My app is WPF, but if a native method exists, I can detect the OS version and then conditionally invoke it. (Or even write an external Windows 10-specific UWP background app to launch if needed.)
I have an application that uses a low level keyboard hook to capture the user's choice of keyboard shortcuts at a global level to activate the application's main window. Because I want to allow sometimes "odd" shortcuts, like F12 or Ctrl+Ctrl (double tap), I use the hook instead of the RegisterHotkey API function. Until Windows 8, this feature worked great. In Windows 8, some windows prevent my application from receiving the event but only while those windows are in the foreground. The Windows 8 Task Manager is one such offender.
Note that, because the problem only occurs while the offending window is in the foreground, I know that my hook is still registered with the system, just temporarily not reaching my application.
The current code base is C# Framework 4.0; however, I tested the previous code base, which was unmanaged C++ and the problem is the same.
Version of Windows is 8.1 Pro with Media Center
One thing I have not yet tried is moving the hook procedure to a separate DLL. I think I read that the low level keyboard hook procedure must be in a DLL but I have never found this to be true. Before I go to the trouble of trying that, I wanted to ask whether I am missing something easier and more obvious.
Now I understand. Although my application runs under a Windows account that is in the Administrators group, it needs to be launched with "Run as Administrator" in order to avoid being blocked by UIPI.
The solution, at least for me, is to ask a Windows 8 end user to launch my application as Administrator, if s/he wants to use "fancy" global keyboard shortcuts like the ones I mention in the question. (I also allow the user to use "simple" shortcuts, which are implemented with RegisterHotkey() instead of with WH_KEYBOARD_LL and therefore do not suffer from UIPI.)
I want to assign a keyboard shortcut to launch my wpf application like window+E for windows explorer.
How can I achieve it?
I know how to assign keys by creating shortcut link of program.But I want the same behavior on every machine .So that if someone presses a Key my WPF program launches.
You have to create a separate application/service, which will have to register a global hotkey, and you can start your application from that app/service.
See this article for more details on how to set up a global hotkey in c#.
Or you can distribute a shortcut with your application with already set up hotkey, and place it in one of those folders during installation:
%UserProfile%\desktop
%AllUsersProfile%\desktop
%UserProfile%\Start Menu
%AllUsersProfile%\Start Menu
This should also work, as this hotkeys are not stored in the registry, but are scanned at logon (and only from those 4 folders) and are actually kept in memory (source: this thread).
Of course this latter option has the drawback to only work with Alt + Ctrl modifiers, as all shourtcut hotkeys.
The first obvious way is to create a shortcut (.LNK) file in the Start Menu (or on Desktop) and in the Properties dialog to assign a keyboard shortcut (let's say Ctrl + Alt + F10).
However, this way seems to have different issues, such as the shortcut key does not work if I'm pressing it in Firefox in Full Screen Mode (F11) or when playing a Flash video (such as a Youtube video) in Full Screen Mode.
Are there any other built-in ways in Windows to define a custom global shortcut? Maybe in the registry, etc.?
I'd like to avoid using RegisterHotKey because it would require my C# program (even simple .NET programs take a lot of memory) to always run in the background waiting for the hotkey (plus it must start with Windows, etc.)
Or are there third-party programs written in native code that are very small and can be deployed with my program to help me accomplish the task of having a hotkey for my C# program?
Here is a solution from a related Stackoverflow post:
Best way to tackle global hotkey processing in c#?
It links to a blog where you can download a library that does what you are looking for.
I'm writing a software for a call-center. It's somewhat like a ATM program: user can only interactive with it, not with underlying Windows. It takes controls when user logs in to Windows, and when user exits, it logs off Windows.
How can I do that in .NET? A demo will be much appreciated.
Thank you.
Replace the Windows Shell.
By that I mean Explorer.exe, by means of editing the Windows Registry. What this does for you is instead of logging on and the system running Explorer.exe which consists of the Start Menu, Taskbar and other similar features you are familiar with, it only runs your program. There is no desktop, no context menu, no taskbar, or start menu. Thus, making your application "The Shell" or the new "Explorer.exe".
However, by doing this the user still has access to Control+Alt+Delete, so they would still be able to access the Windows Task Manager, which mind you can also be disabled via a simple Registry Key Entry.
This is the most pain free, easiest solution because you don't even have to worry about things such as disabling the WindowsKey or other annoyances.
The registry key to this is as follows:
SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
The name of the value to modify is:
Shell
And you can simply enter the value to be the fully qualified path to your program's executable file. You will only want to do this under HKEY_CURRENT_USER and only for the account that is to run your shell program. So you will need two separate accounts.
Administrator account
This account will just be a normal password protected account that will be used to manage the system
Kiosk account
This account will be the account that is logged on at all times, which runs your custom shell (your application)
Additional Notes
To disable the Task Manager the registry path is as follows:
Software\Microsoft\Windows\CurrentVersion\Policies\System
The name of the value is:
DisableTaskMgr
This is a DWORD value which to enforce the policy must be set to '1'.
What I did was to use DirectX and just use full-screen and exclusive modes, which you can see a small example of here: http://www.directxtutorial.com/tutorial9/b-direct3dbasics/dx9B2.aspx.
This is more work, but it will allow you to do what you want.
Depending on what control you have, there are steps you can do with group policy to limit what people can do on the computer. You can look at how people set up a kiosk application on Windows for some ideas.
What you want to do is run the OS in "kiosk mode".
This entails using the Group Policy Management Console to apply the kiosk mode template - as part of this you register your application as the shell.
As such there is no taskbar, or explorer view to fall back on to. The only way to run the usual shell would be to connect a keyboard to the system - press ctl-alt-delete and run explorer from the taskmanager that pops up.
And you can disable even the standard task manager if users are going to have keyboard access to the console. You will want to implement some kind of launch explorer.exe interface otherwise the system might become a bit difficult to manage :P
You can set your applications window to be always on top and to cover the entire screen. If you exclude buttons that close the window the user must know that ALT+F4 closes the window in order to exit. This has been good enough for me those times I've needed it.