1. Herfried K. Wagner’s VB.Any
  2. .NET
  3. Frequently Asked Questions

Showing the keyboard navigation indicators

Showing the keyboard navigation indicators
<URL:https://dotnet.currifex.org/dotnet/faqs/showaccelerators/en/>
----------------------------------------------------------------------------

Showing the keyboard navigation indicators

Windows 2000 introduced a setting for hiding keyboard accelerator keys.  If
this setting is enabled, the shortcuts are not displayed in underlined font
style.  This setting is documented here:

Keyboard Navigation Indicators Are Not Present
<URL:http://support.microsoft.com/?scid=kb;EN-US;223552>

There is no general managed way in .NET 1.1 to show accelerator keys
underlined automatically.  To do that, a 'WM_CHANGEUISTATE' message with
appropriate data must be sent to the window that should show its accelerator
keys.  One of the parameters passed with the message needs the 'MAKELONG'
macro to combine two 16-bit integers to a 32-bit integer.  In our sample, we
use a trick with a structure to provide an easy and managed way to replace
the 'MAKELONG', 'LOWORD', and 'HIWORD' macros:

\\\
Imports System.Runtime.InteropServices

Public Class WordConverter
    <StructLayout(LayoutKind.Explicit)> _
    Private Structure DWord
        <FieldOffset(0)> Public LongValue As Integer
        <FieldOffset(0)> Public LoWord As Short
        <FieldOffset(2)> Public HiWord As Short
    End Structure

    Private Shared m_DWord As DWord

    Public Shared Function MakeLong( _
        ByVal LoWord As Short, _
        ByVal HiWord As Short _
    ) As Integer
        m_DWord.LoWord = LoWord
        m_DWord.HiWord = HiWord
        Return m_DWord.LongValue
    End Function

    Public Shared Function MakeLong( _
        ByVal LoWord As Integer, _
        ByVal HiWord As Integer _
    ) As Integer
        Return MakeLong(CShort(LoWord), CShort(HiWord))
    End Function

    Public Shared Function LoWord(ByVal LongValue As Integer) As Short
        m_DWord.LongValue = LongValue
        Return m_DWord.LoWord
    End Function

    Public Shared Function HiWord(ByVal LongValue As Integer) As Short
        m_DWord.LongValue = LongValue
        Return m_DWord.HiWord
    End Function
End Class
///

The procedure 'MakeAcceleratorsVisible' takes a controls and makes its
accelerator keys visible:

\\\
Private Declare Auto Function SendMessage Lib "user32.dll" ( _
    ByVal hWnd As IntPtr, _
    ByVal wMsg As Int32, _
    ByVal wParam As IntPtr, _
    ByVal lParam As IntPtr _
) As IntPtr

Public Const WM_CHANGEUISTATE As Int32 = &H127

Public Const UIS_CLEAR As Int32 = 2

Public Const UISF_HIDEACCEL As Int16 = &H2

Public Sub MakeAcceleratorsVisible(ByVal Control As Control)
    SendMessage( _
        Control.Handle, _
        WM_CHANGEUISTATE, _
        New IntPtr(WordConverter.MakeLong(UIS_CLEAR, UISF_HIDEACCEL)), _
        IntPtr.Zero _
    )
End Sub
///

If accelerators should be made visible within a Windows Forms control class,
the code below can be used instead of 'MakeAcceleratorsVisible':

\\\
MyBase.WndProc( _
    Message.Create( _
        Me.Handle, _
        WM_CHANGEUISTATE, _
        New IntPtr(WordConverter.MakeLong(UIS_CLEAR, UISF_HIDEACCEL)), _
        IntPtr.Zero _
    ) _
)
///