C# shortcut key underscore not displayed in built application
Asked Answered
B

5

7

I have a small problem with .Net 4.0 ToolStripMenuItem caption.
I want it to underscore the Shortcut (access) key letter in the item text.
I used the ampersand sign in the item text field: '&New map', and it looks fine in the editor:
enter image description here

But, when I build the application, the underscores disappear:
enter image description here

Does anyone know why does it happen and how to make the underscored display in the built form?

Beaufort answered 3/1, 2014 at 12:52 Comment(1)
try pressing alt to bring the underscore back in the running appMelbamelborn
G
7

As mentioned in other answers, this the default behaviour. Accelerators are being shown only after the ALT key is pressed.

However it seems possible to force Windows to display accelerator keys constantly:

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int SystemParametersInfo(int uAction, int uParam, int lpvParam, int fuWinIni);

private const int SPI_SETKEYBOARDCUES = 4107; //100B
private const int SPIF_SENDWININICHANGE = 2;

[STAThread]
static void Main()
{
    // always show accelerator underlines
    SystemParametersInfo(SPI_SETKEYBOARDCUES, 0, 1, 0);

    Application.Run(new MainForm());
}

Found here.

As I've just verified (after ken2k's suggestion in the comments), this unfortunately affects the whole system. So it needs some tweaking: 1) remember current value of SPI_SETKEYBOARDCUES on startup 2) reset the setting to this value on exit, 3) create a domain exception handler, to be sure that the setting always gets reset back.

Unfortunately this behaves this way even if the last parameter is zero, even though documentation says:

This parameter can be zero if you do not want to update the user profile or broadcast the WM_SETTINGCHANGE message

Simple version is of course just:

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int SystemParametersInfo(int uAction, int uParam, int lpvParam, int fuWinIni);

private const int SPI_SETKEYBOARDCUES = 4107; //100B
private const int SPIF_SENDWININICHANGE = 2;

[STAThread]
static void Main()
{
    // always show accelerator underlines
    SystemParametersInfo(SPI_SETKEYBOARDCUES, 0, 1, 0);

    Application.Run(new MainForm());

    SystemParametersInfo(SPI_SETKEYBOARDCUES, 0, 0, 0);
}

In this answer you can find a code example on how to achieve this locally only for your application.

Gert answered 3/1, 2014 at 12:59 Comment(15)
Yes you can do this but it is a bad idea. The user should be allowed to make this choice. The application should not make it for them. Users would be quite rightly upset if they were denied this choice.Extemporaneous
@DavidHeffernan That's not the user's choice, but the choice of application's designer. I think it's OK that you want to make your application look the way YOU want. If you want to involve user in determining the looks of the application, then it's a whole another level - implementing themes etc.Gert
Whole other level? Not at all. The customisation already exists in the ease of access center. Obviously the application designer can choose to disregard the system settings, but in my view that is a mistake.Extemporaneous
@Gert "to make your application look the way YOU want" ==> true, but it's not about the application only, this applies the change to the whole system. If it took a window handle as parameter it would be fine, but changing system parameters for a particular application is not expected from the application.Spongy
@Spongy AFAIK, and as it says in the blog I've linked to, this only changes the behaviour of your application.Gert
@DavidHeffernan In general I agree with you. But in some special cases I can imagine that you really want to do it :)Gert
@Spongy Sorry, you were right. I've just run it, and indeed it affects other applications. I've updated my answer.Gert
Hmm. Remove SPIF_ SENDWININICHANGE.Extemporaneous
@DavidHeffernan Yeah, I've read the docs also. Unfortunately, the 0 doesn't work (msdn.microsoft.com/en-us/library/windows/desktop/…)Gert
There's a clean way to do this for the calling app only, but I can't give the details right now.Extemporaneous
@DavidHeffernan Yeah, that would be nice. I didn't have time also to research this branch ;)Gert
@Gert I added an answer with the details.Extemporaneous
I cannot understand why you accepted this answer given that all the code in it is no good.Extemporaneous
@DavidHeffernan I don't understand it either but perhaps you should comment under the question for OP to be notified.Gert
@Gert asker is notified whenever anyone comments, I thinkExtemporaneous
E
8

That is the default behaviour of Windows. The accelerator keys are hidden unless you invoke the menu with the keyboard. Press ALT to see the accelerators. Note that you can see this behaviour in other programs, for instance try Notepad.

If you wish to change the behaviour on your own machine, you can configure the system to show accelerator keys at all times from the Ease of Access Center. The setting is found under Make the keyboard easier to use and on my Windows 7 machine looks like this:

enter image description here

Note that it is strongly recommended that you let the user make the choice as to whether or not to hide accelerator keys. In other words, your application is already behaving correctly and, in my view, you should make no changes to its current behaviour.

