UI state

Stand: 2017-04-12
Autor: Wolfgang R. Schulz

1. Einführung

Seit Windows 2000 Professional bzw. Windows 2000 Server zeigt Windows in der Grundein­stellung das Fokus-Rechteck sowie die Unterstriche unter Hotkeys nicht mehr an. Erst wenn der Anwender die Alt- oder Tab-Taste verwendet, wird diese Anzeige für das betreffende Programm wieder aktiviert.

Dieses Verhalten lässt sich (zumindest unter WinXP) an zwei verschiedenen Stellen abschal­ten, sodass Fokus-Rechteck und Hotkey-Unterstreichungen wieder ständig angezeigt werden:

Passend zu dieser neuen Spielerei gibt es eine Reihe von Window-Messages, die im Folgen­den beschrieben werden. Darüber hinaus bieten diese Messages auch die Möglichkeit, dieses Verhalten für ein Programm gezielt abzuschalten oder anderweitig zu beeinflussen, wenn einem das sinnvoll erscheint.

[Zurück zum Inhaltsverzeichnis]

2. Neue Windows-Messages

2.1. Vorbemerkung

Die Texte in diesem Kapitel sind größtenteils (sinngemäße) Übersetzungen der original Micro­soft-Dokumentation und klingen von daher an der einen oder anderen Stelle womöglich ein we­nig holperig.

2.2. Konstanten

Es gibt folgende Konstanten:

// Messages
#define WM_CHANGEUISTATE  0x0127  // Benachrichtigung: UI state sollte geändert werden.
#define WM_UPDATEUISTATE  0x0128  // Befehl: UI state ändern.
#define WM_QUERYUISTATE   0x0129  // Aktuellen UI state abfragen.

// Operations
#define UIS_SET           1       // Angegebene(s) Element(e) einschalten.
#define UIS_CLEAR         2       // Angegebene(s) Element(e) ausschalten.
#define UIS_INITIALIZE    3       // Angegebene(s) Element(e) gemäß letztem
                                  //   Eingabeereignis ändern (siehe Anmerkungen).

// Elements
#define UISF_HIDEFOCUS    0x1     // Fokus-Rechteck verbergen.
#define UISF_HIDEACCEL    0x2     // Hotkey-Untersreichungen verbergen.
#define UISF_ACTIVE       0x4     // Ein Control als aktives Control zeichnen.

Interessant ist dabei, dass die Logik hinter den Konstanten ein wenig negiert ist. Will man also z.B. das Fokus-Rechteck anzeigen, so muss man für das Element "UISF_HIDEFOCUS" ein "UIS_CLEAR" schicken (also das Verstecken des Fokus-Rechtecks ausschalten).

[Zurück zum Inhaltsverzeichnis]

2.3. WM_CHANGEUISTATE

Diese Nachricht wird gesendet um anzuzeigen, dass der UI state geändert werden soll.

wParam Im unteren Wort wird die gewünschte Operation angegeben, im oberen Wort die Kombination der Elemente, für die die Operation gelten soll.
lParam Wird nicht verwendet und muss 0 sein.
Anm.: Ein Fenster sollte diese Nachricht an sich selbst oder sein Elternfenster schicken, wenn es den UI state aller Fenster in der gleichen Hierarchieebene ändern muss. Die Win­dows-Procedure muss DefWindowProc diese Nachricht behandeln lassen, um sicher­zustellen, dass der gesamte Fensterbaum einen konsistenten UI-state hat. Wenn das Top-Level-Fenster eine WM_CHANGEUISTATE-Nachricht empfängt, sendet es eine WM_UPDATEUISTATE-Nachricht mit den gleichen Parametern an alle seine Kinder­fenster. Wenn das System die WM_UPDATEUISTATE-Nachricht behandelt, führt es die entsprechenden Änderungen am UI state durch.
  Wenn das untere Wort von wParam UIS_INITIALIZE enthält, dann sendet das System die WM_UPDATEUISTATE-Nachricht mit einem UI state, der auf dem letzten Eingabe­ereignis basiert. Wenn die letzte Eingabe zum Beispiel von der Maus kam, versteckt das System die Tastaturhinweise. Wenn der UI state vom Behandeln der WM_CHANGEUISTATE-Nachricht der gleiche ist wie der vorherige, sendet DefWindowProc keine WM_UPDATEUISTATE-Nachricht.

[Zurück zum Inhaltsverzeichnis]

2.4. WM_UPDATEUISTATE

Diese Nachricht wird von einer Anwendung gesendet, um den UI state eines Fensters und aller seiner Kinderfenster zu ändern.

wParam Im unteren Wort wird die gewünschte Operation angegeben, im oberen Wort die Kombination der Elemente, für die die Operation gelten soll.
lParam Wird nicht verwendet und muss 0 sein.
Anm.: Ein Fenster sollte diese Nachricht senden, um den UI state aller seiner Kinderfenster zu ändern. Im Unterschied zur WM_CHANGEUISTATE-Nachricht, welche eine Benach­richtigung ist, führt DefWindowProc beim Behandeln dieser Nachricht die Änderungen am UI state durch und leitet die Änderungen an alle Kinderfenster weiter.
  Die Funktion DefWindowProc aktualisiert den UI state entsprechend dem Wert in wParam. Wenn der UI state angepasst wird, sendet die Funktion diese Nachricht an alle direten Kinderfenster. DefWindowProc sendet diese Nachricht auch, wenn es eine WM_CHANGEUISTATE-Nachricht erhält, die dem System anzeigt, dass ein Kindfenster seinen UI state ändern möchte.

[Zurück zum Inhaltsverzeichnis]

2.5. WM_QUERYUISTATE

Diese Nachricht wird gesendet, um den UI state eines Fensters abzufragen.

wParam Wird nicht verwendet und muss 0 sein.
lParam Wird nicht verwendet und muss 0 sein.

Der Rückgabewert zeigt an, welche Elemente aktiv (gesetzt) sind. Ist kein Element gesetzt, d.h. das Folus-Rechteck ist sichtbar und die Hotkey-Unterstreichungen werden angezeigt, gibt der Aufruf NULL zurück.

[Zurück zum Inhaltsverzeichnis]

3. UI state für ein Fenster gezielt setzen

Um z.B. dafür zu sorgen, dass in einem Fenster das Fokus-Rechteck angezeigt wird, sendet man eine entsprechende WM_UPDATEUISTATE-Nachricht (nicht WM_CHANGEUISTATE!) an dieses Fenster:

myWnd.SendMessage( WM_UPDATEUISTATE, MAKELPARAM( UIS_CLEAR, UISF_HIDEFOCUS ) );

[Zurück zum Inhaltsverzeichnis]

4. Code-Snippets für .net

Da man in .net keinen "nativen" Zugriff auf die Methode SendMessage hat, muss ein wenig ge­bastelt werden. Wie so etwas in aussehen kann, zeigen die folgenden Beispiele.

4.1. C#

namespace myNamespace
{
  public class Form1
  : Form
  {
    class Win32
    {
      // Messages
      public const int WM_UPDATEUISTATE = 0x0128;

      // UI state operations
      public const int UIS_SET = 1;
      public const int UIS_CLEAR = 2;

      // UI state elements
      public const int UISF_HIDEFOCUS = 0x1;

      // helpers
      public static int
      MakeLParam( int loWord, int hiWord )
      {
        return (hiWord << 16) | (loWord & 0xffff);
      }

      // imported windows functions
      [DllImport("user32.dll")]
      public extern static int SendMessage( IntPtr hWnd
                                          , uint msg
                                          , int wParam
                                          , int lParam
                                          );
    }

    // ...

    protected override void
    OnShown( EventArgs e )
    {
      // display focus rectangle
      Win32.SendMessage( this.Handle
                       , Win32.WM_UPDATEUISTATE
                       , Win32.MakeLParam( Win32.UIS_CLEAR, Win32.UISF_HIDEFOCUS )
                       , 0
                       );

      // call base class
      base.OnShown( e );
    }

    // ...

  } // Form

} // Namespace

[Zurück zum Inhaltsverzeichnis]

4.2. VB.net

Public Class Form1
Inherits Form

  Class Win32
    ' messages
    Public Const WM_UPDATEUISTATE As Integer = 296

    ' UI state options
    Public Const UIS_SET   As Integer = 1
    Public Const UIS_CLEAR As Integer = 2

    ' UI state elements
    Public Const UISF_HIDEFOCUS As Integer = 1

    ' helpers
    Public Shared Function MakeLParam( ByVal loWord As Integer _
                                     , ByVal hiWord As Integer _
                                     ) As Integer
      Return ( hiWord << 16 ) Or ( loWord And &Hffff )
    End Function

    ' imported windows functions
    <DllImport( "user32.dll" )>                                 _
    Public Shared Function SendMessage( ByVal hWnd As IntPtr    _
                                      , ByVal msg As UInteger   _
                                      , ByVal wParam As Integer _
                                      , ByVal lParam As Integer _
                                      ) As Integer
    End Function
  End Class

  ' ...

  Protected Overloads Overrides Sub OnShown( ByVal e As EventArgs )

    ' display focus rectangle
    Win32.SendMessage( Me.Handle                                                  _
                     , Win32.WM_UPDATEUISTATE                                     _
                     , Win32.MakeLParam( Win32.UIS_CLEAR, Win32.UISF_HIDEFOCUS )  _
                     , 0                                                          _
                     )

     ' vall base class
     MyBase.OnShown( e );

  End Sub

  ' ...

End Class ' Form1

[Zurück zum Inhaltsverzeichnis]