Extemporaneous answered 3/1, 2014 at 12:56 Comment(4)
As far as I know, this wasn't always "the default behaviour of Windows", though. In fact, never knew this was a system setting. Glad I can enable it now.Disrepair
Also note, a lot of these menus are triggered by right mouse button, and not by alt, and pressing alt after right-clicking simply closes that menu, meaning you can never see the shortcuts on these. This always annoyed me in internet browsers.Disrepair
@Disrepair I think that early versions of Windows always displayed accelerator key underlines, but in Windows 2000 they became optionalExtemporaneous
As far as I remember, XP did show them on right click menus though. Also, on Win10 they don't even seem to show when you press the context menu button on the keyboard, while the use of that key generally does imply that you want to navigate the menus keyboard-only.Disrepair
G
7

As mentioned in other answers, this the default behaviour. Accelerators are being shown only after the ALT key is pressed.

However it seems possible to force Windows to display accelerator keys constantly:

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int SystemParametersInfo(int uAction, int uParam, int lpvParam, int fuWinIni);

private const int SPI_SETKEYBOARDCUES = 4107; //100B
private const int SPIF_SENDWININICHANGE = 2;

[STAThread]
static void Main()
{
    // always show accelerator underlines
    SystemParametersInfo(SPI_SETKEYBOARDCUES, 0, 1, 0);

    Application.Run(new MainForm());
}

Found here.

As I've just verified (after ken2k's suggestion in the comments), this unfortunately affects the whole system. So it needs some tweaking: 1) remember current value of SPI_SETKEYBOARDCUES on startup 2) reset the setting to this value on exit, 3) create a domain exception handler, to be sure that the setting always gets reset back.

Unfortunately this behaves this way even if the last parameter is zero, even though documentation says:

This parameter can be zero if you do not want to update the user profile or broadcast the WM_SETTINGCHANGE message

Simple version is of course just:

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int SystemParametersInfo(int uAction, int uParam, int lpvParam, int fuWinIni);

private const int SPI_SETKEYBOARDCUES = 4107; //100B
private const int SPIF_SENDWININICHANGE = 2;

[STAThread]
static void Main()
{
    // always show accelerator underlines
    SystemParametersInfo(SPI_SETKEYBOARDCUES, 0, 1, 0);

    Application.Run(new MainForm());

    SystemParametersInfo(SPI_SETKEYBOARDCUES, 0, 0, 0);
}

In this answer you can find a code example on how to achieve this locally only for your application.

Gert answered 3/1, 2014 at 12:59 Comment(15)
Yes you can do this but it is a bad idea. The user should be allowed to make this choice. The application should not make it for them. Users would be quite rightly upset if they were denied this choice.Extemporaneous
@DavidHeffernan That's not the user's choice, but the choice of application's designer. I think it's OK that you want to make your application look the way YOU want. If you want to involve user in determining the looks of the application, then it's a whole another level - implementing themes etc.Gert
Whole other level? Not at all. The customisation already exists in the ease of access center. Obviously the application designer can choose to disregard the system settings, but in my view that is a mistake.Extemporaneous
@Gert "to make your application look the way YOU want" ==> true, but it's not about the application only, this applies the change to the whole system. If it took a window handle as parameter it would be fine, but changing system parameters for a particular application is not expected from the application.Spongy
@Spongy AFAIK, and as it says in the blog I've linked to, this only changes the behaviour of your application.Gert
@DavidHeffernan In general I agree with you. But in some special cases I can imagine that you really want to do it :)Gert
@Spongy Sorry, you were right. I've just run it, and indeed it affects other applications. I've updated my answer.Gert
Hmm. Remove SPIF_ SENDWININICHANGE.Extemporaneous
@DavidHeffernan Yeah, I've read the docs also. Unfortunately, the 0 doesn't work (msdn.microsoft.com/en-us/library/windows/desktop/…)Gert
There's a clean way to do this for the calling app only, but I can't give the details right now.Extemporaneous
@DavidHeffernan Yeah, that would be nice. I didn't have time also to research this branch ;)Gert
@Gert I added an answer with the details.Extemporaneous
I cannot understand why you accepted this answer given that all the code in it is no good.Extemporaneous
@DavidHeffernan I don't understand it either but perhaps you should comment under the question for OP to be notified.Gert
@Gert asker is notified whenever anyone comments, I thinkExtemporaneous
E
2

Other answers have explained the behaviour that you are observing. I won't repeat any of that.

For the sake of completeness, and to expand on BartoszKP's answer, there is a way to control the hiding of accelerator keys in a way that is local to your application. Specifically that is the WM_UPDATEUISTATE message. Pass UIS_CLEAR and UISF_HIDEACCEL. My answer to this question shows how to do it: Show Hotkeys at All Times.

Extemporaneous answered 3/1, 2014 at 14:29 Comment(1)
As expected, this requires the handle of the target window as parameter. Thanks for the details.Spongy
F
1

Since Windows Vista (I think), shortcuts hints are not displayed by default. You need to press Alt to display them. There is a global system setting to change that behavior, in the accessibility settings.

Fenestella answered 3/1, 2014 at 12:56 Comment(0)
H
0

Windows by default no longer shows these shortcuts. You can re-enable them by going into the "Ease of access center" in Control Panel and in the "Make the keyboard easier to use" section tick the option "Underline keyboard shortcuts and access keys" although obviously this only affects the computer you're on.

Hyacinthus answered 3/1, 2014 at 12:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.